M
Mike Smith
I am attempting to serialize objects that have sets, but there is a
NullPointerException thrown when deserializing. The exception is
thrown at a point where deserialization calls on one of the my class's
hashCode() methods. Though the fields are null at this point
deserialization, the object sent in had a non-null value in that field.
The deserialization process is attempting to put this object in a
HashMap before deserialization has provided the field values (which
tend to be essential to a hashCode() override!).
The problem can be reproduced with two simple classes and an instance
of each, wired together (code follows). An instance 'a' of A has a
field reference to an instance 'b' of B. b has a set with the single
instance a within, as well as a name field. b's name field is used to
generate its hashCode (as in a natural key). a's hashCode is derived
from b (it's name).
The result is a NullPointerException. Failures duplicated on both
Solaris-based and Mac OS X-based Java 1.4.2.
Here is the code example:
public class A implements java.io.Serializable {
private B b;
public A() {
}
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (object == null || getClass() != object.getClass()) {
return false;
}
A other = (A) object;
return getB().equals(other.getB());
}
public int hashCode() {
return getB().hashCode(); // FAILS HERE in deserialization.
}
public void setB(B b) {
this.b = b;
}
public B getB() {
return b;
}
}
import java.util.Set;
public class B implements java.io.Serializable {
private Set aSet;
private String name;
public B() {
}
public B(String name) {
this.name = name;
}
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (object == null || getClass() != object.getClass()) {
return false;
}
B other = (B) object;
return getName().equals(other.getName());
}
public int hashCode() {
return getName().hashCode();
}
public String getName() {
return name;
}
public void setASet(Set aSet) {
this.aSet = aSet;
}
public Set getASet() {
return aSet;
}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.ibjectInputStream;
import java.ibjectOutputStream;
import java.util.HashSet;
public class Main {
public Main() {
}
public static void main(String argv[]) {
A a = new A();
B b = new B("FOO");
a.setB(b);
HashSet aSet = new HashSet();
aSet.add(a);
b.setASet(aSet);
try {
FileOutputStream fileOut = new
FileOutputStream("test.srl");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(a);
fileOut.close();
FileInputStream fileIn = new FileInputStream("test.srl");
ObjectInputStream in = new ObjectInputStream(fileIn);
A rehydratedA = (A) in.readObject();
// Won't get this far, will fail above...
System.out.println(rehydratedA);
} catch (Exception anyException) {
anyException.printStackTrace();
}
}
}
The full stack trace:
java.lang.NullPointerException
at A.hashCode(A.java:26)
at java.util.HashMap.hash(HashMap.java:261)
at java.util.HashMap.put(HashMap.java:379)
at java.util.HashSet.readObject(HashSet.java:277)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at
java.ibjectStreamClass.invokeReadObject(ObjectStreamClass.java:838)
at
java.ibjectInputStream.readSerialData(ObjectInputStream.java:1746)
at
java.ibjectInputStream.readOrdinaryObject(ObjectInputStream.java:1646)
at java.ibjectInputStream.readObject0(ObjectInputStream.java:1274)
at
java.ibjectInputStream.defaultReadFields(ObjectInputStream.java:1845)
at
java.ibjectInputStream.readSerialData(ObjectInputStream.java:1769)
at
java.ibjectInputStream.readOrdinaryObject(ObjectInputStream.java:1646)
at java.ibjectInputStream.readObject0(ObjectInputStream.java:1274)
at
java.ibjectInputStream.defaultReadFields(ObjectInputStream.java:1845)
at
java.ibjectInputStream.readSerialData(ObjectInputStream.java:1769)
at
java.ibjectInputStream.readOrdinaryObject(ObjectInputStream.java:1646)
at java.ibjectInputStream.readObject0(ObjectInputStream.java:1274)
at java.ibjectInputStream.readObject(ObjectInputStream.java:324)
at Main.main(Main.java:32)
- Mike
NullPointerException thrown when deserializing. The exception is
thrown at a point where deserialization calls on one of the my class's
hashCode() methods. Though the fields are null at this point
deserialization, the object sent in had a non-null value in that field.
The deserialization process is attempting to put this object in a
HashMap before deserialization has provided the field values (which
tend to be essential to a hashCode() override!).
The problem can be reproduced with two simple classes and an instance
of each, wired together (code follows). An instance 'a' of A has a
field reference to an instance 'b' of B. b has a set with the single
instance a within, as well as a name field. b's name field is used to
generate its hashCode (as in a natural key). a's hashCode is derived
from b (it's name).
The result is a NullPointerException. Failures duplicated on both
Solaris-based and Mac OS X-based Java 1.4.2.
Here is the code example:
public class A implements java.io.Serializable {
private B b;
public A() {
}
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (object == null || getClass() != object.getClass()) {
return false;
}
A other = (A) object;
return getB().equals(other.getB());
}
public int hashCode() {
return getB().hashCode(); // FAILS HERE in deserialization.
}
public void setB(B b) {
this.b = b;
}
public B getB() {
return b;
}
}
import java.util.Set;
public class B implements java.io.Serializable {
private Set aSet;
private String name;
public B() {
}
public B(String name) {
this.name = name;
}
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (object == null || getClass() != object.getClass()) {
return false;
}
B other = (B) object;
return getName().equals(other.getName());
}
public int hashCode() {
return getName().hashCode();
}
public String getName() {
return name;
}
public void setASet(Set aSet) {
this.aSet = aSet;
}
public Set getASet() {
return aSet;
}
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.ibjectInputStream;
import java.ibjectOutputStream;
import java.util.HashSet;
public class Main {
public Main() {
}
public static void main(String argv[]) {
A a = new A();
B b = new B("FOO");
a.setB(b);
HashSet aSet = new HashSet();
aSet.add(a);
b.setASet(aSet);
try {
FileOutputStream fileOut = new
FileOutputStream("test.srl");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(a);
fileOut.close();
FileInputStream fileIn = new FileInputStream("test.srl");
ObjectInputStream in = new ObjectInputStream(fileIn);
A rehydratedA = (A) in.readObject();
// Won't get this far, will fail above...
System.out.println(rehydratedA);
} catch (Exception anyException) {
anyException.printStackTrace();
}
}
}
The full stack trace:
java.lang.NullPointerException
at A.hashCode(A.java:26)
at java.util.HashMap.hash(HashMap.java:261)
at java.util.HashMap.put(HashMap.java:379)
at java.util.HashSet.readObject(HashSet.java:277)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at
java.ibjectStreamClass.invokeReadObject(ObjectStreamClass.java:838)
at
java.ibjectInputStream.readSerialData(ObjectInputStream.java:1746)
at
java.ibjectInputStream.readOrdinaryObject(ObjectInputStream.java:1646)
at java.ibjectInputStream.readObject0(ObjectInputStream.java:1274)
at
java.ibjectInputStream.defaultReadFields(ObjectInputStream.java:1845)
at
java.ibjectInputStream.readSerialData(ObjectInputStream.java:1769)
at
java.ibjectInputStream.readOrdinaryObject(ObjectInputStream.java:1646)
at java.ibjectInputStream.readObject0(ObjectInputStream.java:1274)
at
java.ibjectInputStream.defaultReadFields(ObjectInputStream.java:1845)
at
java.ibjectInputStream.readSerialData(ObjectInputStream.java:1769)
at
java.ibjectInputStream.readOrdinaryObject(ObjectInputStream.java:1646)
at java.ibjectInputStream.readObject0(ObjectInputStream.java:1274)
at java.ibjectInputStream.readObject(ObjectInputStream.java:324)
at Main.main(Main.java:32)
- Mike