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

org.sfm.csv.CsvMapperBuilder 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: 1.10.3
Show newest version
package org.sfm.csv;

import org.sfm.csv.impl.*;
import org.sfm.map.*;
import org.sfm.map.impl.*;
import org.sfm.reflect.*;
import org.sfm.reflect.meta.*;
import org.sfm.utils.ForEachCallBack;

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

public class CsvMapperBuilder {

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

	private final MapperBuilderErrorHandler mapperBuilderErrorHandler;
	private RowHandlerErrorHandler rowHandlerErrorHandler = new RethrowRowHandlerErrorHandler();
	private final PropertyNameMatcherFactory propertyNameMatcherFactory;
	private final Type target;
	private final ReflectionService reflectionService;
	private final ColumnDefinitionProvider columnDefinitions;

	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());
	}
	
	@SuppressWarnings("unchecked")
	public CsvMapperBuilder(final Type target, ReflectionService reflectionService) {
		this(target, (ClassMeta)reflectionService.getRootClassMeta(target));
	}

	public CsvMapperBuilder(final Type target, final ClassMeta classMeta) {
		this(target, classMeta, new IdentityCsvColumnDefinitionProvider());
	}

	public CsvMapperBuilder(final Type target, final ClassMeta classMeta, ColumnDefinitionProvider columnDefinitionProvider) {
		this(target, classMeta, new RethrowMapperBuilderErrorHandler(), columnDefinitionProvider, new DefaultPropertyNameMatcherFactory(), new CellValueReaderFactoryImpl());
	}

	public CsvMapperBuilder(final Type target, final ClassMeta classMeta,
							MapperBuilderErrorHandler mapperBuilderErrorHandler, ColumnDefinitionProvider columnDefinitions, PropertyNameMatcherFactory propertyNameMatcherFactory, CellValueReaderFactory cellValueReaderFactory) throws MapperBuildingException {
		this.target = target;
		this.mapperBuilderErrorHandler = mapperBuilderErrorHandler;
		this.reflectionService = classMeta.getReflectionService();
		this.propertyMappingsBuilder = new PropertyMappingsBuilder(classMeta, propertyNameMatcherFactory, this.mapperBuilderErrorHandler);
		this.propertyNameMatcherFactory = propertyNameMatcherFactory;
		this.columnDefinitions = columnDefinitions;
		this.cellValueReaderFactory = cellValueReaderFactory;
	}

	public final CsvMapperBuilder addMapping(final String columnKey) {
		return addMapping(columnKey, propertyMappingsBuilder.size());
	}

	public final CsvMapperBuilder addMapping(final String columnKey, final CsvColumnDefinition columnDefinition) {
		return addMapping(columnKey, propertyMappingsBuilder.size(), columnDefinition);
	}

	public final CsvMapperBuilder addMapping(final String columnKey, int columnIndex, CsvColumnDefinition columnDefinition) {
		return addMapping(new CsvColumnKey(columnKey, columnIndex), columnDefinition);
	}

	public final CsvMapperBuilder addMapping(final String columnKey, int columnIndex) {
		return addMapping(new CsvColumnKey(columnKey, columnIndex), CsvColumnDefinition.IDENTITY);
	}
	
	public final CsvMapperBuilder addMapping(final CsvColumnKey key, final CsvColumnDefinition columnDefinition) {
		final CsvColumnDefinition composedDefinition = CsvColumnDefinition.compose(getColumnDefinition(key), columnDefinition);
		final CsvColumnKey mappedColumnKey = composedDefinition.rename(key);

		propertyMappingsBuilder.addProperty(mappedColumnKey, composedDefinition);

		return this;
	}


	private 

void addMapping(PropertyMeta propertyMeta, final CsvColumnKey key, final CsvColumnDefinition columnDefinition) { propertyMappingsBuilder.addProperty(key, columnDefinition, propertyMeta); } private CsvColumnDefinition getColumnDefinition(CsvColumnKey key) { return CsvColumnDefinition.compose(CsvColumnDefinition.dateFormatDefinition(defaultDateFormat), columnDefinitions.getColumnDefinition(key)); } public void setDefaultDateFormat(String defaultDateFormat) { this.defaultDateFormat = defaultDateFormat; } public final CsvMapper mapper() { ParsingContextFactoryBuilder parsingContextFactoryBuilder = new ParsingContextFactoryBuilder(propertyMappingsBuilder.size()); return new CsvMapperImpl(getInstantiator(), buildDelayedSetters(parsingContextFactoryBuilder), getSetters(parsingContextFactoryBuilder), getKeys(), parsingContextFactoryBuilder.newFactory(), fieldMapperErrorHandler, rowHandlerErrorHandler); } private CsvColumnKey[] getKeys() { return propertyMappingsBuilder.getKeys().toArray(new CsvColumnKey[propertyMappingsBuilder.size()]); } private Instantiator[], T> getInstantiator() throws MapperBuildingException { InstantiatorFactory instantiatorFactory = reflectionService.getInstantiatorFactory(); try { return instantiatorFactory.getInstantiator(SOURCE, target, propertyMappingsBuilder, buildConstructorParametersDelayedCellSetter(), new GetterFactory[], CsvColumnKey>() { final CellSetterFactory cellSetterFactory = new CellSetterFactory(cellValueReaderFactory); @Override public

Getter[], P> newGetter(Type target, CsvColumnKey key) { return cellSetterFactory.newDelayedGetter(key, target); } }); } catch(Exception e) { throw new MapperBuildingException(e.getMessage(), e); } } private Map[], ?>> buildConstructorParametersDelayedCellSetter() { final Map[], ?>> constructorInjections = new HashMap[], ?>>(); propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() { final CellSetterFactory cellSetterFactory = new CellSetterFactory(cellValueReaderFactory); @SuppressWarnings("unchecked") @Override public void handle(PropertyMapping propMapping) { if(propMapping == null) return; PropertyMeta meta = propMapping.getPropertyMeta(); if (meta == null) return; final CsvColumnKey key = propMapping.getColumnKey(); if (meta.isConstructorProperty()) { syncSetterStart = Math.max(syncSetterStart, key.getIndex() + 1); Getter[], ?> delayedGetter = cellSetterFactory.newDelayedGetter(key, meta.getType()); constructorInjections.put(((ConstructorPropertyMeta) meta).getConstructorParameter(), delayedGetter); } else if (meta instanceof DirectClassMeta.DirectPropertyMeta) { syncSetterStart = Math.max(syncSetterStart, key.getIndex() + 1); } else if (meta.isSubProperty()) { SubPropertyMeta subMeta = (SubPropertyMeta) meta; if (subMeta.getOwnerProperty().isConstructorProperty()) { ConstructorPropertyMeta constPropMeta = (ConstructorPropertyMeta) subMeta.getOwnerProperty(); if (!constructorInjections.containsKey(constPropMeta.getConstructorParameter())) { Getter[], ?> delayedGetter = cellSetterFactory.newDelayedGetter(key, constPropMeta.getType()); constructorInjections.put(constPropMeta.getConstructorParameter(), delayedGetter); } syncSetterStart = Math.max(syncSetterStart, key.getIndex() + 1); } } } }); return constructorInjections; } @SuppressWarnings({ "unchecked" }) private DelayedCellSetterFactory[] buildDelayedSetters(final ParsingContextFactoryBuilder parsingContextFactoryBuilder) { final Map> delegateMapperBuilders = new HashMap>(); final DelayedCellSetterFactory[] delayedSetters = new DelayedCellSetterFactory[syncSetterStart]; propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() { final CellSetterFactory cellSetterFactory = new CellSetterFactory(cellValueReaderFactory); @Override public void handle(PropertyMapping propMapping) { if (propMapping != null) { PropertyMeta prop = propMapping.getPropertyMeta(); CsvColumnKey key = propMapping.getColumnKey(); if (prop != null) { if (prop.isConstructorProperty() || prop instanceof DirectClassMeta.DirectPropertyMeta) { delayedSetters[propMapping.getColumnKey().getIndex()] = cellSetterFactory.getDelayedCellSetter(prop.getType(), key.getIndex(), propMapping.getColumnDefinition(), parsingContextFactoryBuilder); } else if (prop.isSubProperty()) { addSubProperty(delegateMapperBuilders, prop, key, propMapping.getColumnDefinition()); }else { delayedSetters[propMapping.getColumnKey().getIndex()] = cellSetterFactory.getDelayedCellSetter(prop, key.getIndex(), propMapping.getColumnDefinition(), parsingContextFactoryBuilder); } } } } private

void addSubProperty( Map> delegateMapperBuilders, PropertyMeta prop, CsvColumnKey key, CsvColumnDefinition columnDefinition) { 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(), mapperBuilderErrorHandler, columnDefinitions, propertyNameMatcherFactory, cellValueReaderFactory); delegateMapperBuilders.put(propOwner.getName(), delegateMapperBuilder); } delegateMapperBuilder.addMapping(subPropertyMeta.getSubProperty(), key, columnDefinition); } }, 0, syncSetterStart); final Map> mappers = new HashMap>(); propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() { @Override public void handle(PropertyMapping propMapping) { if (propMapping == null) return; PropertyMeta prop = propMapping.getPropertyMeta(); if (prop.isSubProperty()) { addSubPropertyDelayedSetter(delegateMapperBuilders, delayedSetters, mappers, propMapping.getColumnKey().getIndex(), prop); } } private

void addSubPropertyDelayedSetter( Map> delegateMapperBuilders, DelayedCellSetterFactory[] 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[setterIndex] = new DelegateMarkerDelayedCellSetter(mapper); } else { delayedSetters[setterIndex] = new DelegateMarkerDelayedCellSetter(mapper, subProp.getSetter()); } } }, 0, syncSetterStart); return delayedSetters; } @SuppressWarnings({ "unchecked", "rawtypes" }) private CellSetter[] getSetters(final ParsingContextFactoryBuilder parsingContextFactoryBuilder) { final Map> delegateMapperBuilders = new HashMap>(); int maxIndex = propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() { int maxIndex = syncSetterStart; @Override public void handle(PropertyMapping propMapping) { if (propMapping != null) { maxIndex = Math.max(propMapping.getColumnKey().getIndex(), maxIndex); PropertyMeta prop = propMapping.getPropertyMeta(); if (prop != null) { CsvColumnKey key = propMapping.getColumnKey(); if (prop.isConstructorProperty()) { throw new IllegalStateException("Unexpected ConstructorPropertyMeta at " + key.getIndex()); } else if (prop.isSubProperty()) { final PropertyMeta propOwner = ((SubPropertyMeta)prop).getOwnerProperty(); CsvMapperBuilder delegateMapperBuilder = delegateMapperBuilders .get(propOwner.getName()); if (delegateMapperBuilder == null) { delegateMapperBuilder = new CsvMapperBuilder(propOwner.getType(), propOwner.getClassMeta(), mapperBuilderErrorHandler, columnDefinitions, propertyNameMatcherFactory, cellValueReaderFactory); delegateMapperBuilders.put(propOwner.getName(), delegateMapperBuilder); } delegateMapperBuilder.addMapping(((SubPropertyMeta) prop).getSubProperty(), key, propMapping.getColumnDefinition()); } } } } }, syncSetterStart).maxIndex; final CellSetter[] setters = new CellSetter[maxIndex + 1 - syncSetterStart]; propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() { final Map> mappers = new HashMap>(); final CellSetterFactory cellSetterFactory = new CellSetterFactory(cellValueReaderFactory); @Override public void handle(PropertyMapping propMapping) { if (propMapping == null) { return; } PropertyMeta prop = propMapping.getPropertyMeta(); if (prop == null || prop instanceof DirectClassMeta.DirectPropertyMeta) { return; } 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[propMapping.getColumnKey().getIndex()- syncSetterStart] = new DelegateMarkerSetter(mapper, ((SubPropertyMeta) prop).getOwnerProperty().getSetter()); } else { setters[propMapping.getColumnKey().getIndex()- syncSetterStart] = cellSetterFactory.getCellSetter(prop, propMapping.getColumnKey().getIndex(), propMapping.getColumnDefinition(), parsingContextFactoryBuilder); } } }, syncSetterStart); return setters; } public final CsvMapperBuilder fieldMapperErrorHandler(final FieldMapperErrorHandler errorHandler) { fieldMapperErrorHandler = errorHandler; return this; } public final CsvMapperBuilder rowHandlerErrorHandler(RowHandlerErrorHandler rowHandlerErrorHandler) { this.rowHandlerErrorHandler = rowHandlerErrorHandler; return this; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy