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

2023-04-03 21:18:30 +08:00
 nnegier

以下代码意思:请求一个接口,要求返回 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);,但这样就导致了每次写相关代码都要手动转换一下并不优雅。

1707 次点击
所在节点    Java
10 条回复
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
2023-04-03 21:32:55 +08:00
@Saxton 看来 new 是免不了的了,不过这种方式比 Mapper 转换要优雅许多,语义也要更清晰。不过我挺惭愧的,因为我之前在看方法重载时看到了,也去搜了,但还是跑来问了
Saxton
2023-04-03 21:35:19 +08:00
@nnegier 最优解决方案了,不要去试图避免 new ,如果你使用 mapper 方式只会更麻烦。
xuanbg
2023-04-03 23:13:06 +08:00
我在项目里,定义的 Result 对象里面,data 字段的类型用 Object 而不是泛型来规避这种问题。
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
2023-04-03 23:24:17 +08:00
可以试试 feign ,你这个接口定义一个 interface 就实现了

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

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

其次,OP 有空还得好好看看范型部分。
nnegier
2023-04-04 12:22:40 +08:00
@Leviathann 是说有比一楼更优雅的方式吗?
nnegier
2023-04-04 12:24:03 +08:00
@petercui 你是指静态吧,我最开始就是这样想的,至于说每次 new 是指的一楼优雅方式需要每次 new ParameterizedTypeReference ,不是说要 new ObjectMapper 。

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

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

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

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

© 2021 V2EX