I have an exception with a 1-N bidirectional relationship when I serialize, then deserialize the hibernate session (JPA). But first, here are my persistent classes (some info are missing for clarity, but the entities are correct afaik):
Code:
@Entity
public class Parent implements Serializable {
private static final long serialVersionUID=<generated>
@Id private long id;
@Column(name="NAME", nullable=false) private String name;
@OneToMany(mappedBy="parent") private Set<Child> children = new HashSet<Child>();
public int hashcode() {
return name.hashcode();
}
public boolean equals(Object o) {
// test for ==, null, same class etc, then
return this.name.equals(((Parent) o).name);
}
}
public class Child implements Serializable {
private static final long serialVersionUID=<generated>
@Id private long id;
@Column(name="NAME", nullable=false) private String name;
@ManyToOne @JoinColumn(name="PARENT_ID") private Parent parent;
public int hashcode() {
return name.hashcode();
}
public boolean equals(Object o) {
// test for ==, null, same class etc, then
return this.name.equals(((Parent) o).name);
}
}
I have defined equals() and hashcode() based on the name field for both entities because this field is not modified once the entity is created, and it represents a natural business key (there's a unique constraint on this field in the DB).
When I load a parent and its children in the hibernate entity manager, then serialize the EM, then deserialize it, I get a NPE in child.hashcode(), because the name is still null.
The funny part is that the name field in the child is not null before I serialize the session.
Here is the stack trace of this exception. The object that is being deserialized in the 3rd line from the bottom of the stack is the Child object, then (reading from bottom to top) the next readField corresponds to deserialization of Child.parent, then the next readField corresponds to deserialization of Parent.children (actually a Hibernate PersistentSet), then the next readField corresponds to the delegate HashSet of PersistentSet, then there is a HashMap readObject() corresponding to the internal map of HashSet, followed by NPE.
Code:
java.lang.NullPointerException
at com.mycompany.domain.Child.hashCode(Job.java:180)
at java.util.HashMap.hash(HashMap.java:324)
at java.util.HashMap.putForCreate(HashMap.java:601)
at java.util.HashMap.readObject(HashMap.java:1319)
at sun.reflect.GeneratedMethodAccessor16.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:618)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1002)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1834)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1744)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1330)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1933)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1857)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1744)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1330)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1933)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1857)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1744)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1330)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1933)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1857)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1744)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1330)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:364)
at org.hibernate.engine.StatefulPersistenceContext.deserialize(StatefulPersistenceContext.java:1406)
at org.hibernate.impl.SessionImpl.readObject(SessionImpl.java:1923)
This suggests me that the Child object is not fully populated yet when it is being added to its parent's children set.
What shall I do, apart from get rid of equals()/hashcode() in my entities ??