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);
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. 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<?>
or even just UpdatableRecord<?>
, I think with an <R>
type variable, you're going to get cleaner code.
This might work (I only changed the parameters and added the <R>
type variable, nothing else):
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. This answer here explains it nicely . This explains your observation that suddenly things compiled when you had an invariant consumer.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.