Java Generics&jOOQ - 如何创建一个jOOQ列的HashMap到另一个

Luk*_* Xu 2 java inheritance jooq

我有一个界面

public interface HistoryDao<B extends UpdatableRecord<B>, H extends UpdatableRecord<H>> extends TableDao<H>{
    default void saveHistoryForIds(List<Integer> ids) {
        HashMap<? extends TableField<H, ? extends TableField<H, ? extends Serializable>>, ? extends TableField<B, ? extends TableField<B, ? extends Serializable>>> mappings = setUpHistoryMapping();

        List<? extends TableField<H, ? extends Serializable>> tableFields = new ArrayList<>(mappings.keySet());

        ArrayList<H> hs = new ArrayList<>();
        jooq()
            .insertInto(table(), tableFields);

    }

    HashMap<? extends TableField<H, ? extends TableField<H, ? extends Serializable>>, ? extends TableField<B, ? extends TableField<B, ? extends Serializable>>> setUpHistoryMapping();
}
Run Code Online (Sandbox Code Playgroud)

(TableDao是一个界面,但它不是非常重要)

在我的具体课程中,我尝试实施

MyClassHere implements HistoryDao<ApprovalWorkflowRecord, ApprovalWorkflowHistoryRecord>

@Override
public HashMap<? extends TableField<ApprovalWorkflowHistoryRecord, ? extends TableField<ApprovalWorkflowHistoryRecord, ? extends Serializable>>, ? extends TableField<ApprovalWorkflowRecord, ? extends TableField<ApprovalWorkflowRecord, ? extends Serializable>>> setUpHistoryMapping() {
    HashMap<? extends TableField<ApprovalWorkflowHistoryRecord, ? extends TableField<ApprovalWorkflowHistoryRecord, ? extends Serializable>>, ? extends TableField<ApprovalWorkflowRecord, ? extends TableField<ApprovalWorkflowRecord, ? extends Serializable>>> x = new HashMap<>();

    TableField<ApprovalWorkflowHistoryRecord, Integer> id = APPROVAL_WORKFLOW_HISTORY.ID;

    x.put(id, APPROVAL_WORKFLOW.ID);
}
Run Code Online (Sandbox Code Playgroud)

我认为我的问题与协方差有关...(也许)但我一直收到这个错误

x.put(id,APPROVAL_WORKFLOW.ID);

method Map.put(CAP#1,CAP#2) is not applicable
  (argument mismatch; TableField<ApprovalWorkflowHistoryRecord,Integer> cannot be converted to CAP#1)

method AbstractMap.put(CAP#1,CAP#2) is not applicable
  (argument mismatch; TableField<ApprovalWorkflowHistoryRecord,Integer> cannot be converted to CAP#1)

method HashMap.put(CAP#1,CAP#2) is not applicable
  (argument mismatch; TableField<ApprovalWorkflowHistoryRecord,Integer> cannot be converted to CAP#1)   where CAP#1,CAP#2 are fresh type-variables:
CAP#1 extends TableField<ApprovalWorkflowHistoryRecord,? extends TableField<ApprovalWorkflowHistoryRecord,? extends Serializable>> from capture of ? extends TableField<ApprovalWorkflowHistoryRecord,? extends TableField<ApprovalWorkflowHistoryRecord,? extends Serializable>> CAP#2 extends TableField<ApprovalWorkflowRecord,? extends TableField<ApprovalWorkflowRecord,? extends Serializable>> from capture of ? extends TableField<ApprovalWorkflowRecord,? extends TableField<ApprovalWorkflowRecord,? extends Serializable>>
Run Code Online (Sandbox Code Playgroud)

Luk*_*der 7

如果忽略所有的(当然令人印象深刻的)通用的噪音,你的问题可以归结为把一个值与通配符集合中的经典问题:

Map<?, ?> x = new HashMap<>();
x.put("a", "b"); // Doesn't work.
Run Code Online (Sandbox Code Playgroud)

只需删除不需要它们的所有通配符,并用具体类型替换它们.一般的经验法则是:

  • 在方法参数中使用通配符,以允许方法调用者传递一些不太具体的集合.
  • 将泛型类型放入集合时使用通配符,例如List<Class<?>>或在这种情况下List<TableField<H, ?>>.
  • 尽量避免从方法中返回通配符.

以下是如何在您的情况下解决此问题:

public interface HistoryDao<
    B extends UpdatableRecord<B>, 
    H extends UpdatableRecord<H>
> extends TableDao<H> {
    default void saveHistoryForIds(List<Integer> ids) {
        HashMap<TableField<H, ?>, TableField<B, ?>> mappings = setUpHistoryMapping();
        List<TableField<H, ?>> tableFields = new ArrayList<>(mappings.keySet());
        jooq().insertInto(table(), tableFields);
    }

    HashMap<TableField<H, ?>, TableField<B, ?>> setUpHistoryMapping();
}

class MyClassHere implements HistoryDao<
    ApprovalWorkflowRecord, 
    ApprovalWorkflowHistoryRecord
> {

    @Override
    public HashMap<
        TableField<ApprovalWorkflowHistoryRecord, ?>, 
        TableField<ApprovalWorkflowRecord, ?>
    > setUpHistoryMapping() {
        HashMap<
            TableField<ApprovalWorkflowHistoryRecord, ?>, 
            TableField<ApprovalWorkflowRecord, ?>
        > x = new HashMap<>();

        x.put(APPROVAL_WORKFLOW_HISTORY.ID, APPROVAL_WORKFLOW.ID);
    }
}
Run Code Online (Sandbox Code Playgroud)

我改变了什么?

  • 本地Map类型不再在其键/值上使用通配符.而不是Map<? extends TableField<...>, ? extends TableField<...>>,只写Map<TableField<...>, TableField<...>>
  • setUpHistoryMapping()方法的返回类型也是如此.
  • 你不需要? extends Serializable这里.该类型绑定不会添加任何值.只需使用?.
  • TableField<?, TableField<...>>意外地嵌套了.这在jOOQ环境中没有意义.

也可以看看: