flow
flow copied to clipboard
Grid without columns failed to serialize
Description of the bug
Grid without columns failed to serialize with the following exception: cannot assign instance of java.lang.invoke.SerializedLambda to field com.vaadin.flow.data.provider.AbstractDataProvider$DataListenerWrapper.registration of type com.vaadin.flow.shared.Registration in instance of com.vaadin.flow.data.provider.AbstractDataProvider$DataListenerWrapper In own production code the same exception happens also with columns configured but we weren't able to create a minimal reproducible example.
Minimal reproducible example
@Route(value = "grid-serialization")
public class GridSerializationIssue extends VerticalLayout {
private static final long serialVersionUID = 1L;
private final Grid<Currency> grid;
public GridSerializationIssue() {
Button test = new Button("serialize", event -> {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try(ObjectOutputStream oos = new ObjectOutputStream(bos)){
oos.writeObject(GridSerializationIssue.this);
oos.flush();
}
try(ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray())){
try(ObjectInputStream ois = new ObjectInputStream(bis)){
GridSerializationIssue readObject = (GridSerializationIssue) ois.readObject();
}
}
Notification.show("OK");
}catch (Exception e) {
e.printStackTrace();
Notification.show("FAILED: " + e.getMessage());
}
});
add(test);
grid = new Grid<>();
add(grid);
}
public static class Currency implements Serializable{
private static final long serialVersionUID = 1L;
private String code;
private String currency;
private String symbol;
public Currency(){}
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
}
}
Expected behavior
No exception throwed on serialization
Versions:
- Vaadin / Flow version: 23.2.2
- Java version: 17
- OS version: osx/linux
- Browser version (if applicable): -
- Application Server (if applicable): both tomcat and springboot
- IDE (if applicable): -
We managed to reproduce with a simple example also with the columns configured. We also find a even weird case were the first time it work and the second time it fails
Exception with also the columns configured.
@Route(value="grid-serialization-issue", layout = GridSerializationIssueWithColumnLayout.class)
public class GridSerializationIssueWithColumn extends VerticalLayout implements HasUrlParameter<String>{
private static final long serialVersionUID = 1L;
private Grid<Country> grid;
public GridSerializationIssueWithColumn() {
setHeightFull();
grid = new Grid<>();
grid.setSizeFull();
grid.addColumn(Country::getCountrycode).setHeader("ISO Code").setWidth("100px").setFlexGrow(0);
grid.addColumn(Country::getCountry).setHeader("Name").setFlexGrow(1);
grid.setSelectionMode(SelectionMode.NONE);
add(grid);
}
public void onFilterChange(String filter) {
Country france = new Country();
france.setCountry("France");
france.setCountrycode("FR");
grid.setItems(List.of(france));
}
@Override
public void setParameter(BeforeEvent event, @OptionalParameter String parameter) {
onFilterChange(parameter);
}
public static class GridSerializationIssueWithColumnLayout extends AppLayout {
private static final long serialVersionUID = 1L;
public GridSerializationIssueWithColumnLayout() {
Button test = new Button("Serialize", event -> {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try(ObjectOutputStream oos = new ObjectOutputStream(bos)){
oos.writeObject(GridSerializationIssueWithColumnLayout.this);
oos.flush();
}
try(ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray())){
try(ObjectInputStream ois = new ObjectInputStream(bis)){
GridSerializationIssueWithColumnLayout readObject = (GridSerializationIssueWithColumnLayout) ois.readObject();
}
}
Notification.show("OK");
}catch (Exception e) {
e.printStackTrace();
Notification.show("FAILED: " + e.getMessage());
}
});
addToNavbar(test);
}
}
public static class Country implements Serializable {
private static final long serialVersionUID = 1L;
private String country;
private String countrycode;
public Country(){}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getCountrycode() {
return countrycode;
}
public void setCountrycode(String countrycode) {
this.countrycode = countrycode;
}
}
}
The example below succeed the first time but fails the subsequents tries
@Route(value="grid-serialization-issue2")
public class GridSerializationIssue extends VerticalLayout implements HasUrlParameter<String>{
private static final long serialVersionUID = 1L;
private Grid<Country> grid;
public GridSerializationIssue() {
setHeightFull();
Button test = new Button("Serialize", event -> {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try(ObjectOutputStream oos = new ObjectOutputStream(bos)){
oos.writeObject(UI.getCurrent());
oos.flush();
}
try(ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray())){
try(ObjectInputStream ois = new ObjectInputStream(bis)){
UI readObject = (UI) ois.readObject();
}
}
Notification.show("OK");
}catch (Exception e) {
e.printStackTrace();
Notification.show("FAILED: " + e.getMessage());
}
});
add(test);
grid = new Grid<>();
grid.setSizeFull();
grid.addColumn(Country::getCountrycode).setHeader("ISO Code").setWidth("100px").setFlexGrow(0);
grid.addColumn(Country::getCountry).setHeader("Name").setFlexGrow(1);
grid.setSelectionMode(SelectionMode.NONE);
add(grid);
}
public void onFilterChange(String filter) {
Country france = new Country();
france.setCountry("France");
france.setCountrycode("FR");
grid.setItems(List.of(france));
}
@Override
public void setParameter(BeforeEvent event, @OptionalParameter String parameter) {
onFilterChange(parameter);
}
public static class Country implements Serializable {
private static final long serialVersionUID = 1L;
private String country;
private String countrycode;
public Country(){}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getCountrycode() {
return countrycode;
}
public void setCountrycode(String countrycode) {
this.countrycode = countrycode;
}
}
}
Looks similar to this issue https://github.com/vaadin/flow/issues/6216.
This ticket/PR has been released with Vaadin 23.1.13.
@caalador We just retested the examples above with vaadin 23.2.5 which should include the fix (according to https://github.com/vaadin/flow/commits/23.2.5 ) but they are still failing. Also the issue was not present (for us) in vaadin 23.1.x
Flow 23.2.5 will be in Vaadin 23.2.6 that should be available in mvn in a moment
This ticket/PR has been released with Vaadin 23.2.6.