首页 > 解决方案 > 如何使用自定义转换器访问 jOOQ 生成的例程字段作为值?

问题描述

我在从这个问题中已经提到的PL/pgSQL 用户定义函数(结果返回JSON 数据类型)访问生成例程的字段时遇到问题。

这是我get_all_orders()在 JSON 类型的 PL/pgSQL 中创建的函数的结果:

{
  "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类型的方法。

我是否遗漏了一些东西(我知道我正在处理生成的 Routine,但 jOOQ 手册中给出的示例仅包含 Table 字段)......或者我应该创建自定义数据类型绑定类
非常感谢任何建议/帮助。

更新1
我已按照评论中链接的问答中给出的说明进行操作,这就是我添加的内容,并且已经<forcedType>在我的 s 中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 + 检查强制更新快照/发布时,我总共收到 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 clases 中执行导入):

<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 自定义转换器类来解决这个问题,如下所示:

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>
    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 个错误(4 个生成的 Routine 类中的每一个都有 2 个):

对于 JooqJsonConverter 类型,未定义方法 ofNullable(Class, Class, Object::toString, org.jooq.JSON.class::valueOf)

知道缺少什么/我做错了吗?先感谢您。

标签: javajsonxmlplpgsqljooq-codegen-maven

解决方案


你的问题的第一部分在这里得到了回答。在您的更新中,这不是有效的 Java 代码:

org.jooq.JSON.class::valueOf

你的意思是这样写:

org.jooq.JSON::valueOf

推荐阅读