JDK-6541870 : NullPointerException in ObjectInputStream with Externalizables
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.io:serialization
  • Affected Version: 6
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-04-03
  • Updated: 2011-05-18
  • Resolved: 2011-05-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other Other JDK 6 JDK 7
1.4.2_19-revFixed 1.4.2_21Fixed 6u4Fixed 7 b17Fixed
Description
FULL PRODUCT VERSION :
java version "1.6.0"
Java(TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Windows XP

A DESCRIPTION OF THE PROBLEM :
ObjectInputStream throws a NullPointerException when deserializing an ArrayList of Externalizables if there is an IOException while deserializing one of these Externalizables.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the test case class.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
ois.readObject(); throws an IOException
ACTUAL -
ois.readObject(); throws a NullPointerException
java.lang.NullPointerException
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1820)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1719)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)
        at NPEProvoker.main(NPEProvoker.java:28)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

public class NPEProvoker implements java.io.Externalizable {

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        throw new IOException(); //io exception for whatever reason
    }

    public void writeExternal(ObjectOutput out) throws IOException {
    }
    
    public static void main(String[] args){
        try {
            ArrayList<NPEProvoker> list = new ArrayList<NPEProvoker>();
            list.add(new NPEProvoker());
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(list);

            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
            ois.readObject();
        } catch (IOException e) {
            //expected result
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NullPointerException e){
            //this happens
            e.printStackTrace();
        }
    }

}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
No workaround, but I guess the following could fix the problem:

Wrap the content of
private void ObjectInputStream.readExternalData(Externalizable obj, ObjectStreamClass desc)
with a try-catch block and execute
	curContext = oldContext;
in a finally block in order to restore the old context of the stream even though an exception happened.

Comments
SUGGESTED FIX A fix like the submitter suggested seems appropriate: in ObjectInputStream methods that have code like this (readExternalData and readSerialData): CallbackContext oldContext = curContext; curContext = ...; ... curContext = oldContext; should have the code transformed to something like this: CallbackContext oldContext = curContext; try { curContext = ...; ... } finally { curContext = oldContext; }
03-04-2007

EVALUATION This appears to be a regression introduced in 5.0u8 and 6.
03-04-2007