package org.simpleflatmapper.csv.impl; import org.simpleflatmapper.csv.CellValueReader; import org.simpleflatmapper.csv.CellValueReaderFactory; import org.simpleflatmapper.csv.CsvColumnDefinition; import org.simpleflatmapper.csv.CsvColumnKey; import org.simpleflatmapper.csv.impl.cellreader.*; import org.simpleflatmapper.csv.impl.primitive.*; import org.simpleflatmapper.csv.ParsingContextFactoryBuilder; import org.simpleflatmapper.csv.mapper.CellSetter; import org.simpleflatmapper.csv.mapper.CsvMapperCellHandler; import org.simpleflatmapper.csv.mapper.DelayedCellSetterFactory; import org.simpleflatmapper.map.MapperBuilderErrorHandler; import org.simpleflatmapper.map.property.DefaultValueProperty; import org.simpleflatmapper.reflect.Getter; import org.simpleflatmapper.reflect.Instantiator; import org.simpleflatmapper.reflect.InstantiatorDefinition; import org.simpleflatmapper.reflect.instantiator.InstantiatorDefinitions; import org.simpleflatmapper.reflect.meta.SubPropertyMeta; import org.simpleflatmapper.reflect.setter.NullSetter; import org.simpleflatmapper.reflect.ObjectSetterFactory; import org.simpleflatmapper.reflect.Parameter; import org.simpleflatmapper.reflect.Setter; import org.simpleflatmapper.reflect.meta.ClassMeta; import org.simpleflatmapper.reflect.meta.DefaultPropertyNameMatcher; import org.simpleflatmapper.reflect.meta.PropertyMeta; import org.simpleflatmapper.util.ConstantPredicate; import org.simpleflatmapper.util.ErrorDoc; import org.simpleflatmapper.util.Predicate; import org.simpleflatmapper.util.TypeHelper; import java.lang.reflect.Type; import java.util.Date; public final class CellSetterFactory { public static final InstantiatorDefinitions.CompatibilityScorer COMPATIBILITY_SCORER = new InstantiatorDefinitions.CompatibilityScorer() { @Override public int score(InstantiatorDefinition id) { Class<?> type = TypeHelper.toBoxedClass(id.getParameters()[0].getType()); if (type == String.class || type == CharSequence.class) { return 10; } if (Number.class.isAssignableFrom(type)) { return 9; } if (Date.class.isAssignableFrom(type)) { return 8; } return 0; } }; private final CellValueReaderFactory cellValueReaderFactory; private final MapperBuilderErrorHandler mapperBuilderErrorHandler; public CellSetterFactory(CellValueReaderFactory cellValueReaderFactory, MapperBuilderErrorHandler mapperBuilderErrorHandler) { this.cellValueReaderFactory = cellValueReaderFactory; this.mapperBuilderErrorHandler = mapperBuilderErrorHandler; } @SuppressWarnings("unchecked") public <T,P> CellSetter<T> getPrimitiveCellSetter(Class<?> clazz, CellValueReader<? extends P> reader, Setter<? super T, ? super P> setter) { if (boolean.class.equals(clazz)) { return new BooleanCellSetter<T>(ObjectSetterFactory.toBooleanSetter((Setter<? super T, ? super Boolean>) setter), booleanReader(reader)); } else if (byte.class.equals(clazz)) { return new ByteCellSetter<T>(ObjectSetterFactory.toByteSetter((Setter<? super T, ? super Byte>) setter), byteReader(reader)); } else if (char.class.equals(clazz)) { return new CharCellSetter<T>(ObjectSetterFactory.toCharacterSetter((Setter<? super T, ? super Character>) setter), charReader(reader)); } else if (short.class.equals(clazz)) { return new ShortCellSetter<T>(ObjectSetterFactory.toShortSetter((Setter<? super T, ? super Short>) setter), shortReader(reader)); } else if (int.class.equals(clazz)) { return new IntCellSetter<T>(ObjectSetterFactory.toIntSetter((Setter<? super T, ? super Integer>) setter), intReader(reader)); } else if (long.class.equals(clazz)) { return new LongCellSetter<T>(ObjectSetterFactory.toLongSetter((Setter<? super T, ? super Long>) setter), longReader(reader)); } else if (float.class.equals(clazz)) { return new FloatCellSetter<T>(ObjectSetterFactory.toFloatSetter((Setter<? super T, ? super Float>) setter), floatReader(reader)); } else if (double.class.equals(clazz)) { return new DoubleCellSetter<T>(ObjectSetterFactory.toDoubleSetter((Setter<? super T, ? super Double>) setter), doubleReader(reader)); } throw new IllegalArgumentException("Invalid primitive type " + clazz); } @SuppressWarnings("unchecked") private DoubleCellValueReader doubleReader(CellValueReader<?> reader) { if (reader instanceof DoubleCellValueReader) { return (DoubleCellValueReader) reader; } else { return new BoxedDoubleCellValueReader((CellValueReader<Double>) reader); } } @SuppressWarnings("unchecked") private FloatCellValueReader floatReader(CellValueReader<?> reader) { if (reader instanceof FloatCellValueReader) { return (FloatCellValueReader) reader; } else { return new BoxedFloatCellValueReader((CellValueReader<Float>) reader); } } @SuppressWarnings("unchecked") private LongCellValueReader longReader(CellValueReader<?> reader) { if (reader instanceof LongCellValueReader) { return (LongCellValueReader) reader; } else { return new BoxedLongCellValueReader((CellValueReader<Long>) reader); } } @SuppressWarnings("unchecked") private IntegerCellValueReader intReader(CellValueReader<?> reader) { if (reader instanceof IntegerCellValueReader) { return (IntegerCellValueReader) reader; } else { return new BoxedIntegerCellValueReader((CellValueReader<Integer>) reader); } } @SuppressWarnings("unchecked") private ShortCellValueReader shortReader(CellValueReader<?> reader) { if (reader instanceof ShortCellValueReader) { return (ShortCellValueReader) reader; } else { return new BoxedShortCellValueReader((CellValueReader<Short>) reader); } } @SuppressWarnings("unchecked") private CharCellValueReader charReader(CellValueReader<?> reader) { if (reader instanceof CharCellValueReader) { return (CharCellValueReader) reader; } else { return new BoxedCharCellValueReader((CellValueReader<Character>) reader); } } @SuppressWarnings("unchecked") private ByteCellValueReader byteReader(CellValueReader<?> reader) { if (reader instanceof ByteCellValueReader) { return (ByteCellValueReader) reader; } else { return new BoxedByteCellValueReader((CellValueReader<Byte>) reader); } } @SuppressWarnings("unchecked") private BooleanCellValueReader booleanReader(CellValueReader<?> reader) { if (reader instanceof BooleanCellValueReader) { return (BooleanCellValueReader) reader; } else { return new BoxedBooleanCellValueReader((CellValueReader<Boolean>) reader); } } @SuppressWarnings("unchecked") private <T,P> DelayedCellSetterFactory<T, P> getPrimitiveDelayedCellSetter(Class<?> clazz, CellValueReader<? extends P> reader, Setter<? super T, ? super P> setter) { if (boolean.class.equals(clazz)) { return (DelayedCellSetterFactory<T, P>) new BooleanDelayedCellSetterFactory<T>(ObjectSetterFactory.toBooleanSetter((Setter<? super T, ? super Boolean>) setter), booleanReader(reader)); } else if (byte.class.equals(clazz)) { return (DelayedCellSetterFactory<T, P>) new ByteDelayedCellSetterFactory<T>(ObjectSetterFactory.toByteSetter((Setter<? super T, ? super Byte>) setter), byteReader(reader)); } else if (char.class.equals(clazz)) { return (DelayedCellSetterFactory<T, P>) new CharDelayedCellSetterFactory<T>(ObjectSetterFactory.toCharacterSetter((Setter<? super T, ? super Character>) setter), charReader(reader)); } else if (short.class.equals(clazz)) { return (DelayedCellSetterFactory<T, P>) new ShortDelayedCellSetterFactory<T>(ObjectSetterFactory.toShortSetter((Setter<? super T, ? super Short>) setter), shortReader(reader)); } else if (int.class.equals(clazz)) { return (DelayedCellSetterFactory<T, P>) new IntDelayedCellSetterFactory<T>(ObjectSetterFactory.toIntSetter((Setter<? super T, ? super Integer>) setter), intReader(reader)); } else if (long.class.equals(clazz)) { return (DelayedCellSetterFactory<T, P>) new LongDelayedCellSetterFactory<T>(ObjectSetterFactory.toLongSetter((Setter<? super T, ? super Long>) setter), longReader(reader)); } else if (float.class.equals(clazz)) { return (DelayedCellSetterFactory<T, P>) new FloatDelayedCellSetterFactory<T>(ObjectSetterFactory.toFloatSetter((Setter<? super T, ? super Float>) setter), floatReader(reader)); } else if (double.class.equals(clazz)) { return (DelayedCellSetterFactory<T, P>) new DoubleDelayedCellSetterFactory<T>(ObjectSetterFactory.toDoubleSetter((Setter<? super T, ? super Double>) setter), doubleReader(reader)); } throw new IllegalArgumentException("Invalid primitive type " + clazz); } @SuppressWarnings("unchecked") public <T, P> Getter<CsvMapperCellHandler<T>, P> newDelayedGetter(CsvColumnKey key, Type type) { Class<?> clazz = TypeHelper.toClass(type); Getter getter; int columnIndex = key.getIndex(); if (clazz.isPrimitive()) { if (boolean.class.equals(clazz)) { getter = new BooleanDelayedGetter<T>(columnIndex); } else if (byte.class.equals(clazz)) { getter = new ByteDelayedGetter<T>(columnIndex); } else if (char.class.equals(clazz)) { getter = new CharDelayedGetter<T>(columnIndex); } else if (short.class.equals(clazz)) { getter = new ShortDelayedGetter<T>(columnIndex); } else if (int.class.equals(clazz)) { getter = new IntDelayedGetter<T>(columnIndex); } else if (long.class.equals(clazz)) { getter = new LongDelayedGetter<T>(columnIndex); } else if (float.class.equals(clazz)) { getter = new FloatDelayedGetter<T>(columnIndex); } else if (double.class.equals(clazz)) { getter = new DoubleDelayedGetter<T>(columnIndex); } else { throw new IllegalArgumentException("Unexpected primitive " + clazz); } } else { getter = new DelayedGetter<T, P>(columnIndex); } return getter; } @SuppressWarnings({"unchecked" }) private <P> CellValueReader<P> getReader(PropertyMeta<?, P> pm, int index, CsvColumnDefinition columnDefinition, ParsingContextFactoryBuilder parsingContextFactoryBuilder) { CellValueReader<P> reader = null; if (columnDefinition.hasCustomSourceFrom(pm.getOwnerType())) { reader = (CellValueReader<P>) columnDefinition.getCustomReader(); } if (reader == null) { reader = cellValueReaderFromFactory(pm, index, columnDefinition, parsingContextFactoryBuilder); } if (reader == null) { mapperBuilderErrorHandler.accessorNotFound("Could not find reader for " + pm.getPath() + " type " + pm.getPropertyType() + " See " + ErrorDoc.toUrl("CSFM_GETTER_NOT_FOUND")); } return reader; } private <P> CellValueReader<P> cellValueReaderFromFactory(PropertyMeta<?, ?> pm, int index, CsvColumnDefinition columnDefinition, ParsingContextFactoryBuilder parsingContextFactoryBuilder) { Type propertyType = pm.getPropertyType(); CellValueReader<P> reader = null; if (columnDefinition.hasCustomReaderFactory()) { CellValueReaderFactory factory = columnDefinition.getCustomCellValueReaderFactory(); reader = factory.getReader(propertyType, index, columnDefinition, parsingContextFactoryBuilder); } if (reader == null) { reader = cellValueReaderFactory.getReader(propertyType, index, columnDefinition, parsingContextFactoryBuilder); } if (reader == null) { if (!pm.isSelf()) { final ClassMeta<?> classMeta = pm.getPropertyClassMeta(); InstantiatorDefinition id = InstantiatorDefinitions.lookForCompatibleOneArgument(classMeta.getInstantiatorDefinitions(), COMPATIBILITY_SCORER); if (id != null) { final Parameter parameter = id.getParameters()[0]; // look for constructor property matching name final PropertyMeta<?, Object> property = classMeta.newPropertyFinder(new Predicate<PropertyMeta<?, ?>>() { @Override public boolean test(PropertyMeta<?, ?> propertyMeta) { return propertyMeta.isConstructorProperty() || propertyMeta.isSubProperty() && ((SubPropertyMeta)propertyMeta).getOwnerProperty().isConstructorProperty(); } }).findProperty(DefaultPropertyNameMatcher.exact(parameter.getName())); reader = cellValueReaderFromFactory(property, index, columnDefinition, parsingContextFactoryBuilder); if (reader != null) { Instantiator<P, P> instantiator = classMeta.getReflectionService().getInstantiatorFactory().getOneArgIdentityInstantiator(id); return new InstantiatorOnReader<P, P>(instantiator, reader); } } } } return reader; } @SuppressWarnings("unchecked") public <T, P> CellSetter<T> getCellSetter(PropertyMeta<T, P> prop, int index, CsvColumnDefinition columnDefinition, ParsingContextFactoryBuilder parsingContextFactoryBuilder) { Class<? extends P> propertyClass = (Class<? extends P>) TypeHelper.toClass(prop.getPropertyType()); CellValueReader<? extends P> reader = getReader(prop, index, columnDefinition, parsingContextFactoryBuilder); if (propertyClass.isPrimitive()) { return getPrimitiveCellSetter(propertyClass, reader, getSetter(prop)); } else { return new CellSetterImpl<T, P>(reader, getSetter(prop)); } } public <T, P> DelayedCellSetterFactory<T, P> getDelayedCellSetter(PropertyMeta<T, P> prop, int index, CsvColumnDefinition columnDefinition, ParsingContextFactoryBuilder parsingContextFactoryBuilder) { Class<? extends P> propertyClass = TypeHelper.toClass(prop.getPropertyType()); CellValueReader<? extends P> reader = getReader(prop, index, columnDefinition, parsingContextFactoryBuilder); DelayedCellSetterFactory<T, P> factory; final Setter<? super T, ? super P> setter = prop.isConstructorProperty() ? null : getSetter(prop); if (propertyClass.isPrimitive()) { factory = getPrimitiveDelayedCellSetter(propertyClass, reader, setter); } else { factory = new DelayedCellSetterFactoryImpl<T, P>(reader, setter); } final DefaultValueProperty defaultValueProperty = columnDefinition.lookFor(DefaultValueProperty.class); if (defaultValueProperty != null) { factory = new DefaultValueDelayedCallSetterFactory<T, P>(factory, defaultValueProperty, setter); } return factory; } private <T, P> Setter<? super T, ? super P> getSetter(PropertyMeta<T, P> prop) { Setter<? super T, ? super P> setter = prop.getSetter(); if (NullSetter.isNull(setter)) { return null; } else { return setter; } } }