package org.simpleflatmapper.jdbc.impl; import org.simpleflatmapper.converter.Converter; import org.simpleflatmapper.converter.ConverterService; import org.simpleflatmapper.jdbc.JdbcColumnKey; import org.simpleflatmapper.jdbc.impl.setter.ArrayPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.BigDecimalPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.BlobPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.BooleanPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.BooleanPreparedStatementSetter; import org.simpleflatmapper.jdbc.impl.setter.BytePreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.BytePreparedStatementSetter; import org.simpleflatmapper.jdbc.impl.setter.BytesPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.CharacterPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.CharacterPreparedStatementSetter; import org.simpleflatmapper.jdbc.impl.setter.ClobPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.ConvertDelegateIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.DatePreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.DoublePreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.DoublePreparedStatementSetter; import org.simpleflatmapper.jdbc.impl.setter.FloatPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.FloatPreparedStatementSetter; import org.simpleflatmapper.jdbc.impl.setter.InputStreamPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.IntegerPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.IntegerPreparedStatementSetter; import org.simpleflatmapper.jdbc.impl.setter.LongPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.LongPreparedStatementSetter; import org.simpleflatmapper.jdbc.impl.setter.NClobPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.ObjectPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.OrdinalEnumPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.PreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.PreparedStatementSetterImpl; import org.simpleflatmapper.jdbc.impl.setter.ReaderPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.RefPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.RowIdPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.SQLXMLPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.ShortPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.ShortPreparedStatementSetter; import org.simpleflatmapper.jdbc.impl.setter.StringEnumPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.StringPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.TimePreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.TimestampPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.URLPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.UUIDBinaryPreparedStatementIndexSetter; import org.simpleflatmapper.jdbc.impl.setter.UUIDStringPreparedStatementIndexSetter; import org.simpleflatmapper.map.mapper.ColumnDefinition; import org.simpleflatmapper.map.mapper.PropertyMapping; import org.simpleflatmapper.reflect.IndexedSetter; import org.simpleflatmapper.reflect.IndexedSetterFactory; import org.simpleflatmapper.reflect.Setter; import org.simpleflatmapper.reflect.SetterFactory; import org.simpleflatmapper.util.TypeHelper; import java.io.InputStream; import java.io.Reader; import java.lang.reflect.Type; import java.math.BigDecimal; import java.net.URL; import java.sql.Array; import java.sql.Blob; import java.sql.Clob; import java.sql.Date; import java.sql.NClob; import java.sql.PreparedStatement; import java.sql.Ref; import java.sql.RowId; import java.sql.SQLData; import java.sql.SQLXML; import java.sql.Time; import java.sql.Timestamp; import java.sql.Types; import java.util.HashMap; import java.util.Map; import java.util.UUID; public class PreparedStatementIndexedSetterFactory implements IndexedSetterFactory<PreparedStatement, PropertyMapping<?, ?, JdbcColumnKey, ? extends ColumnDefinition<JdbcColumnKey, ?>>> { public static final PreparedStatementIndexedSetterFactory INSTANCE = new PreparedStatementIndexedSetterFactory(); private PreparedStatementIndexedSetterFactory() { } private final Map<Class<?>, Factory> factoryPerClass = new HashMap<Class<?>, Factory>(); { factoryPerClass.put(boolean.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new BooleanPreparedStatementIndexSetter(); } }); factoryPerClass.put(Boolean.class, factoryPerClass.get(boolean.class)); factoryPerClass.put(byte.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new BytePreparedStatementIndexSetter(); } }); factoryPerClass.put(Byte.class, factoryPerClass.get(byte.class)); factoryPerClass.put(char.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new CharacterPreparedStatementIndexSetter(); } }); factoryPerClass.put(Character.class, factoryPerClass.get(char.class)); factoryPerClass.put(short.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new ShortPreparedStatementIndexSetter(); } }); factoryPerClass.put(Short.class, factoryPerClass.get(short.class)); factoryPerClass.put(int.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new IntegerPreparedStatementIndexSetter(); } }); factoryPerClass.put(Integer.class, factoryPerClass.get(int.class)); factoryPerClass.put(long.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new LongPreparedStatementIndexSetter(); } }); factoryPerClass.put(Long.class, factoryPerClass.get(long.class)); factoryPerClass.put(float.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new FloatPreparedStatementIndexSetter(); } }); factoryPerClass.put(Float.class, factoryPerClass.get(float.class)); factoryPerClass.put(double.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new DoublePreparedStatementIndexSetter(); } }); factoryPerClass.put(Double.class, factoryPerClass.get(double.class)); factoryPerClass.put(String.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new StringPreparedStatementIndexSetter(); } }); factoryPerClass.put(Timestamp.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new TimestampPreparedStatementIndexSetter(); } }); factoryPerClass.put(Date.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new DatePreparedStatementIndexSetter(); } }); factoryPerClass.put(Time.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new TimePreparedStatementIndexSetter(); } }); factoryPerClass.put(URL.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new URLPreparedStatementIndexSetter(); } }); factoryPerClass.put(Ref.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new RefPreparedStatementIndexSetter(); } }); factoryPerClass.put(BigDecimal.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new BigDecimalPreparedStatementIndexSetter(); } }); factoryPerClass.put(Array.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new ArrayPreparedStatementIndexSetter(); } }); factoryPerClass.put(byte[].class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new BytesPreparedStatementIndexSetter(); } }); factoryPerClass.put(NClob.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new NClobPreparedStatementIndexSetter(); } }); factoryPerClass.put(RowId.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new RowIdPreparedStatementIndexSetter(); } }); factoryPerClass.put(Blob.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new BlobPreparedStatementIndexSetter(); } }); factoryPerClass.put(Clob.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new ClobPreparedStatementIndexSetter(); } }); factoryPerClass.put(InputStream.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new InputStreamPreparedStatementIndexSetter(); } }); factoryPerClass.put(Reader.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new ReaderPreparedStatementIndexSetter(); } }); factoryPerClass.put(SQLXML.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { return (PreparedStatementIndexSetter<P>) new SQLXMLPreparedStatementIndexSetter(); } }); factoryPerClass.put(UUID.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { switch (key.getSqlType()) { case Types.BINARY: case Types.VARBINARY: case Types.LONGVARBINARY: return (PreparedStatementIndexSetter<P>) new UUIDBinaryPreparedStatementIndexSetter(); case Types.OTHER: // asssume it's a postgres uuid return (PreparedStatementIndexSetter<P>) new ObjectPreparedStatementIndexSetter(); } return (PreparedStatementIndexSetter<P>) new UUIDStringPreparedStatementIndexSetter(); } }); // see http://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html //IFJAVA8_START factoryPerClass.put(java.time.OffsetTime.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { if (key.getSqlType() == Types.TIME_WITH_TIMEZONE) { return (PreparedStatementIndexSetter<P>) new ObjectPreparedStatementIndexSetter(); } return null; } }); factoryPerClass.put(java.time.OffsetDateTime.class, new Factory() { @SuppressWarnings("unchecked") @Override public <P> PreparedStatementIndexSetter<P> getIndexedSetter(JdbcColumnKey key) { if (key.getSqlType() == Types.TIMESTAMP_WITH_TIMEZONE) { return (PreparedStatementIndexSetter<P>) new ObjectPreparedStatementIndexSetter(); } return null; } }); //IFJAVA8_END } @Override public <T> IndexedSetter<PreparedStatement, T> getIndexedSetter(PropertyMapping<?, ?, JdbcColumnKey, ? extends ColumnDefinition<JdbcColumnKey, ?>> arg) { Type propertyType = arg.getPropertyMeta().getPropertyType(); IndexedSetter<PreparedStatement, T> setter = getIndexedSetter(propertyType, arg); if (setter == null) { Class<?> iclass = JDBCTypeHelper.toJavaType(arg.getColumnKey().getSqlType(), propertyType); setter = getSetterWithConvertion(TypeHelper.<T>toClass(propertyType), iclass, arg); } return setter; } @SuppressWarnings("unchecked") private <P, I> IndexedSetter<PreparedStatement, P> getSetterWithConvertion(Class<P> pclazz, Class<I> iclass, PropertyMapping<?, ?, JdbcColumnKey, ? extends ColumnDefinition<JdbcColumnKey, ?>> pm) { Converter<? super P, ? extends I> converter = ConverterService.getInstance().findConverter(pclazz, iclass, pm.getColumnDefinition().properties()); if (converter != null) { IndexedSetter<PreparedStatement, I> indexedSetter = getIndexedSetter(iclass, pm); if (indexedSetter != null) { return new ConvertDelegateIndexSetter<P, I>(indexedSetter, converter); } } return null; } @SuppressWarnings("unchecked") protected <T> IndexedSetter<PreparedStatement, T> getIndexedSetter(Type propertyType, PropertyMapping<?, ?, JdbcColumnKey, ? extends ColumnDefinition<JdbcColumnKey, ?>> arg) { IndexedSetter<PreparedStatement, T> setter = null; if (TypeHelper.isEnum(propertyType)) { switch (arg.getColumnKey().getSqlType()) { case Types.NUMERIC: case Types.BIGINT: case Types.INTEGER: case Types.DECIMAL: case Types.DOUBLE: case Types.FLOAT: case Types.SMALLINT: case Types.REAL: case Types.TINYINT: setter = (IndexedSetter<PreparedStatement, T>) new OrdinalEnumPreparedStatementIndexSetter(); break; default: setter = (IndexedSetter<PreparedStatement, T>) new StringEnumPreparedStatementIndexSetter(); } } if (setter == null) { Factory setterFactory = this.factoryPerClass.get(TypeHelper.toClass(propertyType)); if (setterFactory != null) { setter = setterFactory.<T>getIndexedSetter(arg.getColumnKey()); } } if (setter == null && TypeHelper.isAssignable(SQLData.class, propertyType)) { setter = (IndexedSetter<PreparedStatement, T>) new ObjectPreparedStatementIndexSetter(); } return setter; } public interface Factory extends IndexedSetterFactory<PreparedStatement, JdbcColumnKey> { } }