RestTemplate反序列化嵌套List异常:如何实现完整映射?
问题描述
使用RestTemplate将JSON映射为Java对象时,仅能反序列化得到reservations为空数组的LockerReservations对象;当reservations列表包含数据时,反序列化直接失败。
相关代码与数据
LockerReservations实体类
@Data @AllArgsConstructor @NoArgsConstructor public class LockerReservations { Locker locker; List<Reservation> reservations; }
返回的JSON数据
[ { "locker": { "id": 0, "size": "S" }, "reservations": [] }, { "locker": { "id": 1, "size": "S" }, "reservations": [] }, { "locker": { "id": 4, "size": "S" }, "reservations": [ { "id": 17, "start": "2023-03-14T06:37:07.006", "end": "2023-03-14T12:37:07.006", "user": { "id": 1, "name": "Kiemoon" }, "locker": { "id": 4, "size": "S" } }, { "id": 36, "start": "2023-03-14T14:37:07.006", "end": "2023-03-14T15:37:07.006", "user": { "id": 1, "name": "Kiemoon" }, "locker": { "id": 4, "size": "S" } } ] } ]
RestTemplate调用代码
public List<LockerReservations> getReservationsCheck2(Size size, LocalDateTime start, LocalDateTime end) { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.APPLICATION_JSON); Map<String, Object> sizeTimeMap = new HashMap<>(); sizeTimeMap.put("size", size.toString()); sizeTimeMap.put("start", start.toString()); sizeTimeMap.put("end", end.toString()); HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(sizeTimeMap, httpHeaders); LockerReservations[] exchange = restTemplate.postForObject(url + "reservationsCheck", httpEntity, LockerReservations[].class); return Arrays.asList(exchange); }
解决方案
1. 完善所有嵌套实体类的序列化配置
确保Locker、Reservation、User类都满足以下要求:
- 有无参构造器(通过
@NoArgsConstructor注解生成) - 字段具备可访问性(通过
@Data生成getter/setter,或直接设为public) - 日期字段适配JSON格式
示例实体类实现:
// Locker类 @Data @AllArgsConstructor @NoArgsConstructor public class Locker { private Integer id; private String size; } // User类 @Data @AllArgsConstructor @NoArgsConstructor public class User { private Integer id; private String name; } // Reservation类 @Data @AllArgsConstructor @NoArgsConstructor public class Reservation { private Integer id; @JsonProperty("start") private LocalDateTime startTime; @JsonProperty("end") private LocalDateTime endTime; private User user; private Locker locker; }
2. 配置RestTemplate的Jackson消息转换器
Jackson默认不支持LocalDateTime类型的序列化/反序列化,需添加JavaTimeModule并配置对应日期格式:
@Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); ObjectMapper objectMapper = new ObjectMapper(); // 注册Java 8时间处理模块 objectMapper.registerModule(new JavaTimeModule()); // 禁用时间戳格式,使用字符串格式化 objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); // 匹配JSON中的日期格式 objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS")); converter.setObjectMapper(objectMapper); // 替换默认的Jackson转换器 restTemplate.getMessageConverters().replaceAll(c -> c instanceof MappingJackson2HttpMessageConverter ? converter : c ); return restTemplate; }
3. 异常排查与调试
在调用代码中捕获异常并打印详细栈信息,精准定位反序列化失败的具体字段:
public List<LockerReservations> getReservationsCheck2(Size size, LocalDateTime start, LocalDateTime end) { try { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.APPLICATION_JSON); Map<String, Object> sizeTimeMap = new HashMap<>(); sizeTimeMap.put("size", size.toString()); sizeTimeMap.put("start", start.toString()); sizeTimeMap.put("end", end.toString()); HttpEntity<Map<String, Object>> httpEntity = new HttpEntity<>(sizeTimeMap, httpHeaders); LockerReservations[] exchange = restTemplate.postForObject(url + "reservationsCheck", httpEntity, LockerReservations[].class); return Arrays.asList(exchange); } catch (RestClientException e) { e.printStackTrace(); throw new RuntimeException("反序列化失败", e); } }
4. 字段匹配验证
确保实体类字段名与JSON中的键完全一致,若存在命名差异,使用@JsonProperty显式指定映射关系(例如JSON键为start,实体类字段为startTime时,添加@JsonProperty("start")注解)。
内容的提问来源于stack exchange,提问作者Kiemoon
相关产品推荐
相关产品推荐

