1. 概述
在实际开发中,我们的服务经常需要调用其他 REST 接口来获取数据。Spring 提供了 RestTemplate
来发送同步 HTTP 请求,而返回的数据通常是 JSON 格式,RestTemplate 可以帮我们自动完成反序列化。
本文将介绍三种将 JSON 数组映射为 Java 集合的方式:
- Object[] 数组
- 自定义 POJO 数组
- 使用 ParameterizedTypeReference 映射为 List
2. 示例 JSON、POJO 和服务结构
假设我们有一个接口地址:http://localhost:8080/users
,它返回如下 JSON 数据:
[{
"id": 1,
"name": "user1"
}, {
"id": 2,
"name": "user2"
}]
对应的 Java 实体类如下:
public class User {
private int id;
private String name;
// getters and setters...
}
我们创建一个服务实现类 UserConsumerServiceImpl
,依赖注入 RestTemplate
:
public class UserConsumerServiceImpl implements UserConsumerService {
private final RestTemplate restTemplate;
public UserConsumerServiceImpl(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
...
}
3. 将 JSON 数组映射为 Java 集合的不同方式
当 REST 接口返回的是 JSON 数组时,我们可以采用以下几种方式将其转换为 Java 集合对象。
3.1. 使用 Object[] 接收响应
首先,使用 getForEntity
方法并指定响应类型为 Object[].class
:
ResponseEntity<Object[]> responseEntity =
restTemplate.getForEntity(BASE_URL, Object[].class);
然后从响应中提取 body:
Object[] objects = responseEntity.getBody();
此时每个元素都是 LinkedHashMap 类型(Jackson 默认行为),我们需要借助 ObjectMapper
转换为目标类型:
ObjectMapper mapper = new ObjectMapper();
接着进行类型转换和处理:
return Arrays.stream(objects)
.map(object -> mapper.convertValue(object, User.class))
.map(User::getName)
.collect(Collectors.toList());
✅ 优点:通用性强,可以接收任意结构的 JSON 数组
❌ 缺点:效率低,需要额外转换步骤;类型不明确,容易出错
⚠️ 注意:这种方式实际上是 Jackson 在不知道目标类型的情况下,将 JSON 映射成了 LinkedHashMap,后续再手动转换会带来性能开销。
3.2. 使用 User[] 接收响应
更推荐的做法是直接声明目标数组类型为 User[]
:
ResponseEntity<User[]> responseEntity =
restTemplate.getForEntity(BASE_URL, User[].class);
User[] userArray = responseEntity.getBody();
return Arrays.stream(userArray)
.map(User::getName)
.collect(Collectors.toList());
✅ 优点:类型安全,避免手动转换
❌ 缺点:仍需转为 List 才能方便操作
这种方式省去了 convertValue
的步骤,提高了代码可读性和执行效率。
3.3. 使用 ParameterizedTypeReference 映射为 List
如果我们希望直接拿到 List<User>
类型,而不是数组,就需要使用 exchange
方法配合 ParameterizedTypeReference
:
ResponseEntity<List<User>> responseEntity =
restTemplate.exchange(
BASE_URL,
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<User>>() {}
);
List<User> users = responseEntity.getBody();
return users.stream()
.map(User::getName)
.collect(Collectors.toList());
✅ 优点:直接拿到 List,无需转换,类型清晰
❌ 缺点:语法略复杂
⚠️ 注意:由于 Java 泛型存在类型擦除问题,不能直接使用 List<User>.class
。ParameterizedTypeReference
利用了匿名内部类保留泛型信息的特性,从而绕过这一限制。
4. 总结
方式 | 类型 | 是否推荐 | 说明 |
---|---|---|---|
Object[] |
通用但需手动转换 | ❌ | 效率低,仅适合简单场景 |
User[] |
类型安全,但仍是数组 | ✅ | 简单粗暴,适合大多数情况 |
ParameterizedTypeReference<List<User>> |
泛型 List,类型明确 | ✅✅ | 更符合 Java 集合习惯,推荐用于正式项目 |
📌 建议:
- 如果只是临时读取或统计数量,可以用
Object[]
- 如果要对数据进一步处理,优先考虑
User[]
或List<User>
- 正式项目中建议统一使用
ParameterizedTypeReference
+exchange
,保证类型安全和代码一致性
完整示例代码见 GitHub:https://github.com/eugenp/tutorials/tree/master/spring-web-modules/spring-resttemplate-2