Как мне разобрать этот ответ JSON в POJO

У меня есть следующий тестовый класс:

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();
        }
    }
}

Вот определение класса ElasticResponse:

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
}

Я пытаюсь получить объект ElasticDocument, сопоставленный с данным JSON, но он выдает следующие ошибки ниже. Я пытаюсь отфильтровать JSON, чтобы он был просто: [{_значения исходного документа}]. Эта ошибка возникает в самой первой строке класса Main. Как я могу сопоставить этот 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)

person JamesD    schedule 17.07.2018    source источник
comment
вам нужно будет добавить исходный json (свойство json в первой строке основного метода)   -  person stringy05    schedule 17.07.2018
comment
спасибо stringy05   -  person JamesD    schedule 17.07.2018


Ответы (1)


Исключение связано с тем, что jsonpath возвращает массив вместо объекта, поэтому, если вы исправите jsonpath, чтобы он выглядел так:

$.hits.hits[*]._source

Тогда он будет правильно оценивать. Однако это, вероятно, все еще не делает то, что вы хотите. JsonPath.read() десериализует JSON для вас. Но с этим надо быть осторожнее:

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 + '\'' +
                    '}';
        }
    }
}

Похоже, это работает, однако docs List теперь на самом деле List из Map. По-видимому, можно зарегистрировать JsonPath с Джексоном, но я не могу заставить его работать

В качестве альтернативы вы можете использовать Jackson для десериализации JSON, тогда вам следует создать объектную модель, которая соответствует структуре json, а затем вы можете использовать ObjectMapper для десериализации

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 + '\'' +
                        '}';
            }
        }
}
person stringy05    schedule 17.07.2018
comment
Ваш второй подход - это то, к чему я пытался добраться, хотя и безуспешно. Я не мог понять структуру класса для этого JSON, вы показали мне, как именно это нужно сделать - большое спасибо. - person JamesD; 17.07.2018