mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-24 23:56:36 +00:00
Fix for #111 - Ebean doesn't honor @Transient for non-primitive array properties
This commit is contained in:
+344
-341
@@ -40,355 +40,358 @@ public class DeployCreateProperties {
|
||||
private final DetermineManyType determineManyType;
|
||||
|
||||
private final TypeManager typeManager;
|
||||
|
||||
public DeployCreateProperties(TypeManager typeManager) {
|
||||
this.typeManager = typeManager;
|
||||
this.determineManyType = new DetermineManyType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the appropriate properties for a bean.
|
||||
*/
|
||||
public void createProperties(DeployBeanDescriptor<?> desc) {
|
||||
|
||||
createProperties(desc, desc.getBeanType(), 0);
|
||||
desc.sortProperties();
|
||||
|
||||
// check the transient properties...
|
||||
Iterator<DeployBeanProperty> it = desc.propertiesAll();
|
||||
|
||||
while (it.hasNext()) {
|
||||
DeployBeanProperty prop = it.next();
|
||||
if (prop.isTransient()){
|
||||
if (prop.getWriteMethod() == null || prop.getReadMethod() == null){
|
||||
// Typically a helper method ... this is expected
|
||||
logger.trace("... transient: "+prop.getFullBeanName());
|
||||
} else {
|
||||
// dubious, possible error...
|
||||
String msg = Message.msg("deploy.property.nofield", desc.getFullName(), prop.getName());
|
||||
logger.warn(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we should ignore this field.
|
||||
* <p>
|
||||
* We want to ignore ebean internal fields and some others as well.
|
||||
* </p>
|
||||
*/
|
||||
private boolean ignoreFieldByName(String fieldName) {
|
||||
if (fieldName.startsWith("_ebean_")){
|
||||
// ignore Ebean internal fields
|
||||
return true;
|
||||
}
|
||||
if (fieldName.startsWith("ajc$instance$")) {
|
||||
// ignore AspectJ internal fields
|
||||
return true;
|
||||
}
|
||||
public DeployCreateProperties(TypeManager typeManager) {
|
||||
this.typeManager = typeManager;
|
||||
this.determineManyType = new DetermineManyType();
|
||||
}
|
||||
|
||||
// we are interested in this field
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* reflect the bean properties from Class. Some of these properties may not
|
||||
* map to database columns.
|
||||
*/
|
||||
private void createProperties(DeployBeanDescriptor<?> desc, Class<?> beanType, int level) {
|
||||
/**
|
||||
* Create the appropriate properties for a bean.
|
||||
*/
|
||||
public void createProperties(DeployBeanDescriptor<?> desc) {
|
||||
|
||||
boolean scalaObject = desc.isScalaObject();
|
||||
createProperties(desc, desc.getBeanType(), 0);
|
||||
desc.sortProperties();
|
||||
|
||||
try {
|
||||
Method[] declaredMethods = beanType.getDeclaredMethods();
|
||||
Field[] fields = beanType.getDeclaredFields();
|
||||
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
|
||||
Field field = fields[i];
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
// not interested in static fields
|
||||
|
||||
} else if (Modifier.isTransient(field.getModifiers())) {
|
||||
// not interested in transient fields
|
||||
logger.trace("Skipping transient field "+field.getName()+" in "+beanType.getName());
|
||||
// check the transient properties...
|
||||
Iterator<DeployBeanProperty> it = desc.propertiesAll();
|
||||
|
||||
} else if (ignoreFieldByName(field.getName())) {
|
||||
// not interested this field (ebean or aspectJ field)
|
||||
|
||||
} else {
|
||||
|
||||
String fieldName = getFieldName(field, beanType);
|
||||
String initFieldName = initCap(fieldName);
|
||||
|
||||
Method getter = findGetter(field, initFieldName, declaredMethods, scalaObject);
|
||||
Method setter = findSetter(field, initFieldName, declaredMethods, scalaObject);
|
||||
|
||||
DeployBeanProperty prop = createProp(level, desc, field, beanType, getter, setter);
|
||||
if (prop == null){
|
||||
// transient annotation on unsupported type
|
||||
|
||||
} else {
|
||||
// set a order that gives priority to inherited properties
|
||||
// push Id/EmbeddedId up and CreatedTimestamp/UpdatedTimestamp down
|
||||
int sortOverride = prop.getSortOverride();
|
||||
prop.setSortOrder((level*10000+100-i + sortOverride));
|
||||
|
||||
DeployBeanProperty replaced = desc.addBeanProperty(prop);
|
||||
if (replaced != null){
|
||||
if (replaced.isTransient()) {
|
||||
// expected for inheritance...
|
||||
} else {
|
||||
String msg = "Huh??? property "+prop.getFullBeanName()+" being defined twice";
|
||||
msg += " but replaced property was not transient? This is not expected?";
|
||||
logger.warn(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> superClass = beanType.getSuperclass();
|
||||
|
||||
if (!superClass.equals(Object.class)) {
|
||||
// recursively add any properties in the inheritance heirarchy
|
||||
// up to the Object.class level...
|
||||
createProperties(desc, superClass, level + 1);
|
||||
}
|
||||
|
||||
} catch (PersistenceException ex) {
|
||||
throw ex;
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new PersistenceException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the first letter of the string upper case.
|
||||
*/
|
||||
private String initCap(String str){
|
||||
if (str.length() > 1){
|
||||
return Character.toUpperCase(str.charAt(0))+str.substring(1);
|
||||
} else {
|
||||
// only a single char
|
||||
return str.toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean spec field name (trim of "is" from boolean types)
|
||||
*/
|
||||
private String getFieldName(Field field, Class<?> beanType){
|
||||
|
||||
String name = field.getName();
|
||||
|
||||
if ((Boolean.class.equals(field.getType()) || boolean.class.equals(field.getType()))
|
||||
&& name.startsWith("is") && name.length() > 2){
|
||||
|
||||
// it is a boolean type field starting with "is"
|
||||
char c = name.charAt(2);
|
||||
if (Character.isUpperCase(c)){
|
||||
String msg = "trimming off 'is' from boolean field name "+name+" in class "+beanType.getName();
|
||||
logger.info(msg);
|
||||
|
||||
return name.substring(2);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a public non-static getter method that matches this field (according to bean-spec rules).
|
||||
*/
|
||||
private Method findGetter(Field field, String initFieldName, Method[] declaredMethods, boolean scalaObject){
|
||||
|
||||
String methGetName = "get"+initFieldName;
|
||||
String methIsName = "is"+initFieldName;
|
||||
String scalaGet = field.getName();
|
||||
|
||||
for (int i = 0; i < declaredMethods.length; i++) {
|
||||
Method m = declaredMethods[i];
|
||||
if ((scalaObject && m.getName().equals(scalaGet))
|
||||
|| m.getName().equals(methGetName) || m.getName().equals(methIsName)){
|
||||
|
||||
Class<?>[] params = m.getParameterTypes();
|
||||
if (params.length == 0){
|
||||
if (field.getType().equals(m.getReturnType())){
|
||||
int modifiers = m.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
|
||||
// we find it...
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a public non-static setter method that matches this field (according to bean-spec rules).
|
||||
*/
|
||||
private Method findSetter(Field field, String initFieldName, Method[] declaredMethods, boolean scalaObject){
|
||||
|
||||
String methSetName = "set"+initFieldName;
|
||||
String scalaSetName = field.getName()+"_$eq";
|
||||
|
||||
for (int i = 0; i < declaredMethods.length; i++) {
|
||||
Method m = declaredMethods[i];
|
||||
|
||||
if ((scalaObject && m.getName().equals(scalaSetName))
|
||||
|| m.getName().equals(methSetName)){
|
||||
|
||||
Class<?>[] params = m.getParameterTypes();
|
||||
if (params.length == 1 && field.getType().equals(params[0])){
|
||||
if (void.class.equals(m.getReturnType())){
|
||||
int modifiers = m.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private DeployBeanProperty createManyType(DeployBeanDescriptor<?> desc, Class<?> targetType, ManyType manyType) {
|
||||
|
||||
try {
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(targetType);
|
||||
if (scalarType != null) {
|
||||
return new DeployBeanPropertySimpleCollection(desc, targetType, scalarType, manyType);
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
logger.debug("expected non-scalar type"+e.getMessage());
|
||||
}
|
||||
//TODO: Handle Collection of CompoundType and Embedded Type
|
||||
return new DeployBeanPropertyAssocMany(desc, targetType, manyType);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field) {
|
||||
|
||||
Class<?> propertyType = field.getType();
|
||||
Class<?> innerType = propertyType;
|
||||
|
||||
// check for Collection type (list, set or map)
|
||||
ManyType manyType = determineManyType.getManyType(propertyType);
|
||||
|
||||
if (manyType != null) {
|
||||
// List, Set or Map based object
|
||||
Class<?> targetType = determineTargetType(field);
|
||||
if (targetType == null){
|
||||
Transient transAnnotation = field.getAnnotation(Transient.class);
|
||||
if (transAnnotation != null) {
|
||||
// not supporting this field (generic type used)
|
||||
return null;
|
||||
}
|
||||
logger.warn("Could not find parameter type (via reflection) on "+desc.getFullName()+" "+field.getName());
|
||||
}
|
||||
return createManyType(desc, targetType, manyType);
|
||||
}
|
||||
|
||||
if (innerType.isEnum() || innerType.isPrimitive()){
|
||||
return new DeployBeanProperty(desc, propertyType, null, null);
|
||||
}
|
||||
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(innerType);
|
||||
if (scalarType != null) {
|
||||
return new DeployBeanProperty(desc, propertyType, scalarType, null);
|
||||
}
|
||||
|
||||
CtCompoundType<?> compoundType = typeManager.getCompoundType(innerType);
|
||||
if (compoundType != null) {
|
||||
return new DeployBeanPropertyCompound(desc, propertyType, compoundType, null);
|
||||
}
|
||||
|
||||
if (!isTransientField(field)){
|
||||
try {
|
||||
CheckImmutableResponse checkImmutable = typeManager.checkImmutable(innerType);
|
||||
if (checkImmutable.isImmutable()){
|
||||
if (checkImmutable.isCompoundType()){
|
||||
// use reflection to support compound immutable value objects
|
||||
typeManager.recursiveCreateScalarDataReader(innerType);
|
||||
compoundType = typeManager.getCompoundType(innerType);
|
||||
if (compoundType != null) {
|
||||
return new DeployBeanPropertyCompound(desc, propertyType, compoundType, null);
|
||||
}
|
||||
|
||||
} else {
|
||||
// use reflection to support simple immutable value objects
|
||||
scalarType = typeManager.recursiveCreateScalarTypes(innerType);
|
||||
return new DeployBeanProperty(desc, propertyType, scalarType, null);
|
||||
}
|
||||
}
|
||||
} catch (Exception e){
|
||||
logger.error("Error with " + desc + " field:" + field.getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return new DeployBeanPropertyAssocOne(desc, propertyType);
|
||||
}
|
||||
|
||||
private boolean isTransientField(Field field) {
|
||||
|
||||
Transient t = field.getAnnotation(Transient.class);
|
||||
return (t != null);
|
||||
}
|
||||
|
||||
private DeployBeanProperty createProp(int level, DeployBeanDescriptor<?> desc, Field field, Class<?> beanType, Method getter, Method setter) {
|
||||
|
||||
DeployBeanProperty prop = createProp(desc, field);
|
||||
if (prop == null){
|
||||
// transient annotation on unsupported type
|
||||
return null;
|
||||
while (it.hasNext()) {
|
||||
DeployBeanProperty prop = it.next();
|
||||
if (prop.isTransient()) {
|
||||
if (prop.getWriteMethod() == null || prop.getReadMethod() == null) {
|
||||
// Typically a helper method ... this is expected
|
||||
logger.trace("... transient: " + prop.getFullBeanName());
|
||||
} else {
|
||||
prop.setOwningType(beanType);
|
||||
prop.setName(field.getName());
|
||||
|
||||
// the getter or setter could be null if we are using
|
||||
// javaagent type enhancement. If we are using subclass
|
||||
// generation then we do need to find the getter and setter
|
||||
prop.setReadMethod(getter);
|
||||
prop.setWriteMethod(setter);
|
||||
prop.setField(field);
|
||||
return prop;
|
||||
// dubious, possible error...
|
||||
String msg = Message.msg("deploy.property.nofield", desc.getFullName(), prop.getName());
|
||||
logger.warn(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if we should ignore this field.
|
||||
* <p>
|
||||
* We want to ignore ebean internal fields and some others as well.
|
||||
* </p>
|
||||
*/
|
||||
private boolean ignoreFieldByName(String fieldName) {
|
||||
if (fieldName.startsWith("_ebean_")) {
|
||||
// ignore Ebean internal fields
|
||||
return true;
|
||||
}
|
||||
if (fieldName.startsWith("ajc$instance$")) {
|
||||
// ignore AspectJ internal fields
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the type of the List,Set or Map. Not been set explicitly so
|
||||
* determine this from ParameterizedType.
|
||||
*/
|
||||
private Class<?> determineTargetType(Field field) {
|
||||
|
||||
Type genType = field.getGenericType();
|
||||
if (genType instanceof ParameterizedType) {
|
||||
ParameterizedType ptype = (ParameterizedType) genType;
|
||||
// we are interested in this field
|
||||
return false;
|
||||
}
|
||||
|
||||
Type[] typeArgs = ptype.getActualTypeArguments();
|
||||
if (typeArgs.length == 1) {
|
||||
// probably a Set or List
|
||||
if (typeArgs[0] instanceof Class<?>){
|
||||
return (Class<?>) typeArgs[0];
|
||||
}
|
||||
//throw new RuntimeException("Unexpected Parameterised Type? "+typeArgs[0]);
|
||||
return null;
|
||||
}
|
||||
if (typeArgs.length == 2) {
|
||||
// this is probably a Map
|
||||
if (typeArgs[1] instanceof ParameterizedType) {
|
||||
// not supporting ParameterizedType on Map.
|
||||
return null;
|
||||
}
|
||||
return (Class<?>) typeArgs[1];
|
||||
}
|
||||
}
|
||||
// if targetType is null, then must be set in annotations
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* reflect the bean properties from Class. Some of these properties may not map to database
|
||||
* columns.
|
||||
*/
|
||||
private void createProperties(DeployBeanDescriptor<?> desc, Class<?> beanType, int level) {
|
||||
|
||||
boolean scalaObject = desc.isScalaObject();
|
||||
|
||||
try {
|
||||
Method[] declaredMethods = beanType.getDeclaredMethods();
|
||||
Field[] fields = beanType.getDeclaredFields();
|
||||
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
|
||||
Field field = fields[i];
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
// not interested in static fields
|
||||
|
||||
} else if (Modifier.isTransient(field.getModifiers())) {
|
||||
// not interested in transient fields
|
||||
logger.trace("Skipping transient field " + field.getName() + " in " + beanType.getName());
|
||||
|
||||
} else if (ignoreFieldByName(field.getName())) {
|
||||
// not interested this field (ebean or aspectJ field)
|
||||
|
||||
} else {
|
||||
|
||||
String fieldName = getFieldName(field, beanType);
|
||||
String initFieldName = initCap(fieldName);
|
||||
|
||||
Method getter = findGetter(field, initFieldName, declaredMethods, scalaObject);
|
||||
Method setter = findSetter(field, initFieldName, declaredMethods, scalaObject);
|
||||
|
||||
DeployBeanProperty prop = createProp(level, desc, field, beanType, getter, setter);
|
||||
if (prop == null) {
|
||||
// transient annotation on unsupported type
|
||||
|
||||
} else {
|
||||
// set a order that gives priority to inherited properties
|
||||
// push Id/EmbeddedId up and CreatedTimestamp/UpdatedTimestamp down
|
||||
int sortOverride = prop.getSortOverride();
|
||||
prop.setSortOrder((level * 10000 + 100 - i + sortOverride));
|
||||
|
||||
DeployBeanProperty replaced = desc.addBeanProperty(prop);
|
||||
if (replaced != null) {
|
||||
if (replaced.isTransient()) {
|
||||
// expected for inheritance...
|
||||
} else {
|
||||
String msg = "Huh??? property " + prop.getFullBeanName() + " being defined twice";
|
||||
msg += " but replaced property was not transient? This is not expected?";
|
||||
logger.warn(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> superClass = beanType.getSuperclass();
|
||||
|
||||
if (!superClass.equals(Object.class)) {
|
||||
// recursively add any properties in the inheritance heirarchy
|
||||
// up to the Object.class level...
|
||||
createProperties(desc, superClass, level + 1);
|
||||
}
|
||||
|
||||
} catch (PersistenceException ex) {
|
||||
throw ex;
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new PersistenceException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the first letter of the string upper case.
|
||||
*/
|
||||
private String initCap(String str) {
|
||||
if (str.length() > 1) {
|
||||
return Character.toUpperCase(str.charAt(0)) + str.substring(1);
|
||||
} else {
|
||||
// only a single char
|
||||
return str.toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean spec field name (trim of "is" from boolean types)
|
||||
*/
|
||||
private String getFieldName(Field field, Class<?> beanType) {
|
||||
|
||||
String name = field.getName();
|
||||
|
||||
if ((Boolean.class.equals(field.getType()) || boolean.class.equals(field.getType())) && name.startsWith("is")
|
||||
&& name.length() > 2) {
|
||||
|
||||
// it is a boolean type field starting with "is"
|
||||
char c = name.charAt(2);
|
||||
if (Character.isUpperCase(c)) {
|
||||
String msg = "trimming off 'is' from boolean field name " + name + " in class " + beanType.getName();
|
||||
logger.info(msg);
|
||||
|
||||
return name.substring(2);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a public non-static getter method that matches this field (according to bean-spec rules).
|
||||
*/
|
||||
private Method findGetter(Field field, String initFieldName, Method[] declaredMethods, boolean scalaObject) {
|
||||
|
||||
String methGetName = "get" + initFieldName;
|
||||
String methIsName = "is" + initFieldName;
|
||||
String scalaGet = field.getName();
|
||||
|
||||
for (int i = 0; i < declaredMethods.length; i++) {
|
||||
Method m = declaredMethods[i];
|
||||
if ((scalaObject && m.getName().equals(scalaGet)) || m.getName().equals(methGetName)
|
||||
|| m.getName().equals(methIsName)) {
|
||||
|
||||
Class<?>[] params = m.getParameterTypes();
|
||||
if (params.length == 0) {
|
||||
if (field.getType().equals(m.getReturnType())) {
|
||||
int modifiers = m.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
|
||||
// we find it...
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a public non-static setter method that matches this field (according to bean-spec rules).
|
||||
*/
|
||||
private Method findSetter(Field field, String initFieldName, Method[] declaredMethods, boolean scalaObject) {
|
||||
|
||||
String methSetName = "set" + initFieldName;
|
||||
String scalaSetName = field.getName() + "_$eq";
|
||||
|
||||
for (int i = 0; i < declaredMethods.length; i++) {
|
||||
Method m = declaredMethods[i];
|
||||
|
||||
if ((scalaObject && m.getName().equals(scalaSetName)) || m.getName().equals(methSetName)) {
|
||||
|
||||
Class<?>[] params = m.getParameterTypes();
|
||||
if (params.length == 1 && field.getType().equals(params[0])) {
|
||||
if (void.class.equals(m.getReturnType())) {
|
||||
int modifiers = m.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private DeployBeanProperty createManyType(DeployBeanDescriptor<?> desc, Class<?> targetType, ManyType manyType) {
|
||||
|
||||
try {
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(targetType);
|
||||
if (scalarType != null) {
|
||||
return new DeployBeanPropertySimpleCollection(desc, targetType, scalarType, manyType);
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
logger.debug("expected non-scalar type" + e.getMessage());
|
||||
}
|
||||
// TODO: Handle Collection of CompoundType and Embedded Type
|
||||
return new DeployBeanPropertyAssocMany(desc, targetType, manyType);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field) {
|
||||
|
||||
Class<?> propertyType = field.getType();
|
||||
Class<?> innerType = propertyType;
|
||||
|
||||
// check for Collection type (list, set or map)
|
||||
ManyType manyType = determineManyType.getManyType(propertyType);
|
||||
|
||||
if (manyType != null) {
|
||||
// List, Set or Map based object
|
||||
Class<?> targetType = determineTargetType(field);
|
||||
if (targetType == null) {
|
||||
Transient transAnnotation = field.getAnnotation(Transient.class);
|
||||
if (transAnnotation != null) {
|
||||
// not supporting this field (generic type used)
|
||||
return null;
|
||||
}
|
||||
logger.warn("Could not find parameter type (via reflection) on " + desc.getFullName() + " " + field.getName());
|
||||
}
|
||||
return createManyType(desc, targetType, manyType);
|
||||
}
|
||||
|
||||
if (innerType.isEnum() || innerType.isPrimitive()) {
|
||||
return new DeployBeanProperty(desc, propertyType, null, null);
|
||||
}
|
||||
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(innerType);
|
||||
if (scalarType != null) {
|
||||
return new DeployBeanProperty(desc, propertyType, scalarType, null);
|
||||
}
|
||||
|
||||
CtCompoundType<?> compoundType = typeManager.getCompoundType(innerType);
|
||||
if (compoundType != null) {
|
||||
return new DeployBeanPropertyCompound(desc, propertyType, compoundType, null);
|
||||
}
|
||||
|
||||
if (isTransientField(field)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
CheckImmutableResponse checkImmutable = typeManager.checkImmutable(innerType);
|
||||
if (checkImmutable.isImmutable()) {
|
||||
if (checkImmutable.isCompoundType()) {
|
||||
// use reflection to support compound immutable value objects
|
||||
typeManager.recursiveCreateScalarDataReader(innerType);
|
||||
compoundType = typeManager.getCompoundType(innerType);
|
||||
if (compoundType != null) {
|
||||
return new DeployBeanPropertyCompound(desc, propertyType, compoundType, null);
|
||||
}
|
||||
|
||||
} else {
|
||||
// use reflection to support simple immutable value objects
|
||||
scalarType = typeManager.recursiveCreateScalarTypes(innerType);
|
||||
return new DeployBeanProperty(desc, propertyType, scalarType, null);
|
||||
}
|
||||
}
|
||||
|
||||
return new DeployBeanPropertyAssocOne(desc, propertyType);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error with " + desc + " field:" + field.getName(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isTransientField(Field field) {
|
||||
|
||||
Transient t = field.getAnnotation(Transient.class);
|
||||
return (t != null);
|
||||
}
|
||||
|
||||
private DeployBeanProperty createProp(int level, DeployBeanDescriptor<?> desc, Field field, Class<?> beanType,
|
||||
Method getter, Method setter) {
|
||||
|
||||
DeployBeanProperty prop = createProp(desc, field);
|
||||
if (prop == null) {
|
||||
// transient annotation on unsupported type
|
||||
return null;
|
||||
} else {
|
||||
prop.setOwningType(beanType);
|
||||
prop.setName(field.getName());
|
||||
|
||||
// the getter or setter could be null if we are using
|
||||
// javaagent type enhancement. If we are using subclass
|
||||
// generation then we do need to find the getter and setter
|
||||
prop.setReadMethod(getter);
|
||||
prop.setWriteMethod(setter);
|
||||
prop.setField(field);
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the type of the List,Set or Map. Not been set explicitly so determine this from
|
||||
* ParameterizedType.
|
||||
*/
|
||||
private Class<?> determineTargetType(Field field) {
|
||||
|
||||
Type genType = field.getGenericType();
|
||||
if (genType instanceof ParameterizedType) {
|
||||
ParameterizedType ptype = (ParameterizedType) genType;
|
||||
|
||||
Type[] typeArgs = ptype.getActualTypeArguments();
|
||||
if (typeArgs.length == 1) {
|
||||
// probably a Set or List
|
||||
if (typeArgs[0] instanceof Class<?>) {
|
||||
return (Class<?>) typeArgs[0];
|
||||
}
|
||||
// throw new RuntimeException("Unexpected Parameterised Type? "+typeArgs[0]);
|
||||
return null;
|
||||
}
|
||||
if (typeArgs.length == 2) {
|
||||
// this is probably a Map
|
||||
if (typeArgs[1] instanceof ParameterizedType) {
|
||||
// not supporting ParameterizedType on Map.
|
||||
return null;
|
||||
}
|
||||
return (Class<?>) typeArgs[1];
|
||||
}
|
||||
}
|
||||
// if targetType is null, then must be set in annotations
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user