使用Jackson将JSON数组反序列化为单个Java对象
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Jackson将JSON数组反序列化为单个Java对象相关的知识,希望对你有一定的参考价值。
我的想法是,我想将JSON数组["foo", "bar"]
转换为Java对象,因此我需要通过索引将每个数组元素映射到property。
假设我有以下JSON:
{
"persons": [
[
"John",
"Doe"
],
[
"Jane",
"Doe"
]
]
}
正如您所看到的,每个人只是一个数组,其中第一个名称是索引为0的元素,而最后一个名称是索引为1的元素。
我想将它反序列化为List<Person>
。我使用mapper如下:
mapper.getTypeFactory().constructCollectionType(List.class, Person.class)
其中Person.class
是:
public class Person {
public final String firstName;
public final String lastName;
@JsonCreator
public Person(@JsonProperty() String firstName, @JsonProperty String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
我想知道我是否可以某种方式将数组索引指定为@JsonProperty
参数而不是它的关键名称?
感谢bureaquete建议使用自定义反序列化器。但它更适合我用SimpleModule
而不是@JsonDeserialize
注释注册它。下面是完整的JUnit测试示例:
@RunWith(JUnit4.class)
public class MapArrayToObjectTest {
private static ObjectMapper mapper;
@BeforeClass
public static void setUp() {
mapper = new ObjectMapper();
SimpleModule customModule = new SimpleModule("ExampleModule", new Version(0, 1, 0, null));
customModule.addDeserializer(Person.class, new PersonDeserializer());
mapper.registerModule(customModule);
}
@Test
public void wrapperDeserializationTest() throws IOException {
//language=JSON
final String inputJson = "{\"persons\": [[\"John\", \"Doe\"], [\"Jane\", \"Doe\"]]}";
PersonsListWrapper deserializedList = mapper.readValue(inputJson, PersonsListWrapper.class);
assertThat(deserializedList.persons.get(0).lastName, is(equalTo("Doe")));
assertThat(deserializedList.persons.get(1).firstName, is(equalTo("Jane")));
}
@Test
public void listDeserializationTest() throws IOException {
//language=JSON
final String inputJson = "[[\"John\", \"Doe\"], [\"Jane\", \"Doe\"]]";
List<Person> deserializedList = mapper.readValue(inputJson, mapper.getTypeFactory().constructCollectionType(List.class, Person.class));
assertThat(deserializedList.get(0).lastName, is(equalTo("Doe")));
assertThat(deserializedList.get(1).firstName, is(equalTo("Jane")));
}
}
class PersonsListWrapper {
public List<Person> persons;
}
class Person {
final String firstName;
final String lastName;
Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
class PersonDeserializer extends JsonDeserializer<Person> {
@Override
public Person deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
JsonNode node = jp.readValueAsTree();
return new Person(node.get(0).getTextValue(), node.get(1).getTextValue());
}
}
请注意,如果您不需要包装器对象,则可以使用mapper将JSON数组[["John", "Doe"], ["Jane", "Doe"]]
直接反序列化为List<Person>
,如下所示:
List<Person> deserializedList = mapper.readValue(inputJson, mapper.getTypeFactory().constructCollectionType(List.class, Person.class));
它很容易序列化,但不容易以这种方式反序列化;
可以使用@JsonValue
将以下类序列化为字符串数组;
public class Person {
private String firstName;
private String lastName;
//getter,setter,constructors
@JsonValue
public List<String> craeteArr() {
return Arrays.asList(this.firstName, this.lastName);
}
}
但是要反序列化,我必须创建一个包装类,并使用@JsonDeserialize
自定义反序列化;
public class PersonWrapper {
@JsonDeserialize(using = CustomDeserializer.class)
private List<Person> persons;
//getter,setter,constructors
}
和自定义反序列化器本身;
public class CustomDeserializer extends JsonDeserializer<List<Person>> {
@Override
public List<Person> deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
JsonNode node = jsonParser.readValueAsTree();
ObjectMapper mapper = new ObjectMapper();
return IntStream.range(0, node.size()).boxed()
.map(i -> {
try {
List<String> values = mapper.readValue(node.get(i).toString(), List.class);
return new Person().setFirstName(values.get(0)).setLastName(values.get(1));
} catch (IOException e) {
throw new RuntimeException();
}
}).collect(Collectors.toList());
}
}
您需要在反序列化器逻辑中进行适当的验证,以检查每个迷你数组是否包含正好两个值,但这很有效。
我宁愿使用这些步骤,也许隐藏@JsonDeserialize
,我会做以下事情;
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonDeserialize(using = CustomDeserializer.class)
public @interface AcceptPersonAsArray {}
所以你可以在PersonWrapper
中使用一些自定义注释
public class PersonWrapper {
@AcceptPersonAsArray
private List<Person> persons;
//getter,setter,constructors
}
以上是关于使用Jackson将JSON数组反序列化为单个Java对象的主要内容,如果未能解决你的问题,请参考以下文章
使用 Jackson 和 Spring 将 JavaScript 数组反序列化为 Java LinkedHashSet 不会删除重复项
如何使用 Jackson 将原始 JSON 反序列化为 Java 对象
使用 Jackson 将 JSON 反序列化为 ArrayList<POJO>
在将 json 反序列化为对象时,使用 jackson 将 asp.net / MS 专有 json Dateformat 转换为 java8 LocalDateTime