How do I parse this JSON response into POJO

ε祈祈猫儿з 提交于 2021-01-29 11:03:29

问题


I have the following Test class:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ibm.cio.cloud.cost.model.ElasticResponse;
import com.jayway.jsonpath.JsonPath;

@JsonIgnoreProperties(ignoreUnknown = true)
public class TestJSONPaths {

    private static final String json = "{\"hits\":{\"total\":1,\"hits\":[{\"_id\":\"oEE4j2QBXCNPxFWHqq3i\",\"_score\":1.0,\"_source\":{\"status\":\"SUCCESSFUL\",\"reason\":\"OK, Single ACTIVE status can process\"}}]}}";

    public static void main(String[] args) {
        List<String> strippedJSON = JsonPath.read(json, "$.hits.hits._source");
        ElasticResponse response = null;
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, true);

        try {
            System.out.println("From this json string:" + strippedJSON + "\n");
            response = mapper.readValue(strippedJSON.toString(), ElasticResponse.class);
            System.out.println("ElasticDocument=" + mapper.writerWithDefaultPrettyPrinter().writeValueAsString(response.getDocuments()));
        } catch (JsonGenerationException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Here is the ElasticResponse class def:

public class ElasticResponse {
    private List<ElasticDocument> documents;
    public List<ElasticDocument> getDocuments() {
        return documents;
    }
    public void setDocuments(List<ElasticDocument> documents) {
        this.documents = documents;
    }
}

public class ElasticDocument {
    private String _id;

    private String status;
    private String reason;

   ... getters/setters
}

I'm trying to get a ElasticDocument object mapped from the JSON given but it's throwing the following errors below. I'm attempting to filtered out the JSON to simply be: [{_source document values }]. This error occurs on the very first line in the Main class. How can I map this Json?

[DEBUG] Evaluating path: $['hits']['hits']['_source']
Exception in thread "main" com.jayway.jsonpath.PathNotFoundException: Expected to find an object with property ['_source'] in path $['hits']['hits'] but found 'net.minidev.json.JSONArray'. This is not a json object according to the JsonProvider: 'com.jayway.jsonpath.spi.json.JsonSmartJsonProvider'.
    at com.jayway.jsonpath.internal.path.PropertyPathToken.evaluate(PropertyPathToken.java:71)
    at com.jayway.jsonpath.internal.path.PathToken.handleObjectProperty(PathToken.java:81)
    at com.jayway.jsonpath.internal.path.PropertyPathToken.evaluate(PropertyPathToken.java:79)
    at com.jayway.jsonpath.internal.path.PathToken.handleObjectProperty(PathToken.java:81)
    at com.jayway.jsonpath.internal.path.PropertyPathToken.evaluate(PropertyPathToken.java:79)
    at com.jayway.jsonpath.internal.path.RootPathToken.evaluate(RootPathToken.java:62)
    at com.jayway.jsonpath.internal.path.CompiledPath.evaluate(CompiledPath.java:53)
    at com.jayway.jsonpath.internal.path.CompiledPath.evaluate(CompiledPath.java:61)
    at com.jayway.jsonpath.JsonPath.read(JsonPath.java:187)
    at com.jayway.jsonpath.internal.JsonContext.read(JsonContext.java:102)
    at com.jayway.jsonpath.internal.JsonContext.read(JsonContext.java:89)
    at com.jayway.jsonpath.JsonPath.read(JsonPath.java:502)
    at com.ibm.cio.cloud.cost.TestJSONPaths.main(TestJSONPaths.java:18)

回答1:


The exception is due to the jsonpath returning an array instead of an object, so if you fix the jsonpath to look like this:

$.hits.hits[*]._source

Then it will evaluate properly. However, this probably still doesn't do what you want it to do.. The JsonPath.read() will deserialise the JSON for you. But you have to watch out with this:

public class Test {

    private static final String json = "{\"hits\":{\"total\":1,\"hits\":[{\"_id\":\"oEE4j2QBXCNPxFWHqq3i\",\"_score\":1.0,\"_source\":{\"status\":\"SUCCESSFUL\",\"reason\":\"OK, Single ACTIVE status can process\"}}]}}";


    public static void main(String[] args) {
        List<ElasticDocument> docs = JsonPath.read(json, "$.hits.hits[*]._source");

        System.out.println("elasticDoc: " + docs.get(0));
    }

    public static class ElasticDocument {
        public String _id;

        public String status;
        public String reason;

        @Override
        public String toString() {
            return "ElasticDocument{" +
                    "_id='" + _id + '\'' +
                    ", status='" + status + '\'' +
                    ", reason='" + reason + '\'' +
                    '}';
        }
    }
}

Looks like it works, however the docs List is now actually a List of Maps. Apparently It's possible to register JsonPath with Jackson but I can't make it work

Alternatively you can use Jackson to deserialise the JSON, then you should create an object model that matches the json structure and then you can use the ObjectMapper to do the deserialisation

public class Test {

    private static final String json = "{\"hits\":{\"total\":1,\"hits\":[{\"_id\":\"oEE4j2QBXCNPxFWHqq3i\",\"_score\":1.0,\"_source\":{\"status\":\"SUCCESSFUL\",\"reason\":\"OK, Single ACTIVE status can process\"}}]}}";

    public static void main(String[] args) {

        System.out.println("From this json string:" + json + "\n");

        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY, true);

        try {

            HitsResource hitsResource = mapper.readValue(json, HitsResource.class);

            System.out.println("jackson elasticDoc: " + hitsResource.hitsParent.hits.get(0).source);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static class HitsResource {
        @JsonProperty("hits")
        public HitsParent hitsParent;

        @Override
        public String toString() {
            return "HitsResource{" +
                    "hitsParent=" + hitsParent +
                    '}';
        }
    }

    public static class HitsParent {
        @JsonProperty("total")
        public Long total;
        @JsonProperty("hits")
        public List<Hits> hits;

        @Override
        public String toString() {
            return "HitsParent{" +
                    "total=" + total +
                    ", hits=" + hits +
                    '}';
        }
    }

    public static class Hits {
        @JsonProperty("_id")
        public String id;
        @JsonProperty("_score")
        public BigDecimal score;
        @JsonProperty("_source")
        public ElasticDocument source;

        @Override
        public String toString() {
            return "Hits{" +
                    "id='" + id + '\'' +
                    ", score=" + score +
                    ", source=" + source +
                    '}';
        }
    }

        public static class ElasticDocument {
            @JsonProperty("_id")
            public String _id;

            @JsonProperty("status")
            public String status;

            @JsonProperty("reason")
            public String reason;

            @Override
            public String toString() {
                return "ElasticDocument{" +
                        "_id='" + _id + '\'' +
                        ", status='" + status + '\'' +
                        ", reason='" + reason + '\'' +
                        '}';
            }
        }
}


来源:https://stackoverflow.com/questions/51371785/how-do-i-parse-this-json-response-into-pojo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!