简体   繁体   English

Java Generics 供应商接受方法中的不兼容类型

[英]Java Generics incompatible types in Supplier accept method

I have a method with generic parameters:我有一个带有泛型参数的方法:

public static void addActionColumnAndSetSelectionListener(Grid<? extends UpdatableRecord<?>> grid,
                                                              EditDialog<? extends UpdatableRecord<?>> dialog,
                                                              Callback afterSave, Supplier<UpdatableRecord<?>> onNewRecord,
                                                              Consumer<? extends UpdatableRecord<?>> insteadOfDelete) {
        Button buttonAdd = new Button(grid.getTranslation("Add"));
        buttonAdd.addClickListener(event -> dialog.open(onNewRecord.get(), afterSave));

        grid.addComponentColumn(record -> {
            Button delete = new Button(grid.getTranslation("Delete"));
            delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
            delete.addClickListener(event -> {
                getBean(TransactionTemplate.class).executeWithoutResult(transactionStatus -> {
                    try {
                        if (insteadOfDelete != null) {
                            insteadOfDelete.accept(record);
                        } else {
                            getBean(DSLContext.class).attach(record);
                        }
                        record.delete();
                    } catch (DataAccessException e) {
                        Notification.show(e.getMessage());
                    }
                });
            });

            HorizontalLayout horizontalLayout = new HorizontalLayout(delete);
            horizontalLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
            return horizontalLayout;
        }).setTextAlign(ColumnTextAlign.END).setHeader(buttonAdd);

        grid.addSelectionListener(event -> event.getFirstSelectedItem().ifPresent(record -> dialog.open(record, afterSave)));
    }

The problem is that the line insteadOfDelete.accept(record);问题是行insteadOfDelete.accept(record); does not compile:不编译:

Error:(47, 52) java: incompatible types: org.jooq.UpdatableRecord<capture#1 of ?> cannot be converted to capture#2 of ? extends org.jooq.UpdatableRecord<?>

I don't understand the problem.我不明白这个问题。 If I change如果我改变

Consumer<? extends UpdatableRecord<?>> insteadOfDelete

to

Consumer<UpdatableRecord<?>> insteadOfDelete

it compiles.它编译。

The joys of recursive generics... It could be seen as a design flaw of jOOQ to use them in the UpdatableRecord type hierarchy.递归 generics 的乐趣... 在UpdatableRecord类型层次结构中使用它们可以看作是 jOOQ 的设计缺陷 You should capture the wild card in a generic type variable of your method.您应该在方法的泛型类型变量中捕获通配符。 While it might work to some extent when using ? extends UpdatableRecord<?>虽然它在使用时可能会在某种程度上起作用? extends UpdatableRecord<?> ? extends UpdatableRecord<?> or even just UpdatableRecord<?> , I think with an <R> type variable, you're going to get cleaner code. ? extends UpdatableRecord<?>甚至只是UpdatableRecord<?> ,我认为使用<R>类型变量,您将获得更清晰的代码。

This might work (I only changed the parameters and added the <R> type variable, nothing else):这可能有效(我只更改了参数并添加了<R>类型变量,仅此而已):

public static <R extends UpdatableRecord<R>> void addActionColumnAndSetSelectionListener(
    Grid<R> grid,
    EditDialog<R> dialog,
    Callback afterSave, 
    Supplier<R> onNewRecord,
    Consumer<R> insteadOfDelete
) {
    Button buttonAdd = new Button(grid.getTranslation("Add"));
    buttonAdd.addClickListener(event -> dialog.open(onNewRecord.get(), afterSave));
    grid.addComponentColumn(record -> {
        Button delete = new Button(grid.getTranslation("Delete"));
        delete.addThemeVariants(ButtonVariant.LUMO_ERROR);
        delete.addClickListener(event -> {
            getBean(TransactionTemplate.class).executeWithoutResult(transactionStatus -> {
                try {
                    if (insteadOfDelete != null) {
                        insteadOfDelete.accept(record);
                    } else {
                        getBean(DSLContext.class).attach(record);
                    }
                    record.delete();
                } catch (DataAccessException e) {
                    Notification.show(e.getMessage());
                }
            });
        });
        HorizontalLayout horizontalLayout = new HorizontalLayout(delete);
        horizontalLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
        return horizontalLayout;
    }).setTextAlign(ColumnTextAlign.END).setHeader(buttonAdd);
    grid.addSelectionListener(event -> event.getFirstSelectedItem().ifPresent(
        record -> dialog.open(record, afterSave)));
}

Also, I've removed covariance of your individual method parameters, as I think you probably don't need it.此外,我已经删除了您的各个方法参数的协方差,因为我认为您可能不需要它。 Otherwise, remember that Supplier is covariant and Consumer is contravariant.否则,请记住Supplier是协变的, Consumer是逆变的。 This answer here explains it nicely .这个答案很好地解释了它 This explains your observation that suddenly things compiled when you had an invariant consumer.这解释了你观察到当你有一个不变的消费者时突然编译的东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM