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
>