alejandro-du / crudui

Automatically generate CRUD-like Vaadin views for any Java Bean
https://vaadin.com/directory#!addon/crud-ui-add-on
Apache License 2.0
86 stars 54 forks source link

On Update: ClassCastException - class PersistentBag cannot be cast to Set #70

Closed TobseF closed 4 years ago

TobseF commented 4 years ago

I used the crudui to display a entity which contains a OneToMany relationship with the data type List. Then opening the update dialog fails because of:

java.lang.ClassCastException: 
class org.hibernate.collection.internal.PersistentBag cannot be cast to class java.util.Set 

CrudUI 2.3.1
Vaadin 8.11.0

Person.java

@Entity
@Table(name = "TBL_PERSON")
public class Person implements {
  @Id
  private String serial;
  private String firstName;
  private String lastName;

  @OneToMany(fetch = FetchType.EAGER)
  private List<Address> contacts;
}

To reproduce create a crud for the provided model an click on the update pen.

Problem

The problem is, that the form adds a combobox for the field contacts with a default data model of type Set. But of course, hibernate provides a PersistentBag which is a subtype of List. So it's not possible for the crudui to set the loaded data to the form.

Is there a possibility to add support for displaying a @OneToMany realtionship?

Workaround

As workaround i set a custom CrudFormFactory which provices a custom field provider for the field contancs - which seems to be a very hacky.

var grid = new GridCrud(type, listConfigFix(Person.class));

private VerticalCrudFormFactory<?> listConfigFix(Class<?> type) {
 var verticalCrudFormFactory = new VerticalCrudFormFactory<>(type);
  verticalCrudFormFactory.setFieldProvider("contacts", (FieldProvider) () -> {
    var textField = new ComboBox<>();
    textField.setValue(List.of());
    return textField;
  });
  return verticalCrudFormFactory;
}

Stacktrace

java.lang.ClassCastException: class org.hibernate.collection.internal.PersistentBag cannot be cast to class java.util.Set (org.hibernate.collection.internal.PersistentBag is in unnamed module of loader 'app'; java.util.Set is in module java.base of loader 'bootstrap')
    at com.vaadin.ui.AbstractMultiSelect.setValue(AbstractMultiSelect.java:61)
    at com.vaadin.data.Binder$BindingImpl.initFieldValue(Binder.java:1155)
    at com.vaadin.data.Binder$BindingImpl.access$100(Binder.java:1001)
    at com.vaadin.data.Binder.lambda$readBean$2(Binder.java:1709)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1510)
    at com.vaadin.data.Binder.readBean(Binder.java:1702)
    at org.vaadin.crudui.form.AbstractAutoGeneratedCrudFormFactory.buildFields(AbstractAutoGeneratedCrudFormFactory.java:146)
    at org.vaadin.crudui.form.impl.form.factory.VerticalCrudFormFactory.buildNewForm(VerticalCrudFormFactory.java:23)
    at org.vaadin.crudui.crud.impl.GridCrud.gridSelectionChanged(GridCrud.java:138)
    at org.vaadin.crudui.crud.impl.GridCrud.lambda$initLayout$5e26faff$1(GridCrud.java:86)
    at com.vaadin.ui.components.grid.SingleSelectionModel.lambda$addSelectionListener$91fe6b9f$1(SingleSelectionModel.java:56)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:499)
    at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:273)
    at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:237)
    at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:1014)
    at com.vaadin.ui.components.grid.SingleSelectionModelImpl.setSelectedFromClient(SingleSelectionModelImpl.java:158)
    at com.vaadin.ui.components.grid.SingleSelectionModelImpl$1.select(SingleSelectionModelImpl.java:52)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:155)
    at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:116)
    at com.vaadin.server.communication.ServerRpcHandler.handleInvocation(ServerRpcHandler.java:445)
    at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:410)
    at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:274)
    at com.vaadin.server.communication.PushHandler.lambda$new$1(PushHandler.java:148)
    at com.vaadin.server.communication.PushHandler.callWithUi(PushHandler.java:248)
    at com.vaadin.server.communication.PushHandler.onMessage(PushHandler.java:534)
    at com.vaadin.server.communication.PushAtmosphereHandler.onMessage(PushAtmosphereHandler.java:87)
    at com.vaadin.server.communication.PushAtmosphereHandler.onRequest(PushAtmosphereHandler.java:77)
    at org.atmosphere.cpr.AsynchronousProcessor.action(AsynchronousProcessor.java:225)
    at org.atmosphere.cpr.AsynchronousProcessor.suspended(AsynchronousProcessor.java:114)
    at org.atmosphere.container.Servlet30CometSupport.service(Servlet30CometSupport.java:67)
    at org.atmosphere.cpr.AtmosphereFramework.doCometSupport(AtmosphereFramework.java:2297)
    at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.java:594)
    at org.atmosphere.websocket.DefaultWebSocketProcessor$3.run(DefaultWebSocketProcessor.java:345)
    at org.atmosphere.util.VoidExecutorService.execute(VoidExecutorService.java:101)
    at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.java:340)
    at org.atmosphere.websocket.DefaultWebSocketProcessor.invokeWebSocketProtocol(DefaultWebSocketProcessor.java:448)
    at org.atmosphere.container.JSR356Endpoint$3.onMessage(JSR356Endpoint.java:272)
    at org.atmosphere.container.JSR356Endpoint$3.onMessage(JSR356Endpoint.java:269)
    at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:395)
    at org.apache.tomcat.websocket.server.WsFrameServer.sendMessageText(WsFrameServer.java:119)
    at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:495)
    at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:294)
    at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:133)
    at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:82)
    at org.apache.tomcat.websocket.server.WsFrameServer.doOnDataAvailable(WsFrameServer.java:171)
    at org.apache.tomcat.websocket.server.WsFrameServer.notifyDataAvailable(WsFrameServer.java:151)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.upgradeDispatch(WsHttpUpgradeHandler.java:148)
    at org.apache.coyote.http11.upgrade.UpgradeProcessorInternal.dispatch(UpgradeProcessorInternal.java:54)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:832)
alejandro-du commented 4 years ago

This can be solved using the setConverter method in the latest version of the add-on. Unfortunately, I'm not maintaining the 2.x series anymore.