-
CSR
-
Resolution: Approved
-
P3
-
None
-
behavioral
-
minimal
-
The behavior that is changed only occurs in environments that are not configured to be able to load expected classes and changes unexpected behavior to the expected behavior.
-
Java API
-
Implementation
Summary
java.util.Vector
should throw ClassNotFoundException
instead of StreamCorruptedException
; the wrong exception is thrown due to incorrect handling of a missing class by ObjectInputStream.GetField.get(name, object)
.
Problem
During deserialization, java.util.Vector
uses ObjectInputStream.readFields()
to retrieve the serialized array elements in elementData
.
The problem with OIS.GetField(name, object)
has only been reported as a problem affecting Vector
though it may be affecting other implementations using OIS.readFields()
. The implementation of OIS.GetField.get(name, object)
returns null when it should throw CNFE
. See JDK-8273660.
Vector checks the elementData
and throws StreamCorruptedException
if it is null.
The null can be due to more than one condition, including the field is null, the field is not present in the stream, and the field is null because one of the array elements could not be deserialized due to a missing class.
The first two cases reflect a corrupted stream but the third should result in a ClassNotFoundException
being thrown from OIS.readObject()
.
During deserialization the graph encoded in the stream is reconstructed. If the class of an object is not found, the CNFE is recorded but is not thrown, and deserialization continues. Other instances that depend upon this object are also marked with the exception, all the way up to the root of the object graph. If the root object is marked with a CNFE, the top level OIS.readObject()
call will throw CNFE. Thus, CNFE will be thrown from the top level call if the root object depends transitively on any object for which CNFE was encountered.
If an object's readObject
method throws CNFE, it is handled by deserialization via the dependency mechanism described above. Note that another thrown CNFE does not replace a previously recorded CNFE. However, any other exception type will terminate deserialization and will propagate to the caller. This causes any recorded CNFE to be discarded. The issue in the case of Vector is that it converts the null for elementData
into a StreamCorruptedException
which preempts the normal tracking of the CNFE
to the root of the object graph. The discarding of the CNFE makes it difficult to diagnose the root cause of the deserialization failure.
Solution
In the case of null
elementData
the original ClassNotFoundException
should be preserved. Since CNFE is handled by deserialization, Vector can throw CNFE instead of StreamCorruptedException
in the cases where the latter might discard the original CNFE. The CNFE that is thrown should identify the cause as a null elementData
in the case where it was caused by a missing class or if the field is present and null. For the case where the elementData
field is missing from the stream, StreamCorruptedException
should still be thrown.
Specification
The behavior of Vector
is modified so that if the class of an Element is not found, a ClassNotFoundException
is thrown from the top level OIS.readObject
reflecting the missing class. If the elementData
array in the stream is null
, a ClassNotFoundException
will be thrown with a message indicating that elementData
is null. There are no normal uses of Vector in which this will occur.
There is no specification change for Vector
. Instead of the previous behavior in which a StreamCorruptedException
is erroneously thrown for a missing class, ClassNotFoundException
will be thrown.
- csr of
-
JDK-8277093 Vector should throw ClassNotFoundException for a missing class of an element
- Resolved
-
JDK-8284346 Vector should throw ClassNotFoundException for a missing class of an element
- Resolved