Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
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.
package org.sfm.csv;
import org.sfm.csv.impl.*;
import org.sfm.map.*;
import org.sfm.map.ColumnDefinition;
import org.sfm.map.impl.*;
import org.sfm.reflect.*;
import org.sfm.reflect.meta.*;
import org.sfm.tuples.Tuple3;
import org.sfm.utils.ErrorHelper;
import org.sfm.utils.ForEachCallBack;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CsvMapperBuilder {
public static final int CSV_MAX_METHOD_SIZE = 128;
public static final int NO_ASM_CSV_HANDLER_THRESHOLD = 4096; // see https://github.com/arnaudroger/SimpleFlatMapper/issues/152
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 final int minDelayedSetter;
private String defaultDateFormat = "yyyy-MM-dd HH:mm:ss";
private final boolean failOnAsm;
private final int asmMapperNbFieldsLimit;
private final int maxMethodSize;
public CsvMapperBuilder(final Type target) {
this(target, ReflectionService.newInstance());
}
@SuppressWarnings("unchecked")
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 IdentityCsvColumnDefinitionProvider());
}
public CsvMapperBuilder(final Type target, final ClassMeta classMeta, ColumnDefinitionProvider columnDefinitionProvider) {
this(target, classMeta, new RethrowMapperBuilderErrorHandler(),
columnDefinitionProvider, new DefaultPropertyNameMatcherFactory(),
new CellValueReaderFactoryImpl(), 0, false, NO_ASM_CSV_HANDLER_THRESHOLD, CSV_MAX_METHOD_SIZE);
}
public CsvMapperBuilder(final Type target, final ClassMeta classMeta,
MapperBuilderErrorHandler mapperBuilderErrorHandler,
ColumnDefinitionProvider columnDefinitions,
PropertyNameMatcherFactory propertyNameMatcherFactory,
CellValueReaderFactory cellValueReaderFactory,
int minDelayedSetter,
boolean failOnAsm,
int asmMapperNbFieldsLimit, int maxMethodSize) throws MapperBuildingException {
this.target = target;
this.mapperBuilderErrorHandler = mapperBuilderErrorHandler;
this.minDelayedSetter = minDelayedSetter;
this.reflectionService = classMeta.getReflectionService();
this.propertyMappingsBuilder = new PropertyMappingsBuilder(classMeta, propertyNameMatcherFactory, this.mapperBuilderErrorHandler);
this.propertyNameMatcherFactory = propertyNameMatcherFactory;
this.columnDefinitions = columnDefinitions;
this.cellValueReaderFactory = cellValueReaderFactory;
this.failOnAsm = failOnAsm;
this.asmMapperNbFieldsLimit = asmMapperNbFieldsLimit;
this.maxMethodSize = maxMethodSize;
}
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());
Tuple3, ?>>, Integer, Boolean> constructorParams = buildConstructorParametersDelayedCellSetter();
final Instantiator, T> instantiator = getInstantiator(constructorParams.first());
final CsvColumnKey[] keys = getKeys();
// will build the context factory builder
final CellSetter[] setters = getSetters(parsingContextFactoryBuilder, constructorParams.second());
final DelayedCellSetterFactory[] delayedCellSetterFactories = buildDelayedSetters(parsingContextFactoryBuilder, constructorParams.second(), constructorParams.third());
// needs to happen last
final CsvMapperCellHandlerFactory csvMapperCellHandlerFactory = newCsvMapperCellHandlerFactory(parsingContextFactoryBuilder, instantiator, keys, delayedCellSetterFactories, setters);
return new CsvMapperImpl(csvMapperCellHandlerFactory,
delayedCellSetterFactories,
setters, getJoinKeys(), rowHandlerErrorHandler);
}
private CsvMapperCellHandlerFactory newCsvMapperCellHandlerFactory(ParsingContextFactoryBuilder parsingContextFactoryBuilder,
Instantiator, T> instantiator,
CsvColumnKey[] keys,
DelayedCellSetterFactory[] delayedCellSetterFactories,
CellSetter[] setters
) {
final ParsingContextFactory parsingContextFactory = parsingContextFactoryBuilder.newFactory();
if (isEligibleForAsmHandler()) {
try {
return reflectionService.getAsmFactory()
.createCsvMapperCellHandler(target, delayedCellSetterFactories, setters,
instantiator, keys, parsingContextFactory, fieldMapperErrorHandler,
maxMethodSize);
} catch (Exception e) {
if (failOnAsm || true) {
return ErrorHelper.rethrow(e);
} else {
return new CsvMapperCellHandlerFactory(instantiator, keys, parsingContextFactory, fieldMapperErrorHandler);
}
}
} else {
return new CsvMapperCellHandlerFactory(instantiator, keys, parsingContextFactory, fieldMapperErrorHandler);
}
}
private boolean isEligibleForAsmHandler() {
return reflectionService.getAsmFactory() != null
&& this.propertyMappingsBuilder.size() < asmMapperNbFieldsLimit;
}
private CsvColumnKey[] getKeys() {
return propertyMappingsBuilder.getKeys().toArray(new CsvColumnKey[propertyMappingsBuilder.size()]);
}
private CsvColumnKey[] getJoinKeys() {
final List keys = new ArrayList();
propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() {
@Override
public void handle(PropertyMapping pm) {
if (pm.getColumnDefinition().isKey() && pm.getColumnDefinition().keyAppliesTo().test(pm.getPropertyMeta())) {
keys.add(pm.getColumnKey());
}
}
});
return keys.toArray(new CsvColumnKey[0]);
}
private Instantiator, T> getInstantiator(Map, ?>> params) throws MapperBuildingException {
InstantiatorFactory instantiatorFactory = reflectionService.getInstantiatorFactory();
try {
return instantiatorFactory.getInstantiator(new TypeReference>(){}.getType(), target, propertyMappingsBuilder, params, new GetterFactory, CsvColumnKey>() {
final CellSetterFactory cellSetterFactory = new CellSetterFactory(cellValueReaderFactory);
@Override
public Getter, P> newGetter(Type target, CsvColumnKey key, ColumnDefinition, ?> columnDefinition) {
return cellSetterFactory.newDelayedGetter(key, target);
}
});
} catch(Exception e) {
return ErrorHelper.rethrow(e);
}
}
private Tuple3, ?>>, Integer, Boolean> buildConstructorParametersDelayedCellSetter() {
final BuildConstructorInjections buildConstructorInjections = new BuildConstructorInjections();
propertyMappingsBuilder.forEachProperties(buildConstructorInjections);
return new Tuple3, ?>>, Integer, Boolean>(buildConstructorInjections.constructorInjections,
buildConstructorInjections.delayedSetterEnd, buildConstructorInjections.hasKeys);
}
@SuppressWarnings({ "unchecked" })
private DelayedCellSetterFactory[] buildDelayedSetters(final ParsingContextFactoryBuilder parsingContextFactoryBuilder, int delayedSetterEnd, boolean hasKeys) {
final Map> delegateMapperBuilders = new HashMap>();
final Map propertyToMapperIndex = new HashMap();
final DelayedCellSetterFactory[] delayedSetters = new DelayedCellSetterFactory[delayedSetterEnd];
final int newMinDelayedSetter = minDelayedSetter != 0 ? minDelayedSetter : hasKeys ? delayedSetterEnd : 0;
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.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, newMinDelayedSetter,
failOnAsm, asmMapperNbFieldsLimit, maxMethodSize);
delegateMapperBuilders.put(propOwner.getName(), delegateMapperBuilder);
}
Integer currentIndex = propertyToMapperIndex.get(propOwner.getName());
if (currentIndex == null || currentIndex < key.getIndex()) {
propertyToMapperIndex.put(propOwner.getName(), key.getIndex());
}
delegateMapperBuilder.addMapping(subPropertyMeta.getSubProperty(), key, columnDefinition);
}
}, 0, delayedSetterEnd);
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, propMapping.getColumnKey().getIndex(), prop);
}
}
private void addSubPropertyDelayedSetter(
Map> delegateMapperBuilders,
DelayedCellSetterFactory[] delayedSetters,
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);
}
int indexOfMapper = propertyToMapperIndex.get(propName);
Setter setter = null;
if (!subProp.isConstructorProperty()) {
setter = subProp.getSetter();
}
delayedSetters[setterIndex] = new DelegateMarkerDelayedCellSetterFactory(mapper, setter, setterIndex, indexOfMapper);
}
}, 0, delayedSetterEnd);
return delayedSetters;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private CellSetter[] getSetters(final ParsingContextFactoryBuilder parsingContextFactoryBuilder, final int delayedSetterEnd) {
final Map> delegateMapperBuilders = new HashMap>();
final Map propertyToMapperIndex = new HashMap();
// calculate maxIndex
int maxIndex = propertyMappingsBuilder.forEachProperties(new ForEachCallBack>() {
int maxIndex = delayedSetterEnd;
@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, minDelayedSetter,
failOnAsm, asmMapperNbFieldsLimit, maxMethodSize);
delegateMapperBuilders.put(propOwner.getName(), delegateMapperBuilder);
}
Integer currentIndex = propertyToMapperIndex.get(propOwner.getName());
if (currentIndex == null || currentIndex < key.getIndex()) {
propertyToMapperIndex.put(propOwner.getName(), key.getIndex());
}
delegateMapperBuilder.addMapping(((SubPropertyMeta) prop).getSubProperty(), key, propMapping.getColumnDefinition());
}
}
}
}
}, delayedSetterEnd).maxIndex;
// builder se setters
final CellSetter[] setters = new CellSetter[maxIndex + 1 - delayedSetterEnd];
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) {
DelegateMarkerSetter delegateMarkerSetter = getDelegateMarkerSetter((SubPropertyMeta) prop);
setters[propMapping.getColumnKey().getIndex()- delayedSetterEnd] = delegateMarkerSetter;
} else {
setters[propMapping.getColumnKey().getIndex()- delayedSetterEnd] = cellSetterFactory.getCellSetter(prop, propMapping.getColumnKey().getIndex(), propMapping.getColumnDefinition(), parsingContextFactoryBuilder);
}
}
private DelegateMarkerSetter getDelegateMarkerSetter(SubPropertyMeta prop) {
final String propName = prop.getOwnerProperty().getName();
CsvMapperImpl mapper = (CsvMapperImpl
) mappers.get(propName);
if (mapper == null) {
CsvMapperBuilder
delegateMapperBuilder = (CsvMapperBuilder
) delegateMapperBuilders.get(propName);
mapper = (CsvMapperImpl
) delegateMapperBuilder.mapper();
mappers.put(propName, mapper);
}
int indexOfMapper = propertyToMapperIndex.get(propName);
return new DelegateMarkerSetter(mapper, (Setter)prop.getOwnerProperty().getSetter(), indexOfMapper);
}
}, delayedSetterEnd);
return setters;
}
public final CsvMapperBuilder fieldMapperErrorHandler(final FieldMapperErrorHandler errorHandler) {
fieldMapperErrorHandler = errorHandler;
return this;
}
public final CsvMapperBuilder rowHandlerErrorHandler(RowHandlerErrorHandler rowHandlerErrorHandler) {
this.rowHandlerErrorHandler = rowHandlerErrorHandler;
return this;
}
private class BuildConstructorInjections implements ForEachCallBack> {
final CellSetterFactory cellSetterFactory;
private final Map, ?>> constructorInjections;
int delayedSetterEnd;
boolean hasKeys;
public BuildConstructorInjections() {
this.constructorInjections = new HashMap, ?>>();
cellSetterFactory = new CellSetterFactory(cellValueReaderFactory);
delayedSetterEnd = minDelayedSetter;
}
@SuppressWarnings("unchecked")
@Override
public void handle(PropertyMapping propMapping) {
if (propMapping == null) return;
PropertyMeta meta = propMapping.getPropertyMeta();
hasKeys = hasKeys || propMapping.getColumnDefinition().isKey();
if (meta == null) return;
final CsvColumnKey key = propMapping.getColumnKey();
if (meta.isConstructorProperty()) {
delayedSetterEnd = Math.max(delayedSetterEnd, key.getIndex() + 1);
Getter, ?> delayedGetter = cellSetterFactory.newDelayedGetter(key, meta.getType());
constructorInjections.put(((ConstructorPropertyMeta) meta).getParameter(), delayedGetter);
} else if (meta instanceof DirectClassMeta.DirectPropertyMeta) {
delayedSetterEnd = Math.max(delayedSetterEnd, key.getIndex() + 1);
} else if (meta.isSubProperty()) {
SubPropertyMeta subMeta = (SubPropertyMeta) meta;
if (subMeta.getOwnerProperty().isConstructorProperty()) {
ConstructorPropertyMeta, ?> constPropMeta = (ConstructorPropertyMeta, ?>) subMeta.getOwnerProperty();
Getter, ?> delayedGetter = cellSetterFactory.newDelayedGetter(key, constPropMeta.getType());
constructorInjections.put(constPropMeta.getParameter(), delayedGetter);
delayedSetterEnd = Math.max(delayedSetterEnd, key.getIndex() + 1);
} else if (propMapping.getColumnDefinition().isKey() && propMapping.getColumnDefinition().keyAppliesTo().test(propMapping.getPropertyMeta())) {
delayedSetterEnd = Math.max(delayedSetterEnd, key.getIndex() + 1);
}
} else if (propMapping.getColumnDefinition().isKey() && propMapping.getColumnDefinition().keyAppliesTo().test(propMapping.getPropertyMeta())) {
delayedSetterEnd = Math.max(delayedSetterEnd, key.getIndex() + 1);
}
}
}
}