Flex JSON unable to properly serialize/deserialize

2019-07-17 02:21发布

I tried to serialize and deseriliaze LinkedHashMap data as follow:

LinkedHashMap<String, Object> o = new LinkedHashMap<String, Object>();
o.put("1", "a");
o.put("2", "b");
o.put("3", "c");
o.put("4", new BigDecimal("9999999999999999999999.00999999999999999999999"));

String serialize = new JSONSerializer().deepSerialize(o);
System.out.println("serialize" + serialize);

LinkedHashMap deserialize = new JSONDeserializer<LinkedHashMap>().deserialize(serialize, LinkedHashMap.class);
System.out.println("deserialize:" + deserialize);

and I get ClassCastException:

serialize{"1":"a","2":"b","3":"c","4":9999999999999999999999.00999999999999999999999}
Exception in thread "main" java.lang.ClassCastException: java.util.HashMap cannot be cast to java.util.LinkedHashMap
    at com.JSONUtil.main(JSONUtil.java:161)

So I tried slightly different approach when deserializing as follow:

HashMap deserialize = new JSONDeserializer<HashMap>().deserialize(serialize, HashMap.class);
System.out.println("deserialize:" + deserialize);

This time I get result but the Map is unordered (I think because it is now using HashMap). In addition, the BigDecimal value is not displayed like the original format.

deserialize:{3=c, 2=b, 1=a, 4=1.0E22}

It appears that FlexJSON has issue with sorted Map. I guess this is because it has no way to put 'class' entry like the example below, eg.

"class":"ch.qos.logback.classic.Logger","debugEnabled":true,"errorEnabled":true,"infoEnabled":true}

or perhaps there is another way to do this. Can anyone please help? Thank you


After introducing ObjectFactory as suggested by chubbsondubs:

LinkedHashMap deserialize = new JSONDeserializer<LinkedHashMap>()
.use(LinkedHashMap.class, new ObjectFactory() {
public Object instantiate(ObjectBinder context, Object value, Type targetType, Class targetClass) {
    System.out.println("mymap:"value);
}
}).deserialize(serialize, LinkedHashMap.class);

The value object has HashMap type and it prints:

mymap:{3=c, 2=b, 1=a, 4=flexjson.JsonNumber@104fc23}

1条回答
不美不萌又怎样
2楼-- · 2019-07-17 02:54

By default an object without typing information is interpreted as HashMap which is explained in the docs. The times it won't use a HashMap is if it can determine the type of the object from either an embedded class property (which works, but is unsafe over the network), a specified type by object path, or if you are deserializing into a typed object that it can interpret the type from.

So classes like standard collections there is no way Flexjson can infer the contained type from a Collection/Map class because those are simple Object references at runtime. Numbers are another area where JSON doesn't specify any type information. When we map a number to Java that could be one of several varieties: byte, short, int, long, BigInteger, float, double, BigDecimal. Flexjson has to make a call if no typing information is specified. By default it uses double if its a decimal and long if its an integer. In your case it's a double and that's why it shows it in exponential format.

You'll have to specify the types you want. By either using a typed object, configuring a type on an object path or by creating a custom ObjectFactory. I think a ObjectFactory is the only option for you unless you can create typed object. Reason being is because the values in your Map vary in type. Some entries are string where another is BigDecimal. So you'll have to have a special ObjectFactory that knows to instantiate a LinkedHashMap and copy over all the keys from the source to the target converting them to BigDecimal if the value of the source is JsonNumber.

查看更多
登录 后发表回答