Remove on PersistentSet after deserialization not working


#1

Hello,

currently we’re having a problem calling remove on a PersistentSet after the entity containing that set was serialized/deserialized during the server to client transfer.

We’re using an entity Item which has an id (generated seq), a name (NaturalId) and a set with Labels.
The entity Label has an id (generated seq), language (NaturalId), text and (bidirectional) the item (NaturalId) it belongs to.

the hashcode and equals methods use the NaturalIds of the entities:
hashcode for Label: Objects.hash(getLanguage(), getItem());
hashcode for Item: Objects.hash(getName());

During deserialization of Item the PersistentSet of the labels is incorrectly written, due to Label.item for some reason being null (or partly initialised), which leads to a different hashcode than it should be.

This then leads to Item.removeLabel(lbl) not working, because the Label used for removal has the Item set, leading to another calculated hashcode.

Code snippet of the example below:

// simulate server to client transfer
Item clientItem = (Item) copyObjectBySerialization(item);
Set<Label> clientSet = (Set<Label>) copyObjectBySerialization(item.getLabel());

// just get the first label
Label label = (Label) clientItem.getLabel().toArray()[0];

// remove does not work on the deserialized item
System.out.println(clientItem.removeLabel(label));


// works when the set gets 'reset'
Set<Label> labels = new HashSet<>(clientItem.getLabel());
clientItem.setLabel(labels);
System.out.println(clientItem.removeLabel(label));

// works when calling remove on deserialized set
System.out.println(clientSet.remove(label));

A demo code can be found here https://www.magentacloud.de/lnk/jWm4jO4b

So is there any way to fix the issue, are we maybe supposed to write customized readObject/writeObject methods for all of our entity classes?

Hibernate Version used: 5.2.17
Java Version: 8u152 and 8u172

Hope you can help me out,
kind regards,
René


#2

After you deserialize the entity:

Item clientItem = (Item) copyObjectBySerialization(item);

Make sure you merge it:

clientItem = entityManager.merge(clientItem);

This way, the clientItem will be a managed entity and entity modifications will be detected by the currently running Persistence Context.


#3

I think I explained it wrong, the removeLabel method is getting called on the client side, we don’t have the possibility to merge there.

The user is able to add/remove labels on the client and change one of the other 30+ attributes of the Item.


#4

Try to isolate the problem and extract the Hibernate-related code that you think it’s not working and add it to the thread.


#5

Hello,

not sure if it really is a Hibernate problem or just a serialisation problem.
Either way, I fixed it implementing the writeObject and readObject methods.

Thanks for the quick replies :slight_smile: