{"class":"MapDemo","data":{"key2":"value2","key1":"value1"}}
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Map
at flexjson.factories.BeanObjectFactory.instantiate(BeanObjectFactory.java:17)
at flexjson.ObjectBinder.bind(ObjectBinder.java:86)
at flexjson.ObjectBinder.bindIntoMap(ObjectBinder.java:117)
at flexjson.factories.MapObjectFactory.instantiate(MapObjectFactory.java:16)
at flexjson.ObjectBinder.bind(ObjectBinder.java:86)
at flexjson.ObjectBinder.bindIntoObject(ObjectBinder.java:139)
at flexjson.factories.BeanObjectFactory.instantiate(BeanObjectFactory.java:17)
at flexjson.ObjectBinder.bind(ObjectBinder.java:86)
at flexjson.ObjectBinder.bind(ObjectBinder.java:65)
at flexjson.JSONDeserializer.deserialize(JSONDeserializer.java:158)
at MapDemo.main(MapDemo.java:28)
Any suggestions ?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
packageflexjson.factories;importflexjson.ObjectFactory;importflexjson.ObjectBinder;importflexjson.JSONException;importjava.lang.reflect.Type;importjava.lang.reflect.Constructor;importjava.lang.reflect.InvocationTargetException;importjava.util.Map;publicclassBeanObjectFactoryimplementsObjectFactory{publicObjectinstantiate(ObjectBindercontext,Objectvalue,TypetargetType,ClasstargetClass){try{Objecttarget=instantiate(targetClass);if(valueinstanceofMap)returncontext.bindIntoObject((Map)value,target,targetType);elsereturnvalue;}catch(InstantiationExceptione){thrownewJSONException(context.getCurrentPath()+":There was an exception trying to instantiate an instance of "+targetClass.getName(),e);}catch(IllegalAccessExceptione){thrownewJSONException(context.getCurrentPath()+":There was an exception trying to instantiate an instance of "+targetClass.getName(),e);}catch(InvocationTargetExceptione){thrownewJSONException(context.getCurrentPath()+":There was an exception trying to instantiate an instance of "+targetClass.getName(),e);}catch(NoSuchMethodExceptione){thrownewJSONException(context.getCurrentPath()+": "+targetClass.getName()+" lacks a no argument constructor. Flexjson will instantiate any protected, private, or public no-arg constructor.",e);}}protectedObjectinstantiate(Classclazz)throwsIllegalAccessException,InvocationTargetException,InstantiationException,NoSuchMethodException{Constructorconstructor=clazz.getDeclaredConstructor();constructor.setAccessible(true);returnconstructor.newInstance();}}
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I think there's a better way to fix this issue. The biggest clue is that, with your fix, the code is still calling the BeanObjectFactory to create a primitive value. It should be using the StringObjectFactory. After all, that's the type that needs to be created. So, where did the code mistakenly choose to type the string value as a bean?
Take a look at MapObjectFactory…
public class MapObjectFactory implements ObjectFactory {
public Object instantiate(ObjectBinder context, Object value, Type targetType, Class targetClass) {
if( targetType != null ) {
if( targetType instanceof ParameterizedType ) {
ParameterizedType ptype = (ParameterizedType) targetType;
return context.bindIntoMap( (Map)value, new HashMap<Object,Object>(), ptype.getActualTypeArguments()[0], ptype.getActualTypeArguments()[1] );
}
}
return context.bindIntoMap( (Map)value, new HashMap<Object,Object>(), null, null );
}
}
Note how it assumes that if the map is a parameterized type, then the generic type is the true type of the key and value. In your use case (and mine) the generic type of the value is Object but the actual type is a primitive. I think it's this assumption that's in error.
This doesn't address all cases of sub-classing, but it proves the point with regard to Object as the generic type. By forcing the type to null, I delay the determination of the type to later. It is the same as if the type was not specified by generics. Most importantly, it works.
I'd love to get the authors input on this. Particularly on the subject of the generic type being more specific than object but still a super-class of the actual value type.
Thanks!
-Russell
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ok I took Allenru's fix and tested it against our existing unit tests, added a few more, and marked the defect fix. It's checked in. Thanks for everyone for your help and fixes.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm trying to serialize and deserialize a Entity with a Map<String,Object> member.
The serialization is working fine, but the deserialization fails with java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Map
I'm using flexjson-2.1
DemoClass:
sysout:
Any suggestions ?
I fixed my Problem:
I patched the BeanObjectFactory:
I think there's a better way to fix this issue. The biggest clue is that, with your fix, the code is still calling the BeanObjectFactory to create a primitive value. It should be using the StringObjectFactory. After all, that's the type that needs to be created. So, where did the code mistakenly choose to type the string value as a bean?
Take a look at MapObjectFactory…
Note how it assumes that if the map is a parameterized type, then the generic type is the true type of the key and value. In your use case (and mine) the generic type of the value is Object but the actual type is a primitive. I think it's this assumption that's in error.
I rewrote the MapObjectFactory as follows:
This doesn't address all cases of sub-classing, but it proves the point with regard to Object as the generic type. By forcing the type to null, I delay the determination of the type to later. It is the same as if the type was not specified by generics. Most importantly, it works.
I'd love to get the authors input on this. Particularly on the subject of the generic type being more specific than object but still a super-class of the actual value type.
Thanks!
-Russell
Here is a (pre-existing) bug report on this issue:https://sourceforge.net/tracker/?func=detail&aid=3290478&group_id=194042&atid=947842
Bug #3290478
Ok I took Allenru's fix and tested it against our existing unit tests, added a few more, and marked the defect fix. It's checked in. Thanks for everyone for your help and fixes.
Is it fixed in witch version?
I have the same problem.