2014-11-03 6 views
2

У меня есть база данных postgres с некоторыми столбцами, которые имеют тип varchar[]. jOOQ и pgjdbc-ng не играют хорошо; DefaultBindContext jOOQ имеет что-то вдоль линий:Можно ли написать jOOQ Converter для применения к массиву?

protected final BindContext bindValue0(Object value, Field<?> field) throws SQLException { 
    SQLDialect dialect = configuration.dialect(); 

    // [#650] [#3108] Use the Field's Converter before actually binding any value 
    Converter<?, ?> converter = field.getConverter(); 
    Class<?> type = converter.fromType(); 
    value = ((Converter) converter).to(value); 

    //... 

    else if (type.isArray()) { 
     switch (dialect) { 
      case POSTGRES: { 
       stmt.setString(nextIndex(), toPGArrayString((Object[]) value)); 
       break; 
      } 

который устанавливает переменную заявление в "{\"value1\", \"value2\", \"etc\"}", который, как вы бы задать массив в запросе. Позже, pgjdbc-нг имеет:

public static Object coerceToArray(Format format, Object val, Type type, Class<?> targetType, Map<String, Class<?>> typeMap, PGConnectionImpl connection) throws SQLException { 
    if (val == null) { 
    return null; 
    } 
    else if (val instanceof PGArray) { 
    return coerceToArray(format, ((PGArray) val).getValue(), type, targetType, typeMap, connection); 
    } 
    else if (val.getClass().isArray()) { 
    return coerceToArray(format, val, 0, Array.getLength(val), type, targetType, typeMap, connection); 
    } 

    throw createCoercionException(val.getClass(), targetType); 
} 

Что ожидает, что значение на утверждение будет любого типа PGArray или фактического массива; он не может принудить представление String массива к представлению String массива. :(

Я пытаюсь написать jOOQ конвертер, который будет конвертировать между String[] и PGArray, в идеале, это будет означать, что DefaultBindContext jOOQ был бы оставить преобразованное значение в одиночку достаточно хорошо, а затем pgjdbc-нг будет в состоянии справиться с этим .. правильно

Однако я не смог написать конфигурацию схемы jOOQ, что позволяет мне сделать это, я пробовал вариации:

<customType>  
    <customType> 
     <name>StringArray</name> 
     <type>java.lang.String[]</type> 
     <converter>my.package.PGStringArrayConverter</converter> 
    </customType> 
</customTypes> 

<forcedTypes> 
    <forcedType> 
     <name>StringArray</name> 
     <types>varchar\[\]</types> 
    </forcedType> 
</forcedTypes> 

Не имея каких-либо удачи, сгенерированные объекты таблиц см a String[][] и varchar[] не соответствует ни на чем. Даже если я сломаю его, так что принудительный тип будет соответствовать любому типу, но с <expression>, который соответствует только моему столбцу, а тип конвертера - java.lang.String. Я получаю компилятор java, жалующийся на то, что не смог выполнить Object [] в String [].

Есть ли какой-либо свет в конце этого туннеля, или я должен начать искать миграцию моей базы данных?

ответ

1

Итак, получается, что ответ «любопытный».

Я создал свой класс PGStringArrayConverter назад; Я создал

public abstract class PGArrayConverter implements Converter<String[], PGArray> 

Что в конечном итоге работает было:

public abstract class PGArrayConverter implements Converter<Object, String[]> { 
    @Override 
    public String[] from(final Object databaseObject) { 
     if (databaseObject == null) { 
      return null; 
     } 
     if (databaseObject.getClass().isArray()) { 
      return (String[]) databaseObject; 
     } 
     return (String[]) ((PGArray)databaseObject).getValue(); 
    } 

    @Override 
    public Object to(final String[] userObject) { 
     if (userObject == null) { 
      return null; 
     } 
     return new PGArray(null, null, userObject); 
    } 

    @Override 
    public Class<Object> fromType() { 
     return Object.class; 
    } 

    @Override 
    public Class<String[]> toType() { 
     return String[].class; 
    } 
} 

from() оказалось своего рода нечетной; Я получал массивы строк, а не PGArrays. Я не думаю, что база данных знала, что она «должна» сериализовать их в PGArrays.

Мне также пришлось изменить сгенерированный код, что немного неприятно. Мой файл schema.xml содержал:

<customType> 
    <name>StringArray</name> 
    <type>java.lang.String</type> 
    <converter>my.package.PGStringArrayConverter</converter> 
</customType> 

<forcedType> 
    <name>StringArray</name> 
    <expression>.*tabular_answer_entry.text.*</expression> 
    <types>.*</types> 
</forcedType> 

И я должен был изменить сгенерированные таблицы файлов для удаления .getArrayDataType() вызова типа данных createField в:

public final org.jooq.TableField<my.package.gen.tables.records.TabularAnswerEntryRecord, java.lang.String[]> TEXT = createField("text", org.jooq.impl.DefaultDataType.getDefaultDataType("java.lang.String").getArrayDataType(), this, "", new my.package.PGStringArrayConverter()); 

к:

public final org.jooq.TableField<my.package.gen.tables.records.TabularAnswerEntryRecord, java.lang.String[]> TEXT = createField("text", org.jooq.impl.DefaultDataType.getDefaultDataType("java.lang.String"), this, "", new my.package.PGStringArrayConverter()); 

Все решение кажется взломанным, и я собираюсь написать монстра единичного теста, чтобы убедиться, что это не сломается, когда мы обновляем любой из соответствующих пакетов, но по крайней мере я могу t o читать и записывать в мою базу данных.