org.sfm.map.impl.AbstractFieldMapperMapperBuilder Maven / Gradle / Ivy
package org.sfm.map.impl;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.sfm.jdbc.impl.getter.MapperGetterAdapter;
import org.sfm.map.FieldMapperErrorHandler;
import org.sfm.map.Mapper;
import org.sfm.map.MapperBuilderErrorHandler;
import org.sfm.map.MapperBuildingException;
import org.sfm.map.impl.fieldmapper.FieldMapperImpl;
import org.sfm.reflect.Getter;
import org.sfm.reflect.Instantiator;
import org.sfm.reflect.InstantiatorFactory;
import org.sfm.reflect.ReflectionService;
import org.sfm.reflect.Setter;
import org.sfm.reflect.TypeHelper;
import org.sfm.reflect.asm.ConstructorParameter;
import org.sfm.reflect.meta.ClassMeta;
import org.sfm.reflect.meta.ConstructorPropertyMeta;
import org.sfm.reflect.meta.PropertyMeta;
import org.sfm.reflect.meta.SubPropertyMeta;
import org.sfm.utils.ForEachCallBack;
public abstract class AbstractFieldMapperMapperBuilder> {
private final Type source;
protected final Type target;
private final FieldMapperFactory fieldMapperFactory;
private final GetterFactory getterFactory;
private final PropertyMappingsBuilder propertyMappingsBuilder;
protected final ReflectionService reflectionService;
protected final Map aliases;
protected final Map> customMappings;
protected final List> mappers;
private MapperBuilderErrorHandler mapperBuilderErrorHandler = new RethrowMapperBuilderErrorHandler();
private FieldMapperErrorHandler fieldMapperErrorHandler;
public AbstractFieldMapperMapperBuilder(final Type target, final Type source, final ClassMeta classMeta,
GetterFactory getterFactory, FieldMapperFactory fieldMapperFactory,
Map aliases, Map> customMappings
) throws MapperBuildingException {
this.source = source;
this.getterFactory = getterFactory;
this.fieldMapperFactory = fieldMapperFactory;
this.propertyMappingsBuilder = new PropertyMappingsBuilder(classMeta);
this.target = target;
this.reflectionService = classMeta.getReflectionService();
this.aliases = aliases;
this.customMappings = customMappings;
this.mappers = new ArrayList>();
}
protected Class getTargetClass() {
return TypeHelper.toClass(target);
}
@SuppressWarnings("unchecked")
protected Instantiator getInstantiator() throws MapperBuildingException {
InstantiatorFactory instantiatorFactory = reflectionService.getInstantiatorFactory();
if (TypeHelper.isArray(target)) {
return instantiatorFactory.getArrayInstantiator(TypeHelper.toClass(TypeHelper.getComponentType(target)), propertyMappingsBuilder.forEachProperties(new CalculateMaxIndex()).maxIndex + 1);
} else {
if (!reflectionService.isAsmPresent()) {
try {
return (Instantiator) instantiatorFactory.getInstantiator(TypeHelper.toClass(source), propertyMappingsBuilder.getPropertyFinder().getClassToInstantiate());
} catch(Exception e) {
throw new MapperBuildingException(e.getMessage(), e);
}
} else {
try {
return instantiatorFactory.getInstantiator(TypeHelper.toClass(source), propertyMappingsBuilder.getPropertyFinder().getEligibleConstructorDefinitions(), constructorInjections());
} catch(Exception e) {
throw new MapperBuildingException(e.getMessage(), e);
}
}
}
}
private Map> constructorInjections() {
final Map> injections = new HashMap>();
propertyMappingsBuilder.forEachConstructorProperties(new ForEachCallBack>() {
@Override
public void handle(PropertyMapping t, int index) {
PropertyMeta pm = t.getPropertyMeta();
ConstructorPropertyMeta cProp = (ConstructorPropertyMeta) pm;
ConstructorParameter constructorParameter = cProp.getConstructorParameter();
injections.put(constructorParameter, getterFor(t.getColumnKey(), constructorParameter.getType()));
}
});
final Map> builderToInject = new HashMap>();
propertyMappingsBuilder.forEachSubProperties(new ForEachCallBack>() {
@Override
public void handle(PropertyMapping t, int index) {
PropertyMeta pm = t.getPropertyMeta();
SubPropertyMeta subProp = (SubPropertyMeta) pm;
PropertyMeta propOwner = subProp.getOwnerProperty();
if (propOwner.isConstructorProperty()) {
ConstructorParameter param = ((ConstructorPropertyMeta)propOwner).getConstructorParameter();
AbstractFieldMapperMapperBuilder builder = builderToInject.get(param);
if (builder == null) {
builder = newSubBuilder(propOwner.getType(), propOwner.getClassMeta());
builderToInject.put(param, builder);
}
addPropertyoBuilder(t, subProp, builder);
}
}
@SuppressWarnings("unchecked")
private void addPropertyoBuilder(PropertyMapping t,
SubPropertyMeta subProp,
AbstractFieldMapperMapperBuilder builder) {
((AbstractFieldMapperMapperBuilder)builder).addMapping(t.getColumnKey(), ((SubPropertyMeta)subProp).getSubProperty());
}
});
for(Entry> e : builderToInject.entrySet()) {
injections.put(e.getKey(), newSubMapperGetter(e.getValue()));
}
return injections;
}
@SuppressWarnings("unchecked")
protected void addMapping(K columnKey) {
if (customMappings != null && customMappings.containsKey(columnKey.getName().toUpperCase())) {
mappers.add(
new KeyFieldMapperCouple(columnKey,
(FieldMapper) customMappings.get(columnKey.getName().toUpperCase())));
} else {
K alias = alias(columnKey);
if (! propertyMappingsBuilder.addProperty(alias)) {
mapperBuilderErrorHandler.propertyNotFound(target, columnKey.getName());
}
}
}
private K alias(K key) {
if (aliases == null || aliases.isEmpty()) {
return key;
}
String alias = aliases.get(key.getName().toUpperCase());
if (alias == null) {
return key;
}
return key.alias(alias);
}
protected void addMapping(K columnKey, PropertyMeta prop) {
propertyMappingsBuilder.addProperty(columnKey, prop);
}
private Getter newSubMapperGetter(AbstractFieldMapperMapperBuilder value) {
return new MapperGetterAdapter(value.mapper());
}
@SuppressWarnings("unchecked")
public final FieldMapper[] fields() {
final List> fields = new ArrayList>();
final Map, AbstractFieldMapperMapperBuilder> buildersByOwner =
new HashMap, AbstractFieldMapperMapperBuilder>();
propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() {
final Map> builders = new HashMap>();
@Override
public void handle(PropertyMapping t, int index) {
if (t == null) return;
PropertyMeta meta = t.getPropertyMeta();
if (meta == null) return;
if (meta.isSubProperty()) {
addSubProperty(t, (SubPropertyMeta) meta, t.getColumnKey());
} else if (!meta.isConstructorProperty()) {
fields.add(newFieldMapper(t));
}
}
private void addSubProperty(PropertyMapping pm, SubPropertyMeta subPropertyMeta, K key) {
PropertyMeta propertyOwner = subPropertyMeta.getOwnerProperty();
if (!propertyOwner.isConstructorProperty()) {
AbstractFieldMapperMapperBuilder builder = (AbstractFieldMapperMapperBuilder) builders.get(propertyOwner.getName());
if (builder == null) {
builder = (AbstractFieldMapperMapperBuilder) newSubBuilder(propertyOwner.getType(), propertyOwner.getClassMeta());
builders.put(propertyOwner.getName(), builder);
buildersByOwner.put(pm, builder);
}
builder.addMapping(key, ((SubPropertyMeta)subPropertyMeta).getSubProperty());
}
}
});
for(Entry, AbstractFieldMapperMapperBuilder> e : buildersByOwner.entrySet()) {
SubPropertyMeta prop = (SubPropertyMeta) e.getKey().getPropertyMeta();
fields.add(newSubFieldMapper(prop.getOwnerProperty(), e.getValue(), e.getKey().getColumnKey()));
}
for(KeyFieldMapperCouple keyFieldMapper: mappers) {
FieldMapper mapper = keyFieldMapper.getFieldMapper();
if (fieldMapperErrorHandler != null) {
mapper = new FieldErrorHandlerMapper(keyFieldMapper.getKey(), mapper, fieldMapperErrorHandler);
}
fields.add(mapper);
}
return fields.toArray(new FieldMapper[fields.size()]);
}
@SuppressWarnings("unchecked")
private FieldMapper newSubFieldMapper(PropertyMeta prop,
AbstractFieldMapperMapperBuilder builder, K key) {
Setter setter = (Setter) prop.getSetter();
return newFieldMapper(builder, setter, key);
}
@SuppressWarnings("unchecked")
private FieldMapper newFieldMapper(
AbstractFieldMapperMapperBuilder builder,
Setter setter, K key) {
FieldMapper fm = new FieldMapperImpl((Getter) newSubMapperGetter(builder), setter);
if (fieldMapperErrorHandler != null) {
fm = new FieldErrorHandlerMapper(key, fm, fieldMapperErrorHandler);
}
return fm;
}
protected FieldMapper newFieldMapper(PropertyMapping t) {
FieldMapper fieldMapper = fieldMapperFactory.newFieldMapper(t.getPropertyMeta().getType(), t.getPropertyMeta().getSetter(), t.getColumnKey(), fieldMapperErrorHandler, mapperBuilderErrorHandler);
if (fieldMapperErrorHandler != null) {
fieldMapper = new FieldErrorHandlerMapper(t.getColumnKey(), fieldMapper, fieldMapperErrorHandler);
}
return fieldMapper;
}
private Getter getterFor(K key, Type paramType) {
Getter getter = getterFactory.newGetter(paramType, key);
if (getter == null) {
mapperBuilderErrorHandler.getterNotFound("Could not find getter for " + key + " type " + paramType);
}
return getter;
}
protected abstract AbstractFieldMapperMapperBuilder newSubBuilder(Type type, ClassMeta classMeta);
public abstract Mapper mapper();
protected void setMapperBuilderErrorHandler(MapperBuilderErrorHandler errorHandler) {
this.mapperBuilderErrorHandler = errorHandler;
}
protected void setFieldMapperErrorHandler(
FieldMapperErrorHandler errorHandler) {
this.fieldMapperErrorHandler = errorHandler;
}
}