简体   繁体   English

如何反序列化 Java 中的 JSON 对象数组

[英]How to Deserialize Array of JSON Objects in Java

So I'm used to getting JSON objects from a given API/endpoint, eg:所以我习惯于从给定的 API/端点获取 JSON 对象,例如:

{
    "count": 5,
    "results": [
        {
            "example": "test",
            "is_valid": true
        },
        {
            "example": "test2",
            "is_valid": true
        }
    ]
}

And in a custom deserializer that extends com.fasterxml.jackson.databind.deser.std.并在扩展 com.fasterxml.jackson.databind.deser.std 的自定义解串器中。 StdDeserializer , I know I can use the JsonParser object like so to get the base node to work off of, ie: StdDeserializer ,我知道我可以像这样使用 JsonParser object 来使基本节点正常工作,即:

@Override
public ResultExample deserialize(JsonParser jp, DeserializationContext ctxt) {
    JsonNode node = jp.getCodec().readTree(jp);
    JsonNode count = node.get("count");
    // code to put parsed objects into a ResultExample object...
}

However, I just encountered an API that simply returns an array of JSON objects, eg:但是,我刚刚遇到了一个 API ,它只返回一个 JSON 对象数组,例如:

[
    {
        "example": "test",
        "is_valid": true
    },
    {
        "example": "test2",
        "is_valid": true
    },
]

So, I don't believe I can just parse this the same way as before.所以,我不相信我可以像以前一样解析这个。 What would be the correct way to parse this using Jackson?使用 Jackson 解析这个的正确方法是什么?

This may help you:这可能会帮助您:

import java.io.IOException;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Test {
    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        String json = "[\r\n" + "    {\r\n" + "        \"example\": \"test\",\r\n" + "        \"is_valid\": true\r\n"
                + "    },\r\n" + "    {\r\n" + "        \"example\": \"test2\",\r\n" + "        \"is_valid\": true\r\n"
                + "    }\r\n" + "]";
        Example[] ex = mapper.readValue(json, Example[].class);

    }

}

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({ "example", "is_valid" })
class Example {

    @JsonProperty("example")
    private String example;
    @JsonProperty("is_valid")
    private Boolean isValid;

    public String getExample() {
        return example;
    }

    @JsonProperty("example")
    public void setExample(String example) {
        this.example = example;
    }

    @JsonProperty("is_valid")
    public Boolean getIsValid() {
        return isValid;
    }

    @JsonProperty("is_valid")
    public void setIsValid(Boolean isValid) {
        this.isValid = isValid;
    }
}

When response is a JSON Object you can use default bean deserialiser.当响应是JSON Object ,您可以使用默认的 bean 解串器。 In case it is a JSON Array you can read it as array and create response object manually.如果它是JSON Array ,您可以将其读取为数组并手动创建响应 object。 Below you can find example custom deserialiser and BeanDeserializerModifier which is used to register custom deserialiser.您可以在下面找到示例自定义反序列化器和用于注册自定义反序列化器的BeanDeserializerModifier BeanDeserializerModifier allows to use default deserialiser when JSON payload fits POJO model:JSON有效负载适合POJO model 时, BeanDeserializerModifier允许使用默认解串器:

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.BeanDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializerBase;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.CollectionType;

import java.io.File;
import java.io.IOException;
import java.util.List;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        SimpleModule module = new SimpleModule();
        module.setDeserializerModifier(new BeanDeserializerModifier() {
            @Override
            public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
                if (beanDesc.getBeanClass() == Response.class) {
                    return new ResponseJsonDeserializer((BeanDeserializerBase) deserializer);
                }
                return super.modifyDeserializer(config, beanDesc, deserializer);
            }
        });

        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(module);


        System.out.println(mapper.readValue(jsonFile, Response.class));
    }
}

class ResponseJsonDeserializer extends BeanDeserializer {

    private final BeanDeserializerBase baseDeserializer;

    protected ResponseJsonDeserializer(BeanDeserializerBase src) {
        super(src);
        this.baseDeserializer = src;
    }

    @Override
    public Response deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        if (p.currentToken() == JsonToken.START_OBJECT) {
            return (Response) baseDeserializer.deserialize(p, ctxt);
        }
        if (p.currentToken() == JsonToken.START_ARRAY) {
            CollectionType collectionType = ctxt.getTypeFactory().constructCollectionType(List.class, Item.class);
            JsonDeserializer<Object> deserializer = ctxt.findRootValueDeserializer(collectionType);
            List<Item> results = (List<Item>) deserializer.deserialize(p, ctxt);

            Response response = new Response();
            response.setCount(results.size());
            response.setResults(results);

            return response;
        }

        throw MismatchedInputException.from(p, Response.class, "Only object or array!");
    }
}

class Response {

    private int count;
    private List<Item> results;

    // getters, setters, toString
}

class Item {

    private String example;

    @JsonProperty("is_valid")
    private boolean isValid;

    // getters, setters, toString
}

Above code for JSON Object payload prints:上面的代码JSON Object有效载荷打印:

Response{count=5, results=[Item{example='test', isValid=true}, Item{example='test2', isValid=true}]}

And for JSON Array payload prints:对于JSON Array有效载荷打印:

Response{count=2, results=[Item{example='test', isValid=true}, Item{example='test2', isValid=true}]}

Guess I should have just written the unit test before asking the question, but apparently you can just do it the same way.我想我应该在问问题之前就写好单元测试,但显然你可以用同样的方式来做。 Only difference is the base node is a JsonArray which you have to iterate over.唯一的区别是基节点是一个 JsonArray ,您必须对其进行迭代。 Thanks everyone who looked into this.感谢所有对此进行调查的人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM