You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by "Charles Lamb (JIRA)" <ji...@apache.org> on 2010/02/05 13:37:27 UTC

[jira] Created: (HARMONY-6439) NullPointerException thrown in certain Serialization cases

NullPointerException thrown in certain Serialization cases
----------------------------------------------------------

                 Key: HARMONY-6439
                 URL: https://issues.apache.org/jira/browse/HARMONY-6439
             Project: Harmony
          Issue Type: Bug
          Components: Classlib
    Affects Versions: 5.0M12
         Environment: Windows
            Reporter: Charles Lamb
            Priority: Minor


Harmony object serialization has an initialization bug that causes NullPointerException when overriding the ObjectInputStream.readClassDescriptor and ObjectOutputStream.writeClassDescriptor methods, in order to store the ObjectStreamClass elsewhere.  In Berkeley DB, overriding these methods is necessary to store the ObjectStreamClass in a separate database, to avoid repeating it redundantly in every database record.  This type of overriding is supported by the Java specification, and the problem does not occur in other Java class libraries (specifically, the bug does not occur on the Sun, IBM and BEA Java platforms).

The attached test demonstrates the problem by simply serializing and deserializing an object to/from a byte array, when readClassDescriptor and writeClassDescriptor are overridden.  A NullPointerException occurs because of an uninitialized field during the call to readObject.

C:\temp>java -classpath . ClassDescriptorOverrideBug
java.lang.NullPointerException
        at java.io.ObjectStreamField.resolve(ObjectStreamField.java:336)
        at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1838)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:799)
        at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:2039)
        at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:902)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2251)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2208)
        at ClassDescriptorOverrideBug.doTest(ClassDescriptorOverrideBug.java:49)
        at ClassDescriptorOverrideBug.main(ClassDescriptorOverrideBug.java:29)

Note that this problem only occurs when primitive fields are declared in the serializable class.

A workaround for this bug is to serialize and deserialize the ObjectStreamClass before it is used.  Apparently deserialization causes initialization to occur correctly.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * Demonstrates a Harmony bug in Java serialization, where overriding the
 * ObjectInputStream.readClassDescriptor and
 * ObjectOutputStream.writeClassDescriptor methods, in order to store the
 * ObjectStreamClass elsewhere, causes a NullPointerException.
 */
public class ClassDescriptorOverrideBug {

    private final Map<Integer, ObjectStreamClass> idToDescMap =
        new HashMap<Integer, ObjectStreamClass>();
    private final Map<String, Integer> nameToIdMap =
        new HashMap<String, Integer>();
    private int nextId = 1;

    public static void main(String argv[]) {
        try {
            new ClassDescriptorOverrideBug().doTest();
            System.out.println("SUCCESS");
            System.exit(0);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    /* Write/serialize and read/de-serialize an object. */
    void doTest()
        throws IOException, ClassNotFoundException {

        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        final MyObjectOutputStream oos = new MyObjectOutputStream(baos);
        oos.writeObject(new Data());
        final byte[] bytes = baos.toByteArray();
        final ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        final MyObjectInputStream ois = new MyObjectInputStream(bais);
        /* NullPointerException is thrown by the readObject call below. */
        ois.readObject();
    }
    
    /* Primitive fields are necessary to cause the NullPointerException. */
    static class Data implements Serializable {
        String field1 = "field1";
        String field2 = "field2";
        int field3 = 333;
        int field4 = 444;
        String field5 = "field5";
    }

    /* Overrides writeClassDescriptor to store ObjectStreamClass in map. */
    class MyObjectOutputStream extends ObjectOutputStream {

        MyObjectOutputStream(OutputStream out)
            throws IOException {

            super(out);
        }

        @Override
        protected void writeClassDescriptor(ObjectStreamClass desc)
            throws IOException {

            final String className = desc.getName();
            final int id;
            if (nameToIdMap.containsKey(className)) {
                /* Known class: get ID from map. */
                id = nameToIdMap.get(className);
            } else {
                /* New class: assign ID and store in maps. */
                id = nextId;
                nextId += 1;
                idToDescMap.put(id, desc);
                nameToIdMap.put(className, id);
            }
            /* Write ID of ObjectStreamClass. */
            writeInt(id);
        }
    }

    /* Overrides readClassDescriptor to get ObjectStreamClass from map. */
    class MyObjectInputStream extends ObjectInputStream {

        MyObjectInputStream(InputStream in)
            throws IOException {

            super(in);
        }

        @Override
        protected ObjectStreamClass readClassDescriptor()
            throws IOException, ClassNotFoundException {

            /* Read the ID and get the ObjectStreamClass from a map. */
            final int id = readInt();
            final ObjectStreamClass desc = idToDescMap.get(id);
            if (desc == null) {
                throw new ClassNotFoundException("id not found: " + id);
            }
            return desc;
        }
    }
} 


-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (HARMONY-6439) NullPointerException thrown in certain Serialization cases

Posted by "Jimmy, Jing Lv (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/HARMONY-6439?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12830937#action_12830937 ] 

Jimmy, Jing Lv commented on HARMONY-6439:
-----------------------------------------

it is mainly caused by the Harmony ObjectStreamField does not resolve the primitive fields which are declared in the serializable correctly and miss-initialize the string type.
A quick fix here is add 3 lines in the ObjectStreamField.resolve(ClassLoader loader):

     void resolve(ClassLoader loader) {
+        if (typeString == null && isPrimitive()){
+            // primitive type declared in a serializable class
+            typeString = String.valueOf(getTypeCode());
+        }
         if (typeString.length() == 1) {
             switch (typeString.charAt(0)) {
                 case 'I':


> NullPointerException thrown in certain Serialization cases
> ----------------------------------------------------------
>
>                 Key: HARMONY-6439
>                 URL: https://issues.apache.org/jira/browse/HARMONY-6439
>             Project: Harmony
>          Issue Type: Bug
>          Components: Classlib
>    Affects Versions: 5.0M12
>         Environment: Windows
>            Reporter: Charles Lamb
>            Assignee: Jimmy, Jing Lv
>            Priority: Minor
>         Attachments: ClassDescriptorOverrideBug.java
>
>
> Harmony object serialization has an initialization bug that causes NullPointerException when overriding the ObjectInputStream.readClassDescriptor and ObjectOutputStream.writeClassDescriptor methods, in order to store the ObjectStreamClass elsewhere.  In Berkeley DB, overriding these methods is necessary to store the ObjectStreamClass in a separate database, to avoid repeating it redundantly in every database record.  This type of overriding is supported by the Java specification, and the problem does not occur in other Java class libraries (specifically, the bug does not occur on the Sun, IBM and BEA Java platforms).
> The attached test demonstrates the problem by simply serializing and deserializing an object to/from a byte array, when readClassDescriptor and writeClassDescriptor are overridden.  A NullPointerException occurs because of an uninitialized field during the call to readObject.
> C:\temp>java -classpath . ClassDescriptorOverrideBug
> java.lang.NullPointerException
>         at java.io.ObjectStreamField.resolve(ObjectStreamField.java:336)
>         at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1838)
>         at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:799)
>         at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:2039)
>         at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:902)
>         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2251)
>         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2208)
>         at ClassDescriptorOverrideBug.doTest(ClassDescriptorOverrideBug.java:49)
>         at ClassDescriptorOverrideBug.main(ClassDescriptorOverrideBug.java:29)
> Note that this problem only occurs when primitive fields are declared in the serializable class.
> A workaround for this bug is to serialize and deserialize the ObjectStreamClass before it is used.  Apparently deserialization causes initialization to occur correctly.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (HARMONY-6439) NullPointerException thrown in certain Serialization cases

Posted by "Hudson (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/HARMONY-6439?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12830954#action_12830954 ] 

Hudson commented on HARMONY-6439:
---------------------------------

Integrated in Harmony-1.5-head-linux-x86_64 #612 (See [http://hudson.zones.apache.org/hudson/job/Harmony-1.5-head-linux-x86_64/612/])
    Apply patch for  [classlib][luni] NullPointerException thrown in certain Serialization cases, refine the testcase
Apply patch for  [classlib][luni] NullPointerException thrown in certain Serialization cases
Apply patch for  [classlib][luni] NullPointerException thrown in certain Serialization cases


> NullPointerException thrown in certain Serialization cases
> ----------------------------------------------------------
>
>                 Key: HARMONY-6439
>                 URL: https://issues.apache.org/jira/browse/HARMONY-6439
>             Project: Harmony
>          Issue Type: Bug
>          Components: Classlib
>    Affects Versions: 5.0M12
>         Environment: Windows
>            Reporter: Charles Lamb
>            Assignee: Jimmy, Jing Lv
>            Priority: Minor
>             Fix For: 5.0M12
>
>         Attachments: ClassDescriptorOverrideBug.java
>
>
> Harmony object serialization has an initialization bug that causes NullPointerException when overriding the ObjectInputStream.readClassDescriptor and ObjectOutputStream.writeClassDescriptor methods, in order to store the ObjectStreamClass elsewhere.  In Berkeley DB, overriding these methods is necessary to store the ObjectStreamClass in a separate database, to avoid repeating it redundantly in every database record.  This type of overriding is supported by the Java specification, and the problem does not occur in other Java class libraries (specifically, the bug does not occur on the Sun, IBM and BEA Java platforms).
> The attached test demonstrates the problem by simply serializing and deserializing an object to/from a byte array, when readClassDescriptor and writeClassDescriptor are overridden.  A NullPointerException occurs because of an uninitialized field during the call to readObject.
> C:\temp>java -classpath . ClassDescriptorOverrideBug
> java.lang.NullPointerException
>         at java.io.ObjectStreamField.resolve(ObjectStreamField.java:336)
>         at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1838)
>         at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:799)
>         at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:2039)
>         at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:902)
>         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2251)
>         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2208)
>         at ClassDescriptorOverrideBug.doTest(ClassDescriptorOverrideBug.java:49)
>         at ClassDescriptorOverrideBug.main(ClassDescriptorOverrideBug.java:29)
> Note that this problem only occurs when primitive fields are declared in the serializable class.
> A workaround for this bug is to serialize and deserialize the ObjectStreamClass before it is used.  Apparently deserialization causes initialization to occur correctly.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Assigned: (HARMONY-6439) NullPointerException thrown in certain Serialization cases

Posted by "Jimmy, Jing Lv (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/jira/browse/HARMONY-6439?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Jimmy, Jing Lv reassigned HARMONY-6439:
---------------------------------------

    Assignee: Jimmy, Jing Lv

> NullPointerException thrown in certain Serialization cases
> ----------------------------------------------------------
>
>                 Key: HARMONY-6439
>                 URL: https://issues.apache.org/jira/browse/HARMONY-6439
>             Project: Harmony
>          Issue Type: Bug
>          Components: Classlib
>    Affects Versions: 5.0M12
>         Environment: Windows
>            Reporter: Charles Lamb
>            Assignee: Jimmy, Jing Lv
>            Priority: Minor
>         Attachments: ClassDescriptorOverrideBug.java
>
>
> Harmony object serialization has an initialization bug that causes NullPointerException when overriding the ObjectInputStream.readClassDescriptor and ObjectOutputStream.writeClassDescriptor methods, in order to store the ObjectStreamClass elsewhere.  In Berkeley DB, overriding these methods is necessary to store the ObjectStreamClass in a separate database, to avoid repeating it redundantly in every database record.  This type of overriding is supported by the Java specification, and the problem does not occur in other Java class libraries (specifically, the bug does not occur on the Sun, IBM and BEA Java platforms).
> The attached test demonstrates the problem by simply serializing and deserializing an object to/from a byte array, when readClassDescriptor and writeClassDescriptor are overridden.  A NullPointerException occurs because of an uninitialized field during the call to readObject.
> C:\temp>java -classpath . ClassDescriptorOverrideBug
> java.lang.NullPointerException
>         at java.io.ObjectStreamField.resolve(ObjectStreamField.java:336)
>         at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1838)
>         at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:799)
>         at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:2039)
>         at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:902)
>         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2251)
>         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2208)
>         at ClassDescriptorOverrideBug.doTest(ClassDescriptorOverrideBug.java:49)
>         at ClassDescriptorOverrideBug.main(ClassDescriptorOverrideBug.java:29)
> Note that this problem only occurs when primitive fields are declared in the serializable class.
> A workaround for this bug is to serialize and deserialize the ObjectStreamClass before it is used.  Apparently deserialization causes initialization to occur correctly.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Updated: (HARMONY-6439) NullPointerException thrown in certain Serialization cases

Posted by "Charles Lamb (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/jira/browse/HARMONY-6439?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Charles Lamb updated HARMONY-6439:
----------------------------------

    Attachment: ClassDescriptorOverrideBug.java

> NullPointerException thrown in certain Serialization cases
> ----------------------------------------------------------
>
>                 Key: HARMONY-6439
>                 URL: https://issues.apache.org/jira/browse/HARMONY-6439
>             Project: Harmony
>          Issue Type: Bug
>          Components: Classlib
>    Affects Versions: 5.0M12
>         Environment: Windows
>            Reporter: Charles Lamb
>            Priority: Minor
>         Attachments: ClassDescriptorOverrideBug.java
>
>
> Harmony object serialization has an initialization bug that causes NullPointerException when overriding the ObjectInputStream.readClassDescriptor and ObjectOutputStream.writeClassDescriptor methods, in order to store the ObjectStreamClass elsewhere.  In Berkeley DB, overriding these methods is necessary to store the ObjectStreamClass in a separate database, to avoid repeating it redundantly in every database record.  This type of overriding is supported by the Java specification, and the problem does not occur in other Java class libraries (specifically, the bug does not occur on the Sun, IBM and BEA Java platforms).
> The attached test demonstrates the problem by simply serializing and deserializing an object to/from a byte array, when readClassDescriptor and writeClassDescriptor are overridden.  A NullPointerException occurs because of an uninitialized field during the call to readObject.
> C:\temp>java -classpath . ClassDescriptorOverrideBug
> java.lang.NullPointerException
>         at java.io.ObjectStreamField.resolve(ObjectStreamField.java:336)
>         at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1838)
>         at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:799)
>         at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:2039)
>         at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:902)
>         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2251)
>         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2208)
>         at ClassDescriptorOverrideBug.doTest(ClassDescriptorOverrideBug.java:49)
>         at ClassDescriptorOverrideBug.main(ClassDescriptorOverrideBug.java:29)
> Note that this problem only occurs when primitive fields are declared in the serializable class.
> A workaround for this bug is to serialize and deserialize the ObjectStreamClass before it is used.  Apparently deserialization causes initialization to occur correctly.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Resolved: (HARMONY-6439) NullPointerException thrown in certain Serialization cases

Posted by "Jimmy, Jing Lv (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/jira/browse/HARMONY-6439?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Jimmy, Jing Lv resolved HARMONY-6439.
-------------------------------------

       Resolution: Fixed
    Fix Version/s: 5.0M12

Code committed at 907657,  testcase at 907658, please verify.

> NullPointerException thrown in certain Serialization cases
> ----------------------------------------------------------
>
>                 Key: HARMONY-6439
>                 URL: https://issues.apache.org/jira/browse/HARMONY-6439
>             Project: Harmony
>          Issue Type: Bug
>          Components: Classlib
>    Affects Versions: 5.0M12
>         Environment: Windows
>            Reporter: Charles Lamb
>            Assignee: Jimmy, Jing Lv
>            Priority: Minor
>             Fix For: 5.0M12
>
>         Attachments: ClassDescriptorOverrideBug.java
>
>
> Harmony object serialization has an initialization bug that causes NullPointerException when overriding the ObjectInputStream.readClassDescriptor and ObjectOutputStream.writeClassDescriptor methods, in order to store the ObjectStreamClass elsewhere.  In Berkeley DB, overriding these methods is necessary to store the ObjectStreamClass in a separate database, to avoid repeating it redundantly in every database record.  This type of overriding is supported by the Java specification, and the problem does not occur in other Java class libraries (specifically, the bug does not occur on the Sun, IBM and BEA Java platforms).
> The attached test demonstrates the problem by simply serializing and deserializing an object to/from a byte array, when readClassDescriptor and writeClassDescriptor are overridden.  A NullPointerException occurs because of an uninitialized field during the call to readObject.
> C:\temp>java -classpath . ClassDescriptorOverrideBug
> java.lang.NullPointerException
>         at java.io.ObjectStreamField.resolve(ObjectStreamField.java:336)
>         at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1838)
>         at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:799)
>         at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:2039)
>         at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:902)
>         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2251)
>         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2208)
>         at ClassDescriptorOverrideBug.doTest(ClassDescriptorOverrideBug.java:49)
>         at ClassDescriptorOverrideBug.main(ClassDescriptorOverrideBug.java:29)
> Note that this problem only occurs when primitive fields are declared in the serializable class.
> A workaround for this bug is to serialize and deserialize the ObjectStreamClass before it is used.  Apparently deserialization causes initialization to occur correctly.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Updated: (HARMONY-6439) NullPointerException thrown in certain Serialization cases

Posted by "Charles Lamb (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/jira/browse/HARMONY-6439?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Charles Lamb updated HARMONY-6439:
----------------------------------

    Description: 
Harmony object serialization has an initialization bug that causes NullPointerException when overriding the ObjectInputStream.readClassDescriptor and ObjectOutputStream.writeClassDescriptor methods, in order to store the ObjectStreamClass elsewhere.  In Berkeley DB, overriding these methods is necessary to store the ObjectStreamClass in a separate database, to avoid repeating it redundantly in every database record.  This type of overriding is supported by the Java specification, and the problem does not occur in other Java class libraries (specifically, the bug does not occur on the Sun, IBM and BEA Java platforms).

The attached test demonstrates the problem by simply serializing and deserializing an object to/from a byte array, when readClassDescriptor and writeClassDescriptor are overridden.  A NullPointerException occurs because of an uninitialized field during the call to readObject.

C:\temp>java -classpath . ClassDescriptorOverrideBug
java.lang.NullPointerException
        at java.io.ObjectStreamField.resolve(ObjectStreamField.java:336)
        at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1838)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:799)
        at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:2039)
        at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:902)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2251)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2208)
        at ClassDescriptorOverrideBug.doTest(ClassDescriptorOverrideBug.java:49)
        at ClassDescriptorOverrideBug.main(ClassDescriptorOverrideBug.java:29)

Note that this problem only occurs when primitive fields are declared in the serializable class.

A workaround for this bug is to serialize and deserialize the ObjectStreamClass before it is used.  Apparently deserialization causes initialization to occur correctly.



  was:
Harmony object serialization has an initialization bug that causes NullPointerException when overriding the ObjectInputStream.readClassDescriptor and ObjectOutputStream.writeClassDescriptor methods, in order to store the ObjectStreamClass elsewhere.  In Berkeley DB, overriding these methods is necessary to store the ObjectStreamClass in a separate database, to avoid repeating it redundantly in every database record.  This type of overriding is supported by the Java specification, and the problem does not occur in other Java class libraries (specifically, the bug does not occur on the Sun, IBM and BEA Java platforms).

The attached test demonstrates the problem by simply serializing and deserializing an object to/from a byte array, when readClassDescriptor and writeClassDescriptor are overridden.  A NullPointerException occurs because of an uninitialized field during the call to readObject.

C:\temp>java -classpath . ClassDescriptorOverrideBug
java.lang.NullPointerException
        at java.io.ObjectStreamField.resolve(ObjectStreamField.java:336)
        at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1838)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:799)
        at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:2039)
        at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:902)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2251)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2208)
        at ClassDescriptorOverrideBug.doTest(ClassDescriptorOverrideBug.java:49)
        at ClassDescriptorOverrideBug.main(ClassDescriptorOverrideBug.java:29)

Note that this problem only occurs when primitive fields are declared in the serializable class.

A workaround for this bug is to serialize and deserialize the ObjectStreamClass before it is used.  Apparently deserialization causes initialization to occur correctly.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * Demonstrates a Harmony bug in Java serialization, where overriding the
 * ObjectInputStream.readClassDescriptor and
 * ObjectOutputStream.writeClassDescriptor methods, in order to store the
 * ObjectStreamClass elsewhere, causes a NullPointerException.
 */
public class ClassDescriptorOverrideBug {

    private final Map<Integer, ObjectStreamClass> idToDescMap =
        new HashMap<Integer, ObjectStreamClass>();
    private final Map<String, Integer> nameToIdMap =
        new HashMap<String, Integer>();
    private int nextId = 1;

    public static void main(String argv[]) {
        try {
            new ClassDescriptorOverrideBug().doTest();
            System.out.println("SUCCESS");
            System.exit(0);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    /* Write/serialize and read/de-serialize an object. */
    void doTest()
        throws IOException, ClassNotFoundException {

        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
        final MyObjectOutputStream oos = new MyObjectOutputStream(baos);
        oos.writeObject(new Data());
        final byte[] bytes = baos.toByteArray();
        final ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        final MyObjectInputStream ois = new MyObjectInputStream(bais);
        /* NullPointerException is thrown by the readObject call below. */
        ois.readObject();
    }
    
    /* Primitive fields are necessary to cause the NullPointerException. */
    static class Data implements Serializable {
        String field1 = "field1";
        String field2 = "field2";
        int field3 = 333;
        int field4 = 444;
        String field5 = "field5";
    }

    /* Overrides writeClassDescriptor to store ObjectStreamClass in map. */
    class MyObjectOutputStream extends ObjectOutputStream {

        MyObjectOutputStream(OutputStream out)
            throws IOException {

            super(out);
        }

        @Override
        protected void writeClassDescriptor(ObjectStreamClass desc)
            throws IOException {

            final String className = desc.getName();
            final int id;
            if (nameToIdMap.containsKey(className)) {
                /* Known class: get ID from map. */
                id = nameToIdMap.get(className);
            } else {
                /* New class: assign ID and store in maps. */
                id = nextId;
                nextId += 1;
                idToDescMap.put(id, desc);
                nameToIdMap.put(className, id);
            }
            /* Write ID of ObjectStreamClass. */
            writeInt(id);
        }
    }

    /* Overrides readClassDescriptor to get ObjectStreamClass from map. */
    class MyObjectInputStream extends ObjectInputStream {

        MyObjectInputStream(InputStream in)
            throws IOException {

            super(in);
        }

        @Override
        protected ObjectStreamClass readClassDescriptor()
            throws IOException, ClassNotFoundException {

            /* Read the ID and get the ObjectStreamClass from a map. */
            final int id = readInt();
            final ObjectStreamClass desc = idToDescMap.get(id);
            if (desc == null) {
                throw new ClassNotFoundException("id not found: " + id);
            }
            return desc;
        }
    }
} 



> NullPointerException thrown in certain Serialization cases
> ----------------------------------------------------------
>
>                 Key: HARMONY-6439
>                 URL: https://issues.apache.org/jira/browse/HARMONY-6439
>             Project: Harmony
>          Issue Type: Bug
>          Components: Classlib
>    Affects Versions: 5.0M12
>         Environment: Windows
>            Reporter: Charles Lamb
>            Priority: Minor
>         Attachments: ClassDescriptorOverrideBug.java
>
>
> Harmony object serialization has an initialization bug that causes NullPointerException when overriding the ObjectInputStream.readClassDescriptor and ObjectOutputStream.writeClassDescriptor methods, in order to store the ObjectStreamClass elsewhere.  In Berkeley DB, overriding these methods is necessary to store the ObjectStreamClass in a separate database, to avoid repeating it redundantly in every database record.  This type of overriding is supported by the Java specification, and the problem does not occur in other Java class libraries (specifically, the bug does not occur on the Sun, IBM and BEA Java platforms).
> The attached test demonstrates the problem by simply serializing and deserializing an object to/from a byte array, when readClassDescriptor and writeClassDescriptor are overridden.  A NullPointerException occurs because of an uninitialized field during the call to readObject.
> C:\temp>java -classpath . ClassDescriptorOverrideBug
> java.lang.NullPointerException
>         at java.io.ObjectStreamField.resolve(ObjectStreamField.java:336)
>         at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1838)
>         at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:799)
>         at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:2039)
>         at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:902)
>         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2251)
>         at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2208)
>         at ClassDescriptorOverrideBug.doTest(ClassDescriptorOverrideBug.java:49)
>         at ClassDescriptorOverrideBug.main(ClassDescriptorOverrideBug.java:29)
> Note that this problem only occurs when primitive fields are declared in the serializable class.
> A workaround for this bug is to serialize and deserialize the ObjectStreamClass before it is used.  Apparently deserialization causes initialization to occur correctly.

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.