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

org.sfm.csv.CsvMapperBuilder Maven / Gradle / Ivy

package org.sfm.csv;

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

import org.sfm.csv.impl.CellSetter;
import org.sfm.csv.impl.CellSetterFactory;
import org.sfm.csv.impl.CsvMapperImpl;
import org.sfm.csv.impl.DelayedCellSetter;
import org.sfm.csv.impl.DelayedCellSetterFactory;
import org.sfm.csv.impl.DelayedGetter;
import org.sfm.csv.impl.DelegateMarkerDelayedCellSetter;
import org.sfm.csv.impl.DelegateMarkerSetter;
import org.sfm.csv.impl.ParsingContextFactory;
import org.sfm.csv.impl.primitive.BooleanDelayedGetter;
import org.sfm.csv.impl.primitive.ByteDelayedGetter;
import org.sfm.csv.impl.primitive.CharDelayedGetter;
import org.sfm.csv.impl.primitive.DoubleDelayedGetter;
import org.sfm.csv.impl.primitive.FloatDelayedGetter;
import org.sfm.csv.impl.primitive.IntDelayedGetter;
import org.sfm.csv.impl.primitive.LongDelayedGetter;
import org.sfm.csv.impl.primitive.ShortDelayedGetter;
import org.sfm.map.FieldMapperErrorHandler;
import org.sfm.map.MapperBuilderErrorHandler;
import org.sfm.map.MapperBuildingException;
import org.sfm.map.RowHandlerErrorHandler;
import org.sfm.map.impl.*;
import org.sfm.reflect.Getter;
import org.sfm.reflect.Instantiator;
import org.sfm.reflect.InstantiatorFactory;
import org.sfm.reflect.ReflectionService;
import org.sfm.reflect.TypeHelper;
import org.sfm.reflect.ConstructorParameter;
import org.sfm.reflect.meta.*;
import org.sfm.utils.ForEachCallBack;

public class CsvMapperBuilder {

	private final Class SOURCE_UNTYPE = DelayedCellSetter[].class;
	@SuppressWarnings("unchecked")
	private final Class[]> SOURCE = (Class[]>) SOURCE_UNTYPE;
	private FieldMapperErrorHandler fieldMapperErrorHandler = new RethrowFieldMapperErrorHandler();

	private MapperBuilderErrorHandler mapperBuilderErrorHandler = new RethrowMapperBuilderErrorHandler();
	private RowHandlerErrorHandler rowHandlerErrorHandler = new RethrowRowHandlerErrorHandler();
	private final PropertyNameMatcherFactory propertyNameMatcherFactory;
	private final Type target;
	private final ReflectionService reflectionService;
	private final Map aliases;
	private final Map> customReaders;
	
	private final PropertyMappingsBuilder propertyMappingsBuilder;
	
	private int syncSetterStart;

	private String defaultDateFormat = "yyyy-MM-dd HH:mm:ss";

	public CsvMapperBuilder(final Type target) {
		this(target, ReflectionService.newInstance());
	}
	
	public CsvMapperBuilder(final Type target, ReflectionService reflectionService) {
		this(target, (ClassMeta)reflectionService.getClassMeta(target));
	}

	public CsvMapperBuilder(final Type target, final ClassMeta classMeta) {
		this(target, classMeta,
				new HashMap(),
				new HashMap>(), new DefaultPropertyNameMatcherFactory());
	}

	public CsvMapperBuilder(final Type target, final ClassMeta classMeta,
			Map aliases, Map> customReaders, PropertyNameMatcherFactory propertyNameMatcherFactory) throws MapperBuildingException {
		this.target = target;
		this.reflectionService = classMeta.getReflectionService();
		this.propertyMappingsBuilder = new PropertyMappingsBuilder(classMeta, propertyNameMatcherFactory);
		this.propertyNameMatcherFactory = propertyNameMatcherFactory;
		this.aliases = aliases;
		this.customReaders = customReaders;
	}

	public final CsvMapperBuilder addMapping(final String columnKey) {
		return addMapping(columnKey, propertyMappingsBuilder.size());
	}
	
	public final CsvMapperBuilder addMapping(final String columnKey, int columnIndex) {
		return addMapping(new CsvColumnKey(columnKey, columnIndex));
	}
	
	public final CsvMapperBuilder addMapping(final CsvColumnKey key) {
		final CsvColumnKey mappedColumnKey = alias(key);
		
		if (!propertyMappingsBuilder.addProperty(mappedColumnKey)) {
			mapperBuilderErrorHandler.propertyNotFound(target, key.getName());
		}
		
		return this;
	}
	
	private 

void addMapping(PropertyMeta propertyMeta, final CsvColumnKey key) { propertyMappingsBuilder.addProperty(key, propertyMeta); } private CsvColumnKey alias(CsvColumnKey key) { if (aliases == null || aliases.isEmpty()) { return key; } String alias = aliases.get(key.getName().toUpperCase()); if (alias == null) { return key; } return key.alias(alias); } public void setDefaultDateFormat(String defaultDateFormat) { this.defaultDateFormat = defaultDateFormat; } public final CsvMapper mapper() { return new CsvMapperImpl(getInstantiator(), buildDelayedSetters(), getSetters(), getKeys(), getParserContextFactory(), fieldMapperErrorHandler, rowHandlerErrorHandler); } private CsvColumnKey[] getKeys() { return propertyMappingsBuilder.getKeys().toArray(new CsvColumnKey[propertyMappingsBuilder.size()]); } private ParsingContextFactory getParserContextFactory() { final ParsingContextFactory pcf = new ParsingContextFactory(propertyMappingsBuilder.size()); propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() { @Override public void handle(PropertyMapping propMapping, int i) { if (propMapping == null) return; PropertyMeta prop = propMapping.getPropertyMeta(); if (prop != null) { Class target; if (prop instanceof SubPropertyMeta) { target = TypeHelper.toClass(((SubPropertyMeta) prop) .getFinalType()); } else { target = TypeHelper.toClass(prop.getType()); } if (Date.class.equals(target)) { pcf.setDateFormat(i, getDateFormat(i)); } } } }); return pcf; } private String getDateFormat(int i) { return defaultDateFormat; } private Instantiator[], T> getInstantiator() throws MapperBuildingException { InstantiatorFactory instantiatorFactory = reflectionService.getInstantiatorFactory(); try { return instantiatorFactory.getInstantiator(SOURCE, target, propertyMappingsBuilder, buildConstructorParametersDelayedCellSetter(), customReaders.isEmpty() ); } catch(Exception e) { throw new MapperBuildingException(e.getMessage(), e); } } private Map[], ?>> buildConstructorParametersDelayedCellSetter() { final Map[], ?>> constructorInjections = new HashMap[], ?>>(); propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() { @Override public void handle(PropertyMapping propMapping, int index) { if(propMapping == null) return; PropertyMeta meta = propMapping.getPropertyMeta(); if (meta == null) return; CsvColumnKey key = propMapping.getColumnKey(); if (meta.isConstructorProperty()) { syncSetterStart = index + 1; constructorInjections.put(((ConstructorPropertyMeta) meta).getConstructorParameter(), newDelayedGetter(key, meta.getType())); } else if (meta.isSubProperty()) { SubPropertyMeta subMeta = (SubPropertyMeta) meta; if (subMeta.getOwnerProperty().isConstructorProperty()) { ConstructorPropertyMeta constPropMeta = (ConstructorPropertyMeta) subMeta.getOwnerProperty(); if (!constructorInjections.containsKey(constPropMeta.getConstructorParameter())) { constructorInjections.put(constPropMeta.getConstructorParameter(), newDelayedGetter(key, constPropMeta.getType())); } syncSetterStart = index + 1; } } } }); return constructorInjections; } private Getter[], ?> newDelayedGetter(CsvColumnKey key, Type type) { Class clazz = TypeHelper.toClass(type); Getter[], ?> getter; int columnIndex = key.getIndex(); if (clazz.isPrimitive() && ! customReaders.containsKey(key.getName())) { if (boolean.class.equals(clazz)) { getter = new BooleanDelayedGetter(columnIndex); } else if (byte.class.equals(clazz)) { getter = new ByteDelayedGetter(columnIndex); } else if (char.class.equals(clazz)) { getter = new CharDelayedGetter(columnIndex); } else if (short.class.equals(clazz)) { getter = new ShortDelayedGetter(columnIndex); } else if (int.class.equals(clazz)) { getter = new IntDelayedGetter(columnIndex); } else if (long.class.equals(clazz)) { getter = new LongDelayedGetter(columnIndex); } else if (float.class.equals(clazz)) { getter = new FloatDelayedGetter(columnIndex); } else if (double.class.equals(clazz)) { getter = new DoubleDelayedGetter(columnIndex); } else { throw new IllegalArgumentException("Unexpected primitive " + clazz); } } else { getter = new DelayedGetter(columnIndex); } return getter; } @SuppressWarnings({ "unchecked" }) private DelayedCellSetterFactory[] buildDelayedSetters() { final Map> delegateMapperBuilders = new HashMap>(); final List> delayedSetters = new ArrayList>(syncSetterStart); propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() { CellSetterFactory cellSetterFactory = new CellSetterFactory(customReaders); @Override public void handle(PropertyMapping propMapping, int index) { if (propMapping != null) { PropertyMeta prop = propMapping.getPropertyMeta(); CsvColumnKey key = propMapping.getColumnKey(); if (prop != null) { if (prop.isConstructorProperty()) { delayedSetters.add((DelayedCellSetterFactory)cellSetterFactory.getDelayedCellSetter(prop.getType(), index, key.getName())); } else if (prop.isSubProperty()) { addSubProperty(delegateMapperBuilders, delayedSetters, prop, key); }else { delayedSetters.add(cellSetterFactory.getDelayedCellSetter(prop.getType(), prop.getSetter(), index, key.getName())); } } else { delayedSetters.add(null); } } else { delayedSetters.add(null); } } private

void addSubProperty( Map> delegateMapperBuilders, List> delayedSetters, PropertyMeta prop, CsvColumnKey key) { SubPropertyMeta subPropertyMeta = (SubPropertyMeta)prop; final PropertyMeta propOwner = subPropertyMeta.getOwnerProperty(); CsvMapperBuilder

delegateMapperBuilder = (CsvMapperBuilder

) delegateMapperBuilders .get(propOwner.getName()); if (delegateMapperBuilder == null) { delegateMapperBuilder = new CsvMapperBuilder

(propOwner.getType(), propOwner.getClassMeta(), aliases, customReaders, propertyNameMatcherFactory); delegateMapperBuilders.put(propOwner.getName(), delegateMapperBuilder); } delegateMapperBuilder.addMapping(subPropertyMeta.getSubProperty(), key); delayedSetters.add(null); } }, 0, syncSetterStart); final Map> mappers = new HashMap>(); propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() { @Override public void handle(PropertyMapping propMapping, int index) { if (propMapping == null) return; PropertyMeta prop = propMapping.getPropertyMeta(); if (prop.isSubProperty()) { addSubPropertyDelayedSetter(delegateMapperBuilders, delayedSetters, mappers, index, prop); } } private

void addSubPropertyDelayedSetter( Map> delegateMapperBuilders, List> delayedSetters, Map> mappers, int setterIndex, PropertyMeta prop) { PropertyMeta subProp = ((SubPropertyMeta) prop).getOwnerProperty(); final String propName = subProp.getName(); CsvMapper

mapper = (CsvMapper

) mappers.get(propName); if (mapper == null) { CsvMapperBuilder

delegateMapperBuilder = (CsvMapperBuilder

) delegateMapperBuilders.get(propName); mapper = delegateMapperBuilder.mapper(); mappers.put(propName, mapper); } if (subProp instanceof ConstructorPropertyMeta) { delayedSetters.set(setterIndex , new DelegateMarkerDelayedCellSetter(mapper)); } else { delayedSetters.set(setterIndex , new DelegateMarkerDelayedCellSetter(mapper, subProp.getSetter())); } } }, 0, syncSetterStart); return delayedSetters.toArray(new DelayedCellSetterFactory[syncSetterStart]); } @SuppressWarnings({ "unchecked", "rawtypes" }) private CellSetter[] getSetters() { final Map> delegateMapperBuilders = new HashMap>(); final List> setters = new ArrayList>(); propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() { CellSetterFactory cellSetterFactory = new CellSetterFactory(customReaders); @Override public void handle(PropertyMapping propMapping, int index) { if (propMapping != null) { PropertyMeta prop = propMapping.getPropertyMeta(); if (prop != null) { CsvColumnKey key = propMapping.getColumnKey(); if (prop.isConstructorProperty()) { throw new IllegalStateException("Unexpected ConstructorPropertyMeta at " + index); } else if (prop.isSubProperty()) { final PropertyMeta powner = ((SubPropertyMeta)prop).getOwnerProperty(); CsvMapperBuilder delegateMapperBuilder = delegateMapperBuilders .get(powner.getName()); if (delegateMapperBuilder == null) { delegateMapperBuilder = new CsvMapperBuilder(powner.getType(), powner.getClassMeta(), aliases, customReaders, propertyNameMatcherFactory); delegateMapperBuilders.put(powner.getName(), delegateMapperBuilder); } delegateMapperBuilder.addMapping(((SubPropertyMeta) prop).getSubProperty(), key); setters.add(null); } else { setters.add(cellSetterFactory.getCellSetter(prop.getType(), prop.getSetter(), index, key.getName())); } } else { setters.add(null); } } else { setters.add(null); } } }, syncSetterStart); propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() { final Map> mappers = new HashMap>(); @Override public void handle(PropertyMapping propMapping, int index) { if (propMapping == null) return; PropertyMeta prop = propMapping.getPropertyMeta(); if (prop instanceof SubPropertyMeta) { final String propName = ((SubPropertyMeta)prop).getOwnerProperty().getName(); CsvMapper mapper = mappers.get(propName); if (mapper == null) { CsvMapperBuilder delegateMapperBuilder = delegateMapperBuilders .get(propName); mapper = delegateMapperBuilder.mapper(); mappers.put(propName, mapper); } setters.set(index , new DelegateMarkerSetter(mapper, ((SubPropertyMeta) prop).getOwnerProperty().getSetter())); } } }, syncSetterStart); return setters.toArray(new CellSetter[setters.size()]); } public final CsvMapperBuilder fieldMapperErrorHandler(final FieldMapperErrorHandler errorHandler) { fieldMapperErrorHandler = errorHandler; return this; } public final CsvMapperBuilder mapperBuilderErrorHandler(final MapperBuilderErrorHandler errorHandler) { mapperBuilderErrorHandler = errorHandler; return this; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy