[alibaba/fastjson]Fix issue2430 (反序列化guava的ArrayListMultimap失败)

2024-08-28 808 views
4

fix issue #2430 原因是在对ArrayListMultiMap的类型做判断时,如果用户指定了泛型类型,则直接用==ArrayListMultimap.class的方式会返回False,需要先通过getRawType()方法获得原始类型后再做比较

回答

3

报错信息:com.alibaba.fastjson.JSONException: unsupport type class com.google.common.collect.AbstractMapBasedMultimap$AsMap

at com.alibaba.fastjson.parser.deserializer.MapDeserializer.createMap(MapDeserializer.java:394)
at com.alibaba.fastjson.parser.deserializer.MapDeserializer.createMap(MapDeserializer.java:331)
at com.alibaba.fastjson.parser.deserializer.MapDeserializer.deserialze(MapDeserializer.java:37)
at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:395)
at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1401)
at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1367)
at com.alibaba.fastjson.JSON.parse(JSON.java:183)
at com.alibaba.fastjson.JSON.parse(JSON.java:193)
at com.alibaba.fastjson.JSON.parse(JSON.java:149)
at com.alibaba.fastjson.JSON.parseObject(JSON.java:254)
at org.archer.rpc.processor.GlobalRpcInvokerTest.testMultiMap(GlobalRpcInvokerTest.java:78)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runners.Suite.runChild(Suite.java:127)
at org.junit.runners.Suite.runChild(Suite.java:26)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

Caused by: java.lang.InstantiationException: com.google.common.collect.AbstractMapBasedMultimap$AsMap at java.lang.Class.newInstance(Class.java:427) at com.alibaba.fastjson.parser.deserializer.MapDeserializer.createMap(MapDeserializer.java:392) ... 40 more Caused by: java.lang.NoSuchMethodException: com.google.common.collect.AbstractMapBasedMultimap$AsMap.() at java.lang.Class.getConstructor0(Class.java:3082) at java.lang.Class.newInstance(Class.java:412) ... 41 more

5

看样子好像没有解决。

2

我看了下,这部分代码会报错的原因有两个

  1. 因为序列化启用writeClassName特性的时候把type写成了"@type":"com.google.common.collect.AbstractMapBasedMultimap$AsMap",而不是"@type":"com.google.common.collect.ArrayListMultimap",所以反序列化的时候没有走GuavaCodec中为ArrayListMultimap定义的反序列化逻辑。
  2. stringStudentMultimap = (Multimap<String, Student>) JSON.parseObject(json); 这一行中的强制类型转换无法将JSONObject类转换为Multimap类,建议调用JSON.parseObject(String, Class)的方式手动指定转换类型,如:
    String json = "{\"@type\":\"com.google.common.collect.ArrayListMultimap\",\"xiaoming\":[\"xiaohua\"]}";
    Multimap<String, String> stringStudentMultimap = JSON.parseObject(json, Multimap.class);
    System.out.println(stringStudentMultimap.get("xiaoming"));

这一段代码则是不报错的。 至于1中提到的原因,感觉算是个bug,我定位到的根因是在GuavaCodec.java中的write()方法:

    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
        SerializeWriter out = serializer.out;
        if (object instanceof Multimap) {
            Multimap multimap = (Multimap) object;
            serializer.write(multimap.asMap()); //multimap.asMap()返回的是AbstractMapBasedMultimap.AsMap对象,而不是原本的ArrayListMultimap对象
        }
    }

我目前没有太好的想法, @wenshao 怎么看?