FastJson 根据 Class 反序列化 json 时, Class 是否可以为泛型?

2022-12-10 00:12:45 +08:00
 ufan0

如题,测试代码如下:

    public static void main(String[] args) {
        Foo x = test("{\"X\": \"x\", \"y\": \"y\"}");
    }

    @ToString
    @Getter
    @Setter
    static class Foo {
        private String x;
        private String y;
    }

    // test1
    private static <RESULT> RESULT test(String text) {
    	// return new Gson().fromJson(text, new TypeToken<RESULT>() {}.getType())
        return JSONObject.parseObject(
                text,
                new TypeReference<RESULT>() {}.getType()
        );
    }

    // test2
    private static <RESULT> RESULT test(String text, RESULT result) {
    	// return new Gson().fromJson(text, new TypeToken<RESULT>() {}.getType())
        return JSONObject.parseObject(
                text,
                new TypeReference<RESULT>() {}.getType()
        );
    }

我想使用 test 方法进行jsonRESULT的转换,但是存在问题,调用这个方法的时候会报错,将Fastjson替换成Gson也会:

class com.alibaba.fastjson.JSONObject cannot be cast to class com.xx.xx.Xx
(com.alibaba.fastjson2.JSONObject and com.xx.xx.Xx are in unnamed module of loader 'app')

产生的原因我是知道的,但是不清楚为什么TypeReference不起作用,那么对于这种场景,希望坚持使用泛型处理,可以做到吗?请指正。

2781 次点击
所在节点    Java
8 条回复
zjp
2022-12-10 01:10:15 +08:00
感觉想复杂了
对于 test1 ,直接写 test("{\"X\": \"x\", \"y\": \"y\"}"); 显然 JVM 并不能知道 RESULT 应该是什么类
直接 JSONObject.parseObject(text, Foo.class)就好了
AoEiuV020CN
2022-12-10 01:36:21 +08:00
感觉误会了什么,
首先,答案是不可以,具体类型要么写死 Foo ,要么外面传进来,
如果有办法的话人家就直接封装好了,TypeReference 压根不会存在这么个东西,不会等你来想办法的,

根本上是 JAVA 的泛型擦除,运行时这个 RESULT 已经不存在了,
没有任何办法知道这个 RESULT 应该是什么,

比较友好一点的,比如 kotlin 就可以,有个 inline ,本质上就是你不用写,它自动帮你写上 Foo.class 代替泛型,于是就可以在方法内部获取到这个泛型类型,
但同样要求外面这个 Foo 必须是真实的类,不能是泛型,


最后 TypeReference 是针对 Map<String,List<Foo>这种复杂的类型,通过 TypeReference 生成子类间接获取到一个包含完整泛型信息的 Type ,
必须有这个 Type 才能创建出对象,光有泛型不行,
wangyu17455
2022-12-10 02:24:36 +08:00
java 拿不到对象的泛型,只能拿到字段的泛型,由于类型擦除,把 new ArrayList<String>作为参数传给一个方法,在运行时是没法通过反射得到泛型类型是 String 的,但是如果你定义一个泛型类,然后给方法传入 class ,就可以通过反射得到泛型类型了
xuanbg
2022-12-10 07:33:34 +08:00
Java 的泛型不能支持 OP 你这个操作,必须通过参数告诉反序列化方法你要反序列化成什么类型才行。所以,其实很简单,方法设计成这样就行了:public static <T> T toBean(String json, Class<T> type);
yazinnnn
2022-12-10 09:33:52 +08:00
inline fun <reified R> test(text: String): R {
return JSONObject.parseObject(text,R::class.java)
}


inline+reified 可以拯救一下
ufan0
2022-12-10 21:42:07 +08:00
@zjp #1
@AoEiuV020CN #2
@wangyu17455 #3
@xuanbg #4
@yazinnnn #5

谢谢各位,已经根据 4 楼建议成功处理。
还是我对 Class<>的使用不够熟悉,欸。
xuanbg
2022-12-11 10:40:24 +08:00
Class<SomeClass<T>>这种我没想出来怎么写,但应该是可以做到的。不传入类型,也应该是可以做到的。Rabbit MQ 可以自动将消息内容反序列化,spring web 也是一样能把 requist body 的 JSON 字符串反序列化成你指定的类型。
clownpiece
2022-12-11 12:46:05 +08:00
jackson 可以通过 mapper.readValue(string, mapper.getTypeFactory().constructParametricType(SomeClass.class, T.class))来实现

fastjson 因为不太熟,不清楚有没有对应的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/901455

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX