Как получить доступ к сгенерированному jOOQ рутинному полю в качестве значения с помощью пользовательского конвертера?

У меня возникла проблема с доступом к полю сгенерированной подпрограммы из определяемой пользователем функции PL/pgSQL (которая в результате возвращает тип данных JSON), уже упомянутой в этот вопрос.

Это мой результат функции get_all_orders(), созданной в PL/pgSQL типа JSON:

{
  "orders": [
    {
      "order_id": 1,
      "total_price": 29.99,
      "order_date": "2019-08-22T10:06:33",
      "user": {
        "user_id": 1,
        "username": "test"
      },
      "order_items": [
        {
          "order_item_id": 1,
          "amount": 1,
          "book": {
            "book_id": 1,
            "title": "Harry Potter and the Philosopher's Stone",
            "price": 29.99,
            "amount": 400,
            "is_deleted": false,
            "authors": [
              {
                "author_id": 4,
                "first_name": "JK",
                "last_name": "Rowling"
              }
            ],
            "categories": [
              {
                "category_id": 2,
                "name": "Lyric",
                "is_deleted": false
              }
            ]
          },
          "order_id": 1,
          "total_order_item_price": 29.99
        }
      ]
    },
    {
      "order_id": 2,
      "total_price": 29.99,
      "order_date": "2019-08-22T10:10:13",
      "user": {
        "user_id": 1,
        "username": "test"
      },
      "order_items": [
        {
          "order_item_id": 2,
          "amount": 1,
          "book": {
            "book_id": 1,
            "title": "Harry Potter and the Philosopher's Stone",
            "price": 29.99,
            "amount": 400,
            "is_deleted": false,
            "authors": [
              {
                "author_id": 4,
                "first_name": "JK",
                "last_name": "Rowling"
              }
            ],
            "categories": [
              {
                "category_id": 2,
                "name": "Lyric",
                "is_deleted": false
              }
            ]
          },
          "order_id": 2,
          "total_order_item_price": 29.99
        }
      ]
    }
  ]
}

Я пытаюсь получить доступ к рутине как к полю, следуя Руководство по привязке пользовательских типов данных, и то, что мне удалось сделать до сих пор, это создать собственный конвертер для преобразования org.jooq.JSON в io.vertx.core.json.JsonObject:

public class JSONJsonObjectConverter implements Converter<JSON, JsonObject>{    
    private static final long serialVersionUID = -4773701755042752633L;

    @Override
    public JsonObject from(JSON jooqJson) {
        String strVal = (jooqJson == null ? null : jooqJson.toString());
        return strVal == null ? null : JsonObject.mapFrom(strVal);
    }

    @Override
    public JSON to(JsonObject vertxJson) {
        String strVal = (vertxJson == null ? null : vertxJson.toString());      
        return strVal == null ? null : JSON.valueOf(strVal);
    }

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

    @Override
    public Class<JsonObject> toType() {
        return JsonObject.class;
    }

}

... это ссылка на исходный код QueryResult, и я использую этот метод для его вызова (конвертер, созданный пользователем):

public static JsonObject convertGetAllOrdersQRToJsonObject(QueryResult qr) {
        //JsonArray ordersJA = qr.get("orders", JsonArray.class);
        DataType<JsonObject> jsonObjectType = SQLDataType.JSON.asConvertedDataType(new JSONJsonObjectConverter());
        //DataType<JsonArray> jsonArrayType = SQLDataType.JSONArray.asConvertedDataType(new JsonArrayConverter());
        DataType<JsonObject> jsonObjectTypeDefault = SQLDataType.JSON.asConvertedDataType((Binding<? super JSON, JsonObject>) new JsonObjectConverter());
        Field<JsonObject> ordersFieldDefault = DSL.field("get_all_orders", jsonObjectTypeDefault);
        Field<JsonObject> ordersField = DSL.field("get_all_orders", jsonObjectType);
        JsonObject orders = qr.get("orders", JsonObject.class);
        
//      return new JsonObject().put("orders", orders);
        return new JsonObject().put("orders", ordersField); // try ordersFieldDefault(.toString()) as value parameter
        
    }

Я вызываю вышеупомянутые методы внутри следующего:

Future<QueryResult> ordersFuture = queryExecutor.transaction(qe -> qe
            .query(dsl -> dsl
                .select(Routines.getAllOrders())
        ));                     
        LOGGER.info("Passed ordersFuture...");
        ordersFuture.onComplete(handler -> {
            if (handler.succeeded()) {                              
                QueryResult qRes = handler.result();                    
                JsonObject ordersJsonObject = OrderUtilHelper.convertGetAllOrdersQRToJsonObject(qRes);
                LOGGER.info("ordersJsonObject.encodePrettily(): " + ordersJsonObject.encodePrettily());
                resultHandler.handle(Future.succeededFuture(ordersJsonObject));
            } else {
                LOGGER.error("Error, something failed in retrivening ALL orders! handler.cause() = " + handler.cause());
                queryExecutor.rollback();               
                resultHandler.handle(Future.failedFuture(handler.cause()));
            }
        });         

... и это сгенерированный метод в классе Routines.java, который используется в последнем упомянутом выше коде в выражении, которое возвращает значение в dsl -> dsl.select(Routines.getAllOrders()) часть заявления:

/**
 * Convenience access to all stored procedures and functions in public
 */
@SuppressWarnings({ "all", "unchecked", "rawtypes" })
public class Routines {
/**
     * Get <code>public.get_all_orders</code> as a field.
     */
    public static Field<JSON> getAllOrders() {
        GetAllOrders f = new GetAllOrders();

        return f.asField();
    }
}

... и (наконец) вот мой класс *.jooq.routines.GetAllOrders.java:

/**
 * This class is generated by jOOQ.
 */
@SuppressWarnings({ "all", "unchecked", "rawtypes" })
public class GetAllOrders extends AbstractRoutine<JSON> {

    private static final long serialVersionUID = 917599810;

    /**
     * The parameter <code>public.get_all_orders.RETURN_VALUE</code>.
     */
    public static final Parameter<JSON> RETURN_VALUE = Internal.createParameter("RETURN_VALUE", org.jooq.impl.SQLDataType.JSON, false, false);

    /**
     * Create a new routine call instance
     */
    public GetAllOrders() {
        super("get_all_orders", Public.PUBLIC, org.jooq.impl.SQLDataType.JSON);

        setReturnParameter(RETURN_VALUE);
    }
}

Кстати, библиотека Vertx также использует класс JsonArray, который раньше работал с массивами, но не вижу способа сопоставить УЖЕ сгенерированный org.jooq.JSON с типом org.jooq.impl.JSONArray, а затем с типом io.vertx.core.json.JsonArray.

Я что-то упускаю (я знаю, что имею дело с сгенерированной подпрограммой, но пример, приведенный в руководстве jOOQ, содержит только поле таблицы)... или, может быть, я должен был создан класс привязки пользовательского типа данных?
Любое предложение/помощь приветствуется.

ОБНОВЛЕНИЕ 1:
я следовал инструкциям, приведенным в связанных вопросах и ответах в комментариях, и это то, что я добавил и уже добавил <forcedType> в свой pom.xml :

    <!-- Convert varchar column with name 'someJsonObject' to a io.vertx.core.json.JsonObject -->
    <forcedType>
        <userType>io.vertx.core.json.JsonObject</userType>
        <converter>io.github.jklingsporn.vertx.jooq.shared.JsonObjectConverter</converter>
        <includeExpression>someJsonObject</includeExpression>
        <includeTypes>.*</includeTypes>
        <nullability>ALL</nullability>
        <objectType>ALL</objectType>
    </forcedType>
    <!-- Convert varchar column with name 'someJsonArray' to a io.vertx.core.json.JsonArray -->
    <forcedType>
        <userType>io.vertx.core.json.JsonArray</userType>
        <converter>
            io.github.jklingsporn.vertx.jooq.shared.JsonArrayConverter</converter>
        <includeExpression>someJsonArray</includeExpression>
        <includeTypes>.*</includeTypes>
        <nullability>ALL</nullability>
        <objectType>ALL</objectType>
    </forcedType>
    <forcedType>
        <userType>io.vertx.core.json.JsonObject</userType>>
        <!-- also tried to use "org.jooq.Converter.ofNullable(Integer.class, String.class, Object::toString, Integer::valueOf)" 
and it did NOT work so I gave this custom created Conveter a try and it ALSO did NOT work! -->
        <converter>
            com.ns.vertx.pg.converters.JSONJsonObjectConverter.ofNullable(JSON.class, JsonObject.class, JsonObject::toString, JSON::valueOf)
        </converter>
        <includeExpression>(?i:get_all_orders|return_value)</includeExpressio>
    </forcedType>

... и когда я делаю Maven › Update Project + отмечаю Force Update of Snapshots/Releases, я получаю в целом 32 следующих сообщения об ОШИБКЕ:

JsonObject не может быть разрешен

...а также

JsonObject не может быть разрешен к типу

... и это мой сгенерированный класс *.jooq.routines.GetAllOrders.java:

 // This class is generated by jOOQ.     
@SuppressWarnings({ "all", "unchecked", "rawtypes" })
public class GetAllOrders extends AbstractRoutine<JsonObject> {   
    private static final long serialVersionUID = -431575258;

     // The parameter <code>public.get_all_orders.RETURN_VALUE</code>.         
    public static final Parameter<JsonObject> RETURN_VALUE = Internal.createParameter("RETURN_VALUE", org.jooq.impl.SQLDataType.JSON, false, false, org.jooq.Converter.ofNullable(JSON.class, JsonObject.class, JsonObject::toString, JSON::valueOf));
       
     //Create a new routine call instance
    public GetAllOrders() {
        super("get_all_orders", Public.PUBLIC, org.jooq.impl.SQLDataType.JSON, org.jooq.Converter.ofNullable(JSON.class, JsonObject.class, JsonObject::toString, JSON::valueOf));

        setReturnParameter(RETURN_VALUE);
    }
}

У меня уже есть этот программно созданный преобразователь для этого генератора ClassicReactiveVertxGenerator (дополнительная информация доступна здесь) для io.vertx.core.json.JsonObject в первом упомянутом <forcedType>. Любое предложение, как решить эту проблему?

UPDATE2:
Я также пытался использовать этот преобразователь org.jooq.Converter следующим образом (пришлось использовать квалифицированную ссылку для класса JSON, иначе он не выполнял импорт в классах Generated Routine):

<forcedType>
    <userType>java.lang.String</userType>
    <converter>
        org.jooq.Converter.ofNullable(org.jooq.JSON.class, String.class, Object::toString,org.jooq.JSON.class::valueOf)
    </converter>
    <includeExpression>(?i:get_all_orders|return_value)  </includeExpression>
</forcedType>

... и я получаю это в сгенерированном классе GetAllOrders.java:

 @SuppressWarnings({ "all", "unchecked", "rawtypes" })
    public class GetAllOrders extends AbstractRoutine<String> {
        private static final long serialVersionUID = 1922028137;

         // The parameter <code>public.get_all_orders.RETURN_VALUE</code>.         
        public static final Parameter<String> RETURN_VALUE = Internal.createParameter("RETURN_VALUE", org.jooq.impl.SQLDataType.JSON, false, false, org.jooq.Converter.ofNullable(org.jooq.JSON.class, String.class, Object::toString, org.jooq.JSON.class::valueOf));    
// in above value I get ERROR "The method ofNullable(Class<T>, Class<U>, Function<? super T,? extends U>, Function<? super U,? extends T>) in the type Converter is not applicable for the arguments (Class<JSON>, Class<String>, Object::toString, org.jooq.JSON.class::valueOf)"
// ... for org.jooq.Converter.ofNullable(..) method + 23 same/similar ERRORS

         // Create a new routine call instance         
        public GetAllOrders() {
            super("get_all_orders", Public.PUBLIC, org.jooq.impl.SQLDataType.JSON, org.jooq.Converter.ofNullable(org.jooq.JSON.class, String.class, Object::toString, org.jooq.JSON.class::valueOf));   
            setReturnParameter(RETURN_VALUE);
        }
    }

Поскольку это НЕ сработало, я попытался решить эту проблему, создав JooqJsonConverter.java класс Custom Converter следующим образом:

public class JooqJsonConverter implements Converter<String, JSON>{

    private static final long serialVersionUID = -4773701755042752633L;

    @Override
    public JSON from(String jooqJson) { return jooqJson == null ? null : JSON.valueOf(jooqJson); }

    @Override
    public String to(JSON jooqJson) { return jooqJson == null ? null : jooqJson.toString(); }

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

    @Override
    public Class<JSON> toType() { return JSON.class; }

}

...и меняем Converter под тегом:

<converter>
    com.ns.vertx.pg.converters.JooqJsonConverter.ofNullable(org.jooq.JSON.class, String.class, Object::toString,org.jooq.JSON.class::valueOf)
</converter>

... и я получаю тот же код класса GetAllOrders.java с небольшой разницей

 public static final Parameter<String> RETURN_VALUE = Internal.createParameter("RETURN_VALUE", org.jooq.impl.SQLDataType.JSON, false, false, com.ns.vertx.pg.converters.JooqJsonConverter.ofNullable(org.jooq.JSON.class, String.class, Object::toString, org.jooq.JSON.class::valueOf));

    public GetAllOrders() {
        super("get_all_orders", Public.PUBLIC, org.jooq.impl.SQLDataType.JSON, com.ns.vertx.pg.converters.JooqJsonConverter.ofNullable(org.jooq.JSON.class, String.class, Object::toString, org.jooq.JSON.class::valueOf));
        setReturnParameter(RETURN_VALUE);
    }

... и ТОЛЬКО эти 8 ошибок (по 2 для каждого из 4 сгенерированных классов рутин):

Метод ofNullable(Class, Class, Object::toString, org.jooq.JSON.class::valueOf) не определен для типа JooqJsonConverter

Любая идея, чего не хватает / я делаю неправильно? Заранее спасибо.


person NikolaS    schedule 25.06.2020    source источник
comment
Я не нашел ни одного из этих решений в ваших комментариях, но я пробовал, и это не сработало. Я обновил свой вопрос в разделе UPDATE1, поэтому, пожалуйста, посмотрите.   -  person NikolaS    schedule 25.06.2020
comment
Я также пытался использовать то же решение, что и вы, в связанных вопросах и ответах, а затем также создал свой собственный пользовательский конвертер и попробовал его. Результаты можно увидеть в разделе UPDATE2 моего вопроса. Пожалуйста, взгляните.   -  person NikolaS    schedule 26.06.2020
comment
Итак, на самом деле использование <forcedType/> было ответом на ваш первоначальный вопрос. Обычно рекомендуется сосредоточить вопросы здесь на переполнении стека, потому что будущие посетители сочтут их более полезными, если каждый вопрос обсуждает только одну проблему. Вы можете легко задавать новые, целенаправленные вопросы, касающиеся другой темы. В качестве бонуса вы получите более качественные и целенаправленные ответы. Выиграй, выиграй :)   -  person Lukas Eder    schedule 26.06.2020
comment
Я понимаю, о чем вы говорите, но похоже, что проблемы, с которыми я сталкиваюсь в моем коде, явно содержат больше подзадач. Поскольку это так, я создам один или несколько отдельных вопросов.   -  person NikolaS    schedule 26.06.2020


Ответы (1)


Ответ на первую часть вашего вопроса здесь. В ваших обновлениях это недопустимый код Java:

org.jooq.JSON.class::valueOf

Вы хотели написать это:

org.jooq.JSON::valueOf
person Lukas Eder    schedule 26.06.2020
comment
Действительно, глупая опечатка при копировании кода. Мне удалось исправить другие ОШИБКИ при генерации кода jOOQ (используя ДВА элемента <forcedType>, как вы предложили в связанных вопросах и ответах вашего ответа), и столкнулся с новой проблемой для создания правильного преобразователя для типа параметра INPUT функции < /б>. Поэтому я создал НОВЫЙ вопрос. :) Пожалуйста, взгляните. - person NikolaS; 27.06.2020