【问题标题】:How to deserialise Json into Immutable Object - Spring, RestTemplate如何将 Json 反序列化为不可变对象 - Spring、RestTemplate
【发布时间】:2022-01-02 02:18:26
【问题描述】:

我有一个看起来像这样的模型:

@Data
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;
    }
}

接下来,我有一个方法用restTempate 调用另一个服务。

该调用的结果我应该保存在上面显示的模型中。

我有这段代码应该从外部服务调用并返回结果:

RegistrationRequestDto userProfile = new RegistrationRequestDto();
        try {
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            // httpHeaders.set("Authorization", "Bearer " + responseToken.getAccess_token());
            HttpEntity<String> request = new HttpEntity<String>(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) {
                userProfile.setUserId(map.get("sub").toString());
                userProfile.setGiven_name(map.get("given_name").toString());
                userProfile.setFamily_name(map.get("family_name").toString());
                userProfile.setEmail(map.get("email").toString());
                userProfile.setEmail_verified(map.get("email_verified").toString());
                //userProfile.setPhoto(Optional.ofNullable(map.get("photo").toString()));
            }
    
        } catch (Exception e) {
            e.printStackTrace();
        }
        return userProfile;

所以,在这段代码中我正在使用

if (map != null) {
   userProfile.setUserId(map.get("sub").toString());
   userProfile.setGiven_name(map.get("given_name").toString());
   userProfile.setFamily_name(map.get("family_name").toString());
   userProfile.setEmail(map.get("email").toString());
   userProfile.setEmail_verified(map.get("email_verified").toString());
}

RegistrationRequestDto 模型中的变量只是 private 时,我可以使用它。

但是现在变量是public final我不知道如何将结果存储在地图中?

【问题讨论】:

  • DTO 上的 @Data 注释是什么?是龙目岛吗?
  • 是的,它是龙目岛
  • 为什么不创建合约类并在交换方法中传递该类类型。它会给你解析的对象而不是地图。
  • @Pirate 我该怎么做?您是否有我可以查看的示例代码?
  • 最终变量只能初始化一次。在调用代码中,您创建了一个新的 DTO,但没有参数,这是有效的(尽管我不知道为什么 notNull 调用不会阻止这一点。)然后您尝试针对已经初始化的变量运行单个设置器。

标签: java spring-boot linkedhashmap


【解决方案1】:

您的 dto 类的构造函数上必须有一个 fasterxml @JsonCreator。 类似于下面的dto:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Value;

@Value
public class User {
    public final int id;
    public final String name;

    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public User(@JsonProperty("id") int id, @JsonProperty("name") String name) {
        this.id = id;
        this.name = name;
    }

}

在其余的调用中传递User.class 而不是Object.class。如下所示:

ResponseEntity<User> response = restTemplate.exchange(uri, HttpMethod.GET, HttpEntity.EMPTY, User.class);

User user = response.getBody();

注意:这里需要@JsonProperty("...")。此外,@Value@Data 更适合您的用例。

【讨论】:

    【解决方案2】:

    您可以根据 api 返回的响应创建 Pojo。

    即如果您有一些 api https://www.mockapis.not/users/user/123 并且它返回类似这样的响应,

    {
       "name":"stack",
       "age":21,
       "phone":123456789,
       "dob":"01-06-2011"
    }
    

    然后你可以用给定的属性创建一个java类。

    class User {
        private String name;
        private int age;
        private long phone;
        private Date dob;
    
        //getter setter or lombok @Data or @Getter @Setter
    }
    

    然后你可以如下调用你的api,你可以从响应实体中获取用户对象。

    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<User> response = restTemplate.exchange(apiUrl, HttpMethod.GET, User.class);
    User user = response.getBody();
    

    现在您不需要解析对象。会被自动解析。

    更多详情可以访问Resttemplate

    【讨论】:

    • 感谢您的回答,但我想使用公共最终变量。我知道如何使用这个私有变量而不是最终变量,这是我的问题
    • 这不适用于不可变对象
    • @MohammadYasin 是的,这不适用于最终变量,我的问题是我试图找出有效的方法:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-10
    • 2018-10-11
    • 1970-01-01
    相关资源
    最近更新 更多