package org.simpleflatmapper.map.fieldmapper; import org.simpleflatmapper.converter.Converter; import org.simpleflatmapper.converter.ConverterService; import org.simpleflatmapper.map.property.FieldMapperColumnDefinition; import org.simpleflatmapper.map.context.MappingContextFactoryBuilder; import org.simpleflatmapper.map.mapper.PropertyMapping; import org.simpleflatmapper.reflect.Getter; import org.simpleflatmapper.reflect.Instantiator; import org.simpleflatmapper.reflect.InstantiatorDefinition; import org.simpleflatmapper.reflect.getter.GetterWithConverter; import org.simpleflatmapper.reflect.instantiator.InstantiatorDefinitions; import org.simpleflatmapper.reflect.getter.InstantiatorGetter; import org.simpleflatmapper.reflect.ObjectGetterFactory; import org.simpleflatmapper.reflect.ObjectSetterFactory; import org.simpleflatmapper.reflect.Setter; import org.simpleflatmapper.reflect.getter.GetterFactory; import org.simpleflatmapper.reflect.meta.ClassMeta; import org.simpleflatmapper.reflect.meta.PropertyMeta; import org.simpleflatmapper.map.FieldKey; import org.simpleflatmapper.map.FieldMapper; import org.simpleflatmapper.map.MapperBuilderErrorHandler; import org.simpleflatmapper.util.ErrorDoc; import org.simpleflatmapper.util.Supplier; import org.simpleflatmapper.util.TypeHelper; import java.lang.reflect.Type; import java.util.Collection; import java.util.HashSet; public final class ConstantSourceFieldMapperFactoryImpl<S, K extends FieldKey<K>> implements ConstantSourceFieldMapperFactory<S,K> { private final GetterFactory<? super S, ? super K> getterFactory; private final ConverterService converterService; private final Type sourceType; public ConstantSourceFieldMapperFactoryImpl(GetterFactory<? super S, ? super K> getterFactory, ConverterService converterService, Type sourceType) { this.getterFactory = getterFactory; this.converterService = converterService; this.sourceType = sourceType; } @SuppressWarnings("unchecked") private <T, P> FieldMapper<S, T> primitiveIndexedFieldMapper(final Class<P> type, final Setter<? super T, ? super P> setter, final Getter<? super S, ? extends P> getter) { if (type.equals(Boolean.TYPE)) { return new BooleanFieldMapper<S, T>( ObjectGetterFactory.<S>toBooleanGetter((Getter<S, ? extends Boolean>) getter), ObjectSetterFactory.<T>toBooleanSetter((Setter<T, ? super Boolean>) setter)); } else if (type.equals(Integer.TYPE)) { return new IntFieldMapper<S, T>( ObjectGetterFactory.<S>toIntGetter((Getter<S, ? extends Integer>) getter), ObjectSetterFactory.<T>toIntSetter((Setter<T, ? super Integer>) setter)); } else if (type.equals(Long.TYPE)) { return new LongFieldMapper<S, T>( ObjectGetterFactory.<S>toLongGetter((Getter<S, ? extends Long>) getter), ObjectSetterFactory.<T>toLongSetter((Setter<T, ? super Long>) setter)); } else if (type.equals(Float.TYPE)) { return new FloatFieldMapper<S, T>( ObjectGetterFactory.<S>toFloatGetter((Getter<S, ? extends Float>) getter), ObjectSetterFactory.<T>toFloatSetter((Setter<T, ? super Float>) setter)); } else if (type.equals(Double.TYPE)) { return new DoubleFieldMapper<S, T>( ObjectGetterFactory.<S>toDoubleGetter((Getter<S, ? extends Double>) getter), ObjectSetterFactory.<T>toDoubleSetter((Setter<T, ? super Double>) setter)); } else if (type.equals(Byte.TYPE)) { return new ByteFieldMapper<S, T>( ObjectGetterFactory.<S>toByteGetter((Getter<S, ? extends Byte>) getter), ObjectSetterFactory.<T>toByteSetter((Setter<T, ? super Byte>) setter)); } else if (type.equals(Character.TYPE)) { return new CharacterFieldMapper<S, T>( ObjectGetterFactory.<S>toCharGetter((Getter<S, ? extends Character>) getter), ObjectSetterFactory.<T>toCharacterSetter((Setter<T, ? super Character>) setter)); } else if (type.equals(Short.TYPE)) { return new ShortFieldMapper<S, T>( ObjectGetterFactory.<S>toShortGetter((Getter<S, ? extends Short>) getter), ObjectSetterFactory.<T>toShortSetter((Setter<T, ? super Short>) setter)); } else { throw new UnsupportedOperationException("Type " + type + " is not primitive"); } } @Override @SuppressWarnings("unchecked") public <T, P> FieldMapper<S, T> newFieldMapper(PropertyMapping<T, P, K, FieldMapperColumnDefinition<K>> propertyMapping, MappingContextFactoryBuilder contextFactoryBuilder, MapperBuilderErrorHandler mappingErrorHandler) { final PropertyMeta<T, P> propertyMeta = propertyMapping.getPropertyMeta(); final Type propertyType = propertyMeta.getPropertyType(); final Setter<? super T, ? super P> setter = propertyMeta.getSetter(); final K key = propertyMapping.getColumnKey(); final Class<P> type = TypeHelper.toClass(propertyType); Getter<? super S, ? extends P> getter = getGetterFromSource(key, propertyMapping.getPropertyMeta().getPropertyType(), propertyMapping.getColumnDefinition(), propertyMeta.getPropertyClassMetaSupplier()); if (getter == null) { mappingErrorHandler.accessorNotFound("Could not find getter for " + key + " type " + propertyType + " path " + propertyMapping.getPropertyMeta().getPath() + " See " + ErrorDoc.toUrl("CSFM_GETTER_NOT_FOUND")); return null; } else { if (type.isPrimitive() ) { return this.<T, P>primitiveIndexedFieldMapper(type, setter, getter); } return new FieldMapperImpl<S, T, P>(getter, setter); } } @Override public <P> Getter<? super S, ? extends P> getGetterFromSource(K columnKey, Type propertyType, FieldMapperColumnDefinition<K> columnDefinition, Supplier<ClassMeta<P>> propertyClassMetaSupplier) { @SuppressWarnings("unchecked") Getter<? super S, ? extends P> getter = (Getter<? super S, ? extends P>) columnDefinition.getCustomGetterFrom(sourceType); if (getter == null) { GetterFactory<? super S, K> customGetterFactory = (GetterFactory<? super S, K>) columnDefinition.getCustomGetterFactoryFrom(sourceType); if (customGetterFactory != null) { getter = customGetterFactory.newGetter(propertyType, columnKey, columnDefinition.properties()); } } if (getter == null) { getter = getterFactory.newGetter(propertyType, columnKey, columnDefinition.properties()); } // try to identify constructor that we could build from if (getter == null) { getter = lookForAlternativeGetter(propertyClassMetaSupplier.get(), columnKey, columnDefinition, new HashSet<Type>()); } return getter; } private <P, J> Getter<? super S, ? extends P> lookForAlternativeGetter(ClassMeta<P> classMeta, K key, FieldMapperColumnDefinition<K> columnDefinition, Collection<Type> types) { // look for converter Type propertyType = classMeta.getType(); Type sourceType = key.getType(propertyType); Object[] properties = columnDefinition.properties(); Converter<? super J, ? extends P> converter = converterService.findConverter(sourceType, propertyType, properties); if (converter != null) { Getter<? super S, ? extends J> getter = getterFactory.newGetter(sourceType, key, properties); return new GetterWithConverter<S, J, P>(converter, getter); } return lookForInstantiatorGetter(classMeta, key, columnDefinition, types); } public <P> Getter<? super S, ? extends P> lookForInstantiatorGetter(ClassMeta<P> classMeta, K key, FieldMapperColumnDefinition<K> columnDefinition, Collection<Type> types) { InstantiatorDefinitions.CompatibilityScorer scorer = InstantiatorDefinitions.getCompatibilityScorer(key); InstantiatorDefinition id = InstantiatorDefinitions.lookForCompatibleOneArgument(classMeta.getInstantiatorDefinitions(), scorer); if (id != null) { return getGettetInstantiator(classMeta, id, key, columnDefinition, types); } return null; } private <T, P> Getter<? super S, ? extends P> getGettetInstantiator( ClassMeta<P> classMeta, InstantiatorDefinition id, K key, FieldMapperColumnDefinition<K> columnDefinition, Collection<Type> types) { Instantiator<? super T, ? extends P> instantiator = classMeta.getReflectionService().getInstantiatorFactory().getOneArgIdentityInstantiator(id); final Type sourceType = id.getParameters()[0].getGenericType(); Getter<? super S, ? extends T> subGetter = getterFactory.newGetter(sourceType, key, columnDefinition); if (subGetter == null) { if (types.contains(sourceType)) { // loop circuit cutter return null; } types.add(sourceType); subGetter = lookForInstantiatorGetter(classMeta.getReflectionService().<T>getClassMeta(sourceType), key, columnDefinition, types); } if (subGetter != null) { return new InstantiatorGetter<T, S, P>(instantiator, subGetter); } else return null; } }