org.sfm.reflect.meta.ObjectClassMeta Maven / Gradle / Ivy
Show all versions of simpleFlatMapper Show documentation
package org.sfm.reflect.meta;
import org.sfm.map.MapperBuildingException;
import org.sfm.reflect.*;
import org.sfm.utils.ErrorHelper;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.*;
public final class ObjectClassMeta implements ClassMeta {
public static final String[] EMPTY_STRING_ARRAY = new String[0];
private final List> properties;
private final List> constructorProperties;
private final List instantiatorDefinitions;
private final ReflectionService reflectService;
private final Type target;
private final Map fieldAliases;
public ObjectClassMeta(Type target, ReflectionService reflectService) throws MapperBuildingException {
this.target = target;
this.reflectService = reflectService;
try {
this.instantiatorDefinitions = reflectService.extractConstructors(target);
this.constructorProperties = Collections.unmodifiableList(listProperties(instantiatorDefinitions));
} catch(Exception e) {
ErrorHelper.rethrow(e);
throw new IllegalStateException();
}
this.fieldAliases = Collections.unmodifiableMap(aliases(reflectService, TypeHelper.toClass(target)));
this.properties = Collections.unmodifiableList(listProperties(reflectService, target));
}
public ObjectClassMeta(Type target,
List instantiatorDefinitions,
List> constructorProperties,
List> properties,
ReflectionService reflectService) {
this.target = target;
this.properties = properties;
this.constructorProperties = constructorProperties;
this.instantiatorDefinitions = instantiatorDefinitions;
this.fieldAliases = Collections.unmodifiableMap(aliases(reflectService, TypeHelper.toClass(target)));
this.reflectService = reflectService;
}
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) {
map.put(SetterHelper.getPropertyNameFromMethodName(method.getName()), alias);
}
}
@Override
public void field(Field field) {
String alias = reflectService.getColumnName(field);
if (alias != null) {
map.put(field.getName(), alias);
}
}
});
return map;
}
private List> listProperties(List instantiatorDefinitions) {
if (instantiatorDefinitions == null) return null;
List> constructorProperties = new ArrayList>();
for(InstantiatorDefinition cd : instantiatorDefinitions) {
for(Parameter param : cd.getParameters()) {
String paramName = param.getName();
constructorProperties.add(constructorMeta(param, paramName));
}
}
return constructorProperties;
}
private ConstructorPropertyMeta constructorMeta(Parameter param, String paramName) {
Class tClass = TypeHelper.toClass(this.target);
return new ConstructorPropertyMeta(paramName, reflectService, param, tClass);
}
private List> listProperties(final ReflectionService reflectService, Type targetType) {
final Class target = TypeHelper.toClass(targetType);
final List> properties = new ArrayList>();
final Map, Type> typeVariableTypeMap = TypeHelper.getTypesMap(targetType, target);
ClassVisitor.visit(target, new FieldAndMethodCallBack() {
@Override
public void method(Method method) {
final String name = method.getName();
if (SetterHelper.methodModifiersMatches(method.getModifiers()) && SetterHelper.isSetter(name)) {
final String propertyName = SetterHelper.getPropertyNameFromMethodName(name);
int indexOfProperty = findProperty(properties, propertyName);
Type resolvedType = method.getGenericParameterTypes()[0];
if (resolvedType instanceof TypeVariable) {
Type mappedType = typeVariableTypeMap.get(resolvedType);
if (mappedType != null) {
resolvedType = mappedType;
}
}
MethodPropertyMeta propertyMeta = new MethodPropertyMeta(propertyName, reflectService, method, resolvedType);
if (indexOfProperty == -1) {
properties.add(propertyMeta);
} else {
properties.set(indexOfProperty, propertyMeta);
}
}
}
@Override
public void field(Field field) {
final String name = field.getName();
if (SetterHelper.fieldModifiersMatches(field.getModifiers())) {
int indexOfProperty = findProperty(properties, name);
if (indexOfProperty == -1) {
Type resolvedType = field.getGenericType();
if (resolvedType instanceof TypeVariable) {
Type mappedType = typeVariableTypeMap.get(resolvedType);
if (mappedType != null) {
resolvedType = mappedType;
}
}
properties.add(new FieldPropertyMeta(field.getName(), reflectService, field, resolvedType));
}
}
}
private int findProperty(List> properties, String name) {
for(int i = 0; i < properties.size(); i++) {
if (properties.get(i).getName().equals(name)) {
return i;
}
}
return -1;
}
});
return properties;
}
protected String getAlias(String propertyName) {
String columnName = this.fieldAliases.get(propertyName);
if (columnName == null) {
columnName = propertyName;
}
return columnName;
}
@Override
public List getInstantiatorDefinitions() {
return instantiatorDefinitions;
}
List> getProperties() {
return properties;
}
List> getConstructorProperties() {
return constructorProperties;
}
@Override
public ReflectionService getReflectionService() {
return reflectService;
}
@Override
public PropertyFinder newPropertyFinder() {
return new ObjectPropertyFinder(this);
}
@Override
public Type getType() {
return target;
}
@Override
public String[] generateHeaders() {
List strings = new ArrayList();
for(PropertyMeta cpm : constructorProperties) {
extractProperties(strings, cpm);
}
for(PropertyMeta cpm : properties) {
extractProperties(strings, cpm);
}
return strings.toArray(EMPTY_STRING_ARRAY);
}
private void extractProperties(List properties, PropertyMeta cpm) {
String prefix = cpm.getName();
ClassMeta> classMeta = cpm.getClassMeta();
if (classMeta != null) {
for(String prop : classMeta.generateHeaders()) {
String name = prop.length() == 0 ? prefix : prefix + "_" + prop;
if (!properties.contains(name)) {
properties.add(name);
}
}
} else {
if (!properties.contains(prefix)) {
properties.add(prefix);
}
}
}
@Override
public boolean isLeaf() {
return false;
}
}