为什么ResponseEntity<Foo>和ResponseEntity<String>得到不同的结果?

huangapple go评论51阅读模式
英文:

Why is ResponseEntity<Foo> geting a different result to ResponseEntity<String>?

问题

对于我的Java Spring Boot应用程序(v2.7.12),我正在使用restTemplate.exchange()执行GET请求,传入正确的url、带有正确标头的HttpEntity和响应类型Profile.class

将其分配给ResponseEntity&lt;Profile&gt; response

ResponseEntity&lt;Profile&gt; response = restTemplate.exchange(url, HttpMethod.GET, httpEntity, Profile.class);

现在,当我将其分配给String类型:ResponseEntity&lt;String&gt; response而不是Profile时,response.getBody()返回正确的JSON主体,具有正确的数据:name: random

&lt;200,{&quot;user&quot;:{&quot;username=&#39;instagram&#39;, full_name=&#39;instagram&#39;}}

但是,当我将其分配给Profile类型:ResponseEntity&lt;Profile&gt; response时,它返回正确的JSON主体,但数据无效:name: null

&lt;200,{&quot;user&quot;:{&quot;username=&#39;null&#39;, full_name=&#39;null&#39;}}

我想要做的是将确切的API属性分配给我的Profile模型类,而无需为HTML类型自己解析JSON。

@JsonIgnoreProperties(ignoreUnknown = false)
public class Profile {
    @JsonProperty(&quot;username&quot;)
    private String username;
    @JsonProperty(&quot;full_name&quot;)
    private String full_name;
    @JsonProperty(&quot;is_private&quot;)
    private boolean is_private;
    @JsonProperty(&quot;status&quot;)
    private String status;
    @JsonProperty(&quot;profile_pic_url&quot;)
    private String profile_pic_url;
    @JsonProperty(&quot;follower_count&quot;)
    private int follower_count;
    @JsonProperty(&quot;following_count&quot;)
    private int following_count;
    @JsonProperty(&quot;biography&quot;)
    private String biography;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

这是我的restTemplate:

@Controller
public class WebController {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder){
        return builder.build();
    }
}

我知道这个问题有一个简单的解决方法。我尝试过使用Jackson API从String类型的响应主体解析JSON,但我希望这是备选方案。

我尝试过更改URL格式,但没有任何区别。标头没问题。API本身没有错误。

Profile profile = restTemplate.getForObject(uri, Profile.class)

我尝试过使用.getForObject,之前可以工作,但我需要传递标头,它不能这样做。

英文:

For my Java Spring Boot Application (v2.7.12), I am performing a GET request using restTemplate.exchange() which passes in my correct url, HttpEntity with the correct headers, and response type Profile.class.

It assigns this to ResponseEntity&lt;Profile&gt; response

ResponseEntity&lt;Profile&gt; response = restTemplate.exchange(url, HttpMethod.GET, httpEntity, Profile.class);

Now,
when I assign it to a String type: ResponseEntity&lt;String&gt; response instead of Profile, the response.getBody() returns the correct json body, with the correct data: name: random

&lt;200,{&quot;user&quot;:{&quot;username=&#39;instagram&#39;, full_name=&#39;instagram&#39;}

However,
when I assign it to a Profile type: ResponseEntity&lt;Profile&gt; response, it returns the correct json body, but with invalid data: name: null

&lt;200,{&quot;user&quot;:{&quot;username=&#39;null&#39;, full_name=&#39;null&#39;}

What I want to do is assign the exact API attributes to my Profile model class, without needing to parse JSON myself for the HTML type.

    @JsonIgnoreProperties(ignoreUnknown = false)
public class Profile {
    @JsonProperty(&quot;username&quot;)
    private String username;
    @JsonProperty(&quot;full_name&quot;)
    private String full_name;
    @JsonProperty(&quot;is_private&quot;)
    private boolean is_private;
    @JsonProperty(&quot;status&quot;)
    private String status;
    @JsonProperty(&quot;profile_pic_url&quot;)
    private String profile_pic_url;
    @JsonProperty(&quot;follower_count&quot;)
    private int follower_count;
    @JsonProperty(&quot;following_count&quot;)
    private int following_count;
    @JsonProperty(&quot;biography&quot;)
    private String biography;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

This is my restTemplate:

@Controller
public class WebController {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder){
        return builder.build();
    }

I know this issue has an easy workaround. I have tried using Jackson API to parse JSON from the String type response body, but I wish this to be Plan B.

I have tried changing the URL formatting, and it makes no difference.
The headers are fine.
The API itself is not wrong.

Profile profile = restTemplate.getForObject(uri, Profile.class)

I tried using .getForObject which worked before, but I needed to pass in headers, and it can't do that.

答案1

得分: 1

Your JSON has a root element named user. You're trying to deserialize assuming that there's no root element. That's why it is not working, Jackson tries to find the fields of the Profile class on the root, but it never finds any of them, because they are wrapped into another object.

首先,按照以下方式配置您的 ObjectMapper(最好将此代码放在一个带有 @Configuration 注释的类中):

@Bean
public ObjectMapper objectMapper(ObjectMapper objectMapper) {
    objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
    
    return objectMapper;
}

这将告诉对象映射器允许使用根值进行反序列化。

现在,在您的 Profile 类上加上 @JsonRootName 注释:

@JsonRootName(value = "user")
public class Profile {
    // ...
}

这样,在反序列化时,Jackson 将在将 JSON 反序列化为 Profile 对象之前取消包装您的值。

英文:

Your JSON has a root element named user. You're trying to deserialize assuming that there's no root element. That's why it is not working, Jackson tries to find the fields of the Profile class on the root, but it never finds any of them, because they are wrapped into another object.

First, configure your ObjectMapper this way (preferably put this code in a @Configuration annotated class:

@Bean
public ObjectMapper objectMapper(ObjectMapper objectMapper) {
    objectMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
    
    return objectMapper;
}

This will tell object mapper to allow deserialization with root value.

Now, annotate your Profile class with @JsonRootName:

@JsonRootName(value = &quot;user&quot;)
public class Profile {
    // ...
}

This way, on deserialization, Jackson will unwrap your value before deserializing the JSON into a Profile object.

huangapple
  • 本文由 发表于 2023年5月25日 00:56:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76325849.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定