package org.simpleflatmapper.datastax.impl;
import com.datastax.driver.core.*;
import org.simpleflatmapper.converter.ConverterService;
import org.simpleflatmapper.datastax.DataTypeHelper;
import org.simpleflatmapper.datastax.DatastaxColumnKey;
import org.simpleflatmapper.map.Mapper;
import org.simpleflatmapper.map.MapperConfig;
import org.simpleflatmapper.map.property.FieldMapperColumnDefinition;
import org.simpleflatmapper.map.mapper.ColumnDefinition;
import org.simpleflatmapper.map.mapper.PropertyMapping;
import org.simpleflatmapper.reflect.setter.ConvertDelegateSetter;
import org.simpleflatmapper.reflect.ReflectionService;
import org.simpleflatmapper.reflect.Setter;
import org.simpleflatmapper.reflect.SetterFactory;
import org.simpleflatmapper.converter.Converter;
import org.simpleflatmapper.datastax.impl.setter.BigDecimalSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.BigIntegerSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.ByteSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.ConverterToTupleValueMapper;
import org.simpleflatmapper.datastax.impl.setter.ConverterToUDTValueMapper;
import org.simpleflatmapper.datastax.impl.setter.DateSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.DoubleSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.FloatSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.InetAddressSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.IntSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.ListSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.ListWithConverterSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.LongSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.MapSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.MapWithConverterSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.OrdinalEnumSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.SetSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.SetWithConverterSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.ShortSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.StringEnumSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.StringSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.TimeSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.TimestampSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.TupleValueSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.UDTObjectSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.UDTValueSettableDataSetter;
import org.simpleflatmapper.datastax.impl.setter.UUIDSettableDataSetter;
import org.simpleflatmapper.util.TypeHelper;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.util.*;
public class SettableDataSetterFactory
implements
SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>
{
private final Map<Class<?>, SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>> factoryPerClass =
new HashMap<Class<?>, SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>>();
private final MapperConfig<DatastaxColumnKey, FieldMapperColumnDefinition<DatastaxColumnKey>> mapperConfig;
private final ReflectionService reflectionService;
{
factoryPerClass.put(short.class, new SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>() {
@SuppressWarnings("unchecked")
@Override
public <P> Setter<SettableByIndexData, P> getSetter(PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>> arg) {
return (Setter<SettableByIndexData, P>) new ShortSettableDataSetter(arg.getColumnKey().getIndex());
}
});
factoryPerClass.put(Short.class, factoryPerClass.get(short.class));
factoryPerClass.put(byte.class, new SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>() {
@SuppressWarnings("unchecked")
@Override
public <P> Setter<SettableByIndexData, P> getSetter(PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>> arg) {
return (Setter<SettableByIndexData, P>) new ByteSettableDataSetter(arg.getColumnKey().getIndex());
}
});
factoryPerClass.put(Byte.class, factoryPerClass.get(byte.class));
factoryPerClass.put(int.class, new SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>() {
@SuppressWarnings("unchecked")
@Override
public <P> Setter<SettableByIndexData, P> getSetter(PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>> arg) {
return (Setter<SettableByIndexData, P>) new IntSettableDataSetter(arg.getColumnKey().getIndex());
}
});
factoryPerClass.put(Integer.class, factoryPerClass.get(int.class));
factoryPerClass.put(long.class, new SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>() {
@SuppressWarnings("unchecked")
@Override
public <P> Setter<SettableByIndexData, P> getSetter(PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>> arg) {
if (DataTypeHelper.isTime(arg.getColumnKey().getDataType().getName())) {
return (Setter<SettableByIndexData, P>)new TimeSettableDataSetter(arg.getColumnKey().getIndex());
}
return (Setter<SettableByIndexData, P>) new LongSettableDataSetter(arg.getColumnKey().getIndex());
}
});
factoryPerClass.put(Long.class, factoryPerClass.get(long.class));
factoryPerClass.put(float.class, new SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>() {
@SuppressWarnings("unchecked")
@Override
public <P> Setter<SettableByIndexData, P> getSetter(PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>> arg) {
return (Setter<SettableByIndexData, P>) new FloatSettableDataSetter(arg.getColumnKey().getIndex());
}
});
factoryPerClass.put(Float.class, factoryPerClass.get(float.class));
factoryPerClass.put(double.class, new SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>() {
@SuppressWarnings("unchecked")
@Override
public <P> Setter<SettableByIndexData, P> getSetter(PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>> arg) {
return (Setter<SettableByIndexData, P>) new DoubleSettableDataSetter(arg.getColumnKey().getIndex());
}
});
factoryPerClass.put(Double.class, factoryPerClass.get(double.class));
factoryPerClass.put(String.class, new SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>() {
@SuppressWarnings("unchecked")
@Override
public <P> Setter<SettableByIndexData, P> getSetter(PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>> arg) {
return (Setter<SettableByIndexData, P>) new StringSettableDataSetter(arg.getColumnKey().getIndex());
}
});
factoryPerClass.put(Date.class, new SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>() {
@SuppressWarnings("unchecked")
@Override
public <P> Setter<SettableByIndexData, P> getSetter(PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>> arg) {
return (Setter<SettableByIndexData, P>) new TimestampSettableDataSetter(arg.getColumnKey().getIndex());
}
});
factoryPerClass.put(UUID.class, new SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>() {
@SuppressWarnings("unchecked")
@Override
public <P> Setter<SettableByIndexData, P> getSetter(PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>> arg) {
return (Setter<SettableByIndexData, P>) new UUIDSettableDataSetter(arg.getColumnKey().getIndex());
}
});
factoryPerClass.put(BigDecimal.class, new SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>() {
@SuppressWarnings("unchecked")
@Override
public <P> Setter<SettableByIndexData, P> getSetter(PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>> arg) {
return (Setter<SettableByIndexData, P>) new BigDecimalSettableDataSetter(arg.getColumnKey().getIndex());
}
});
factoryPerClass.put(BigInteger.class, new SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>() {
@SuppressWarnings("unchecked")
@Override
public <P> Setter<SettableByIndexData, P> getSetter(PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>> arg) {
return (Setter<SettableByIndexData, P>) new BigIntegerSettableDataSetter(arg.getColumnKey().getIndex());
}
});
factoryPerClass.put(InetAddress.class, new SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>() {
@SuppressWarnings("unchecked")
@Override
public <P> Setter<SettableByIndexData, P> getSetter(PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>> arg) {
return (Setter<SettableByIndexData, P>) new InetAddressSettableDataSetter(arg.getColumnKey().getIndex());
}
});
factoryPerClass.put(TupleValue.class, new SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>() {
@SuppressWarnings("unchecked")
@Override
public <P> Setter<SettableByIndexData, P> getSetter(PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>> arg) {
return (Setter<SettableByIndexData, P>) new TupleValueSettableDataSetter(arg.getColumnKey().getIndex());
}
});
if (DataTypeHelper.localDateClass != null) {
factoryPerClass.put(DataTypeHelper.localDateClass, new SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>>() {
@SuppressWarnings("unchecked")
@Override
public <P> Setter<SettableByIndexData, P> getSetter(PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>> arg) {
return (Setter<SettableByIndexData, P>) new DateSettableDataSetter(arg.getColumnKey().getIndex());
}
});
}
}
public SettableDataSetterFactory(MapperConfig<DatastaxColumnKey, FieldMapperColumnDefinition<DatastaxColumnKey>> mapperConfig, ReflectionService reflectionService) {
this.mapperConfig = mapperConfig;
this.reflectionService = reflectionService;
}
@SuppressWarnings("unchecked")
@Override
public <P> Setter<SettableByIndexData, P> getSetter(PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>> arg) {
Setter<SettableByIndexData, P> setter = null;
Type propertyType = arg.getPropertyMeta().getPropertyType();
final DataType dataType = arg.getColumnKey().getDataType();
Type type = dataType != null ? DataTypeHelper.asJavaClass(dataType) : null;
if (type == null) {
type = propertyType;
}
if (TypeHelper.isEnum(propertyType)) {
if (TypeHelper.areEquals(type, String.class)) {
return (Setter<SettableByIndexData, P>) new StringEnumSettableDataSetter(arg.getColumnKey().getIndex());
} else {
return (Setter<SettableByIndexData, P>) new OrdinalEnumSettableDataSetter(arg.getColumnKey().getIndex());
}
}
SetterFactory<SettableByIndexData, PropertyMapping<?, ?, DatastaxColumnKey, ? extends ColumnDefinition<DatastaxColumnKey, ?>>> setterFactory =
this.factoryPerClass.get(TypeHelper.toClass(type));
if (setterFactory != null) {
setter = setterFactory.getSetter(arg);
if (!TypeHelper.areEquals(TypeHelper.toBoxedClass(type), TypeHelper.toBoxedClass(propertyType))) {
Converter<?, ?> converter = getConverter(propertyType, TypeHelper.toClass(type), dataType, arg.getColumnDefinition());
if (converter != null) {
setter = (Setter<SettableByIndexData, P>) new ConvertDelegateSetter<SettableByIndexData, Object, P>(setter, (Converter<Object, P>) converter);
} else {
setter = null;
}
}
}
if (setter == null && dataType != null) {
if (dataType instanceof UserType) {
if (propertyType.equals(UDTValue.class)) {
setter = (Setter<SettableByIndexData, P>) new UDTValueSettableDataSetter(arg.getColumnKey().getIndex());
} else {
setter = (Setter<SettableByIndexData, P>) UDTObjectSettableDataSetter.newInstance(propertyType, (UserType) dataType, arg.getColumnKey().getIndex(), mapperConfig, reflectionService);
}
} else if (TypeHelper.isAssignable(List.class, type) && TypeHelper.isAssignable(List.class, propertyType)) {
DataType dataTypeElt = dataType.getTypeArguments().get(0);
Class<?> dEltType = DataTypeHelper.asJavaClass(dataTypeElt);
Type lEltType = TypeHelper.getComponentTypeOfListOrArray(propertyType);
if (TypeHelper.areEquals(lEltType, dEltType)) {
setter = new ListSettableDataSetter(arg.getColumnKey().getIndex());
} else {
Converter<?, ?> converter = getConverter(lEltType, dEltType, dataTypeElt, arg.getColumnDefinition());
if (converter != null) {
setter = new ListWithConverterSettableDataSetter(arg.getColumnKey().getIndex(), converter);
}
}
} else if (TypeHelper.isAssignable(Set.class, type) && TypeHelper.isAssignable(Set.class, propertyType)) {
DataType dataTypeElt = dataType.getTypeArguments().get(0);
Class<?> dEltType = DataTypeHelper.asJavaClass(dataTypeElt);
Type lEltType = TypeHelper.getComponentTypeOfListOrArray(propertyType);
if (TypeHelper.areEquals(lEltType, dEltType)) {
setter = new SetSettableDataSetter(arg.getColumnKey().getIndex());
} else {
Converter<?, ?> converter = getConverter(lEltType, dEltType, dataTypeElt, arg.getColumnDefinition());
if (converter != null) {
setter = new SetWithConverterSettableDataSetter(arg.getColumnKey().getIndex(), converter);
}
}
} else if (TypeHelper.isAssignable(Map.class, type) && TypeHelper.isAssignable(Map.class, propertyType)) {
DataType dtKeyType = dataType.getTypeArguments().get(0);
DataType dtValueType = dataType.getTypeArguments().get(1);
TypeHelper.MapEntryTypes keyValueTypeOfMap = TypeHelper.getKeyValueTypeOfMap(propertyType);
if (areSame(dtKeyType, keyValueTypeOfMap.getKeyType()) && areSame(dtValueType, keyValueTypeOfMap.getValueType())) {
setter = new MapSettableDataSetter(arg.getColumnKey().getIndex());
} else {
setter = new MapWithConverterSettableDataSetter(arg.getColumnKey().getIndex(),
getConverter(keyValueTypeOfMap.getKeyType(), DataTypeHelper.asJavaClass(dtKeyType), dtKeyType, arg.getColumnDefinition()),
getConverter(keyValueTypeOfMap.getValueType(), DataTypeHelper.asJavaClass(dtValueType), dtValueType, arg.getColumnDefinition())
);
}
}
}
return setter;
}
private boolean areSame(DataType dtKeyType, Type element0) {
return TypeHelper.areEquals(element0, DataTypeHelper.asJavaClass(dtKeyType));
}
@SuppressWarnings("unchecked")
private Converter<?, ?> getConverter(Type elementType, Class<?> dataTypeElt, DataType dtElt, ColumnDefinition<DatastaxColumnKey, ?> columnDefinition) {
if (dtElt != null) {
if (UDTValue.class.equals(dataTypeElt)) {
Mapper mapper = UDTObjectSettableDataSetter.newUDTMapper(elementType, (UserType) dtElt, mapperConfig, reflectionService);
return new ConverterToUDTValueMapper(mapper, (UserType) dtElt);
}
if (TupleValue.class.equals(dataTypeElt)) {
Mapper mapper = TupleValueSettableDataSetter.newTupleMapper(elementType, (TupleType) dtElt, mapperConfig, reflectionService);
return new ConverterToTupleValueMapper(mapper, (TupleType) dtElt);
}
}
return ConverterService.getInstance().findConverter(TypeHelper.toClass(elementType), dataTypeElt, columnDefinition.properties());
}
}