【问题标题】:Hibernate OneToMany relation is PersistentBag instead of ListHibernate OneToMany 关系是 PersistentBag 而不是 List
【发布时间】:2018-10-24 00:19:09
【问题描述】:

我正在 javafx 中开发一个通过 RMI 与 EAR 连接的应用程序。此 EAR 连接到 SQLServer 数据库并使用休眠映射 POJOS。

这些 POJOS 包含双向 OneToMany 和 ManyToOne 关系。因此,这些关系被映射为 List 。

Company.java

@Entity
@Table(name = "Company")
public class Company implements Serializable{

/**
 * 
 */
private static final long serialVersionUID = 1L;

@Id
@Column(name="id_company",nullable = false)
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;

@OneToMany(mappedBy = "company",cascade = CascadeType.ALL )
@ElementCollection
private List<Client> Clients;

//GETTERS&SETTERS   

}

Client.java

@Entity
@Table(name = "Client")
public class Client implements Serializable{

/**
 * 
 */
private static final long serialVersionUID = 1L;

@Id
@Column(name="id_client",nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id; 

@ManyToOne
private Company company;

//GETTERS&SETTERS   

}

当我执行这个时,T 是公司:

public default T selectById(Serializable id, Class<T> entityClass,Session session)throws HibernateException {
    T obj = null;
    obj = session.get(entityClass, id);
    return obj;
}

结果是包含所有相应信息的 POJO,但在调试视图中看到:

对象已成功实例化,并且我的桌面应用程序完美地接收到了该对象,但如果该对象使用接收对象 Company 作为参数的方法再次将其发送到服务器,则出现此错误。

javax.ejb.EJBException: java.io.StreamCorruptedException: serialVersionUID does not match!
at org.jboss.as.ejb3.remote.AssociationImpl.receiveInvocationRequest(AssociationImpl.java:128)
at org.jboss.ejb.protocol.remote.EJBServerChannel$ReceiverImpl.handleInvocationRequest(EJBServerChannel.java:450)
at org.jboss.ejb.protocol.remote.EJBServerChannel$ReceiverImpl.handleMessage(EJBServerChannel.java:188)
at org.jboss.remoting3.remote.RemoteConnectionChannel.lambda$handleMessageData$3(RemoteConnectionChannel.java:430)
at org.jboss.remoting3.EndpointImpl$TrackingExecutor.lambda$execute$0(EndpointImpl.java:926)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Caused by: java.io.StreamCorruptedException: serialVersionUID does not match!
    at org.jboss.marshalling.AbstractClassResolver.resolveClass(AbstractClassResolver.java:108)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadClassDescriptor(RiverUnmarshaller.java:1025)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1354)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:275)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:223)
at org.jboss.marshalling.river.RiverUnmarshaller.readFields(RiverUnmarshaller.java:1856)
at org.jboss.marshalling.river.RiverUnmarshaller.doInitSerializable(RiverUnmarshaller.java:1769)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1397)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:275)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:208)
at org.jboss.marshalling.AbstractObjectInput.readObject(AbstractObjectInput.java:41)
at org.jboss.ejb.protocol.remote.EJBServerChannel$RemotingInvocationRequest.getRequestContent(EJBServerChannel.java:805)
at org.jboss.as.ejb3.remote.AssociationImpl.receiveInvocationRequest(AssociationImpl.java:126)
... 7 more
Caused by: an exception which occurred:
    in field com.persistence.pojo.Company.Clients
in object com.persistence.pojo.Company@47368172
in object of type com.persistence.pojo.Company

我正在使用 Wildfly10.x 服务器。 hibernatecore的版本是5.2.17.Final

很抱歉,如果解释得不好,但项目相当复杂,本质上我需要休眠来映射到 List 对象而不是 Persistentbag。

【问题讨论】:

    标签: java hibernate ejb wildfly rmi


    【解决方案1】:

    在你的ClientEntity中你需要生成动态serialVersionUID,生成一个这样的

    private static final long serialVersionUID = -558553967080513790L;
    

    你可以看到in this link如何生成serialVersionUID。 如需更多信息,请参阅response

    【讨论】:

    • 我也有你说的serialVersionUID配置,给了我同样的错误。
    • 总是使用同一个ID,比如1L表示以后如果类定义发生变化导致序列化对象的结构发生变化,那么在尝试的时候很有可能出现问题反序列化一个对象。因此,尝试使用生成序列版本 ID。不要使用 1L。
    • 这个想法是生成一个对于某个类的某个版本唯一的ID,然后当有新的细节添加到类中时改变它,例如一个新的字段,这会影响序列化对象的结构。
    • 我知道 serialversionUID 存在的原因以及每个类应该是唯一的原因。谢谢你告诉我,但正如我之前所说的,就像它是一个独特的序列一样,就像它是 1L 一样,我之前解释的错误不断出现。谢谢。
    • 使用不同的 serialVersionUID 不会改变任何事情。这里的问题是,OP 试图序列化的对象实际上是另一个类而不是看起来的(休眠代理类)
    【解决方案2】:

    这里的问题是,您从休眠中获得的对象属于某个休眠代理类,而不是您的实际实体类。这是休眠的正常行为。 这个代理类是自动生成的,它的 serialVersionUID 也是。

    一般来说,直接序列化/发送实体类对象不是一个好习惯,因为这些问题,还因为延迟初始化问题以及所有与将对象绑定到实体管理器上下文相关的问题。

    最常见的解决方案是创建“数据传输对象”或 DTO,它们可能具有相同的字段(或非常相似 - 例如用字符串替换枚举等,取决于您的需要),仅此而已。根据您的示例,您可以拥有这样的课程:

    public class CompanyDTO implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    private int id;
    
    private List<ClientDTO> Clients;
    
    //GETTERS&SETTERS   
    
    }
    

    (以此类推,您也需要创建 ClientDTO 类)。

    使用这个类代替,用于外部(外部不一定是远程的,只是你需要从 EM 上下文中分离的地方)通信。

    您可以手动填充它,也可以通过任何其他方式填充它(例如使用 BeanUtils 进行反射,使用复制属性的 Company 参数的构造函数 [我不建议这样做,因为它会中断应用程序层分离,但出于本次对话的目的这是一种有效的方法])。唯一重要的是您从实体管理器上下文中填充它

    【讨论】:

    • 我最初的想法是不使用 DTO,而是使用延迟初始化。例如,如果我需要来自客户的公司列表,我会调用一个返回公司列表的方法,并且它们的延迟初始化方式不那么繁重。另一方面,如果我想进入其中一家公司以在屏幕上显示他们的数据,我会再次请求通过他们的 id 获取一家公司,这将在发送之前初始化客户列表。根据您的评论,我了解到没有代理无法强制休眠创建列表。不要?谢谢。
    • 不,据我所知没有办法做到这一点
    • @Zeromus 如果我按照您在第二条评论中所说的做,那么该集合仍然是一个 PersistentBag。第一条评论我不太理解。
    猜你喜欢
    • 2019-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 1970-01-01
    • 2019-01-12
    • 1970-01-01
    • 2012-08-14
    相关资源
    最近更新 更多