gpt4 book ai didi

java - Retrofit 2.0,Jackson 和多态性 : Could not find creator property with name <. ..>

转载 作者:行者123 更新时间:2023-11-30 01:50:48 24 4
gpt4 key购买 nike

我目前正在使用 RetroFit 和 Jackson 的 REST API。在以下情况下基于搜索查询检索用户时考虑以下响应 JSON:

找到一个结果

{
name: "API name",
results: {
count: 1
users: {
username: "username",
age: 15
}
}
}

找到多个结果

{
name: "API name",
results: {
count: 2,
users: [{
username: "username1",
age: 18
}, {
username: "username2",
age: 19
}]
}
}

如您所见,users-property 包含动态 JSON:根据找到的结果,“users”的值可以是用户对象列表,也可以是 1 个用户对象。

因此,我使用多态设计了我的 Java POJO,如下所示:

public class UserResponse {
@JsonProperty("name")
private String apiName

@JsonProperty("results")
private AResultList resultList

//Getters & Setters

//Constructor
@JsonCreator
public UserResponse(@JsonProperty("name") String name, @JsonProperty("results") AResultList r) {
this.apiName = name;
this.resultList = r;
}
}

@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "classType"
)
@JsonSubTypes({
@JsonSubTypes.Type(value = ResultObject.class, name="ResultObject"),
@JsonSubTypes.Type(value = ResultList.class, name="ResultList")
})
public abstract class AResultList {
@JsonProperty("count)
private long totalCount;

//Getters & Setters

//Constructors
@JsonCreator
public AResultList(@JsonProperty("count) long count) {
this.totalCount = count;
}
}

public class ResultObject extends AResultList {
@JsonProperty("users")
private User user;

//Getters & Setters

//Constructor
@JsonCreator
public ResultObject(@JsonProperty("count) long count, @JsonProperty("users") User u) {
super(count);

this.user = u;
}
}

public class ResultList extends AResultList {
@JsonProperty("users")
private List<User> users;

//Getters & Setters

//Constructor
@JsonCreator
public ResultObject(@JsonProperty("count) long count, @JsonProperty("users") List<User> u) {
super(count);

this.users = u;
}
}

public class User {
@JsonProperty("username")
private String username;

@JsonProperty("age")
private long userAge;

//Getters & Setters

//Constructor
@JsonCreator
public User(@JsonProperty("username") String u, @JsonProperty("age") long a) {
this.userAge = a;
this.username = u;
}
}

供您引用:用于实例化 RetroFit 的 fragment

ObjectMapper o = new ObjectMapper();

retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(JacksonConverterFactory.create(o))
.client(okClient)
.build();

然而,尝试检索此信息会导致以下错误:

com.fasterxml.jackson.databind.JsonMappingException: Could not find creator property with name 'count' (in class org.namespace.AResultList)
at [Source: java.io.InputStreamReader@41cd2648; line: 1, column: 1]

我已经被这个“动态数据”问题困住了 2 天了。已经尝试使用 GSON 库和许多其他东西但无济于事。所以想问一下:
- 为什么 jackson 会造成这种情况?这是一个错误吗?一些用户已经问过这个问题,但提供的解决方案不适用于我的情况。
- 这是处理动态数据的正确方法吗?

我已经在不使用多态类(并且只从 API 中检索 1 个用户)和对象映射的情况下完美地测试了我的代码。问题是由多态性引起的,但我不知道如何解决它。

最佳答案

您在 Jackson 注释中指定的多态性配置建议 {"classType":"ResultObject",...}{"classType":"ResultList",...} 将在 JSON 中——但事实并非如此。我不确定您收到的错误的确切原因,但它似乎正在寻找抽象类的创建者,因为没有类型属性。

[对于多态性,Jackson 需要从 JSON 中读取一些内容以确定此时要反序列化的 bean 类型:您实际上没有,只有 users 的数组/对象。因此我认为 Jackson 的多态性支持不适合这种情况]

事实上,要允许属性获取单个项目或项目列表,您只需启用 ACCEPT_SINGLE_VALUE_AS_ARRAY 反序列化功能。但是,这需要全局启用,似乎没有办法将其定位到特定属性。

public static final class UserResponse {
public String name;
public Results results;

public static final class Results {
public int count;
public List<User> users;
}

public static final class User {
public String username;
public int age;
}
}

@Test
public void reads_single_result() throws Exception {
ObjectReader reader = new ObjectMapper().reader(UserResponse.class)
.with(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
.with(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES).with(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
UserResponse response = reader.readValue("{ name: 'API name', results: { count: 1,"
+ " users: { username: 'username', age: 15 } } }");
assertThat(response.results.users, iterableWithSize(1));
assertThat(response.results.users.get(0).username, equalTo("username"));
}

@Test
public void reads_two_results() throws Exception {
ObjectReader reader = new ObjectMapper().reader(UserResponse.class)
.with(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
.with(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES).with(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
UserResponse response = reader.readValue("{ name: 'API name', results: { count: 2,"
+ " users: [{ username: 'username1', age: 18 }, { username: 'username2', age: 19 }] } }");
assertThat(response.results.users, iterableWithSize(2));
assertThat(response.results.users.get(0).username, equalTo("username1"));
assertThat(response.results.users.get(1).username, equalTo("username2"));
}

哦,如果你想摆脱其中无用的结果对象,你可以使用转换器来实现:

public static final class UserResponseWithConverter {
public String name;
@JsonProperty("results")
@JsonDeserialize(converter = ConvertResultsToUserList.class)
public List<User> users;

public static final class Results {
public int count;
public List<User> users;
}

public static final class User {
public String username;
public int age;
}

public static final class ConvertResultsToUserList extends StdConverter<Results, List<User>> {
@Override
public List<User> convert(Results value) {
return value.users;
}
}
}

配置正确的序列化作为练习留给读者 ;)

关于java - Retrofit 2.0,Jackson 和多态性 : Could not find creator property with name <. ..>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33069401/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com