如何创建 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;