英文:
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<Profile> response
:
ResponseEntity<Profile> response = restTemplate.exchange(url, HttpMethod.GET, httpEntity, Profile.class);
现在,当我将其分配给String类型:ResponseEntity<String> response
而不是Profile时,response.getBody()
返回正确的JSON主体,具有正确的数据:name: random
。
<200,{"user":{"username='instagram', full_name='instagram'}}
但是,当我将其分配给Profile类型:ResponseEntity<Profile> response
时,它返回正确的JSON主体,但数据无效:name: null
。
<200,{"user":{"username='null', full_name='null'}}
我想要做的是将确切的API属性分配给我的Profile模型类,而无需为HTML类型自己解析JSON。
@JsonIgnoreProperties(ignoreUnknown = false)
public class Profile {
@JsonProperty("username")
private String username;
@JsonProperty("full_name")
private String full_name;
@JsonProperty("is_private")
private boolean is_private;
@JsonProperty("status")
private String status;
@JsonProperty("profile_pic_url")
private String profile_pic_url;
@JsonProperty("follower_count")
private int follower_count;
@JsonProperty("following_count")
private int following_count;
@JsonProperty("biography")
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<Profile> response
ResponseEntity<Profile> response = restTemplate.exchange(url, HttpMethod.GET, httpEntity, Profile.class);
Now,
when I assign it to a String type: ResponseEntity<String> response
instead of Profile, the response.getBody()
returns the correct json body, with the correct data: name: random
<200,{"user":{"username='instagram', full_name='instagram'}
However,
when I assign it to a Profile type: ResponseEntity<Profile> response
, it returns the correct json body, but with invalid data: name: null
<200,{"user":{"username='null', full_name='null'}
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("username")
private String username;
@JsonProperty("full_name")
private String full_name;
@JsonProperty("is_private")
private boolean is_private;
@JsonProperty("status")
private String status;
@JsonProperty("profile_pic_url")
private String profile_pic_url;
@JsonProperty("follower_count")
private int follower_count;
@JsonProperty("following_count")
private int following_count;
@JsonProperty("biography")
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 = "user")
public class Profile {
// ...
}
This way, on deserialization, Jackson will unwrap your value before deserializing the JSON into a Profile
object.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论