Spring RestTemplate如何将JSON反序列化为不可变对象
解决方案
不可变类的所有final字段必须在对象实例化时完成赋值,对象创建后无法修改字段值,因此你需要先拿到所有接口返回的参数,再调用构造方法创建实例,而不是先创建空对象再用setter赋值。
基础修改方案
直接调整接口调用逻辑,先取值再构造对象:
RegistrationRequestDto userProfile = null; try { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED); HttpEntity<String> request = new HttpEntity<>(httpHeaders); ResponseEntity<Object> result = restTemplate.exchange(uri, HttpMethod.POST, request, Object.class); log.info("{}", result); log.info("{}", result.getBody()); LinkedHashMap<String, Object> map = (LinkedHashMap<String, Object>) result.getBody(); if (map != null) { // 先从返回结果中取出所有需要的字段,做好字段映射 String keycloakId = map.get("sub").toString(); String firstName = map.get("given_name").toString(); String lastName = map.get("family_name").toString(); String email = map.get("email").toString(); // 其他字段如username、password、confirmPassword根据业务逻辑补全默认值 String username = email; String password = "默认占位值"; String confirmPassword = "默认占位值"; // 调用全参构造直接创建不可变对象 userProfile = new RegistrationRequestDto( email, username, password, confirmPassword, firstName, lastName, keycloakId ); } } catch (Exception e) { e.printStackTrace(); } return userProfile;
优化方案(推荐)
如果觉得全参构造参数太多容易混淆,可以给Dto加Lombok的@Builder注解,代码可读性更高:
- 先修改
RegistrationRequestDto定义:
@Data @Builder // 新增Builder注解 public class RegistrationRequestDto { public final String email; public final String username; public final String password; public final String confirmPassword; public final String firstName; public final String lastName; public final String keycloakId; public RegistrationRequestDto( String email, String username, String password, String confirmPassword, String firstName, String lastName, String keycloakId) { notNull(email, "email must be set"); notNull(username, "username must be set"); notNull(password, "password must be set"); notNull(firstName, "firstName must be set"); notNull(lastName, "lastName must be set"); this.email = email; this.username = username; this.password = password; this.confirmPassword = confirmPassword; this.firstName = firstName; this.lastName = lastName; this.keycloakId = keycloakId; } }
- 创建对象时使用Builder模式:
userProfile = RegistrationRequestDto.builder() .email(email) .username(username) .password(password) .confirmPassword(confirmPassword) .firstName(firstName) .lastName(lastName) .keycloakId(keycloakId) .build();
注意事项
- 原代码中的
new RegistrationRequestDto()会编译报错,因为你没有定义无参构造方法,final字段也不支持无参构造后赋值 - 原构造方法已经加了非空校验,传入必填字段时要确保不会传null,避免触发校验异常
内容的提问来源于stack exchange,提问作者user9347049
相关产品推荐
相关产品推荐

