org.simpleflatmapper.reflect.meta.ObjectClassMeta Maven / Gradle / Ivy
Show all versions of sfm-reflect Show documentation
package org.simpleflatmapper.reflect.meta;
import org.simpleflatmapper.reflect.getter.GetterHelper;
import org.simpleflatmapper.reflect.getter.NullGetter;
import org.simpleflatmapper.reflect.impl.ParamNameDeductor;
import org.simpleflatmapper.reflect.*;
import org.simpleflatmapper.reflect.setter.NullSetter;
import org.simpleflatmapper.reflect.setter.SetterHelper;
import org.simpleflatmapper.reflect.InstantiatorDefinition;
import org.simpleflatmapper.util.Consumer;
import org.simpleflatmapper.util.ErrorHelper;
import org.simpleflatmapper.util.ListCollector;
import org.simpleflatmapper.util.Predicate;
import org.simpleflatmapper.util.TypeHelper;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;
public final class ObjectClassMeta implements ClassMeta {
private final List> properties;
private final List> constructorProperties;
private final List instantiatorDefinitions;
private final ReflectionService reflectService;
private final Type target;
private final Map fieldAliases;
private final boolean needTransformer;
public ObjectClassMeta(Type target, ReflectionService reflectService) {
this(target, null, reflectService);
}
public ObjectClassMeta(Type target, Member builderInstantiator, ReflectionService reflectService) {
try {
this.target = target;
this.needTransformer = TypeHelper.toClass(target).isAnnotationPresent(ModifyInjectedParams.class);
this.reflectService = reflectService;
this.instantiatorDefinitions = reflectService.extractInstantiator(target, builderInstantiator);
this.constructorProperties = listConstructorProperties(instantiatorDefinitions, reflectService.builderIgnoresNullValues());
this.fieldAliases = Collections.unmodifiableMap(aliases(reflectService, TypeHelper.toClass(target)));
this.properties = Collections.unmodifiableList(listProperties(reflectService, target));
} catch(Exception e) {
ErrorHelper.rethrow(e);
throw new IllegalStateException();
}
}
public ObjectClassMeta(Type target,
List instantiatorDefinitions,
List> constructorProperties,
Map fieldAliases,
List> properties,
ReflectionService reflectService,
boolean needTransformer) {
this.target = target;
this.reflectService = reflectService;
this.instantiatorDefinitions = instantiatorDefinitions;
this.constructorProperties = constructorProperties;
this.fieldAliases = fieldAliases;
this.properties = properties;
this.needTransformer = needTransformer;
}
@Override
public ClassMeta withReflectionService(ReflectionService reflectionService) {
return new ObjectClassMeta(target,
instantiatorDefinitions,
withReflectionServiceConstructor(constructorProperties, reflectionService),
fieldAliases,
withReflectionService(properties, reflectionService),
reflectionService,
needTransformer
);
}
private Map aliases(final ReflectionService reflectService, Class target) {
final Map map = new HashMap();
ClassVisitor.visit(target, new FieldAndMethodCallBack() {
@Override
public void method(Method method) {
String alias = reflectService.getColumnName(method);
if (alias != null && !alias.isEmpty()) {
final String name;
if (SetterHelper.isSetter(method)) {
name = SetterHelper.getPropertyNameFromMethodName(method.getName());
} else if (GetterHelper.isGetter(method)) {
name = GetterHelper.getPropertyNameFromMethodName(method.getName());
} else {
throw new IllegalArgumentException("Annotation on non accessor method " + method);
}
map.put(name, alias);
}
}
@Override
public void field(Field field) {
String alias = reflectService.getColumnName(field);
if (alias != null && !alias.isEmpty()) {
map.put(field.getName(), alias);
}
}
});
return map;
}
private List> listConstructorProperties(List instantiatorDefinitions, boolean builderIgnoresNullValues) {
if (instantiatorDefinitions == null) return null;
List> constructorProperties = new ArrayList>();
ParamNameDeductor paramNameDeductor = null;
for(InstantiatorDefinition cd : instantiatorDefinitions) {
for(org.simpleflatmapper.reflect.Parameter param : cd.getParameters()) {
String paramName = param.getName();
if (paramName == null) {
if (paramNameDeductor == null) {
paramNameDeductor = new ParamNameDeductor(TypeHelper.toClass(target));
}
paramName = paramNameDeductor.findParamName(cd, param, builderIgnoresNullValues);
}
constructorProperties.add(constructorMeta(param, paramName, cd));
}
}
return constructorProperties;
}
private ConstructorPropertyMeta constructorMeta(org.simpleflatmapper.reflect.Parameter param, String paramName, InstantiatorDefinition instantiatorDefinition) {
return new ConstructorPropertyMeta(paramName, target, reflectService, param, instantiatorDefinition, null);
}
private List> listProperties(final ReflectionService reflectService, final Type targetType) {
final Class target = TypeHelper.toClass(targetType);
final List> properties = new ArrayList>();
final Map, Type> typeVariableTypeMap = TypeHelper.getTypesMap(targetType);
ClassVisitor.visit(target, new FieldAndMethodCallBack() {
@Override
public void method(Method method) {
final String name = method.getName();
if (SetterHelper.isSetter(method)) {
final String propertyName = SetterHelper.getPropertyNameFromMethodName(name);
Setter methodSetter = reflectService.getObjectSetterFactory().getMethodSetter(method);
register(propertyName,
method.getGenericParameterTypes()[0],
ScoredGetter.nullGetter(),
ScoredSetter.ofMethod(method, methodSetter), getDefineProperties(method));
} else if (GetterHelper.isGetter(method)) {
final String propertyName = GetterHelper.getPropertyNameFromMethodName(name);
Getter methodGetter = reflectService.getObjectGetterFactory().getMethodGetter(method);
register(propertyName,
method.getGenericReturnType(),
ScoredGetter.ofMethod(method, methodGetter),
ScoredSetter.nullSetter(), getDefineProperties(method));
if ((method.getReturnType().equals(boolean.class)
|| method.getReturnType().equals(Boolean.class))
&& name.startsWith("is")
) {
// is there a constructor on the name
if (findProperty(constructorProperties, name, method.getReturnType()) != -1) {
register(name,
method.getGenericReturnType(),
ScoredGetter.ofMethod(method, methodGetter),
ScoredSetter.nullSetter(), getDefineProperties(method));
};
}
}
}
@SuppressWarnings("unchecked")
private void register(String propertyName, Type type, ScoredGetter getter, ScoredSetter setter, Object[] defineProperties) {
if (type instanceof TypeVariable) {
Type mappedType = typeVariableTypeMap.get(type);
if (mappedType != null) {
type = mappedType;
}
}
int indexOfProperty = findProperty(constructorProperties, propertyName, type);
if (indexOfProperty != -1) {
ConstructorPropertyMeta constructorPropertyMeta = (ConstructorPropertyMeta) constructorProperties.get(indexOfProperty);
if (defineProperties != null && defineProperties.length > 0) {
constructorPropertyMeta = constructorPropertyMeta.defineProperties(defineProperties);
constructorProperties.set(indexOfProperty, constructorPropertyMeta);
}
if (getter != null && GetterHelper.isCompatible(constructorPropertyMeta.getPropertyType(), type)) {
constructorPropertyMeta = constructorPropertyMeta.getter(getter);
constructorProperties.set(indexOfProperty, constructorPropertyMeta);
}
if (setter != null && SetterHelper.isCompatible(constructorPropertyMeta.getPropertyType(), type)) {
constructorPropertyMeta = constructorPropertyMeta.setter(setter);
constructorProperties.set(indexOfProperty, constructorPropertyMeta);
}
} else {
indexOfProperty = findProperty(properties, propertyName, type);
if (indexOfProperty == -1) {
properties.add(new ObjectPropertyMeta(propertyName, targetType, reflectService, type, getter, setter, defineProperties));
} else {
ObjectPropertyMeta meta = (ObjectPropertyMeta) properties.get(indexOfProperty);
ScoredGetter compatibleGetter = GetterHelper.isCompatible(meta.getPropertyType(), type) ? getter : ScoredGetter.nullGetter();
ScoredSetter compatibleSetter = SetterHelper.isCompatible(meta.getPropertyType(), type) ? setter : ScoredSetter.nullSetter();
properties.set(indexOfProperty,
meta.getterSetter(compatibleGetter, compatibleSetter, defineProperties));
}
}
}
@Override
public void field(Field field) {
final String name = field.getName();
if (!Modifier.isStatic(field.getModifiers())) {
if (Modifier.isPublic(field.getModifiers())) {
ScoredGetter getter = ScoredGetter.ofField(field, reflectService.getObjectGetterFactory().getFieldGetter(field));
ScoredSetter setter;
if (!Modifier.isFinal(field.getModifiers())) {
setter = ScoredSetter.ofField(field, reflectService.getObjectSetterFactory().getFieldSetter(field));
} else {
setter = ScoredSetter.nullSetter();
}
register(name,
field.getGenericType(),
getter,
setter, getDefineProperties(field));
} else {
register(name, field.getGenericType(), ScoredGetter.nullGetter(), ScoredSetter.nullSetter(), getDefineProperties(field));
}
}
}
private int findProperty(List extends PropertyMeta> properties, String name, Type type) {
for(int i = 0; i < properties.size(); i++) {
PropertyMeta propertyMeta = properties.get(i);
String propertyMetaName = propertyMeta.getName();
if (propertyMetaName != null && propertyMetaName.equals(name) &&
TypeHelper.isAssignable(propertyMeta.getPropertyType(), type)) {
return i;
}
}
return -1;
}
});
// filter out private field only;
for(Iterator> it = properties.iterator(); it.hasNext();) {
PropertyMeta propertyMeta = it.next();
if (NullSetter.isNull(propertyMeta.getSetter()) && NullGetter.isNull(propertyMeta.getGetter())) {
it.remove();
}
}
return properties;
}
private Object[] getDefineProperties(AnnotatedElement annotatedElement) {
ListCollector