All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.simpleflatmapper.map.mapper.DefaultConstantSourceMapperBuilder Maven / Gradle / Ivy

Go to download

Java library to map flat record - ResultSet, csv - to java object with minimum configuration and low footprint.

The newest version!
package org.simpleflatmapper.map.mapper;

import org.simpleflatmapper.converter.Context;
import org.simpleflatmapper.converter.ConverterService;
import org.simpleflatmapper.map.FieldKey;
import org.simpleflatmapper.map.FieldMapperErrorHandler;
import org.simpleflatmapper.map.MapperBuildingException;
import org.simpleflatmapper.map.MappingContext;
import org.simpleflatmapper.map.SourceFieldMapper;
import org.simpleflatmapper.map.asm.MapperAsmFactory;
import org.simpleflatmapper.map.context.KeyAndPredicate;
import org.simpleflatmapper.map.context.KeySourceGetter;
import org.simpleflatmapper.map.context.MappingContextFactory;
import org.simpleflatmapper.map.getter.ContextualGetter;
import org.simpleflatmapper.map.getter.ContextualGetterFactory;
import org.simpleflatmapper.map.fieldmapper.MapperFieldMapper;
import org.simpleflatmapper.map.getter.NullContextualGetter;
import org.simpleflatmapper.map.impl.DiscriminatorPropertyFinder;
import org.simpleflatmapper.map.impl.GetterMapper;
import org.simpleflatmapper.map.impl.JoinUtils;
import org.simpleflatmapper.map.property.*;
import org.simpleflatmapper.map.context.MappingContextFactoryBuilder;
import org.simpleflatmapper.map.fieldmapper.ConstantSourceFieldMapperFactory;
import org.simpleflatmapper.map.fieldmapper.ConstantSourceFieldMapperFactoryImpl;
import org.simpleflatmapper.reflect.BiInstantiator;
import org.simpleflatmapper.reflect.BuilderInstantiatorDefinition;
import org.simpleflatmapper.reflect.InstantiatorDefinition;
import org.simpleflatmapper.reflect.InstantiatorFactory;
import org.simpleflatmapper.reflect.Parameter;
import org.simpleflatmapper.reflect.ReflectionService;
import org.simpleflatmapper.reflect.Setter;
import org.simpleflatmapper.reflect.asm.AsmFactory;
import org.simpleflatmapper.reflect.getter.ConstantGetter;
import org.simpleflatmapper.reflect.BuilderBiInstantiator;
import org.simpleflatmapper.reflect.meta.ClassMeta;
import org.simpleflatmapper.reflect.meta.ConstructorPropertyMeta;
import org.simpleflatmapper.reflect.meta.PropertyFinder;
import org.simpleflatmapper.reflect.meta.PropertyMeta;
import org.simpleflatmapper.reflect.meta.SelfPropertyMeta;
import org.simpleflatmapper.reflect.meta.SubPropertyMeta;
import org.simpleflatmapper.map.FieldMapper;
import org.simpleflatmapper.map.SourceMapper;
import org.simpleflatmapper.map.MapperConfig;
import org.simpleflatmapper.reflect.setter.NullSetter;
import org.simpleflatmapper.util.*;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.*;

import static org.simpleflatmapper.util.Asserts.requireNonNull;
import static org.simpleflatmapper.util.ErrorDoc.CSFM_GETTER_NOT_FOUND;

public final class DefaultConstantSourceMapperBuilder> extends ConstantSourceMapperBuilder {

    private static final FieldKey[] FIELD_KEYS = new FieldKey[0];
    public static final FieldMapper[] EMPTY_FIELD_MAPPERS = new FieldMapper[0];

    private final Type target;

	private final ConstantSourceFieldMapperFactory fieldMapperFactory;

	protected final PropertyMappingsBuilder propertyMappingsBuilder;
	protected final ReflectionService reflectionService;

	private final List> additionalMappers = new ArrayList>();

    private final MapperSource mapperSource;
    private final MapperConfig mapperConfig;
    protected final MappingContextFactoryBuilder mappingContextFactoryBuilder;

    private final KeyFactory keyFactory;

    public DefaultConstantSourceMapperBuilder(
            final MapperSource mapperSource,
            final ClassMeta classMeta,
            final MapperConfig mapperConfig,
            MappingContextFactoryBuilder mappingContextFactoryBuilder,
            KeyFactory keyFactory, 
            PropertyFinder propertyFinder) throws MapperBuildingException {
        final ContextualGetterFactory getterFactory = mapperSource.getterFactory();
        
        this.mapperSource = requireNonNull("fieldMapperSource", mapperSource);
        this.mapperConfig = requireNonNull("mapperConfig", mapperConfig);
        this.mappingContextFactoryBuilder = mappingContextFactoryBuilder;
        this.fieldMapperFactory = new ConstantSourceFieldMapperFactoryImpl(getterFactory, ConverterService.getInstance(), mapperSource.source());
        this.keyFactory = keyFactory;
        this.propertyMappingsBuilder =
                PropertyMappingsBuilder.of(classMeta, mapperConfig, new PropertyMappingsBuilder.PropertyPredicateFactory() {
                    @Override
                    public PropertyFinder.PropertyFilter predicate(final K k, final Object[] properties, final List accessorNotFounds) {
                        if (k != null) {
                            final MappingContextFactoryBuilder mappingContextFactoryBuilder1 = new MappingContextFactoryBuilder(new KeySourceGetter() {
                                @Override
                                public Object getValue(K key, Object source) throws Exception {
                                    return null;
                                }
                            }, !mapperConfig.unorderedJoin());
                            Predicate> propertyMetaPredicate = new Predicate>() {
                                @Override
                                public boolean test(PropertyMeta propertyMeta) {

                                    if (!PropertyWithSetterOrConstructor.INSTANCE.test(propertyMeta))
                                        return false;

                                    try {
                                        ContextualGetter getterFromSource = getContextualGetter(propertyMeta);
                                        if (NullContextualGetter.isNull(getterFromSource)) {
                                            accessorNotFounds.add(new PropertyMappingsBuilder.AccessorNotFound(k, propertyMeta.getPath(), propertyMeta.getPropertyType(), CSFM_GETTER_NOT_FOUND, propertyMeta));
                                            return false;
                                        }
                                        return true;
                                    } catch (Exception e) {
                                        return false;
                                    }
                                }

                                public  ContextualGetter getContextualGetter(PropertyMeta propertyMeta) {
                                    return fieldMapperFactory.

getGetterFromSource( k, propertyMeta.getPropertyType(), FieldMapperColumnDefinition.of(properties), propertyMeta.getPropertyClassMetaSupplier(), mappingContextFactoryBuilder1); } }; return new PropertyFinder.PropertyFilter(propertyMetaPredicate, PropertyWithSetterOrConstructor.INSTANCE); } return new PropertyFinder.PropertyFilter(PropertyWithSetterOrConstructor.INSTANCE); } }, propertyFinder); this.target = requireNonNull("classMeta", classMeta).getType(); this.reflectionService = requireNonNull("classMeta", classMeta).getReflectionService(); } @Override @SuppressWarnings("unchecked") public final ConstantSourceMapperBuilder addMapping(K key, final ColumnDefinition columnDefinition) { final ColumnDefinition composedDefinition = columnDefinition.compose(mapperConfig.columnDefinitions().getColumnDefinition(key)); final K mappedColumnKey = composedDefinition.rename(key); FieldMapperProperty prop = columnDefinition.lookFor(FieldMapperProperty.class); if (prop != null) { addMapper((FieldMapper) prop.getFieldMapper()); } else { PropertyMapping propertyMapping = propertyMappingsBuilder.addProperty(mappedColumnKey, composedDefinition); if (propertyMapping != null) { ColumnDefinition effectiveColumnDefinition = propertyMapping.getColumnDefinition(); if (effectiveColumnDefinition.isKey() && effectiveColumnDefinition.keyAppliesTo().test(propertyMapping.getPropertyMeta())) { Predicate predicate = buildKeyPredicate(propertyMapping.getPropertyMeta(), effectiveColumnDefinition.keyAppliesTo()); mappingContextFactoryBuilder.addKey(new KeyAndPredicate(mappedColumnKey, predicate)); } else if (effectiveColumnDefinition.isInferNull() && effectiveColumnDefinition.inferNullsAppliesTo().test(propertyMapping.getPropertyMeta())) { Predicate predicate = buildKeyPredicate(propertyMapping.getPropertyMeta(), effectiveColumnDefinition.inferNullsAppliesTo()); mappingContextFactoryBuilder.addInferNull(new KeyAndPredicate(mappedColumnKey, predicate)); } } } return this; } @Override @SuppressWarnings("unchecked") public ContextualSourceFieldMapperImpl mapper() { SourceFieldMapper mapper = sourceFieldMapper(); return new ContextualSourceFieldMapperImpl(mappingContextFactoryBuilder.build(), mapper); } @Override public SourceFieldMapper sourceFieldMapper() { // look for property with a default value property but no definition. mapperConfig .columnDefinitions() .forEach( DefaultValueProperty.class, new BiConsumer, DefaultValueProperty>() { @Override public void accept(Predicate predicate, DefaultValueProperty columnProperty) { if (propertyMappingsBuilder.hasKey(predicate)){ return; } if (predicate instanceof Named) { String name = ((Named)predicate).getName(); GetterProperty getterProperty = new GetterProperty(new ConstantGetter(columnProperty.getValue()), mapperSource.source(), columnProperty.getValue().getClass()); final FieldMapperColumnDefinition columnDefinition = FieldMapperColumnDefinition.identity().add(columnProperty, getterProperty); propertyMappingsBuilder.addPropertyIfPresent(keyFactory.newKey(name, propertyMappingsBuilder.maxIndex() + 1), columnDefinition); } } }); final List missingProperties = new ArrayList(); // mapperConfig .columnDefinitions() .forEach( MandatoryProperty.class, new BiConsumer, MandatoryProperty>() { @Override public void accept(Predicate predicate, MandatoryProperty columnProperty) { if (!propertyMappingsBuilder.hasKey(predicate)){ if (predicate instanceof Named) { missingProperties.add(((Named)predicate).getName()); } else { missingProperties.add(predicate.toString()); } } } }); if (!missingProperties.isEmpty()) { throw new MissingPropertyException(missingProperties); } SourceFieldMapper mapper; List injectionParams = constructorInjections(); if (isTargetForTransformer(injectionParams)) { mapper = buildMapperWithTransformer(injectionParams); } else { ConstructorInjections constructorInjections = toConstructorInjections(injectionParams); InstantiatorAndFieldMappers constructorFieldMappersAndInstantiator = getConstructorFieldMappersAndInstantiator(constructorInjections); mapper = buildMapper(targetFieldMappers(), constructorFieldMappersAndInstantiator, getKeys().toArray(FIELD_KEYS), getTargetClass(), reflectionService, mapperSource, mapperConfig); } return mapper; } private boolean isTargetForTransformer(List injectionParams) { return propertyMappingsBuilder.getClassMeta().needTransformer() || needGenericBuilder(injectionParams) // is aggregate and constructor injection || (mapperConfig.assumeInjectionModifiesValues() && (!mappingContextFactoryBuilder.hasNoDependentKeys() && !injectionParams.isEmpty())) ; } @SuppressWarnings("unchecked") private SourceFieldMapper buildMapperWithTransformer(List injections) { boolean forceGenericBuilder = needGenericBuilder(injections); BuilderInstantiatorDefinition mutableBuilder = getMutableBuilder(); // already has mutable builder if (!forceGenericBuilder && mutableBuilder != null) { return builderWithTransformer(injections, mutableBuilder); } else { return buildWithGenericBuilder(injections, fields(), getKeys().toArray(FIELD_KEYS)); } } private boolean needGenericBuilder(List injections) { boolean forceGenericBuilder = false; // handle builder with an injection needing transformation for(InjectionParam ip : injections) { if (ip.needTransformer()) { forceGenericBuilder = true; break; } } return forceGenericBuilder; } private BuilderInstantiatorDefinition getMutableBuilder() { List eligibleInstantiatorDefinitions = propertyMappingsBuilder.getPropertyFinder().getEligibleInstantiatorDefinitions(); for(int i = 0; i < eligibleInstantiatorDefinitions.size(); i++) { InstantiatorDefinition instantiatorDefinition = eligibleInstantiatorDefinitions.get(i); if (instantiatorDefinition.getType() == InstantiatorDefinition.Type.BUILDER) { BuilderInstantiatorDefinition bid = (BuilderInstantiatorDefinition) instantiatorDefinition; if (bid.isMutable()) { return bid; } } } return null; } @SuppressWarnings("unchecked") private SourceFieldMapper buildWithGenericBuilder( List params, List fields, FieldKey[] keys) { GenericBuilderMapping gbm = getGenericBuilderMapping(params, fields, keys); return buildWithGenericBuilder(gbm); } public GenericBuilderMapping getGenericBuilderMapping() { return getGenericBuilderMapping(constructorInjections(), fields(), getKeys().toArray(FIELD_KEYS)); } private GenericBuilderMapping getGenericBuilderMapping(List params, List fields, FieldKey[] keys) { int nbParams = params.size(); final Parameter[] indexMapping = new Parameter[nbParams]; final Function[] transformers = new Function[nbParams]; List>> genericBuilderFieldMappers = new ArrayList>>(); List> targetConstructorFieldMapper = new ArrayList>(); List> targetFieldMappers = new ArrayList>(); List>> targetFieldSetters = new ArrayList>>(); int i = 0; // Generic builder can have all as field mapper not need for constructor injection // for(InjectionParam p : params) { GenericBuilderGetterAndFieldMapper getterAndFieldMapper = p.getterAndfieldMapperGenericBuilder(i); if (getterAndFieldMapper != null) { if (getterAndFieldMapper.fieldMapper == null) { throw new IllegalStateException(); } genericBuilderFieldMappers.add(getterAndFieldMapper.fieldMapper); if (getterAndFieldMapper.fieldMapperAfterConstruct != null) { targetConstructorFieldMapper.add(getterAndFieldMapper.fieldMapperAfterConstruct); } indexMapping[i] = p.parameter; transformers[i] = getterAndFieldMapper.transform; i++; } } for(FieldMeta fm : fields) { FieldGenericBuilderInfo fieldGenericBuilderInfo = fm.fieldGenericBuilderInfo(i); targetFieldMappers.add(fieldGenericBuilderInfo.targetFieldMapper); genericBuilderFieldMappers.add(fieldGenericBuilderInfo.fieldMapperGeneric); targetFieldSetters.add(fieldGenericBuilderInfo.fieldSetter); i++; } final BiInstantiator targetInstantiatorFromGenericBuilder = targetInstantiatorFromGenericBuilder(indexMapping, transformers); GenericBuildBiInstantiator genericBuilderInstantiator = new GenericBuildBiInstantiator( genericBuilderFieldMappers.>>toArray(EMPTY_FIELD_MAPPERS), targetInstantiatorFromGenericBuilder, targetFieldSetters.toArray(new Setter[0])); InstantiatorAndFieldMappers> instantiatorAndFieldMappers = new InstantiatorAndFieldMappers>( new ConstructorInjections(Collections.emptyMap(), new FieldMapper[0]), genericBuilderInstantiator); FieldMapper[] targetFMappers = merge(targetConstructorFieldMapper.toArray(EMPTY_FIELD_MAPPERS), targetFieldMappers.toArray(EMPTY_FIELD_MAPPERS)); return new GenericBuilderMapping( genericBuilderInstantiator, instantiatorAndFieldMappers, genericBuilderFieldMappers.toArray(EMPTY_FIELD_MAPPERS), targetFMappers, keys ); } private SourceFieldMapper buildWithGenericBuilder(GenericBuilderMapping gbm) { SourceFieldMapper> delegate = DefaultConstantSourceMapperBuilder., K>buildMapper( gbm.genericBuilderFieldMappers, gbm.instantiatorAndFieldMappers, gbm.keys, (Class>)(Class)GenericBuilder.class, reflectionService, mapperSource, mapperConfig); return new TransformSourceFieldMapper, T>(delegate, gbm.targetFieldMappers, GenericBuilder.buildFunction()); } public Type getTargetType() { return propertyMappingsBuilder.getClassMeta().getType(); } public List findAllDiscriminatorKeys(final Object discriminatorId) { final List keys = new ArrayList(); propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() { @Override public void handle(PropertyMapping tkPropertyMapping) { ColumnDefinition columnDefinition = tkPropertyMapping.getColumnDefinition(); if (columnDefinition.has(DiscriminatorColumnProperty.class)) { DiscriminatorColumnProperty[] properties = columnDefinition.lookForAll(DiscriminatorColumnProperty.class); for(DiscriminatorColumnProperty p : properties) { if (MapperConfig.sameDiscriminatorId(discriminatorId , p.getDiscriminatorId()) && p.test(getTargetType())) { keys.add(tkPropertyMapping.getColumnKey()); return; } } } } }); return keys; } public static class GenericBuilderMapping> { public final GenericBuildBiInstantiator genericBuilderInstantiator; public final InstantiatorAndFieldMappers> instantiatorAndFieldMappers; public final FieldMapper>[] genericBuilderFieldMappers; public final FieldMapper[] targetFieldMappers; public final FieldKey[] keys; public GenericBuilderMapping( GenericBuildBiInstantiator genericBuilderInstantiator, InstantiatorAndFieldMappers> instantiatorAndFieldMappers, FieldMapper>[] genericBuilderFieldMappers, FieldMapper[] targetFieldMappers, FieldKey[] keys) { this.genericBuilderInstantiator = genericBuilderInstantiator; this.instantiatorAndFieldMappers = instantiatorAndFieldMappers; this.genericBuilderFieldMappers = genericBuilderFieldMappers; this.targetFieldMappers = targetFieldMappers; this.keys = keys; } } private FieldMapper[] merge(FieldMapper[] fieldMappers, FieldMapper[] fields) { FieldMapper[] f = new FieldMapper[fieldMappers.length + fields.length]; System.arraycopy(fieldMappers, 0, f, 0, fieldMappers.length); System.arraycopy(fields, 0, f, fieldMappers.length, fields.length); return f; } private BiInstantiator targetInstantiatorFromGenericBuilder(Parameter[] indexMapping, Function[] transformers) { InstantiatorFactory instantiatorFactory = reflectionService.getInstantiatorFactory(); Map> params = new HashMap>(); for(int i = 0; i < indexMapping.length; i++) { Parameter parameter = indexMapping[i]; final int builderIndex = i; final Function transformer = transformers[i]; if (transformer == null) { params.put(parameter, new DefaultConstantSourceMapperBuilder.TargetFromBuilderParamBiFunction(builderIndex)); } else { params.put(parameter, new DefaultConstantSourceMapperBuilder.TargetFromBuilderWithTransformBiFunction(transformer, builderIndex)); } } BiInstantiator targetInstantiator = instantiatorFactory.getBiInstantiator(getTargetClass(), Object[].class, Object.class, propertyMappingsBuilder.getPropertyFinder().getEligibleInstantiatorDefinitions(), params, reflectionService.isAsmActivated(), reflectionService.builderIgnoresNullValues()); return targetInstantiator; } public static class GenericBuildBiInstantiator implements BiInstantiator, GenericBuilder> { private final BiInstantiator targetInstantiatorFromGenericBuilder; private final Setter>[] targetFieldSetters; private final FieldMapper>[] genericBuilderFieldMappers; public GenericBuildBiInstantiator( FieldMapper>[] genericBuilderFieldMappers, BiInstantiator targetInstantiatorFromGenericBuilder, Setter>[] targetFieldSetters) { this.genericBuilderFieldMappers = genericBuilderFieldMappers; this.targetInstantiatorFromGenericBuilder = targetInstantiatorFromGenericBuilder; this.targetFieldSetters = targetFieldSetters; } @Override public GenericBuilder newInstance(S o, MappingContext o2) { return new GenericBuilder(genericBuilderFieldMappers, targetInstantiatorFromGenericBuilder, targetFieldSetters); } } @SuppressWarnings("unchecked") private SourceFieldMapper builderWithTransformer(final List params, final BuilderInstantiatorDefinition builder) { final FieldMapper[] fields = targetFieldMappers(); final Method buildMethod = builder.getBuildMethod(); final Class targetClass = buildMethod.getDeclaringClass(); final Function f = Modifier.isStatic(buildMethod.getModifiers()) ? new StaticMethodFunction(buildMethod) : new MethodFunction(buildMethod); ConstructorInjections constructorInjections = toConstructorInjections(params); InstantiatorFactory instantiatorFactory = reflectionService.getInstantiatorFactory(); final BuilderBiInstantiator builderBiInstantiator = instantiatorFactory.builderBiInstantiator(builder, MapperBiInstantiatorFactory.convertToBiInstantiator(constructorInjections.parameterGetterMap), reflectionService.isAsmActivated(), reflectionService.builderIgnoresNullValues()); InstantiatorAndFieldMappers newConstantSourceMapperBuilder = new InstantiatorAndFieldMappers(constructorInjections, new BiInstantiator() { @Override public Object newInstance(Object o, Object o2) throws Exception { return builderBiInstantiator.newInitialisedBuilderInstace(o, o2); } }); SourceFieldMapper delegate = buildMapper(fields, newConstantSourceMapperBuilder, getKeys().toArray(FIELD_KEYS), targetClass, reflectionService, mapperSource, mapperConfig); return new TransformSourceFieldMapper(delegate, fields, f); } public static > SourceFieldMapper buildMapper( FieldMapper[] fields, InstantiatorAndFieldMappers constructorFieldMappersAndInstantiator, FieldKey[] keys, Class target, ReflectionService reflectionService, MapperSource mapperSource, MapperConfig mapperConfig) { SourceFieldMapper mapper; if (reflectionService.isAsmActivated() && fields.length + constructorFieldMappersAndInstantiator.constructorInjections.parameterGetterMap.size() < mapperConfig.asmMapperNbFieldsLimit()) { try { MapperAsmFactory mapperAsmFactory = reflectionService .getAsmFactory(target.getClassLoader()) .registerOrCreate(MapperAsmFactory.class, new UnaryFactory() { @Override public MapperAsmFactory newInstance(AsmFactory asmFactory) { return new MapperAsmFactory(asmFactory); } }); mapper = mapperAsmFactory .createMapper( keys, fields, constructorFieldMappersAndInstantiator.constructorInjections.fieldMappers, constructorFieldMappersAndInstantiator.instantiator, mapperSource.source(), target); } catch (Throwable e) { if (mapperConfig.failOnAsm()) { return ErrorHelper.rethrow(e); } else { mapper = new MapperImpl(fields, constructorFieldMappersAndInstantiator.constructorInjections.fieldMappers, constructorFieldMappersAndInstantiator.instantiator); } } } else { mapper = new MapperImpl(fields, constructorFieldMappersAndInstantiator.constructorInjections.fieldMappers, constructorFieldMappersAndInstantiator.instantiator); } return mapper; } @Override public boolean isRootAggregate() { return mappingContextFactoryBuilder.isRoot() && !mappingContextFactoryBuilder.hasNoDependentKeys(); } private Class getTargetClass() { return TypeHelper.toClass(target); } private ConstructorInjections toConstructorInjections(List params) throws MapperBuildingException { Map> injections = new HashMap>(); List> fieldMappers = new ArrayList>(); for(int i = 0; i < params.size(); i++) { InjectionParam p = params.get(i); GetterAndFieldMapper getterAndFieldMapper = p.getterAndfieldMapper(); injections.put(p.parameter, getterAndFieldMapper.getter); if (getterAndFieldMapper.fieldMapper != null) { fieldMappers.add((FieldMapper) getterAndFieldMapper.fieldMapper); } } return new ConstructorInjections(injections, fieldMappers.toArray(EMPTY_FIELD_MAPPERS)); } @SuppressWarnings("unchecked") private InstantiatorAndFieldMappers getConstructorFieldMappersAndInstantiator(ConstructorInjections constructorInjections) throws MapperBuildingException { InstantiatorFactory instantiatorFactory = reflectionService.getInstantiatorFactory(); try { Map> injections = constructorInjections.parameterGetterMap; MapperBiInstantiatorFactory mapperBiInstantiatorFactory = new MapperBiInstantiatorFactory(instantiatorFactory); ContextualGetterFactory getterFactory = fieldMapperAsGetterFactory(); BiInstantiator, T> instantiator = mapperBiInstantiatorFactory. getBiInstantiator(mapperSource.source(), target, propertyMappingsBuilder, injections, getterFactory, reflectionService.builderIgnoresNullValues(), mappingContextFactoryBuilder); return new InstantiatorAndFieldMappers(constructorInjections, instantiator); } catch(Exception e) { return ErrorHelper.rethrow(e); } } private ContextualGetterFactory fieldMapperAsGetterFactory() { return new FieldMapperFactoryGetterFactoryAdapter(mapperConfig.fieldMapperErrorHandler()); } @SuppressWarnings("unchecked") /** * Build the list of constructor prop and fieldmappers */ private List constructorInjections() { final List injectionParams = new ArrayList(); final Set parameters = new HashSet(); propertyMappingsBuilder.forEachConstructorProperties(new ForEachCallBack>() { @SuppressWarnings("unchecked") @Override public void handle(PropertyMapping propertyMapping) { if (!isTargetForMapperFieldMapper(propertyMapping) && ! propertyMapping.getPropertyMeta().isNonMapped()) { PropertyMeta pm = propertyMapping.getPropertyMeta(); ConstructorPropertyMeta cProp = (ConstructorPropertyMeta) pm; injectionParams.add(new ConstructorParam(cProp.getParameter(), cProp, propertyMapping)); parameters.add(cProp.getParameter()); } } }); for(PropertyPerOwner e : getSubPropertyPerOwner()) { if (e.owner.isConstructorProperty()) { ConstructorPropertyMeta meta = (ConstructorPropertyMeta) e.owner; // ignore if no mapped properties if (hasMappedProperties(e.propertyMappings)) { injectionParams.add(new SubPropertyParam(meta.getParameter(), meta, e.propertyMappings, this)); parameters.add(meta.getParameter()); } } } addContextParam(injectionParams, parameters); return injectionParams; } private boolean hasMappedProperties(List> propertyMappings) { for(PropertyMapping pm : propertyMappings) { if (!pm.getPropertyMeta().isNonMapped()) return true; } return false; } private void addContextParam(List injectionParams, Set parameters) { Parameter mappingContext = null; for(InstantiatorDefinition id : propertyMappingsBuilder.getPropertyFinder().getEligibleInstantiatorDefinitions()) { for(Parameter p : id.getParameters()) { if (TypeHelper.areEquals(p.getType(), Context.class) && ! parameters.contains(p)) { if (mappingContext != null && ! p.equals(mappingContext)) { // multiple context ignore to avoid constructor selection issue return; } mappingContext = p; } } } if (mappingContext != null) { injectionParams.add(new ContextParam(mappingContext, null)); } } private

SourceMapper getterPropertyMapper(PropertyMeta owner, PropertyMapping propertyMapping) { PropertyMeta pm = propertyMapping.getPropertyMeta(); final ContextualGetter getter = (ContextualGetter) fieldMapperFactory.getGetterFromSource(propertyMapping.getColumnKey(), pm.getPropertyType(), propertyMapping.getColumnDefinition(), pm.getPropertyClassMetaSupplier(), mappingContextFactoryBuilder); return new GetterMapper(getter); } private MappingContextFactoryBuilder getMapperContextFactoryBuilder(PropertyMeta owner, List> properties) { final List> subKeys = getSubKeys(properties); final List> inferNullColumns = getInferNulls(properties); return mappingContextFactoryBuilder.newBuilder(subKeys, inferNullColumns, owner); } @SuppressWarnings("unchecked") private

FieldMapper newMapperFieldMapper(List> properties, PropertyMeta meta, SourceMapper mapper, MappingContextFactoryBuilder mappingContextFactoryBuilder) { return newMapperFieldMapper(properties, (Setter) meta.getSetter(), mapper, mappingContextFactoryBuilder); } private

FieldMapper newMapperFieldMapper(List> properties, Setter setter, SourceMapper mapper, MappingContextFactoryBuilder mappingContextFactoryBuilder) { final MapperFieldMapper fieldMapper = new MapperFieldMapper(mapper, (Setter)setter, mappingContextFactoryBuilder.nullChecker(), mappingContextFactoryBuilder.currentIndex()); return wrapFieldMapperWithErrorHandler(properties.get(0).getColumnKey(), fieldMapper); } @SuppressWarnings("unchecked") private

ContextualGetter newMapperGetterAdapter(SourceMapper mapper, MappingContextFactoryBuilder builder) { return new MapperFieldMapperGetterAdapter((SourceMapper)mapper, builder.nullChecker(), builder.currentIndex()); } // call use towards sub jdbcMapper // the keys are initialised protected

void addMapping(K columnKey, ColumnDefinition columnDefinition, PropertyMeta prop) { propertyMappingsBuilder.addProperty(columnKey, columnDefinition, prop); } private FieldMapper[] targetFieldMappers() { List fields = fields(); FieldMapper[] fieldMappers = new FieldMapper[fields.size()]; for(int i = 0; i < fields.size(); i++) { fieldMappers[i] = fields.get(i).targetFieldMapper(); } return fieldMappers; } @SuppressWarnings("unchecked") private List fields() { final List fields = new ArrayList(); propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() { @Override public void handle(PropertyMapping t) { if (t == null || isTargetForMapperFieldMapper(t)) return; PropertyMeta meta = t.getPropertyMeta(); if (meta == null || (meta instanceof SelfPropertyMeta)) return; if (!meta.isConstructorProperty() && !isTargetForMapperFieldMapper(t) && !meta.isNonMapped()) { fields.add(new PropertyFieldMeta(t)); } } }); List subPropertyPerOwner = getSubPropertyPerOwner(); for(PropertyPerOwner e : subPropertyPerOwner) { if (!e.owner.isConstructorProperty()) { List> propertyMappings = filterNonMappedAndCompress(e.propertyMappings); if (propertyMappings.isEmpty()) { // non mapped property continue; // ignore no actual prop } final SourceMapper mapper; final MappingContextFactoryBuilder currentBuilder = getMapperContextFactoryBuilder(e.owner, e.propertyMappings); if (propertyMappings.size() == 1 && JoinUtils.isArrayElement(propertyMappings.get(0).getPropertyMeta())) { mapper = getterPropertyMapper(e.owner, propertyMappings.get(0)); } else { mapper = subPropertyMapper(e.owner, e.propertyMappings, currentBuilder); } fields.add(new SubPropertyFieldMeta(mapper, e.propertyMappings, e.owner, currentBuilder)); } } for(FieldMapper mapper : additionalMappers) { fields.add(new FieldMapperFieldMeta(mapper)); } return fields; } private List> filterNonMappedAndCompress(List> propertyMappings) { ArrayList> filtered = new ArrayList>(propertyMappings); ListIterator> iterator = filtered.listIterator(); while(iterator.hasNext()) { PropertyMapping pm = iterator.next(); if (pm.getPropertyMeta().isNonMapped()) { iterator.remove(); } else { iterator.set(pm.compressSubSelf()); } } return filtered; } @Override public MappingContextFactory contextFactory() { return mappingContextFactoryBuilder.build(); } private static class MethodFunction implements Function { private final Method buildMethod; public MethodFunction(Method buildMethod) { this.buildMethod = buildMethod; } @Override public Object apply(Object o) { try { return buildMethod.invoke(o); } catch (Exception e) { return ErrorHelper.rethrow(e); } } } private static class StaticMethodFunction implements Function { private final Method buildMethod; public StaticMethodFunction(Method buildMethod) { this.buildMethod = buildMethod; } @Override public Object apply(Object o) { try { return buildMethod.invoke(null, o); } catch (Exception e) { return ErrorHelper.rethrow(e); } } } class FieldGenericBuilderInfo { final FieldMapper targetFieldMapper; final FieldMapper> fieldMapperGeneric; final Setter> fieldSetter; FieldGenericBuilderInfo(FieldMapper targetFieldMapper, FieldMapper> fieldMapperGeneric, Setter> fieldSetter) { this.targetFieldMapper = targetFieldMapper; this.fieldMapperGeneric = fieldMapperGeneric; this.fieldSetter = fieldSetter; } } abstract class FieldMeta { abstract FieldMapper targetFieldMapper(); public abstract FieldGenericBuilderInfo fieldGenericBuilderInfo(int index); } class PropertyFieldMeta extends FieldMeta { final PropertyMapping propertyMapping; PropertyFieldMeta(PropertyMapping propertyMapping) { this.propertyMapping = propertyMapping; } public FieldMapper targetFieldMapper() { return newFieldMapper(propertyMapping); } @Override public FieldGenericBuilderInfo fieldGenericBuilderInfo(final int index) { final Setter setter = propertyMapping.getPropertyMeta().getSetter(); final ContextualGetter getter = fieldMapperFactory.getGetterFromSource( propertyMapping.getColumnKey(), propertyMapping.getPropertyMeta().getPropertyType(), propertyMapping.getColumnDefinition(), propertyMapping.getPropertyMeta().getPropertyClassMetaSupplier(), mappingContextFactoryBuilder); return new FieldGenericBuilderInfo(targetFieldMapper(), new FieldMapper>() { @Override public void mapTo(S source, GenericBuilder target, MappingContext context) throws Exception { target.objects[index] = getter.get(source, context); } }, new Setter>() { @Override public void set(T target, GenericBuilder value) throws Exception { setter.set(target, value.objects[index]); } }); } } class SubPropertyFieldMeta extends FieldMeta { final SourceMapper mapper; final List> propertyMappings; final PropertyMeta owner; final MappingContextFactoryBuilder currentBuilder; SubPropertyFieldMeta(SourceMapper mapper, List> propertyMappings, PropertyMeta owner, MappingContextFactoryBuilder currentBuilder) { this.mapper = mapper; this.propertyMappings = propertyMappings; this.owner = owner; this.currentBuilder = currentBuilder; } @Override FieldMapper targetFieldMapper() { return newMapperFieldMapper(propertyMappings, owner, mapper, currentBuilder); } @Override public FieldGenericBuilderInfo fieldGenericBuilderInfo(final int index) { final Setter setter = owner.getSetter(); return new FieldGenericBuilderInfo( targetFieldMapper(), (FieldMapper>) newMapperFieldMapper( propertyMappings, new Setter() { @Override public void set(Object target, Object value) throws Exception { GenericBuilder genericBuilder = (GenericBuilder) target; genericBuilder.objects[index] = value; } }, mapper, currentBuilder), new Setter>() { @Override public void set(T target, GenericBuilder value) throws Exception { setter.set(target, value.objects[index]); } }); } } class FieldMapperFieldMeta extends FieldMeta { final FieldMapper fieldMapper; FieldMapperFieldMeta(FieldMapper fieldMapper) { this.fieldMapper = fieldMapper; } @Override FieldMapper targetFieldMapper() { return fieldMapper; } @Override public FieldGenericBuilderInfo fieldGenericBuilderInfo(int index) { throw new UnsupportedOperationException(); } } private boolean isTargetForMapperFieldMapper(PropertyMapping pm) { return pm.getPropertyMeta().isSubProperty() || (JoinUtils.isArrayElement(pm.getPropertyMeta()) && isKeyOrHasKey(pm)); } private boolean isKeyOrHasKey(final PropertyMapping pm) { if (pm.getColumnDefinition().isInferNull()) return true; // looked for non mapped property with same owner return propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() { boolean hasKey; @Override public void handle(PropertyMapping tkPropertyMapping) { if (tkPropertyMapping.getPropertyMeta().isSubProperty()) { SubPropertyMeta subPropertyMeta = (SubPropertyMeta) tkPropertyMapping.getPropertyMeta(); if (subPropertyMeta.getOwnerProperty().equals(pm.getPropertyMeta())) { hasKey |= tkPropertyMapping.getColumnDefinition().isInferNull(); } } } }).hasKey; } private List getSubPropertyPerOwner() { final List subPropertiesList = new ArrayList(); propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() { @SuppressWarnings("unchecked") @Override public void handle(PropertyMapping t) { if (t == null) return; PropertyMeta meta = t.getPropertyMeta(); if (meta == null) return; if (isTargetForMapperFieldMapper(t)) { addSubProperty(t, meta, t.getColumnKey()); } } private

void addSubProperty(PropertyMapping pm, PropertyMeta propertyMeta, K key) { PropertyMeta propertyOwner = getOwner(propertyMeta); List> props = getList(propertyOwner); if (props == null) { props = new ArrayList>(); subPropertiesList.add(new PropertyPerOwner(propertyOwner, props)); } props.add(pm); } private PropertyMeta getOwner(PropertyMeta propertyMeta) { if (propertyMeta.isSubProperty()) { return ((SubPropertyMeta)propertyMeta).getOwnerProperty(); } return propertyMeta; } private List> getList(PropertyMeta owner) { for(PropertyPerOwner tuple : subPropertiesList) { if (tuple.owner.equals(owner)) { return tuple.propertyMappings; } } return null; } }); return subPropertiesList; } @SuppressWarnings("unchecked") private

SourceMapper subPropertyMapper(PropertyMeta owner, List> properties, MappingContextFactoryBuilder mappingContextFactoryBuilder) { final ConstantSourceMapperBuilder builder = newSubBuilder(owner, mappingContextFactoryBuilder, (PropertyFinder

) propertyMappingsBuilder.getPropertyFinder().getSubPropertyFinder(owner)); for(PropertyMapping pm : properties) { final SubPropertyMeta propertyMeta = (SubPropertyMeta) pm.getPropertyMeta(); final PropertyMeta subProperty = ((SubPropertyMeta) propertyMeta).getSubProperty(); builder.addMapping(pm.getColumnKey(), pm.getColumnDefinition(), subProperty); } return builder.sourceFieldMapper(); } @SuppressWarnings("unchecked") protected

FieldMapper newFieldMapper(PropertyMapping t) { ColumnDefinition columnDefinition = t.getColumnDefinition(); FieldMapper fieldMapper = null; if (columnDefinition.has(FieldMapperProperty.class)) { fieldMapper = (FieldMapper) columnDefinition.lookFor(FieldMapperProperty.class).getFieldMapper(); } if (fieldMapper == null) { fieldMapper = fieldMapperFactory.newFieldMapper(t, mappingContextFactoryBuilder, mapperConfig.mapperBuilderErrorHandler()); } return wrapFieldMapperWithErrorHandler(t.getColumnKey(), fieldMapper); } private FieldMapper wrapFieldMapperWithErrorHandler(final K columnKey, final FieldMapper fieldMapper) { if (fieldMapper != null && mapperConfig.hasFieldMapperErrorHandler()) { return FieldErrorHandlerMapper.of(columnKey, fieldMapper, mapperConfig.fieldMapperErrorHandler()); } return fieldMapper; } private ContextualGetter wrapGetterWithErrorHandler(final K columnKey, final ContextualGetter getter) { if (getter != null && mapperConfig.hasFieldMapperErrorHandler()) { return FieldErrorHandlerGetter.of(columnKey, getter, mapperConfig.fieldMapperErrorHandler()); } return getter; } @Override public void addMapper(FieldMapper mapper) { additionalMappers.add(mapper); } private ConstantSourceMapperBuilder newSubBuilder( PropertyMeta propertyMeta, MappingContextFactoryBuilder mappingContextFactoryBuilder, PropertyFinder propertyFinder) { return ConstantSourceMapperBuilder.newConstantSourceMapperBuilder( mapperSource, propertyMeta, mapperConfig, mappingContextFactoryBuilder, keyFactory, propertyFinder); } @Override public List getKeys() { return propertyMappingsBuilder.getKeys(); } @Override public >> H forEachProperties(H handler) { return propertyMappingsBuilder.forEachProperties(handler); } @SuppressWarnings("unchecked") private List> getSubKeys(List> properties) { List> keys = new ArrayList>(); // look for keys property of the object for (PropertyMapping pm : properties) { Predicate> propertyMetaKeyPredicate = pm.getColumnDefinition().keyAppliesTo(); if (pm.getPropertyMeta().isSubProperty()) { SubPropertyMeta subPropertyMeta = (SubPropertyMeta) pm.getPropertyMeta(); if (!(JoinUtils.isArrayElement(subPropertyMeta.getSubProperty()))) { // ignore ArrayElementPropertyMeta as it's a direct getter and will be managed in the setter if (pm.getColumnDefinition().isKey()) { if (propertyMetaKeyPredicate.test(subPropertyMeta.getSubProperty())) { Predicate predicate = buildKeyPredicate(subPropertyMeta.getSubProperty(), propertyMetaKeyPredicate);; keys.add(new KeyAndPredicate(pm.getColumnKey(), predicate)); } } } } else { if (pm.getColumnDefinition().isKey()) { if (propertyMetaKeyPredicate.test(pm.getPropertyMeta())) { keys.add(new KeyAndPredicate(pm.getColumnKey(), null)); } } } } return keys; } private List> getInferNulls(List> properties) { List> keys = new ArrayList>(); // look for keys property of the object for (PropertyMapping pm : properties) { Predicate> propertyMetaKeyPredicate = pm.getColumnDefinition().inferNullsAppliesTo(); if (pm.getPropertyMeta().isSubProperty()) { SubPropertyMeta subPropertyMeta = (SubPropertyMeta) pm.getPropertyMeta(); if (!(JoinUtils.isArrayElement(subPropertyMeta.getSubProperty()))) { // ignore ArrayElementPropertyMeta as it's a direct getter and will be managed in the setter if (pm.getColumnDefinition().isInferNull()) { if (propertyMetaKeyPredicate.test(subPropertyMeta.getSubProperty())) { Predicate predicate = buildKeyPredicate(subPropertyMeta.getSubProperty(), propertyMetaKeyPredicate);; keys.add(new KeyAndPredicate(pm.getColumnKey(), predicate)); } } } } else { if (pm.getColumnDefinition().isInferNull()) { if (propertyMetaKeyPredicate.test(pm.getPropertyMeta())) { keys.add(new KeyAndPredicate(pm.getColumnKey(), null)); } } } } return keys; } private Predicate buildKeyPredicate(final PropertyMeta propertyMeta, final Predicate> propertyMetaPredicate) { Predicate predicate = null; if (propertyMeta instanceof DiscriminatorPropertyFinder.DiscriminatorPropertyMeta) { final DiscriminatorPropertyFinder.DiscriminatorPropertyMeta dpm = (DiscriminatorPropertyFinder.DiscriminatorPropertyMeta) propertyMeta; final List> not = dpm.forEachProperty(new Consumer() { List> not = new ArrayList>(); @Override public void accept(DiscriminatorPropertyFinder.DiscriminatorMatch dm) { Type type = dm.type; PropertyMeta propertyMeta = dm.matchedProperty.getPropertyMeta(); if (!propertyMetaPredicate.test(propertyMeta)) { MapperConfig.Discriminator[] discriminators = mapperConfig.getDiscriminators(dpm.getOwnerType()); for (MapperConfig.Discriminator discriminator : discriminators) { if (MapperConfig.sameDiscriminatorId(dm.discriminatorId, discriminator.discriminatorId)) { not.add(discriminator.getCase(type).predicateFactory.apply(findAllDiscriminatorKeys(discriminator.discriminatorId))); } } } else { Predicate p = buildKeyPredicate(propertyMeta, propertyMetaPredicate); if (p != null) { not.add(p); } } } }).not; if (not.isEmpty()) return null; return new DiscriminatorKeyPredicate(not); } else if (propertyMeta.isSubProperty()) { SubPropertyMeta subPropertyMeta = (SubPropertyMeta) propertyMeta; predicate = buildKeyPredicate(subPropertyMeta.getSubProperty(), propertyMetaPredicate); } return predicate; } public static class TargetFromBuilderParamBiFunction implements BiFunction { private final int builderIndex; public TargetFromBuilderParamBiFunction(int builderIndex) { this.builderIndex = builderIndex; } @Override public Object apply(Object[] objects, Object o) { return objects[builderIndex]; } } public static class TargetFromBuilderWithTransformBiFunction implements BiFunction { private final Function transformer; private final int builderIndex; public TargetFromBuilderWithTransformBiFunction(Function transformer, int builderIndex) { this.transformer = transformer; this.builderIndex = builderIndex; } @Override public Object apply(Object[] objects, Object o) { return transformer.apply(objects[builderIndex]); } } public static class InstantiatorAndFieldMappers { public final ConstructorInjections constructorInjections; public final BiInstantiator, T> instantiator; public InstantiatorAndFieldMappers(ConstructorInjections constructorInjections, BiInstantiator, T> instantiator) { this.constructorInjections = constructorInjections; this.instantiator = instantiator; } } public static class ConstructorInjections { private final Map> parameterGetterMap; private final FieldMapper[] fieldMappers; public ConstructorInjections(Map> parameterGetterMap, FieldMapper[] fieldMappers) { this.parameterGetterMap = parameterGetterMap; this.fieldMappers = fieldMappers; } } public static abstract class InjectionParam { final Parameter parameter; final PropertyMeta propertyMeta; private InjectionParam(Parameter parameter, PropertyMeta propertyMeta) { this.parameter = parameter; this.propertyMeta = propertyMeta; } abstract GetterAndFieldMapper getterAndfieldMapper(); abstract GenericBuilderGetterAndFieldMapper getterAndfieldMapperGenericBuilder(int i); public abstract boolean needTransformer(); boolean needTransformer(PropertyMeta propertyMeta) { if (propertyMeta.isNonMapped()) return false; if (propertyMeta.isSubProperty()) { SubPropertyMeta sb = (SubPropertyMeta) propertyMeta; return needTransformer(sb.getOwnerProperty()) || needTransformer(sb.getSubProperty()); } else { return !propertyMeta.isSelf() && propertyMeta.getPropertyClassMeta().needTransformer(); } } } private class ConstructorParam extends InjectionParam { private final PropertyMapping propertyMapping; private ConstructorParam(Parameter parameter, ConstructorPropertyMeta propertyMeta, PropertyMapping propertyMapping) { super(parameter, propertyMeta); this.propertyMapping = propertyMapping; } public GetterAndFieldMapper getterAndfieldMapper() { ContextualGetter getter = wrapGetterWithErrorHandler(propertyMapping.getColumnKey(), (ContextualGetter)getGetter()); FieldMapper fieldMapper; if (NullSetter.isNull(propertyMeta.getSetter())) { fieldMapper = null; } else { fieldMapper = wrapFieldMapperWithErrorHandler(propertyMapping.getColumnKey(), fieldMapperFactory.newFieldMapper(propertyMapping, mappingContextFactoryBuilder, mapperConfig.mapperBuilderErrorHandler())); } return new GetterAndFieldMapper((ContextualGetter) getter, fieldMapper); } private ContextualGetter getGetter() { ContextualGetter getter = fieldMapperFactory.getGetterFromSource(propertyMapping.getColumnKey(), propertyMeta.getPropertyType(), propertyMapping.getColumnDefinition(), propertyMeta.getPropertyClassMetaSupplier(), mappingContextFactoryBuilder); if (NullContextualGetter.isNull(getter)) { PropertyMapping propertyMapping = this.propertyMapping; mapperConfig.mapperBuilderErrorHandler() .accessorNotFound(getterNotFoundErrorMessage(propertyMapping)); } return getter; } @Override GenericBuilderGetterAndFieldMapper getterAndfieldMapperGenericBuilder(final int index) { final ContextualGetter getter = getGetter(); if (NullContextualGetter.isNull(getter)) { PropertyMapping propertyMapping = this.propertyMapping; mapperConfig.mapperBuilderErrorHandler() .accessorNotFound(getterNotFoundErrorMessage(propertyMapping)); return null; } FieldMapper> fieldMapper = wrapFieldMapperWithErrorHandler(propertyMapping.getColumnKey(), new GenericBuilderFieldMapper(index, getter)); FieldMapper fieldMapperAfterConstruct = NullSetter.isNull(propertyMeta.getSetter()) ? null : wrapFieldMapperWithErrorHandler(propertyMapping.getColumnKey(), fieldMapperFactory.newFieldMapper(propertyMapping, mappingContextFactoryBuilder, mapperConfig.mapperBuilderErrorHandler())); return new GenericBuilderGetterAndFieldMapper((ContextualGetter) getter, fieldMapper, null, fieldMapperAfterConstruct); } @Override public boolean needTransformer() { return needTransformer(propertyMeta); } } private static class GenericBuilderFieldMapper implements FieldMapper> { private final int index; private final ContextualGetter getter; public GenericBuilderFieldMapper(int index, ContextualGetter getter) { this.index = index; this.getter = getter; } @Override public void mapTo(S source, GenericBuilder target, MappingContext context) throws Exception { target.objects[index] = getter.get(source, context); } } private class ContextParam extends InjectionParam { private ContextParam(Parameter parameter, ConstructorPropertyMeta propertyMeta) { super(parameter, propertyMeta); } public GetterAndFieldMapper getterAndfieldMapper() { ContextualGetter getter = getGetter(); return new GetterAndFieldMapper((ContextualGetter) getter, null); } private ContextualGetter getGetter() { return new ContextualGetter() { @Override public Object get(S s, Context context) throws Exception { return context; } }; } @Override GenericBuilderGetterAndFieldMapper getterAndfieldMapperGenericBuilder(final int index) { final ContextualGetter getter = getGetter(); FieldMapper> fieldMapper = new GenericBuilderFieldMapper(index, getter); return new GenericBuilderGetterAndFieldMapper((ContextualGetter) getter, fieldMapper, null, null); } @Override public boolean needTransformer() { return false; } } public static class SubPropertyParam> extends InjectionParam { final List> propertyMappings; final DefaultConstantSourceMapperBuilder builder; private SubPropertyParam(Parameter parameter, ConstructorPropertyMeta propertyMeta, List> propertyMappings, DefaultConstantSourceMapperBuilder builder) { super(parameter, propertyMeta); this.propertyMappings = propertyMappings; this.builder = builder; } public GetterAndFieldMapper getterAndfieldMapper() { final MappingContextFactoryBuilder currentBuilder = builder.getMapperContextFactoryBuilder(propertyMeta, propertyMappings); final SourceMapper mapper = getsSourceMapper(currentBuilder); ContextualGetter biFunction = builder.newMapperGetterAdapter(mapper, currentBuilder); FieldMapper fieldMapper = builder.newMapperFieldMapper(propertyMappings, propertyMeta, mapper, currentBuilder); return new GetterAndFieldMapper(biFunction, fieldMapper); } @Override GenericBuilderGetterAndFieldMapper getterAndfieldMapperGenericBuilder(final int i) { final MappingContextFactoryBuilder currentBuilder = builder.getMapperContextFactoryBuilder(propertyMeta, propertyMappings); SourceMapper mapper = getsSourceMapper(currentBuilder); Function transform = null; if (mapper instanceof TransformSourceFieldMapper) { transform = ((TransformSourceFieldMapper) mapper).transform; mapper = ((TransformSourceFieldMapper) mapper).delegate; } ContextualGetter biFunction = builder.newMapperGetterAdapter(mapper, currentBuilder); FieldMapper> fieldMapper = builder.newMapperFieldMapper(propertyMappings, new GenericBuilderSetter(i), mapper , currentBuilder); FieldMapper fieldMapperAfterConstruct = builder.newMapperFieldMapper(propertyMappings, propertyMeta, mapper, currentBuilder); return new GenericBuilderGetterAndFieldMapper(biFunction, fieldMapper, transform, fieldMapperAfterConstruct); } @Override public boolean needTransformer() { if (needTransformer(propertyMeta)) { return true; } for(PropertyMapping pm : propertyMappings) { if (needTransformer(pm.getPropertyMeta())) return true; } return false; } private SourceMapper getsSourceMapper(MappingContextFactoryBuilder currentBuilder) { final SourceMapper mapper; if (propertyMappings.size() == 1 && JoinUtils.isArrayElement(propertyMappings.get(0).getPropertyMeta())) { mapper = builder.getterPropertyMapper(propertyMeta, propertyMappings.get(0)); } else { mapper = builder.subPropertyMapper(propertyMeta, propertyMappings, currentBuilder); } return mapper; } private class GenericBuilderSetter implements Setter, Object> { private final int index; public GenericBuilderSetter(int index) { this.index = index; } @Override public void set(GenericBuilder target, Object value) throws Exception { target.objects[index] = value; } } } public static class GetterAndFieldMapper { final ContextualGetter getter; final FieldMapper fieldMapper; private GetterAndFieldMapper(ContextualGetter getter, FieldMapper fieldMapper) { this.getter = getter; this.fieldMapper = fieldMapper; } } public static class GenericBuilderGetterAndFieldMapper { final ContextualGetter getter; final FieldMapper fieldMapper; final Function transform; final FieldMapper fieldMapperAfterConstruct; private GenericBuilderGetterAndFieldMapper(ContextualGetter getter, FieldMapper fieldMapper, Function transform, FieldMapper fieldMapperAfterConstruct) { this.getter = getter; this.fieldMapper = fieldMapper; this.transform = transform; this.fieldMapperAfterConstruct = fieldMapperAfterConstruct; } } private class PropertyPerOwner { private final PropertyMeta owner; private final List> propertyMappings; private PropertyPerOwner(PropertyMeta owner, List> propertyMappings) { this.owner = owner; this.propertyMappings = propertyMappings; } } private class FieldMapperFactoryGetterFactoryAdapter implements ContextualGetterFactory { private final FieldMapperErrorHandler fieldMapperErrorHandler; public FieldMapperFactoryGetterFactoryAdapter(FieldMapperErrorHandler fieldMapperErrorHandler) { this.fieldMapperErrorHandler = fieldMapperErrorHandler; } @SuppressWarnings("unchecked") @Override public

ContextualGetter newGetter(Type target, K key, MappingContextFactoryBuilder> mappingContextFactoryBuilder, Object... properties) { FieldMapperColumnDefinition columnDefinition = FieldMapperColumnDefinition.identity().add(properties); ContextualGetter getterFromSource = fieldMapperFactory.getGetterFromSource(key, target, columnDefinition, new ClassMetaSupplier

(target), mappingContextFactoryBuilder); if (fieldMapperErrorHandler != null) { return FieldErrorHandlerGetter.of(key, getterFromSource, fieldMapperErrorHandler); } return (ContextualGetter) getterFromSource; } } private class ClassMetaSupplier

implements Supplier> { private final Type target; public ClassMetaSupplier(Type target) { this.target = target; } @Override public ClassMeta

get() { return reflectionService.

getClassMeta(target); } } public static String getterNotFoundErrorMessage(PropertyMapping propertyMapping) { String currentPath = propertyMapping.getPropertyMeta().getPath(); return "Could not find getter for " + propertyMapping.getColumnKey() + " type " + propertyMapping.getPropertyMeta().getPropertyType() + " path " + currentPath + ". See " + CSFM_GETTER_NOT_FOUND.toUrl(); } private static class DiscriminatorKeyPredicate implements Predicate { private final List> not; public DiscriminatorKeyPredicate(List> not) { this.not = not; } @Override public boolean test(S s) { for(Predicate p : not) { if (p.test(s)) { return false; } } return true; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DiscriminatorKeyPredicate that = (DiscriminatorKeyPredicate) o; return not != null ? not.equals(that.not) : that.not == null; } @Override public int hashCode() { return not != null ? not.hashCode() : 0; } } }