dekaf-jdbc/src/impl/JdbcValueGetters.java (573 lines of code) (raw):

package org.jetbrains.dekaf.jdbc.impl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.dekaf.inter.exceptions.DBFetchingException; import org.jetbrains.dekaf.inter.exceptions.DBPreparingException; import org.jetbrains.dekaf.jdbc.utils.Numbers; import java.math.BigDecimal; import java.math.BigInteger; import java.sql.*; import java.util.HashMap; import java.util.Map; import static java.lang.String.format; /** * Value getters factory. * <p/> * Stateless service. * * @author Leonid Bushuev from JetBrains */ public final class JdbcValueGetters { //// INTERNAL STRUCTURES \\\\ protected static final class SpecificKey { final int jdbcType; final @NotNull Class<?> desiredClass; SpecificKey(final int jdbcType, final @NotNull Class<?> desiredClass) { this.jdbcType = jdbcType; this.desiredClass = desiredClass; } @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SpecificKey that = (SpecificKey) o; return this.jdbcType == that.jdbcType && this.desiredClass == that.desiredClass; } @Override public int hashCode() { return Math.abs(jdbcType)*17 + desiredClass.hashCode(); } } //// INSTANCE PLENTY \\\\ @NotNull private static final Map<@NotNull Class<?>, @NotNull JdbcValueGetter<?>> NORMAL_GETTERS; @NotNull private static final Map<@NotNull SpecificKey, @NotNull JdbcValueGetter<?>> SPECIFIC_GETTERS; static { NORMAL_GETTERS = new HashMap<>(32); NORMAL_GETTERS.put(boolean.class, IntBoolGetter.INSTANCE); NORMAL_GETTERS.put(Boolean.class, IntBoolGetter.INSTANCE); NORMAL_GETTERS.put(byte.class, ByteGetter.INSTANCE); NORMAL_GETTERS.put(Byte.class, ByteGetter.INSTANCE); NORMAL_GETTERS.put(short.class, ShortGetter.INSTANCE); NORMAL_GETTERS.put(Short.class, ShortGetter.INSTANCE); NORMAL_GETTERS.put(int.class, IntGetter.INSTANCE); NORMAL_GETTERS.put(Integer.class, IntGetter.INSTANCE); NORMAL_GETTERS.put(long.class, LongGetter.INSTANCE); NORMAL_GETTERS.put(Long.class, LongGetter.INSTANCE); NORMAL_GETTERS.put(float.class, FloatGetter.INSTANCE); NORMAL_GETTERS.put(Float.class, FloatGetter.INSTANCE); NORMAL_GETTERS.put(double.class, DoubleGetter.INSTANCE); NORMAL_GETTERS.put(Double.class, DoubleGetter.INSTANCE); NORMAL_GETTERS.put(BigInteger.class, BigIntegerGetter.INSTANCE); NORMAL_GETTERS.put(BigDecimal.class, BigDecimalGetter.INSTANCE); NORMAL_GETTERS.put(Number.class, GenericNumberGetter.INSTANCE); NORMAL_GETTERS.put(String.class, StringGetter.INSTANCE); NORMAL_GETTERS.put(char.class, CharGetter.INSTANCE); NORMAL_GETTERS.put(Character.class, CharGetter.INSTANCE); NORMAL_GETTERS.put(java.util.Date.class, JavaDateGetter.INSTANCE); NORMAL_GETTERS.put(java.sql.Date.class, DateGetter.INSTANCE); NORMAL_GETTERS.put(Timestamp.class, TimestampGetter.INSTANCE); NORMAL_GETTERS.put(java.sql.Time.class, TimeGetter.INSTANCE); NORMAL_GETTERS.put(Object.class, ObjectGetter.INSTANCE); NORMAL_GETTERS.put(byte[].class, ArrayOfByteGetter.INSTANCE); NORMAL_GETTERS.put(short[].class, ArrayOfShortGetter.INSTANCE); NORMAL_GETTERS.put(int[].class, ArrayOfIntGetter.INSTANCE); NORMAL_GETTERS.put(long[].class, ArrayOfLongGetter.INSTANCE); NORMAL_GETTERS.put(Number[].class, ArrayOfNumberGetter.INSTANCE); NORMAL_GETTERS.put(String[].class, ArrayOfStringGetter.INSTANCE); SPECIFIC_GETTERS = new HashMap<>(48); SPECIFIC_GETTERS.put(new SpecificKey(Types.BOOLEAN, boolean.class), BoolBoolGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BOOLEAN, Boolean.class), BoolBoolGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BOOLEAN, Object.class), BoolBoolGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BOOLEAN, byte.class), BoolByteGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BOOLEAN, Byte.class), BoolByteGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BOOLEAN, short.class), BoolShortGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BOOLEAN, Short.class), BoolShortGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BOOLEAN, int.class), BoolIntGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BOOLEAN, Integer.class), BoolIntGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BOOLEAN, Number.class), BoolByteGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BIT, boolean.class), BoolBoolGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BIT, Boolean.class), BoolBoolGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BIT, byte.class), BoolByteGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BIT, Byte.class), BoolByteGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BIT, short.class), BoolShortGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BIT, Short.class), BoolShortGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BIT, int.class), BoolIntGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BIT, Integer.class), BoolIntGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BIT, Number.class), BoolByteGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BIT, Object.class), BoolByteGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.TINYINT, boolean.class), IntBoolGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.TINYINT, Boolean.class), IntBoolGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.TINYINT, Number.class), ByteGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.TINYINT, Object.class), ByteGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.SMALLINT, boolean.class), IntBoolGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.SMALLINT, Boolean.class), IntBoolGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.SMALLINT, Number.class), ShortGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.SMALLINT, Object.class), ShortGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.INTEGER, boolean.class), IntBoolGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.INTEGER, Boolean.class), IntBoolGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.INTEGER, Number.class), IntGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BIGINT, Number.class), LongGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BIGINT, Object.class), LongGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.REAL, Number.class), FloatGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.REAL, Object.class), FloatGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.FLOAT, Number.class), DoubleGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.FLOAT, Object.class), DoubleGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.DOUBLE, Number.class), DoubleGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.DOUBLE, Object.class), DoubleGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.DECIMAL, Number.class), BigDecimalGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.DECIMAL, Object.class), BigDecimalGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BINARY, byte[].class), BinaryGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.BINARY, Object.class), BinaryGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.VARBINARY, byte[].class), BinaryGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.VARBINARY, Object.class), BinaryGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.LONGVARBINARY, byte[].class), BinaryGetter.INSTANCE); SPECIFIC_GETTERS.put(new SpecificKey(Types.LONGVARBINARY, Object.class), BinaryGetter.INSTANCE); } @NotNull @SuppressWarnings("unchecked") static <W> JdbcValueGetter<W> of(final int jdbcType, @NotNull final Class<? extends W> clazz) { JdbcValueGetter<W> getter = find(jdbcType, clazz); if (getter != null) { return getter; } else { String message = format("Unknown how to get a value of class %s for jdbc type %d", clazz.getSimpleName(), jdbcType); throw new DBPreparingException(message, (String) null); } } @Nullable @SuppressWarnings("unchecked") static <W> JdbcValueGetter<W> find(final int jdbcType, @NotNull final Class<? extends W> clazz) { JdbcValueGetter<?> getter = null; if (jdbcType != Types.OTHER) getter = SPECIFIC_GETTERS.get(new SpecificKey(jdbcType, clazz)); if (getter == null) getter = NORMAL_GETTERS.get(clazz); if (getter == null && clazz.isArray()) getter = lookForArrayGetter(clazz); return (JdbcValueGetter<W>) getter; } @Nullable protected static <W> JdbcValueGetter<W> lookForArrayGetter(@NotNull final Class<W> clazz) { return new ArrayGetter<W>(clazz); } @NotNull private static Class<?> getArrayComponentClass(@NotNull final Class<?> arrayClass) { Class<?> c = arrayClass; while (c.isArray()) c = c.getComponentType(); return c; } //// GETTERS \\\\ static final class BoolBoolGetter extends JdbcValueGetter<Boolean> { @Override @Nullable Boolean getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final boolean value = rset.getBoolean(index); return rset.wasNull() ? null : value; } static final BoolBoolGetter INSTANCE = new BoolBoolGetter(); } @SuppressWarnings("UnnecessaryBoxing") static final class BoolByteGetter extends JdbcValueGetter<Byte> { @Override @Nullable Byte getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final boolean value = rset.getBoolean(index); return rset.wasNull() ? null : value ? _1_ : _0_; } private final static Byte _1_ = Byte.valueOf((byte)1); private final static Byte _0_ = Byte.valueOf((byte)0); final static BoolByteGetter INSTANCE = new BoolByteGetter(); } @SuppressWarnings("UnnecessaryBoxing") static final class BoolShortGetter extends JdbcValueGetter<Short> { @Override @Nullable Short getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final boolean value = rset.getBoolean(index); return rset.wasNull() ? null : value ? _1_ : _0_; } private final static Short _1_ = Short.valueOf((short)1); private final static Short _0_ = Short.valueOf((short)0); final static BoolShortGetter INSTANCE = new BoolShortGetter(); } @SuppressWarnings("UnnecessaryBoxing") static final class BoolIntGetter extends JdbcValueGetter<Integer> { @Override @Nullable Integer getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final boolean value = rset.getBoolean(index); return rset.wasNull() ? null : value ? _1_ : _0_; } private final static Integer _1_ = Integer.valueOf((int)1); private final static Integer _0_ = Integer.valueOf((int)0); final static BoolIntGetter INSTANCE = new BoolIntGetter(); } static final class IntBoolGetter extends JdbcValueGetter<Boolean> { @Override @Nullable Boolean getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final int value = rset.getInt(index); return rset.wasNull() ? null : value > 0; } static final IntBoolGetter INSTANCE = new IntBoolGetter(); } static final class ByteGetter extends JdbcValueGetter<Byte> { @Override @Nullable Byte getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final byte value = rset.getByte(index); return rset.wasNull() ? null : value; } final static ByteGetter INSTANCE = new ByteGetter(); } static final class ShortGetter extends JdbcValueGetter<Short> { @Override @Nullable Short getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final short value = rset.getShort(index); return rset.wasNull() ? null : value; } final static ShortGetter INSTANCE = new ShortGetter(); } static final class IntGetter extends JdbcValueGetter<Integer> { @Override @Nullable Integer getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final int value = rset.getInt(index); return rset.wasNull() ? null : value; } final static IntGetter INSTANCE = new IntGetter(); } static final class LongGetter extends JdbcValueGetter<Long> { @Override @Nullable Long getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final long value = rset.getLong(index); return rset.wasNull() ? null : value; } final static LongGetter INSTANCE = new LongGetter(); } static final class FloatGetter extends JdbcValueGetter<Float> { @Override @Nullable Float getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final float value = rset.getFloat(index); return rset.wasNull() ? null : value; } final static FloatGetter INSTANCE = new FloatGetter(); } static final class DoubleGetter extends JdbcValueGetter<Double> { @Override @Nullable Double getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final double value = rset.getDouble(index); return rset.wasNull() ? null : value; } final static DoubleGetter INSTANCE = new DoubleGetter(); } static final class BigIntegerGetter extends JdbcValueGetter<BigInteger> { @Override @Nullable BigInteger getValue(@NotNull final ResultSet rset, final int index) throws SQLException { BigDecimal bd = rset.getBigDecimal(index); if (rset.wasNull()) return null; return bd.toBigInteger(); } final static BigDecimalGetter INSTANCE = new BigDecimalGetter(); } static final class BigDecimalGetter extends JdbcValueGetter<BigDecimal> { @Override @Nullable BigDecimal getValue(@NotNull final ResultSet rset, final int index) throws SQLException { return rset.getBigDecimal(index); } final static BigDecimalGetter INSTANCE = new BigDecimalGetter(); } static final class GenericNumberGetter extends JdbcValueGetter<Number> { @Override @Nullable Number getValue(@NotNull final ResultSet rset, final int index) throws SQLException { return Numbers.convertNumberSmartly(rset.getBigDecimal(index)); } final static GenericNumberGetter INSTANCE = new GenericNumberGetter(); } static final class BinaryGetter extends JdbcValueGetter<byte[]> { @Nullable @Override byte[] getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final byte[] binaryValue = rset.getBytes(index); return rset.wasNull() ? null : binaryValue; } static final BinaryGetter INSTANCE = new BinaryGetter(); } static final class StringGetter extends JdbcValueGetter<String> { @Override @Nullable String getValue(@NotNull final ResultSet rset, final int index) throws SQLException { return rset.getString(index); } static final StringGetter INSTANCE = new StringGetter(); } static final class CharGetter extends JdbcValueGetter<Character> { @Override @Nullable Character getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final String str = rset.getString(index); if (rset.wasNull() || str == null || str.length() == 0) { return null; } return str.charAt(0); } final static CharGetter INSTANCE = new CharGetter(); } static final class JavaDateGetter extends JdbcValueGetter<java.util.Date> { @Override @Nullable java.util.Date getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final Timestamp timestamp = rset.getTimestamp(index); return timestamp != null ? new java.util.Date(timestamp.getTime()) : null; } final static JavaDateGetter INSTANCE = new JavaDateGetter(); } static final class DateGetter extends JdbcValueGetter<java.sql.Date> { @Override @Nullable java.sql.Date getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final java.sql.Date date = rset.getDate(index); return date != null ? new Date(date.getTime()) : null; } final static DateGetter INSTANCE = new DateGetter(); } static final class TimestampGetter extends JdbcValueGetter<Timestamp> { @Override @Nullable Timestamp getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final Timestamp timestamp = rset.getTimestamp(index); return timestamp != null ? new Timestamp(timestamp.getTime()) : null; } final static TimestampGetter INSTANCE = new TimestampGetter(); } static final class TimeGetter extends JdbcValueGetter<java.sql.Time> { @Override @Nullable java.sql.Time getValue(@NotNull final ResultSet rset, final int index) throws SQLException { final Time time = rset.getTime(index); return time != null ? new Time(time.getTime()) : null; } final static TimeGetter INSTANCE = new TimeGetter(); } static final class ObjectGetter extends JdbcValueGetter<Object> { @Override @Nullable Object getValue(@NotNull final ResultSet rset, final int index) throws SQLException { return rset.getObject(index); } static final ObjectGetter INSTANCE = new ObjectGetter(); } static abstract class AbstractArrayGetter<A> extends JdbcValueGetter<A> { @Nullable @Override A getValue(@NotNull final ResultSet rset, final int index) throws SQLException { Array array = rset.getArray(index); if (array == null) return null; try { if (rset.wasNull()) return null; return convertArray(array); } finally { array.free(); } } protected abstract A convertArray(final Array array) throws SQLException; } static final class ArrayGetter<A> extends AbstractArrayGetter<A> { private final Class<A> arrayClass; ArrayGetter(final Class<A> arrayClass) { this.arrayClass = arrayClass; } @Override protected A convertArray(final Array array) throws SQLException { Object gotArray = array.getArray(); final Object result; try { if (arrayClass.isAssignableFrom(gotArray.getClass())) { result = gotArray; } else { result = copySlice(arrayClass, gotArray); } } catch (Exception e) { String msg = String.format("Failed to fetch an array value. " + "Required type: %s, actual type: %s. " + "Encountered exception class %s with message %s.", arrayClass.getCanonicalName(), gotArray.getClass().getCanonicalName(), e.getClass().getSimpleName(), e.getMessage()); throw new DBFetchingException(msg, e, null); } //noinspection unchecked return (A) result; } private static Object copySlice(Class<?> sliceClass, Object sliceSource) { Class<?> componentType = sliceClass.getComponentType(); int n = java.lang.reflect.Array.getLength(sliceSource); Object result = java.lang.reflect.Array.newInstance(sliceClass.getComponentType(), n); if (n == 0) return result; for (int i = 0; i < n; i++) { final Object x = java.lang.reflect.Array.get(sliceSource, i); if (x == null) continue; final Class<?> xClass = x.getClass(); final Object component; if (componentType.isAssignableFrom(xClass)) { component = x; } else if (componentType == String.class) { component = x.toString(); } else if (componentType.isArray()) { component = copySlice(componentType, x); } else if ((componentType.isPrimitive() || Number.class.isAssignableFrom(componentType)) && Number.class.isAssignableFrom(xClass)) { //noinspection unchecked component = Numbers.convertNumber((Class<Number>) componentType, (Number) x); } else { String message = String.format("Array value fetching problem: unknown how to convert value (%s) of type %s to %s.", x.toString(), xClass.getCanonicalName(), componentType.getCanonicalName()); throw new IllegalStateException(message); } java.lang.reflect.Array.set(result, i, component); } return result; } } static final class ArrayOfByteGetter extends AbstractArrayGetter<byte[]> { @Override protected byte[] convertArray(final Array array) throws SQLException { Object arr = array.getArray(); if (arr instanceof byte[]) { return (byte[]) arr; } else if (arr instanceof Number[]) { Number[] arrN = (Number[]) arr; int n = arrN.length; byte[] result = new byte[n]; for (int i = 0; i < n; i++) { Number v = arrN[i]; result[i] = v != null ? v.byteValue() : 0; } return result; } else { throw new DBFetchingException("Unknown how to convert "+arr.getClass().getSimpleName()+" to byte[]", null); } } static final ArrayOfByteGetter INSTANCE = new ArrayOfByteGetter(); } static final class ArrayOfShortGetter extends AbstractArrayGetter<short[]> { @Override protected short[] convertArray(final Array array) throws SQLException { Object arr = array.getArray(); if (arr instanceof short[]) { return (short[]) arr; } else if (arr instanceof Number[]) { Number[] arrN = (Number[]) arr; int n = arrN.length; short[] result = new short[n]; for (int i = 0; i < n; i++) { Number v = arrN[i]; result[i] = v != null ? v.shortValue() : 0; } return result; } else { throw new DBFetchingException("Unknown how to convert "+arr.getClass().getSimpleName()+" to short[]", null); } } static final ArrayOfShortGetter INSTANCE = new ArrayOfShortGetter(); } static final class ArrayOfIntGetter extends AbstractArrayGetter<int[]> { @Override protected int[] convertArray(final Array array) throws SQLException { Object arr = array.getArray(); if (arr instanceof int[]) { return (int[]) arr; } else if (arr instanceof Number[]) { Number[] arrN = (Number[]) arr; int n = arrN.length; int[] result = new int[n]; for (int i = 0; i < n; i++) { Number v = arrN[i]; result[i] = v != null ? v.intValue() : 0; } return result; } else { throw new DBFetchingException("Unknown how to convert "+arr.getClass().getSimpleName()+" to int[]", null); } } static final ArrayOfIntGetter INSTANCE = new ArrayOfIntGetter(); } static final class ArrayOfLongGetter extends AbstractArrayGetter<long[]> { @Override protected long[] convertArray(final Array array) throws SQLException { Object arr = array.getArray(); if (arr instanceof long[]) { return (long[]) arr; } else if (arr instanceof Number[]) { Number[] arrN = (Number[]) arr; int n = arrN.length; long[] result = new long[n]; for (int i = 0; i < n; i++) { Number v = arrN[i]; result[i] = v != null ? v.longValue() : 0; } return result; } else { throw new DBFetchingException("Unknown how to convert "+arr.getClass().getSimpleName()+" to long[]", null); } } static final ArrayOfLongGetter INSTANCE = new ArrayOfLongGetter(); } static final class ArrayOfNumberGetter extends AbstractArrayGetter<Number[]> { @Override protected Number[] convertArray(final Array array) throws SQLException { Object arr = array.getArray(); if (arr instanceof Number[]) { return (Number[]) arr; } else { throw new DBFetchingException("Unknown how to convert "+arr.getClass().getSimpleName()+" to Number[]", null); } } static final ArrayOfNumberGetter INSTANCE = new ArrayOfNumberGetter(); } static final class ArrayOfStringGetter extends AbstractArrayGetter<String[]> { @Override protected String[] convertArray(final Array array) throws SQLException { Object arr = array.getArray(); if (arr instanceof String[]) { return (String[]) arr; } else if (arr instanceof Object[]) { Object[] objects = (Object[]) arr; int n = objects.length; String[] result = new String[n]; for (int i = 0; i < n; i++) { Object object = objects[i]; result[i] = object != null ? object.toString() : null; } return result; } else { throw new DBFetchingException("Unknown how to convert "+arr.getClass().getSimpleName()+" to String[]", null); } } static final ArrayOfStringGetter INSTANCE = new ArrayOfStringGetter(); } static final class DumbNullGetter extends JdbcValueGetter<Object> { @Nullable @Override Object getValue(@NotNull final ResultSet rset, final int index) { return null; } static final DumbNullGetter INSTANCE = new DumbNullGetter(); } }