V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ufan0
V2EX  ›  Java

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

  •  
  •   ufan0 · 2022-12-10 00:12:45 +08:00 · 2431 次点击
    这是一个创建于 503 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如题,测试代码如下:

        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不起作用,那么对于这种场景,希望坚持使用泛型处理,可以做到吗?请指正。

    第 1 条附言  ·  2022-12-10 22:20:18 +08:00
    做事要有始有终,问题已经解决,记录下:

    TypeReference 是可以起作用的,附言不支持 markdown ,不贴完整代码了,以下两种修改方案均可生效,
    修改 test 方法入参 RESULT result:

    a. Class<RESP> respClass ,入参示例:Foo.class;
    b. java.lang.reflect.Type type ,入参示例:new TypeReference<Foo>() {}.getType()。

    此时又想到一个问题,若这个参数是 Class<SomeClass<T>>,这时候调用者应该怎么构建参数呢。
    8 条回复    2022-12-11 12:46:05 +08:00
    zjp
        1
    zjp  
       2022-12-10 01:10:15 +08:00 via Android   ❤️ 1
    感觉想复杂了
    对于 test1 ,直接写 test("{\"X\": \"x\", \"y\": \"y\"}"); 显然 JVM 并不能知道 RESULT 应该是什么类
    直接 JSONObject.parseObject(text, Foo.class)就好了
    AoEiuV020CN
        2
    AoEiuV020CN  
       2022-12-10 01:36:21 +08:00 via Android   ❤️ 1
    感觉误会了什么,
    首先,答案是不可以,具体类型要么写死 Foo ,要么外面传进来,
    如果有办法的话人家就直接封装好了,TypeReference 压根不会存在这么个东西,不会等你来想办法的,

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

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


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


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

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

    fastjson 因为不太熟,不清楚有没有对应的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3544 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 04:45 · PVG 12:45 · LAX 21:45 · JFK 00:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.