java - JOOq:更新通用表

标签 java generics casting jooq

我想使用 JOOq 创建一个通用方法,该方法使用来自 JSON 对象的值更新表(由字符串指定)。我在此示例中不包括任何表/字段验证。

public void updateTable(String table, JsonObject data) {
    Table<?> table = PUBLIC.getTable(table);

    UpdateSetFirstStep<?> update = DSL.using(fooConfig).update(table);

    // Loop through JSON {field1: value1, field2: value2, ...}
    for (Map.Entry<String, Object> entry : data) {
        String fieldName = entry.getKey();
        Field<?> field = table.field(fieldName);

        Object value = entry.getValue();

        // error: no suitable method found for set(Field<CAP#1>,CAP#2)
        update.set(field, field.getType().cast(value));
    }
}

但是我得到一个编译时错误:no suitable method found for set(Field<CAP#1>,CAP#2) .

我认为问题是编译器不知道字段的类型和值的类型将是相同的(因此 CAP#1 和 CAP#2)。

有什么办法可以做到这一点吗?

最佳答案

I think the problem is that the compiler doesn't know that the type of the field and the type of the value will be the same (hence CAP#1 and CAP#2).

这就是确切的问题。同一通配符类型的两种不同用途产生了两种不同的新捕获类型。

解决方案是引入一个小方法,其中通配符类型使用一次并绑定(bind)到一个类型参数。当它绑定(bind)到一个类型参数时,编译器会识别出它的不同用途是指相同类型。

像这样:

public void updateTable(String name, JsonObject data) {
    Table<?> table = PUBLIC.getTable(name);

    UpdateSetFirstStep<?> update = DSL.using(fooConfig).update(table);

    // Loop through JSON {field1: value1, field2: value2, ...}
    for (Map.Entry<String, Object> entry : data) {
        String fieldName = entry.getKey();
        Field<?> field = table.field(fieldName);

        Object value = entry.getValue();

        // Here the wildcard type is bound to the
        // type variable of the updateField method
        updateField(update, field, value);
    }
}

public <T> void updateField(UpdateSetStep<?> update, Field<T> field, Object value) {
    // When the wildcard is bound to T it can be used
    // multiple times without a problem
    update.set(field, field.getType().cast(value));
}

另一种解决方案

...是将字段类型转换为某种具体类型:

@SuppressWarnings("unchecked")
Field<Object> field = (Field<Object>) table.field(fieldName);
update.set(field, field.getType().cast(entry.getValue()));

输入的代码更少,在这个简单的示例中它运行良好。但它的类型安全性也较低,因此在更复杂的代码中引入带有类型参数的方法可能更好。

例如,以下类型检查但可能在运行时崩溃:

update.set(field, entry);

第三个有趣的解决方案

...将能够为 Field 声明一个本地类型变量:

<T> Field<T> field = table.field(fieldName);

但这当然不是合法的 Java,类型变量只能作为参数引入类和方法,不能引入局部变量。


第四种解决方案,使用 lambdas

...就是定义一个util方法,传递一个lambda对象给它。它的工作方式与第一个解决方案相同,但您不必为要执行此操作的每件事都创建自定义方法。

// Loop through JSON {field1: value1, field2: value2, ...}
for (Map.Entry<String, Object> entry : data) {
    String fieldName = entry.getKey();
    Field<?> field = table.field(fieldName);

    Object value = entry.getValue();

    captureType(field, f -> update.set(f, f.getType().cast(value)));
}

public static <T> void captureType(T o, Consumer<T> c) {
    c.accept(o);
}

这个的一个变体是使用一些现有的方法来获得相同的结果:

Optional.of(field).ifPresent(f -> update.set(f, f.getType().cast(value)));

关于java - JOOq:更新通用表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42169503/

相关文章:

java - 属性 setData 的不兼容类型 [JSON+Struts2 插件]

java - 在java中覆盖列表结果类型

python - 通用多对多关系

c++ - (int) ch 与 int(ch) : Are they different syntaxes for the same thing?

c++ - 将 PyArrayObject* 转换为 int* 失败

c# - 混淆 C# 枚举和显式转换

Java MessagePack 空检查

java - 如何使用可执行 jar 内的 .txt、.xml 和 .properties 文件?

java - Android SQLITE,无法仅在 Marshmallow 中打开数据库

java - 如何在运行时捕获方法类型(泛型类型)