• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: WOXMLCoder uses objectIDRef for mutable objects
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: WOXMLCoder uses objectIDRef for mutable objects


  • Subject: Re: WOXMLCoder uses objectIDRef for mutable objects
  • From: Timo Hoepfner <email@hidden>
  • Date: Fri, 4 Jul 2008 13:11:35 +0200

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 (email@hidden)
Help/Unsubscribe/Update your Subscription:
40logicunited.com


This email sent to email@hidden


_______________________________________________ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list (email@hidden) Help/Unsubscribe/Update your Subscription: This email sent to email@hidden
  • Follow-Ups:
    • Re: WOXMLCoder uses objectIDRef for mutable objects
      • From: Mike Schrag <email@hidden>
References: 
 >WOXMLCoder uses objectIDRef for mutable objects (From: Timo Hoepfner <email@hidden>)
 >Re: WOXMLCoder uses objectIDRef for mutable objects (From: Anjo Krank <email@hidden>)

  • Prev by Date: empty relationship qualifier question
  • Next by Date: Re: ERXLocalizer getting rid of the binding errors?
  • Previous by thread: Re: WOXMLCoder uses objectIDRef for mutable objects
  • Next by thread: Re: WOXMLCoder uses objectIDRef for mutable objects
  • Index(es):
    • Date
    • Thread