如何创建 POJO 来处理 JSON 具有元素数组和元素数组的数据
How to create the POJO to handle JSON data having array of elements as well as array of array of elements
我们有一个场景,我们有 JSON
个字段有 2 个不同的值。我们想使用相同的 POJO
解析所有 json。您可以在下方找到这 2 个 JSON
有效负载:
{
"values": [
[
{
"name": "item_name",
"value": "pool"
}
],
[
{
"name": "item_name",
"value": "Mob"
}
]
],
"name": "lines"
}
并且:
{
"values": [
{
"name": "pack",
"value": "Enter, HD"
}
],
"name": "lines"
}
目前,如果我如下指定 POJO,第二个 json 会抛出异常
class ValuesModel extends Serializable {
@BeanProperty
var values: List[List[ValueModel]] = _
}
如果我如下指定 POJO,第一个 json 抛出异常
class ValuesModel extends Serializable {
@BeanProperty
var values: List[ValueModel] = _
}
有没有一种方法可以创建一个 POJO
来同时解析两个 json 而不是捕获异常并使用另一个模式进行解析?我正在使用 Jackson
来解析。
在这种情况下,您想要处理多个 JSON
模式并能够将其反序列化为相同的 POJO
模型,您需要实现自定义反序列化器并实现所有必需的场景。
您可以在下面的 Java
中找到如何反序列化两个 JSON
有效负载的示例:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.node.MissingNode;
import com.fasterxml.jackson.databind.type.SimpleType;
import com.fasterxml.jackson.databind.util.TokenBuffer;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./src/main/resources/test.json");
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue(jsonFile, ValuesModel.class));
}
}
class ValuesModelJsonDeserializer extends JsonDeserializer<List<ValueModel>> {
@Override
public List<ValueModel> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
final JsonDeserializer<Object> deserializer = ctxt.findRootValueDeserializer(SimpleType.constructUnsafe(ValueModel.class));
final JsonNode root = p.readValueAsTree();
// If node is a JSON object
if (root.isObject()) {
return Collections.singletonList(deserialize(p.getCodec(), root, deserializer, ctxt));
}
if (!root.isArray()) {
// value is null or primitive
return Collections.emptyList();
}
return StreamSupport.stream(root.spliterator(), false)
.map(this::unwrap)
.filter(node -> !node.isMissingNode())
.map(node -> deserialize(p.getCodec(), node, deserializer, ctxt))
.collect(Collectors.toList());
}
private JsonNode unwrap(JsonNode node) {
if (node.isArray()) {
if (node.isEmpty()) {
return MissingNode.getInstance();
}
return node.iterator().next();
}
return node;
}
private ValueModel deserialize(ObjectCodec codec, JsonNode value, JsonDeserializer<Object> valueDeser, DeserializationContext ctxt) {
try (JsonParser jsonParser = createNestedParser(codec, value)) {
return (ValueModel) valueDeser.deserialize(jsonParser, ctxt);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
private JsonParser createNestedParser(ObjectCodec codec, JsonNode value) throws IOException {
TokenBuffer buffer = new TokenBuffer(codec, false);
codec.writeTree(buffer, value);
JsonParser parser = buffer.asParser();
parser.nextToken();
return parser;
}
}
要注册自定义反序列化器,您可以使用 @JsonDeserialize
注释:
@JsonDeserialize(using = ValuesModelJsonDeserializer.class)
private List<ValueModel> values;
我们有一个场景,我们有 JSON
个字段有 2 个不同的值。我们想使用相同的 POJO
解析所有 json。您可以在下方找到这 2 个 JSON
有效负载:
{
"values": [
[
{
"name": "item_name",
"value": "pool"
}
],
[
{
"name": "item_name",
"value": "Mob"
}
]
],
"name": "lines"
}
并且:
{
"values": [
{
"name": "pack",
"value": "Enter, HD"
}
],
"name": "lines"
}
目前,如果我如下指定 POJO,第二个 json 会抛出异常
class ValuesModel extends Serializable {
@BeanProperty
var values: List[List[ValueModel]] = _
}
如果我如下指定 POJO,第一个 json 抛出异常
class ValuesModel extends Serializable {
@BeanProperty
var values: List[ValueModel] = _
}
有没有一种方法可以创建一个 POJO
来同时解析两个 json 而不是捕获异常并使用另一个模式进行解析?我正在使用 Jackson
来解析。
在这种情况下,您想要处理多个 JSON
模式并能够将其反序列化为相同的 POJO
模型,您需要实现自定义反序列化器并实现所有必需的场景。
您可以在下面的 Java
中找到如何反序列化两个 JSON
有效负载的示例:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.node.MissingNode;
import com.fasterxml.jackson.databind.type.SimpleType;
import com.fasterxml.jackson.databind.util.TokenBuffer;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./src/main/resources/test.json");
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.readValue(jsonFile, ValuesModel.class));
}
}
class ValuesModelJsonDeserializer extends JsonDeserializer<List<ValueModel>> {
@Override
public List<ValueModel> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
final JsonDeserializer<Object> deserializer = ctxt.findRootValueDeserializer(SimpleType.constructUnsafe(ValueModel.class));
final JsonNode root = p.readValueAsTree();
// If node is a JSON object
if (root.isObject()) {
return Collections.singletonList(deserialize(p.getCodec(), root, deserializer, ctxt));
}
if (!root.isArray()) {
// value is null or primitive
return Collections.emptyList();
}
return StreamSupport.stream(root.spliterator(), false)
.map(this::unwrap)
.filter(node -> !node.isMissingNode())
.map(node -> deserialize(p.getCodec(), node, deserializer, ctxt))
.collect(Collectors.toList());
}
private JsonNode unwrap(JsonNode node) {
if (node.isArray()) {
if (node.isEmpty()) {
return MissingNode.getInstance();
}
return node.iterator().next();
}
return node;
}
private ValueModel deserialize(ObjectCodec codec, JsonNode value, JsonDeserializer<Object> valueDeser, DeserializationContext ctxt) {
try (JsonParser jsonParser = createNestedParser(codec, value)) {
return (ValueModel) valueDeser.deserialize(jsonParser, ctxt);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
private JsonParser createNestedParser(ObjectCodec codec, JsonNode value) throws IOException {
TokenBuffer buffer = new TokenBuffer(codec, false);
codec.writeTree(buffer, value);
JsonParser parser = buffer.asParser();
parser.nextToken();
return parser;
}
}
要注册自定义反序列化器,您可以使用 @JsonDeserialize
注释:
@JsonDeserialize(using = ValuesModelJsonDeserializer.class)
private List<ValueModel> values;