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

Spring RestTemplate Jackson 网络请求 json 类型匹配错误问题,是否有更优雅的解决方式?

  •  
  •   nnegier · 2023-04-03 21:18:30 +08:00 · 1666 次点击
    这是一个创建于 600 天前的主题,其中的信息可能已经有所发展或是发生改变。

    以下代码意思:请求一个接口,要求返回 Result<GlobalUser>。

    ResponseEntity<Result> response = restTemplate.exchange(url, HttpMethod.PUT, null, Result.class); //①
    if (response.getStatusCode().is2xxSuccessful()){
    	Result<GlobalUser> result = response.getBody(); 
            if(result.getCode()==200){
        	    GlobalUser globalUser = result.getData(); //这行代码会出错
            }
    }
    

    报错内容:java.util.LinkedHashMap cannot be cast to cn.timetr.server.bean.GlobalUser 也就是说,一个 json 对象给我匹配成键值对 HashMap 了,我估计是上面第一行代码①导致的。

    于是我想写成这样:ResponseEntity<Result<GlobalUser>> response = restTemplate.exchange(url, HttpMethod.PUT, null, Result<GlobalUser>.class); 但这样不行,Result<GlobalUser>.class 报错,不能这样写,但我想按这个思路寻求有何解? 当然不按这个思路,可以将报错代码用 Mapper 转换一下改成这样,GlobalUser globalUser = new ObjectMapper().convertValue(result.getData(), GlobalUser.class);,但这样就导致了每次写相关代码都要手动转换一下并不优雅。

    10 条回复    2023-04-04 12:24:03 +08:00
    Saxton
        1
    Saxton  
       2023-04-03 21:23:51 +08:00
    // 使用 ParameterizedTypeReference 进行包装
    ParameterizedTypeReference<Result<GlobalUser>> reference = new ParameterizedTypeReference<Result<GlobalUser>>() {};
    ResponseEntity<Result<GlobalUser>> response = restTemplate.exchange(url, HttpMethod.PUT, null, reference); //①
    if (response.getStatusCode().is2xxSuccessful()){
    Result<GlobalUser> result = response.getBody();
    if(result.getCode()==200){
    GlobalUser globalUser = result.getData(); //这行代码会出错
    }
    }
    nnegier
        2
    nnegier  
    OP
       2023-04-03 21:32:55 +08:00
    @Saxton 看来 new 是免不了的了,不过这种方式比 Mapper 转换要优雅许多,语义也要更清晰。不过我挺惭愧的,因为我之前在看方法重载时看到了,也去搜了,但还是跑来问了
    Saxton
        3
    Saxton  
       2023-04-03 21:35:19 +08:00
    @nnegier 最优解决方案了,不要去试图避免 new ,如果你使用 mapper 方式只会更麻烦。
    xuanbg
        4
    xuanbg  
       2023-04-03 23:13:06 +08:00
    我在项目里,定义的 Result 对象里面,data 字段的类型用 Object 而不是泛型来规避这种问题。
    xuanbg
        5
    xuanbg  
       2023-04-03 23:17:58 +08:00
    或者,ResponseEntity<Result> response = restTemplate.exchange(url, HttpMethod.PUT, null, Result.class);这行代码我会写成:ResponseEntity< GlobalUser > response = restTemplate.exchange(url, HttpMethod.PUT, null, GlobalUser.class);对的,Result 是个泛型类,那么 exchange 这个方法指定的类型应该是 Result 对象中的 data 字段的类型才对。
    humpy
        6
    humpy  
       2023-04-03 23:24:17 +08:00
    可以试试 feign ,你这个接口定义一个 interface 就实现了

    @FeignClients(url=${xxx.url})
    interface Api {

    @PutMapping("/xxx")
    Result<GlobalUser> xxx();
    }
    Leviathann
        7
    Leviathann  
       2023-04-04 00:20:37 +08:00
    java 半擦除,可以通过继承获取泛型参数
    petercui
        8
    petercui  
       2023-04-04 09:23:14 +08:00
    首先 ObjectMapper 每个工程基本上只需要维护一个实例,并不需要每次都 new 出来。

    其次,OP 有空还得好好看看范型部分。
    nnegier
        9
    nnegier  
    OP
       2023-04-04 12:22:40 +08:00
    @Leviathann 是说有比一楼更优雅的方式吗?
    nnegier
        10
    nnegier  
    OP
       2023-04-04 12:24:03 +08:00
    @petercui 你是指静态吧,我最开始就是这样想的,至于说每次 new 是指的一楼优雅方式需要每次 new ParameterizedTypeReference ,不是说要 new ObjectMapper 。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1819 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 16:34 · PVG 00:34 · LAX 08:34 · JFK 11:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.