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

org.simpleflatmapper.map.mapper.PropertyMappingsBuilder 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.map.CaseInsensitiveFieldKeyNamePredicate;
import org.simpleflatmapper.map.FieldKey;
import org.simpleflatmapper.map.MapperBuilderErrorHandler;
import org.simpleflatmapper.map.MapperBuildingException;
import org.simpleflatmapper.map.MapperConfig;
import org.simpleflatmapper.map.impl.ExtendPropertyFinder;
import org.simpleflatmapper.map.property.GetterProperty;
import org.simpleflatmapper.map.property.OptionalProperty;
import org.simpleflatmapper.map.property.SetterProperty;
import org.simpleflatmapper.reflect.TypeAffinity;
import org.simpleflatmapper.reflect.getter.NullGetter;
import org.simpleflatmapper.reflect.meta.ClassMeta;
import org.simpleflatmapper.reflect.meta.PropertyFinder;
import org.simpleflatmapper.reflect.meta.PropertyMeta;
import org.simpleflatmapper.map.PropertyNameMatcherFactory;
import org.simpleflatmapper.reflect.meta.PropertyNameMatcher;
import org.simpleflatmapper.reflect.meta.SelfPropertyMeta;
import org.simpleflatmapper.reflect.setter.NullSetter;
import org.simpleflatmapper.util.BiConsumer;
import org.simpleflatmapper.util.ErrorDoc;
import org.simpleflatmapper.util.ForEachCallBack;
import org.simpleflatmapper.util.Function;
import org.simpleflatmapper.util.Predicate;
import org.simpleflatmapper.util.TypeHelper;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public final class PropertyMappingsBuilder> {

	protected final PropertyFinder propertyFinder;

	protected final List> properties = new ArrayList>();

	protected final PropertyNameMatcherFactory propertyNameMatcherFactory;

	private final MapperBuilderErrorHandler _mapperBuilderErrorHandler;
	private final ClassMeta classMeta;
	private final PropertyMappingsBuilderProbe propertyMappingsBuilderProbe;
	private final PropertyPredicateFactory isValidPropertyMeta;

	protected boolean modifiable = true;

	private List> customProperties;

	private PropertyMappingsBuilder(final ClassMeta classMeta,
									final PropertyNameMatcherFactory propertyNameMatcherFactory,
									final MapperBuilderErrorHandler mapperBuilderErrorHandler,
									final PropertyPredicateFactory isValidPropertyMetaFactory,
									final PropertyFinder propertyFinder,
									List> customProperties,
									PropertyMappingsBuilderProbe propertyMappingsBuilderProbe)  throws MapperBuildingException {
		this.isValidPropertyMeta = isValidPropertyMetaFactory;
		this._mapperBuilderErrorHandler = mapperBuilderErrorHandler;
		this.customProperties = customProperties;
		this.propertyMappingsBuilderProbe = propertyMappingsBuilderProbe;
		this.propertyFinder = propertyFinder != null ? propertyFinder : classMeta.newPropertyFinder();
		this.propertyNameMatcherFactory = propertyNameMatcherFactory;
		this.classMeta = classMeta;
	}


	public 

PropertyMapping addProperty(final K key, final ColumnDefinition columnDefinition) { return _addProperty(key, columnDefinition, _mapperBuilderErrorHandler); } public

PropertyMapping addPropertyIfPresent(final K key, final ColumnDefinition columnDefinition) { return _addProperty(key, columnDefinition, MapperBuilderErrorHandler.NULL); } @SuppressWarnings("unchecked") private

PropertyMapping _addProperty(final K key, final ColumnDefinition columnDefinition, MapperBuilderErrorHandler mapperBuilderErrorHandler) { if (!modifiable) throw new IllegalStateException("Builder not modifiable"); if (columnDefinition.ignore()) { propertyMappingsBuilderProbe.ignore(key, columnDefinition); properties.add(null); return null; } PropertyFinder effectivePropertyFinder = wrapPropertyFinder(this.propertyFinder); PropertyNameMatcher propertyNameMatcher = propertyNameMatcherFactory.newInstance(key); List accessorNotFounds = new ArrayList(); Predicate> propertyFilter = isValidPropertyMeta.predicate(key, columnDefinition.properties(), accessorNotFounds); final PropertyMeta prop = (PropertyMeta) effectivePropertyFinder .findProperty(propertyNameMatcher, columnDefinition.properties(), toTypeAffinity(key), propertyMappingsBuilderProbe.propertyFinderProbe(propertyNameMatcher), propertyFilter); if (prop == null) { if (!columnDefinition.has(OptionalProperty.class)) { AccessorNotFound accessorNotFound = selectAccessotNotFound(accessorNotFounds); if (accessorNotFound == null) { mapperBuilderErrorHandler.propertyNotFound(classMeta.getType(), key.getName()); } else { mapperBuilderErrorHandler.accessorNotFound(accessorNotFounds.iterator().next().toString()); } } properties.add(null); return null; } else { PropertyMapping propertyMapping = addProperty(key, columnDefinition, prop); propertyMappingsBuilderProbe.map(key, columnDefinition, prop); handleSelfPropertyMetaInvalidation(mapperBuilderErrorHandler); return propertyMapping; } } private AccessorNotFound selectAccessotNotFound(List accessorNotFounds) { for(AccessorNotFound accessorNotFound : accessorNotFounds) { if (!accessorNotFound.propertyMeta.isSelf()) return accessorNotFound; } return null; } private TypeAffinity toTypeAffinity(K key) { if (key instanceof TypeAffinity) { return (TypeAffinity) key; } return null; } private PropertyFinder wrapPropertyFinder(PropertyFinder propertyFinder) { if (!customProperties.isEmpty()) { return new ExtendPropertyFinder(propertyFinder, customProperties, new Function() { @Override public PropertyFinder.PropertyFinderTransformer apply(PropertyFinder.PropertyFinderTransformer propertyFinderTransformer) { return new ExtendPropertyFinder.ExtendPropertyFinderTransformer(propertyFinderTransformer, customProperties); } }); } return propertyFinder; } private void handleSelfPropertyMetaInvalidation(MapperBuilderErrorHandler errorHandler) { List invalidateKeys = new ArrayList(); for(ListIterator> iterator = properties.listIterator(); iterator.hasNext();) { PropertyMapping propertyMapping = iterator.next(); if (propertyMapping != null && !propertyMapping.getPropertyMeta().isValid()) { iterator.set(null); if (!propertyMapping.getColumnDefinition().has(OptionalProperty.class)) { invalidateKeys.add(propertyMapping.getColumnKey()); } } } for(K k : invalidateKeys) { errorHandler.propertyNotFound(classMeta.getType(), k.getName()); } } public

PropertyMapping addProperty(final K key, final ColumnDefinition columnDefinition, final PropertyMeta prop) { if (columnDefinition.hasCustomSourceFrom(prop.getOwnerType())) { Type type = prop.getPropertyType(); if (!checkTypeCompatibility(key, columnDefinition.getCustomSourceReturnTypeFrom(prop.getOwnerType()), type)) { properties.add(null); return null; } } Object[] definedProperties = prop.getDefinedProperties(); ColumnDefinition mergeColumnDefinition = definedProperties != null ? columnDefinition.add(definedProperties) : columnDefinition; PropertyMapping propertyMapping = new PropertyMapping(prop, key, mergeColumnDefinition); properties.add(propertyMapping); propertyFinder.manualMatch(prop); return propertyMapping; } private boolean checkTypeCompatibility(K key, Type customSourceReturnType, Type propertyMetaType) { if (customSourceReturnType == null) { // cannot determine type return true; } else if(!areCompatible(propertyMetaType, customSourceReturnType)) { _mapperBuilderErrorHandler.customFieldError(key, "Incompatible customReader on '" + key.getName()+ "' type " + customSourceReturnType + " expected " + propertyMetaType ); return false; } return true; } private boolean areCompatible(Type propertyMetaType, Type customSourceReturnType) { Class propertyMetaClass = TypeHelper.toBoxedClass(TypeHelper.toClass(propertyMetaType)); Class customSourceReturnClass = TypeHelper.toBoxedClass(TypeHelper.toClass(customSourceReturnType)); return propertyMetaClass.isAssignableFrom(customSourceReturnClass); } public List getKeys() { modifiable = false; List keys = new ArrayList(properties.size()); for (PropertyMapping propMapping : properties) { if (propMapping != null) { keys.add(propMapping.getColumnKey()); } else { keys.add(null); } } return keys; } public void forEachConstructorProperties(ForEachCallBack> handler) { modifiable = false; for (PropertyMapping property : properties) { if (property != null) { PropertyMeta propertyMeta = property.getPropertyMeta(); if (propertyMeta != null && propertyMeta.isConstructorProperty() && ! propertyMeta.isSubProperty()) { handler.handle(property); } } } } public List> currentProperties() { return new ArrayList>(properties); } public >> H forEachProperties(H handler) { return forEachProperties(handler, -1 ); } public >> F forEachProperties(F handler, int start) { return forEachProperties(handler, start, -1 ); } public >> F forEachProperties(F handler, int start, int end) { modifiable = false; for (PropertyMapping prop : properties) { if (prop != null && (prop.getColumnKey().getIndex() >= start || start == -1) && (prop.getColumnKey().getIndex() < end || end == -1)) { handler.handle(prop); } } return handler; } public PropertyFinder getPropertyFinder() { modifiable = false; return propertyFinder; } public int size() { return properties.size(); } public boolean isSelfProperty() { return (properties.size() == 1 && properties.get(0) != null && properties.get(0).getPropertyMeta() instanceof SelfPropertyMeta); } public int maxIndex() { int i = -1; for (PropertyMapping prop : properties) { if (prop != null) { i = Math.max(i, prop.getColumnKey().getIndex()); } } return i; } public boolean hasKey(Predicate predicate) { for (PropertyMapping propMapping : properties) { if (propMapping != null && predicate.test(propMapping.getColumnKey())) { return true; } } return false; } public ClassMeta getClassMeta() { return classMeta; } public static , S> PropertyMappingsBuilder of( ClassMeta classMeta, MapperConfig mapperConfig, PropertyPredicateFactory propertyPredicateFactory) { return of(classMeta, mapperConfig, propertyPredicateFactory, null); } public static , S> PropertyMappingsBuilder of( final ClassMeta classMeta, final MapperConfig mapperConfig, final PropertyPredicateFactory propertyPredicateFactory, final PropertyFinder propertyFinder) { final List> customProperties = new ArrayList>(); final Predicate> propertyPredicate = propertyPredicateFactory.predicate(null, null, new ArrayList()); // setter mapperConfig.columnDefinitions().forEach(SetterProperty.class, new BiConsumer, SetterProperty>() { @Override public void accept(Predicate predicate, SetterProperty setterProperty) { if (predicate instanceof CaseInsensitiveFieldKeyNamePredicate) { CaseInsensitiveFieldKeyNamePredicate p = (CaseInsensitiveFieldKeyNamePredicate) predicate; ExtendPropertyFinder.CustomProperty cp = new ExtendPropertyFinder.CustomProperty(setterProperty.getTargetType(), classMeta.getReflectionService(), p.getName(), setterProperty.getPropertyType(), setterProperty.getSetter(), NullGetter.getter()); if (propertyPredicate.test(cp)) { customProperties.add(cp); } } } }); // getter mapperConfig.columnDefinitions().forEach(GetterProperty.class, new BiConsumer, GetterProperty>() { @Override public void accept(Predicate predicate, GetterProperty getterProperty) { if (predicate instanceof CaseInsensitiveFieldKeyNamePredicate) { CaseInsensitiveFieldKeyNamePredicate p = (CaseInsensitiveFieldKeyNamePredicate) predicate; ExtendPropertyFinder.CustomProperty cp = new ExtendPropertyFinder.CustomProperty(getterProperty.getSourceType(), classMeta.getReflectionService(), p.getName(), getterProperty.getReturnType(), NullSetter.NULL_SETTER, getterProperty.getGetter()); if (propertyPredicate.test(cp)) { customProperties.add(cp); } } } }); return new PropertyMappingsBuilder( classMeta, mapperConfig.propertyNameMatcherFactory(), mapperConfig.mapperBuilderErrorHandler(), propertyPredicateFactory, propertyFinder, customProperties, DefaultPropertyMappingsBuilderProbe.INSTANCE); } public interface PropertyMappingsBuilderProbe { void ignore(FieldKey key, ColumnDefinition columnDefinition); void map(FieldKey key, ColumnDefinition columnDefinition, PropertyMeta prop); PropertyFinder.PropertyFinderProbe propertyFinderProbe(PropertyNameMatcher matcher); } private static class DefaultPropertyMappingsBuilderProbe implements PropertyMappingsBuilderProbe { static final DefaultPropertyMappingsBuilderProbe INSTANCE = new DefaultPropertyMappingsBuilderProbe(); private static final boolean DEBUG = Boolean.getBoolean("org.simpleflatmapper.probe.propertyMappingsBuilder"); @Override public void ignore(FieldKey key, ColumnDefinition columnDefinition) { if (DEBUG) { System.out.println("PropertyMappingsBuilder - ignore " + key); } } @Override public void map(FieldKey key, ColumnDefinition columnDefinition, PropertyMeta prop) { if (DEBUG) { String path = prop.getPath(); System.out.println("PropertyMappingsBuilder - map " + key.getName() + " to " + path); } } @Override public PropertyFinder.PropertyFinderProbe propertyFinderProbe(PropertyNameMatcher matcher) { return new PropertyFinder.DefaultPropertyFinderProbe(matcher); } } public interface PropertyPredicateFactory> { Predicate> predicate(K key, Object[] properties, List accessorNotFounds); } public static final class AccessorNotFound { public final FieldKey key; public final String path; public final Type to; public final ErrorDoc errorDoc; public final PropertyMeta propertyMeta; public AccessorNotFound(FieldKey key, String path, Type to, ErrorDoc errorDoc, PropertyMeta propertyMeta) { this.key = key; this.path = path; this.to = to; this.errorDoc = errorDoc; this.propertyMeta = propertyMeta; } public String toString() { String accessor = "NA"; switch (errorDoc) { case CSFM_GETTER_NOT_FOUND: accessor = "Getter"; break; case PROPERTY_NOT_FOUND: accessor = "property"; break; case CTFM_SETTER_NOT_FOUND: accessor = "Setter"; break; case CTFM_GETTER_NOT_FOUND: accessor = "Getter"; break; } return "Could not find " + accessor + " for " + key + " returning type " + to + " path " + path + ". See " + errorDoc.toUrl(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy