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

org.sfm.map.AbstractMapperBuilderImpl Maven / Gradle / Ivy

package org.sfm.map;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.sfm.jdbc.MapperBuilder;
import org.sfm.jdbc.MapperGetterAdapter;
import org.sfm.reflect.Getter;
import org.sfm.reflect.Instantiator;
import org.sfm.reflect.InstantiatorFactory;
import org.sfm.reflect.ReflectionService;
import org.sfm.reflect.Setter;
import org.sfm.reflect.TypeHelper;
import org.sfm.reflect.asm.ConstructorParameter;
import org.sfm.reflect.meta.ClassMeta;
import org.sfm.reflect.meta.ConstructorPropertyMeta;
import org.sfm.reflect.meta.PropertyFinder;
import org.sfm.reflect.meta.PropertyMeta;
import org.sfm.reflect.meta.SubProperty;
import org.sfm.reflect.meta.SubPropertyMeta;

public abstract class AbstractMapperBuilderImpl,  B extends MapperBuilder> 
	implements MapperBuilder {

	private FieldMapperErrorHandler fieldMapperErrorHandler;
	private MapperBuilderErrorHandler mapperBuilderErrorHandler = new RethrowMapperBuilderErrorHandler();
	private final Type target;
	private final Type source;
	private final PropertyFinder propertyFinder;
	private final List> fields = new ArrayList>();
	private final Map> constructorInjections;
	private final List> subProperties = new ArrayList>();
	private final FieldMapperFactory fieldMapperFactory;
	private final GetterFactory getterFactory;

	protected final ReflectionService reflectionService;
	
	public AbstractMapperBuilderImpl(final Type target, final Type source, final ClassMeta classMeta,   
			GetterFactory getterFactory, FieldMapperFactory fieldMapperFactory) throws MapperBuildingException {
		this.target = target;
		this.source = source;
		this.reflectionService = classMeta.getReflectionService();
		this.constructorInjections = new HashMap>();
		this.propertyFinder = classMeta.newPropertyFinder();
		this.getterFactory = getterFactory;
		this.fieldMapperFactory = fieldMapperFactory;
	}

	@SuppressWarnings("unchecked")
	public final B fieldMapperErrorHandler(final FieldMapperErrorHandler errorHandler) {
		if (!fields.isEmpty()) {
			throw new IllegalStateException(
					"Error Handler need to be set before adding fields");
		}
		fieldMapperErrorHandler = errorHandler;
		return (B) this;
	}

	@SuppressWarnings("unchecked")
	public final B mapperBuilderErrorHandler(final MapperBuilderErrorHandler errorHandler) {
		mapperBuilderErrorHandler = errorHandler;
		return (B) this;
	}

	@SuppressWarnings("unchecked")
	public final B addMapping(final String propertyName, final K columnKey) {
		FieldMapper fieldMapper = getCustomMapper(columnKey);
		if (fieldMapper != null) {
			if (fieldMapperErrorHandler != null) {
				fieldMapper = new FieldErrorHandlerMapper(columnKey, fieldMapper, fieldMapperErrorHandler);
			}
			fields.add(fieldMapper);
		} else {
			final PropertyMeta property = propertyFinder.findProperty(propertyName);
			if (property == null) {
					mapperBuilderErrorHandler.propertyNotFound(target, propertyName);
			} else {
				addMapping(property, columnKey);
			}
		}
		return (B) this;
	}

	protected FieldMapper getCustomMapper(K columnKey) {
		return null;
	}


	protected Class getTargetClass() {
		return TypeHelper.toClass(target);
	}

	@SuppressWarnings("unchecked")
	protected Instantiator getInstantiator() throws MapperBuildingException {
		InstantiatorFactory instantiatorFactory = reflectionService.getInstantiatorFactory();
		if (!reflectionService.isAsmPresent()) {
			try {
				return (Instantiator) instantiatorFactory.getInstantiator(TypeHelper.toClass(source), propertyFinder.getClassToInstantiate());
			} catch(Exception e) {
				throw new MapperBuildingException(e.getMessage(), e);
			}
		} else {
			try {
				return instantiatorFactory.getInstantiator(TypeHelper.toClass(source), propertyFinder.getEligibleConstructorDefinitions(), constructorInjections());
			} catch(Exception e) {
				throw new MapperBuildingException(e.getMessage(), e);
			}
		}
	}

	@SuppressWarnings({  "rawtypes" })
	private Map> constructorInjections() {
		Map> injections = new HashMap>(constructorInjections);
		
		for(SubProperty subProp : subProperties) {
			PropertyMeta prop = subProp.getSubProperty().getProperty();
			if (prop instanceof ConstructorPropertyMeta) {
				MapperBuilder builder = subProp.getMapperBuilder();
				
				final Mapper mapper = builder.mapper();
				
				Getter getter = new MapperGetterAdapter(mapper); 
				
				injections.put(((ConstructorPropertyMeta) prop).getConstructorParameter(), getter);
			}
			
		}
		
		return injections;
	}

	public abstract M mapper();
	
	@SuppressWarnings("unchecked")
	public final FieldMapper[] fields() {
		List> fields = new ArrayList>(this.fields);
		
		for(SubProperty subProp : subProperties) {
			PropertyMeta prop = subProp.getSubProperty().getProperty();
			
			if (!(prop instanceof ConstructorPropertyMeta)) {
				Setter setter = (Setter) prop.getSetter();
				Mapper mapper = (Mapper) subProp.getMapperBuilder().mapper();
				Getter getter = new MapperGetterAdapter(mapper);
				
				fields.add(new FieldMapperImpl(getter, setter));
			}
			
		}
		
		return fields.toArray(new FieldMapper[fields.size()]);
	}

	private SubProperty getOrAddSubPropertyMapperBuilder(SubPropertyMeta property) {
		
		for(SubProperty subProp : subProperties) {
			if (subProp.getSubProperty().getName().equals(property.getName())) {
				return subProp;
			}
		}
		
		MapperBuilder builder = newMapperBuilder(property.getType(), property.getClassMeta());
		SubProperty subProp = new SubProperty(builder, property);
		
		subProperties.add(subProp);
		
		return subProp;
	}

	protected abstract MapperBuilder newMapperBuilder(Type type, ClassMeta classMeta);

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public B addMapping(PropertyMeta property, K key) {
		if (property instanceof ConstructorPropertyMeta) {
			ConstructorParameter constructorParameter = ((ConstructorPropertyMeta) property).getConstructorParameter();
			Getter getter = getterFactory.newGetter(constructorParameter.getType(), key);
			if (getter == null) {
				mapperBuilderErrorHandler.getterNotFound("Could not find getter for " + key + " type " + constructorParameter.getType());
			}
			constructorInjections.put(constructorParameter, getter);
		} else if (property instanceof SubPropertyMeta) {
			SubProperty subProp = getOrAddSubPropertyMapperBuilder((SubPropertyMeta)property);
			MapperBuilder mapperBuilder = subProp.getMapperBuilder();
			mapperBuilder.addMapping(((SubPropertyMeta) property).getSubProperty(), key);
		} else {
			FieldMapper fieldMapper = fieldMapperFactory.newFieldMapper(property.getSetter(), key, fieldMapperErrorHandler, mapperBuilderErrorHandler);
			if (fieldMapperErrorHandler != null) {
				fieldMapper = new FieldErrorHandlerMapper(key, fieldMapper, fieldMapperErrorHandler);
			}
			fields.add(fieldMapper);
		}
		return (B) this;
	}

	@SuppressWarnings("unchecked")
	public B addMapper(FieldMapper mapper) {
		fields.add(mapper);
		return (B) this;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy