You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@harmony.apache.org by nisen <ni...@gmail.com> on 2010/03/05 08:08:01 UTC

Re: Harmony-6439: Bug in Serialization found while running Berkeley DB Java Edition on Android

Oh。it's so great。From this mail I notice an effective ask, a good
answer 。In the different companies to different people collaborate
with each other to promote technology development
I was a newer,  I see the power of the community, it's great.

Charles may be come from oracle,
Jimmy come from IBM  in China,
I come from China .

Everyone can  get benefits:
Charles of the issue is resolved
Jimmy received a feedback
I learned more about how to participate in community.


2010/2/8 Jimmy,Jing Lv <fi...@gmail.com>:
> Hi Charles,
>
>     Sorry for late reply.
>     Thanks a lot for reporting this bug for Harmony and the testcase is
> perfect. I've been reading the code, found 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.
> I've got a quick fix, it works well on your testcase. I am running the full
> testcases on it. Will commit soon if everything appears good.
>     Please review and tell if you have more questions.
>
> 2010/2/5 Charles Lamb <ch...@gmail.com>
>
>> Hello,
>>
>> I have submitted Jira HARMONY-6439 for this issue.  Credit to my
>> colleagues Mark Hayes and Haomian Wang for narrowing this down.
>>
>> 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 Java Edition, 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;
>>        }
>>    }
>> }
>>
>>
>>
>>
>
>
> --
>
> Best Regards!
>
> Jimmy, Jing Lv
> China Software Development Lab, IBM
>