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

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

Go to download

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

There is a newer version: 9.0.2
Show newest version
package org.simpleflatmapper.map.mapper;

import org.simpleflatmapper.converter.ConverterService;
import org.simpleflatmapper.map.FieldKey;
import org.simpleflatmapper.map.MapperBuildingException;
import org.simpleflatmapper.map.MappingContext;
import org.simpleflatmapper.map.asm.MapperAsmFactory;
import org.simpleflatmapper.map.fieldmapper.MapperFieldMapper;
import org.simpleflatmapper.map.impl.GetterMapper;
import org.simpleflatmapper.map.property.DefaultValueProperty;
import org.simpleflatmapper.map.property.FieldMapperColumnDefinition;
import org.simpleflatmapper.map.property.GetterProperty;
import org.simpleflatmapper.map.context.MappingContextFactoryBuilder;
import org.simpleflatmapper.map.impl.FieldErrorHandlerMapper;
import org.simpleflatmapper.map.fieldmapper.ConstantSourceFieldMapperFactory;
import org.simpleflatmapper.map.fieldmapper.ConstantSourceFieldMapperFactoryImpl;
import org.simpleflatmapper.reflect.BiInstantiator;
import org.simpleflatmapper.reflect.Getter;
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.BiFunctionGetter;
import org.simpleflatmapper.reflect.getter.ConstantGetter;
import org.simpleflatmapper.reflect.getter.GetterFactory;
import org.simpleflatmapper.reflect.getter.NullGetter;
import org.simpleflatmapper.reflect.meta.ArrayElementPropertyMeta;
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.Mapper;
import org.simpleflatmapper.map.MapperConfig;
import org.simpleflatmapper.reflect.setter.NullSetter;
import org.simpleflatmapper.util.BiConsumer;
import org.simpleflatmapper.util.BiFunction;
import org.simpleflatmapper.util.ErrorDoc;
import org.simpleflatmapper.util.ErrorHelper;
import org.simpleflatmapper.util.ForEachCallBack;
import org.simpleflatmapper.util.Named;
import org.simpleflatmapper.util.Predicate;
import org.simpleflatmapper.util.Supplier;
import org.simpleflatmapper.util.TypeHelper;
import org.simpleflatmapper.util.UnaryFactory;

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

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

public final class ConstantSourceMapperBuilder>  {

    private static final FieldKey[] FIELD_KEYS = new FieldKey[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 ConstantSourceMapperBuilder(
            final MapperSource mapperSource,
            final ClassMeta classMeta,
            final MapperConfig> mapperConfig,
            MappingContextFactoryBuilder mappingContextFactoryBuilder,
            KeyFactory keyFactory) throws MapperBuildingException {
                this(mapperSource, classMeta, mapperConfig, mappingContextFactoryBuilder, keyFactory, null);
    }

    public ConstantSourceMapperBuilder(
            final MapperSource mapperSource,
            final ClassMeta classMeta,
            final MapperConfig> mapperConfig,
            MappingContextFactoryBuilder mappingContextFactoryBuilder,
            KeyFactory keyFactory, PropertyFinder propertyFinder) throws MapperBuildingException {
        this.mapperSource = requireNonNull("fieldMapperSource", mapperSource);
        this.mapperConfig = requireNonNull("mapperConfig", mapperConfig);
        this.mappingContextFactoryBuilder = mappingContextFactoryBuilder;
		this.fieldMapperFactory = new ConstantSourceFieldMapperFactoryImpl(mapperSource.getterFactory(), ConverterService.getInstance(), mapperSource.source());
        this.keyFactory = keyFactory;
        this.propertyMappingsBuilder =
                PropertyMappingsBuilder.of(classMeta, mapperConfig, PropertyWithSetterOrConstructor.INSTANCE, propertyFinder);
		this.target = requireNonNull("classMeta", classMeta).getType();
		this.reflectionService = requireNonNull("classMeta", classMeta).getReflectionService();
	}

    @SuppressWarnings("unchecked")
    public final ConstantSourceMapperBuilder addMapping(K key, final FieldMapperColumnDefinition columnDefinition) {
        final FieldMapperColumnDefinition composedDefinition = columnDefinition.compose(mapperConfig.columnDefinitions().getColumnDefinition(key));
        final K mappedColumnKey = composedDefinition.rename(key);

        if (columnDefinition.getCustomFieldMapper() != null) {
            addMapper((FieldMapper) columnDefinition.getCustomFieldMapper());
        } else {
            PropertyMapping> propertyMapping = propertyMappingsBuilder.addProperty(mappedColumnKey, composedDefinition);
            if (propertyMapping != null) {
                FieldMapperColumnDefinition effectiveColumnDefinition = propertyMapping.getColumnDefinition();
                if (effectiveColumnDefinition.isKey() && effectiveColumnDefinition.keyAppliesTo().test(propertyMapping.getPropertyMeta())) {
                    mappingContextFactoryBuilder.addKey(key);
                }
            }
        }
        return this;
    }

    public Mapper mapper() {
        // 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);
                                }
                            }
                        });


        FieldMapper[] fields = fields();
        InstantiatorAndFieldMappers constructorFieldMappersAndInstantiator = getConstructorFieldMappersAndInstantiator();

        Mapper mapper;

        if (isEligibleForAsmMapper()) {
            try {
                mapper =
                        reflectionService
                                .getAsmFactory()
                                .registerOrCreate(MapperAsmFactory.class,
                                        new UnaryFactory() {
                                            @Override
                                            public MapperAsmFactory newInstance(AsmFactory asmFactory) {
                                                return new MapperAsmFactory(asmFactory);
                                            }
                                        })
                                .createMapper(
                                        getKeys(),
                                        fields, constructorFieldMappersAndInstantiator.fieldMappers,
                                        constructorFieldMappersAndInstantiator.instantiator,
                                        mapperSource.source(),
                                        getTargetClass()
                                );
            } catch (Throwable e) {
                if (mapperConfig.failOnAsm()) {
                    return ErrorHelper.rethrow(e);
                } else {
                    mapper = new MapperImpl(fields, constructorFieldMappersAndInstantiator.fieldMappers, constructorFieldMappersAndInstantiator.instantiator);
                }
            }
        } else {
            mapper = new MapperImpl(fields, constructorFieldMappersAndInstantiator.fieldMappers, constructorFieldMappersAndInstantiator.instantiator);
        }
        return mapper;
    }

    public boolean hasJoin() {
        return mappingContextFactoryBuilder.isRoot()
                && !mappingContextFactoryBuilder.hasNoDependentKeys();
    }
	private Class getTargetClass() {
		return TypeHelper.toClass(target);
	}

	@SuppressWarnings("unchecked")
    private InstantiatorAndFieldMappers getConstructorFieldMappersAndInstantiator() throws MapperBuildingException {

		InstantiatorFactory instantiatorFactory = reflectionService.getInstantiatorFactory();
		try {
            ConstructorInjections constructorInjections = constructorInjections();
            Map, ?>> injections = constructorInjections.parameterGetterMap;
            MapperBiInstantiatorFactory mapperBiInstantiatorFactory = new MapperBiInstantiatorFactory(instantiatorFactory);
            GetterFactory getterFactory = fieldMapperAsGetterFactory();
            BiInstantiator, T> instantiator =
                    mapperBiInstantiatorFactory.
                            >
                                    getBiInstantiator(mapperSource.source(), target, propertyMappingsBuilder, injections, getterFactory, reflectionService.builderIgnoresNullValues());
            return new InstantiatorAndFieldMappers(constructorInjections.fieldMappers, instantiator);
		} catch(Exception e) {
            return ErrorHelper.rethrow(e);
		}
	}

    private GetterFactory fieldMapperAsGetterFactory() {
        return new FieldMapperFactoryGetterFactoryAdapter();
    }

    @SuppressWarnings("unchecked")
    private ConstructorInjections constructorInjections() {
		final Map, ?>> injections = new HashMap, ?>>();
		final List> fieldMappers = new ArrayList>();
		propertyMappingsBuilder.forEachConstructorProperties(new ForEachCallBack>>() {

            @SuppressWarnings("unchecked")
			@Override
			public void handle(PropertyMapping> propertyMapping) {
                if (!isTargetForMapperFieldMapper(propertyMapping)) {
                    PropertyMeta pm = propertyMapping.getPropertyMeta();
                    ConstructorPropertyMeta cProp = (ConstructorPropertyMeta) pm;
                    Parameter parameter = cProp.getParameter();
                    Getter getter =
                            fieldMapperFactory.getGetterFromSource(propertyMapping.getColumnKey(), pm.getPropertyType(), propertyMapping.getColumnDefinition(), pm.getPropertyClassMetaSupplier());
                    if (NullGetter.isNull(getter)) {
                        mapperConfig.mapperBuilderErrorHandler()
                                .accessorNotFound("Could not find getter for " + propertyMapping.getColumnKey() + " type "
                                        + propertyMapping.getPropertyMeta().getPropertyType()
                                        + " path " + propertyMapping.getPropertyMeta().getPath()
                                        + " See " + ErrorDoc.toUrl("FMMB_GETTER_NOT_FOUND"));
                    } else {
                        injections.put(parameter, new BiFunctionGetter, Object>(getter));
                    }
                    if (!NullSetter.isNull(cProp.getSetter())) {
                        fieldMappers.add(fieldMapperFactory.newFieldMapper(propertyMapping, mappingContextFactoryBuilder, mapperConfig.mapperBuilderErrorHandler()));
                    }
                }
			}
		});

        for(PropertyPerOwner e :
                getSubPropertyPerOwner()) {
            if (e.owner.isConstructorProperty()) {
                final List>> properties = e.propertyMappings;

                final MappingContextFactoryBuilder currentBuilder = getMapperContextFactoryBuilder(e.owner, properties);

                final Mapper mapper;
                if (properties.size() == 1 && properties.get(0).getPropertyMeta() instanceof ArrayElementPropertyMeta) {
                    mapper = getterPropertyMapper(e.owner, properties.get(0));
                } else {
                    mapper = subPropertyMapper(e.owner, properties, currentBuilder);
                }
                ConstructorPropertyMeta meta = (ConstructorPropertyMeta) e.owner;
                injections.put(meta.getParameter(), newMapperGetterAdapter(mapper, currentBuilder));
                fieldMappers.add(newMapperFieldMapper(properties, meta, mapper, currentBuilder));
            }
        }
		return new ConstructorInjections(injections, fieldMappers.toArray(new FieldMapper[0]));
	}

    private 

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

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

BiFunction, P> newMapperGetterAdapter(Mapper mapper, MappingContextFactoryBuilder builder) { return new MapperBiFunctionAdapter((Mapper)mapper, builder.nullChecker(), builder.currentIndex()); } // call use towards sub jdbcMapper // the keys are initialised private

void addMapping(K columnKey, FieldMapperColumnDefinition columnDefinition, PropertyMeta prop) { propertyMappingsBuilder.addProperty(columnKey, columnDefinition, prop); } @SuppressWarnings("unchecked") private FieldMapper[] 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)) { fields.add(newFieldMapper(t)); } } }); for(PropertyPerOwner e : getSubPropertyPerOwner()) { if (!e.owner.isConstructorProperty()) { final MappingContextFactoryBuilder currentBuilder = getMapperContextFactoryBuilder(e.owner, e.propertyMappings); final Mapper mapper; if (e.propertyMappings.size() == 1 && e.propertyMappings.get(0).getPropertyMeta() instanceof ArrayElementPropertyMeta) { mapper = getterPropertyMapper(e.owner, e.propertyMappings.get(0)); } else { mapper = subPropertyMapper(e.owner, e.propertyMappings, currentBuilder); } fields.add(newMapperFieldMapper(e.propertyMappings, e.owner, mapper, currentBuilder)); } } for(FieldMapper mapper : additionalMappers) { fields.add(mapper); } return fields.toArray(new FieldMapper[0]); } private boolean isTargetForMapperFieldMapper(PropertyMapping pm) { return pm.getPropertyMeta().isSubProperty() || (pm.getPropertyMeta() instanceof ArrayElementPropertyMeta && pm.getColumnDefinition().isKey()); } 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

Mapper subPropertyMapper(PropertyMeta owner, List>> properties, MappingContextFactoryBuilder mappingContextFactoryBuilder) { final ConstantSourceMapperBuilder builder = newSubBuilder(owner.getPropertyClassMeta(), 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.mapper(); } @SuppressWarnings("unchecked") protected

FieldMapper newFieldMapper(PropertyMapping> t) { FieldMapper fieldMapper = (FieldMapper) t.getColumnDefinition().getCustomFieldMapper(); if (fieldMapper == null) { fieldMapper = fieldMapperFactory.newFieldMapper(t, mappingContextFactoryBuilder, mapperConfig.mapperBuilderErrorHandler()); } return wrapFieldMapperWithErrorHandler(t, fieldMapper); } private

FieldMapper wrapFieldMapperWithErrorHandler(final PropertyMapping> t, final FieldMapper fieldMapper) { if (fieldMapper != null && mapperConfig.hasFieldMapperErrorHandler()) { return new FieldErrorHandlerMapper(t.getColumnKey(), fieldMapper, mapperConfig.fieldMapperErrorHandler()); } return fieldMapper; } public void addMapper(FieldMapper mapper) { additionalMappers.add(mapper); } private ConstantSourceMapperBuilder newSubBuilder( ClassMeta classMeta, MappingContextFactoryBuilder mappingContextFactoryBuilder, PropertyFinder propertyFinder) { return new ConstantSourceMapperBuilder( mapperSource, classMeta, mapperConfig, mappingContextFactoryBuilder, keyFactory, propertyFinder); } private FieldKey[] getKeys() { return propertyMappingsBuilder.getKeys().toArray(FIELD_KEYS); } private boolean isEligibleForAsmMapper() { return reflectionService.isAsmActivated() && propertyMappingsBuilder.size() < mapperConfig.asmMapperNbFieldsLimit(); } @SuppressWarnings("unchecked") private List getSubKeys(List>> properties) { List keys = new ArrayList(); // look for keys property of the object for (PropertyMapping> pm : properties) { if (pm.getPropertyMeta().isSubProperty()) { SubPropertyMeta subPropertyMeta = (SubPropertyMeta) pm.getPropertyMeta(); if (!(subPropertyMeta.getSubProperty() instanceof ArrayElementPropertyMeta)) { // ignore ArrayElementPropertyMeta as it's a direct getter and will be managed in the setter if (pm.getColumnDefinition().isKey()) { if (pm.getColumnDefinition().keyAppliesTo().test(subPropertyMeta.getSubProperty())) { keys.add(pm.getColumnKey()); } } } } else { if (pm.getColumnDefinition().isKey()) { if (pm.getColumnDefinition().keyAppliesTo().test(pm.getPropertyMeta())) { keys.add(pm.getColumnKey()); } } } } return keys; } private class InstantiatorAndFieldMappers { private final FieldMapper[] fieldMappers; private final BiInstantiator, T> instantiator; private InstantiatorAndFieldMappers(FieldMapper[] fieldMappers, BiInstantiator, T> instantiator) { this.fieldMappers = fieldMappers; this.instantiator = instantiator; } } private class ConstructorInjections { private final Map, ?>> parameterGetterMap; private final FieldMapper[] fieldMappers; private ConstructorInjections(Map, ?>> parameterGetterMap, FieldMapper[] fieldMappers) { this.parameterGetterMap = parameterGetterMap; this.fieldMappers = fieldMappers; } } 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 GetterFactory { @SuppressWarnings("unchecked") @Override public

Getter newGetter(Type target, K key, Object... properties) { FieldMapperColumnDefinition columnDefinition = FieldMapperColumnDefinition.identity().add(properties); return (Getter) fieldMapperFactory.getGetterFromSource(key, target , columnDefinition, new ClassMetaSupplier

(target)); } } private class ClassMetaSupplier

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

get() { return reflectionService.

getClassMeta(target); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy