Anjo is right, I was wrong. I thought, System.identityHashCode() would be safe, at least when the objects are in 32 bit address space and are not garbage collected during the process, but a simple test turned out that this is wrong, probably due to the JVM memory management shuffeling around the objects in memory. Using System.identityHashCode(object) lowers the probability of the problem, but it doesn't solve it.

One solution I could think to which should work would be to use an IdentityHasMap inside of WOXMLCoder to keep track ofthe objects.

Timo


Am 04.07.2008 um 05:39 schrieb Anjo Krank:

Neither is OK. object.hashCode is not unique (can be a constant if overridden) and System.identityHashCode is not unique either.

Cheers, Anjo

Am 03.07.2008 um 22:35 schrieb Timo Hoepfner:

FYI: I just filed this as rdar://6053207


Summary:
========

WOXMLCoder uses objectIDRef for mutable objects. IMHO it should only use objectIDRefs, when it encounters an object with the same System.identityHashCode(object) as a previously serialized object. Currently it seems to rely on object.hashCode(), which is OK for immutable objects, but not for mutable objects.



Steps to Reproduce:
===================

NSMutableArray a = new NSMutableArray();
NSMutableArray b = new NSMutableArray();

System.out.println("a: "+a);
System.out.println("b: "+b);
System.out.println("a==b? " + (a == b));
System.out.println("----------------------");

NSArray wrapper = new NSArray(new Object[] { a, b });
WOXMLCoder coder = WOXMLCoder.coder();
String s = coder.encodeRootObjectForKey(wrapper, "wrapper");

System.out.print(s);
System.out.println("----------------------");

WOXMLDecoder decoder = WOXMLDecoder.decoder();
NSArray deserializedWrapper = (NSArray) decoder.decodeRootObject (new NSData(s.getBytes()));

NSMutableArray deserializedA = (NSMutableArray) deserializedWrapper.objectAtIndex(0); NSMutableArray deserializedB = (NSMutableArray) deserializedWrapper.objectAtIndex(1);

System.out.println("deserializedA: " + deserializedA);
System.out.println("deserializedB: " + deserializedB);
System.out.println("deserializedA==deserializedB? " + (deserializedA == deserializedB));
System.out.println("----------------------");

System.out.println("Adding 'foo' to 'a'");
deserializedA.addObject("foo");
System.out.println("Adding 'bar' to 'b'");
deserializedB.addObject("bar");
System.out.println("----------------------");

System.out.println("deserializedA: " + deserializedA);
System.out.println("deserializedB: " + deserializedB);



Actual Results:
===============

a: ()
b: ()
a==b? false
----------------------
<wrapper type="com.webobjects.foundation.NSArray" objectID="1">
<element type="com.webobjects.foundation.NSMutableArray" objectID="2">
        </element>
<element type="com.webobjects.foundation.NSMutableArray" objectIDRef="2"></element>
</wrapper>
----------------------
deserializedA: ()
deserializedB: ()
deserializedA==deserializedB? true
----------------------
Adding 'foo' to 'a'
Adding 'bar' to 'b'
----------------------
deserializedA: ("foo", "bar")
deserializedB: ("foo", "bar")



Expected Results:
=================

deserializedA==deserializedB? false



Workarounds:
============

This subclass of WOXMLCoder hacks around the problem:

public class PDXMLCoder extends WOXMLCoder {
        @SuppressWarnings("unchecked")
        @Override
        public void encodeObjectForKey(Object object, String s) {
                if (object instanceof NSMutableArray) {
                        object = new _MutableArray((NSMutableArray) object);
                }
                else if (object instanceof NSMutableDictionary) {
                        object = new _MutableDictionary((NSMutableDictionary) 
object);
                }
                else if (object instanceof NSMutableData) {
                        object = new _MutableData((NSMutableData) object);
                }
                super.encodeObjectForKey(object, s);
        }

        public PDXMLCoder() {
                super();
        }

        public static WOXMLCoder coder() {
                return new PDXMLCoder();
        }

        @SuppressWarnings("unchecked")
        public static class _MutableArray extends NSMutableArray {
                public _MutableArray() {
                        super();
                }

                public _MutableArray(NSArray array) {
                        super(array);
                }

                @Override
                public Class classForCoder() {
                        return NSMutableArray.class;
                }

                @Override
                public int hashCode() {
                        return System.identityHashCode(this);
                }
        }

        @SuppressWarnings("unchecked")
        public static class _MutableDictionary extends NSMutableDictionary {
                public _MutableDictionary() {
                        super();
                }

                public _MutableDictionary(NSDictionary dict) {
                        super(dict);
                }

                @Override
                public Class classForCoder() {
                        return NSMutableDictionary.class;
                }

                @Override
                public int hashCode() {
                        return System.identityHashCode(this);
                }
        }

        @SuppressWarnings("unchecked")
        public static class _MutableData extends NSMutableData {
                public _MutableData() {
                        super();
                }

                public _MutableData(NSMutableData data) {
                        super(data);
                }

                @Override
                public Class classForCoder() {
                        return NSMutableData.class;
                }

                @Override
                public int hashCode() {
                        return System.identityHashCode(this);
                }
        }
}

If you already have screwed serialized data, using this subclass of WOXMLDecoder for deserializing can help in some situations:

public class PDXMLDecoder extends WOXMLDecoder {
        @SuppressWarnings("unchecked")
        @Override
        public Object decodeObjectForKey(String s) {
                Object object = super.decodeObjectForKey(s);
                if (object instanceof NSMutableArray) {
                        NSMutableArray a = (NSMutableArray) object;
                        object = a.mutableClone();
                }
                else if (object instanceof NSMutableDictionary) {
                        NSMutableDictionary d = (NSMutableDictionary) object;
                        object = d.mutableClone();
                }
                else if (object instanceof NSMutableData) {
                        NSMutableData d = (NSMutableData) object;
                        object = d.clone();
                }
                return object;
        }

        public PDXMLDecoder() {
                super();
        }
        
        public static WOXMLDecoder decoder(){
                return new PDXMLDecoder();
        }
}

_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list      (Webobjects-dev@lists.apple.com)
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/webobjects-dev/krank% 40logicunited.com

This email sent to [EMAIL PROTECTED]


_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list      (Webobjects-dev@lists.apple.com)
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]

Reply via email to