Skip to content
This repository was archived by the owner on Jun 26, 2021. It is now read-only.
This repository was archived by the owner on Jun 26, 2021. It is now read-only.

EMapDeserializer creates ArrayList instead of EList when map value is a list #115

@krissrex

Description

@krissrex

Description: I am trying to deserialize an EMap with BasicEMap.Entry<String,EList<String>> as its contents.
Example of this structure:

{ 
  "myMap": { 
    "someKey": ["a", "b", "c"],
    "key2": ["a", "b"] 
  }
}

It uses this construct from Ecore:

public class StringToStringsMapImpl extends MinimalEObjectImpl.Container implements BasicEMap.Entry<String,EList<String>> {

  // ...

    @Override
    public EList<String> setValue(EList<String> value) {
        EList<String> oldValue = getValue();
        getTypedValue().clear();
        getTypedValue().addAll(value);
        return oldValue;
    }

I have a valid json that I created with this library. I then try to deserialize it back into this EMap.

Expected: The values in the map entries would be EList instances.

Actual: ClassCast exceptions.
The org.emfjson.jackson.databind.deser.EMapDeserializer sees a token that is not START_OBJECT (but rather START_ARRAY) and performs a readValue with Object.class. Jackson does its lookups and concludes a com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer should be used, and this creates an ArrayList at line 840.
The org.eclipse.emf.ecore.util.EcoreEMap runs a setValue on line 270 with the ArrayList value, and this triggers a ClassCastException because this list should have been an EList.

Stacktrace:

Exception in thread "main" java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class org.eclipse.emf.common.util.EList (java.util.ArrayList is in module java.base of loader 'bootstrap'; org.eclipse.emf.common.util.EList is in unnamed module of loader 'app')
	at no.ntnu.stud.treedocumentmodel.impl.NodeTypeToNodeTypesMapImpl.setValue(NodeTypeToNodeTypesMapImpl.java:1)
	at org.eclipse.emf.ecore.util.EcoreEMap.newEntry(EcoreEMap.java:270)
	at org.eclipse.emf.common.util.BasicEMap.put(BasicEMap.java:584)
	at org.emfjson.jackson.databind.deser.EMapDeserializer.deserialize(EMapDeserializer.java:66)
	at org.emfjson.jackson.databind.deser.EMapDeserializer.deserialize(EMapDeserializer.java:30)
	at org.emfjson.jackson.databind.property.EObjectFeatureProperty.deserializeAndSet(EObjectFeatureProperty.java:64)
	at org.emfjson.jackson.databind.deser.EObjectDeserializer.deserialize(EObjectDeserializer.java:78)
	at org.emfjson.jackson.databind.deser.EObjectDeserializer.deserialize(EObjectDeserializer.java:38)
	at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1608)
	at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1292)

Assumed fixes:

  1. Perhaps do a check for START_ARRAY in EMapDeserializer#57 and treat this differently?
  2. Register EList as a deserialization class for json array
  3. Check in EMapDeserializer if the value is ArrayList and convert it to EList. I think this is a bad solution; more of a band-aid fix for this particular case

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions