-
Bug
-
Resolution: Fixed
-
P4
-
1.2.0
-
None
-
beta
-
generic
-
generic
In the current implementation of serialization, ObjectInputStream has a private
readObject() method which takes a single boolean parameter "requireLocalClass".
When this parameter is set to true, the readObject() call should succeed only
if the class of the object to be deserialized can be resolved locally. If
requireLocalClass is set to false, then deserialization should succeed even
if a local class for the object is not found. This facility is used when
deserializing the values of object fields which have no equivalent in the
local class, and also when skipping over unread object data originally written
by class-defined writeObject()/writeExternal() methods. In both of these
cases, the object is not needed by whatever referenced it, so failure to resolve
the object's class shouldn't cause deserialization to fail for the
referencing object.
For example, imagine that VM 1 is marshalling the following class A to VM 2:
class A implements Serializable {
B b;
C c;
}
Also imagine that VM 2 has a local version of class A which does not include
field "b", and does not have a local version of class B available:
class A implements Serializable {
C c;
}
When VM 2 deserializes an instance a of class A, deserialization should succeed:
since field "b" doesn't exist in VM 2's version of A, the value of b is
considered irrelevant, and is read in with requireLocalFields set to false,
so the absence of class B does not cause an exception to be thrown. In
ObjectInputStream's internal wire handle table, a null is inserted in the
place where field b's object value would have been stored.
So far, so good. However, what if a back reference to b's value occurs later
on in the serialization stream? Furthermore, what happens if the back
reference occurs in a context in which the local class needs to be resolved?
Currently, ObjectInputStream will simply return a null reference, since
that's what it found in the wire handle table. This is inconsistent
behavior--the back reference read should result in a ClassNotFoundException,
just as it would have if the write of object a had not preceded the (direct)
write of object b.
For a more concrete example, refer to the attached sample code.
readObject() method which takes a single boolean parameter "requireLocalClass".
When this parameter is set to true, the readObject() call should succeed only
if the class of the object to be deserialized can be resolved locally. If
requireLocalClass is set to false, then deserialization should succeed even
if a local class for the object is not found. This facility is used when
deserializing the values of object fields which have no equivalent in the
local class, and also when skipping over unread object data originally written
by class-defined writeObject()/writeExternal() methods. In both of these
cases, the object is not needed by whatever referenced it, so failure to resolve
the object's class shouldn't cause deserialization to fail for the
referencing object.
For example, imagine that VM 1 is marshalling the following class A to VM 2:
class A implements Serializable {
B b;
C c;
}
Also imagine that VM 2 has a local version of class A which does not include
field "b", and does not have a local version of class B available:
class A implements Serializable {
C c;
}
When VM 2 deserializes an instance a of class A, deserialization should succeed:
since field "b" doesn't exist in VM 2's version of A, the value of b is
considered irrelevant, and is read in with requireLocalFields set to false,
so the absence of class B does not cause an exception to be thrown. In
ObjectInputStream's internal wire handle table, a null is inserted in the
place where field b's object value would have been stored.
So far, so good. However, what if a back reference to b's value occurs later
on in the serialization stream? Furthermore, what happens if the back
reference occurs in a context in which the local class needs to be resolved?
Currently, ObjectInputStream will simply return a null reference, since
that's what it found in the wire handle table. This is inconsistent
behavior--the back reference read should result in a ClassNotFoundException,
just as it would have if the write of object a had not preceded the (direct)
write of object b.
For a more concrete example, refer to the attached sample code.
- relates to
-
JDK-4363673 ClassNotFoundException-tolerant readObject() variant needed
-
- Open
-