Отношение Hibernate OneToMany - это PersistentBag вместо List

Я разрабатываю приложение на javafx, которое подключается через RMI к EAR. Этот EAR подключается к базе данных SQLServer и отображает POJOS в спящем режиме.

Эти POJOS содержат двунаправленные отношения OneToMany и ManyToOne. Как следствие, эти отношения отображаются как Список.

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 со всей соответствующей информацией, но в режиме отладки посмотрите следующее:

Отношение Hibernate OneToMany - это PersistentBag вместо List

Объект успешно создан, и мое настольное приложение получает объект отлично, но если объект снова отправил его на сервер с помощью метода, который получает в качестве параметра объект 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.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
9 126
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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 и вместо этого использовать ленивую инициализацию. Например, если мне нужен список компаний от клиента, я бы вызвал метод, который возвращает список компаний, и то, как они имеют ленивую инициализацию, менее сложны. С другой стороны, если я хочу войти в одну из этих компаний, чтобы показать их данные на экране, я бы сделал еще один запрос на получение компании по их идентификатору, которая инициализировала бы список клиентов перед его отправкой. По вашему комментарию я понимаю, что нет способа заставить спящий режим создать список без прокси. не? Спасибо.

Sonk4x4 14.05.2018 13:48

Нет, насколько мне известно, это невозможно сделать

Jan Ossowski 14.05.2018 14:47

@Zeromus Если я сделаю то, что вы сказали во втором комментарии, коллекция по-прежнему является PersistentBag. И первый комментарий я не очень понял.

Sonk4x4 14.05.2018 18:11

В вашем Client Entity вам нужно сгенерировать динамический serialVersionUID, сгенерировать такой

private static final long serialVersionUID = -558553967080513790L;

Вы можете увидеть в этой ссылке, как сгенерировать serialVersionUID. Для получения дополнительной информации см. Этот отклик.

У меня также была конфигурация serialVersionUID, как вы говорите, и выдает ту же ошибку.

Sonk4x4 14.05.2018 13:46

Всегда использовать один и тот же идентификатор, например 1L, означает, что в будущем, если определение класса будет изменено, что приведет к изменениям в структуре сериализованного объекта, возникнет большая вероятность возникновения проблем при попытке десериализации объекта. Итак, попробуйте использовать сгенерировать идентификатор серийной версии. Не используйте 1 л.

Mahmoud 14.05.2018 13:52

Идея состоит в том, чтобы сгенерировать идентификатор, который является уникальным для определенной версии класса, который затем изменяется, когда в класс добавляются новые детали, такие как новое поле, которое повлияет на структуру сериализованного объекта.

Mahmoud 14.05.2018 13:53

Я знаю причины, по которым существует serialversionUID и почему он должен быть уникальным для каждого класса. Спасибо, что сказали мне, но, как я уже сказал, как будто это с уникальным серийным номером, как будто это 1L ошибка, которую я объяснил ранее, продолжает появляться. Спасибо.

Sonk4x4 14.05.2018 14:00

Добавьте конструктор по умолчанию в свои классы и попробуйте очистить файлы проекта .class и перестроить проект.

Mahmoud 14.05.2018 14:09

использование другого serialVersionUID ничего не изменит. Проблема здесь в том, что объект, который OP пытается сериализовать, на самом деле принадлежит к другому классу, чем кажется (прокси-класс спящего режима)

Jan Ossowski 14.05.2018 14:49

Другие вопросы по теме