Issue Details (XML | Word | Printable)

Key: GDS-588
Type: Bug Bug
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: William Draï
Reporter: Doug Keen
Votes: 0
Watchers: 2
Operations

If you were logged in you would be able to see more operations.
GraniteDS

Extraneous instances of Enums created when maps with Enum-typed keys are deserialized from AMF

Created: 15/Dec/09 03:07 AM   Updated: 16/Jun/10 05:12 PM   Resolved: 02/Apr/10 11:22 AM
Component/s: AMF3 (de)serialization
Affects Version/s: 2.1.0_RC1
Fix Version/s: 2.2.0_beta1

Environment: Flex 3.4, GraniteDS 2.1.0_RC1, JBoss 5.1.0.GA
Issue Links:
Duplicate
 


 Description  « Hide
When deserializing an object with a Map property that has an Enum type as a key, the Enum constants are not used. Rather, a new Enum instance (outside of the set of constants) is created. This makes the resulting dictionaries fields in the created BasicMap instance essentially useless... strict equality checks against those Enum keys always fail!

E.g.:

Our Java bean:
public class MyBean {
    public Map<MyEnum, String> myMap;

    ...
}

Our Flex bean:
public class MyBeanBase implements IExternalizable {
    private var _myMap:IMap;

    public get myMap():IMap {
        return _myMap;
    }

    public set myMap(value:IMap):void {
       _myMap = value;
    }

    ...

    public function readExternal(input:IDataInput):void {
        __initialized = input.readObject() as Boolean;
        __detachedState = input.readObject() as String;
        if (meta::isInitialized()) {
            ...
            _myMap = input.readObject() as IMap; // <- This does not deserialize the Enum keys properly (creates a new instances... does not use static constants)
            ...
        }
        else {
            ...
        }
    }
}

Some Flex client code:
var bean:MyBean = beanGeneratedFromRemoteObjectResult;
bean.myMap.containsKey(MyEnum.Red); // <- This is always false, since the enum key object is a different instance from the MyEnum.Red const instance

Doug Keen added a comment - 15/Dec/09 03:16 AM
See org.granite.collections.BasicMap.readExternal()

        public function readExternal(input:IDataInput):void {
            var elements:Array = input.readObject() as Array; // <- New Enum instances are created here... constants aren't used
            for each (var pair:Array in elements) {
                _keySet.addItem(pair[0]);
                _values.addItem(pair[1]);
                _entrySet[pair[0]] = pair;
            }
        }

William Draï added a comment - 29/Dec/09 11:50 AM
It's probably the same with ArrayCollections or Arrays of enums.
The only way to fix this is to rewrite the collection content after readExternal.
In the trunk, this can be done by using Tide.getContext().meta_mergeExternalData(collection/map).

Franck Wolff added a comment - 09/Feb/10 02:40 PM
The best solution would be to plug specific IDataInput implementation that overrides the readObject method and (when necessary) transforms the result before returning it. I don't know how to achieve that and if it is even possible...

Andreas Bergander added a comment - 15/Feb/10 09:57 PM
This issue also causes the mergeMap function in the tide EntityManager to fail when the key is a enum.

Line 985 in tide EntityManager (2.1.0.RC2) where the keys are compared:

if (_mergeUpdate) {
for each (key in prevMap.keySet) {
var found:Boolean = false;
for each (var k:Object in map.keySet) {
if (objectEquals(k, key)) {
found = true;
break;
}
}
if (!found)
prevMap.remove(key);
}
}
                    
                    
Perhaps this could be fixed by changing objectEquals to include something like this:

if (obj1 is Enum && obj2 is Enum && obj1 != null && obj1.equals(obj2))
return true;

Should a new Jira issue be created for this?

William Draï added a comment - 15/Feb/10 11:25 PM
This issue GDS-588 is fixed when using Tide and the test TestMergeMap2 does work.
Your suggestion looks fine, but do you have any example or test of a non working merge of map with enum keys using the latest trunk ?

William Draï added a comment - 15/Feb/10 11:33 PM
Forget it, you're right, my unit test was bad.

Franck Wolff added a comment - 02/Apr/10 11:22 AM
The fix should solve the issue for GDS collections (BasicMap, UIDSet, UIDList, Persistent*). There is no possible solutions for simple ArrayCollections that contain Enum instances (except by check their content by hand).