You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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注解,代码可读性更高:

  1. 先修改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;
    }
}
  1. 创建对象时使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 05:15:03