将Json数组映射到Java模型

时间:2019-03-11 09:37:46

标签: java json gson

我在here中有一个复杂的json

我正在尝试将其映射到模型类“ ChromeJsonModel”中:

Type collectionType = new TypeToken<List<ChromeJsonModel>>(){}.getType();
List<ChromeJsonModel> jsonModelList = (List<ChromeJsonModel>) new Gson().fromJson( jsonPrettyPrintString , collectionType);

但是我收到以下错误。

Expected BEGIN_ARRAY but was BEGIN_OBJECT

我为什么会在哪里出问题?

3 个答案:

答案 0 :(得分:1)

您有非常复杂的JSON有效负载,其中相同的属性可能具有一个JSON objectJSON array个对象。 Gson默认情况下不处理这种情况,我们需要为这种one-or-many属性实现自定义反序列化器。下面,我创建了一个简单的POJO模型来表示您的JSON有效负载:

class TestResponse {

    @SerializedName("test-run")
    private TestRun testRun;

    // other properties, getters, setters, toString
}

class TestRun {

    @SerializedName("test-suite")
    private List<TestSuite> testSuite;

    // other properties, getters, setters, toString
}

class TestSuite {
    private String result;
    private double duration;

    @SerializedName("test-suite")
    private List<TestSuite> testSuites;

    @SerializedName("test-case")
    private List<TestCase> testCases;

    // other properties, getters, setters, toString
}

class TestCase {

    private String fullname;

    // other properties, getters, setters, toString
}

您会看到test-suitetest-caseList-es属性。让我们为这些属性实现自定义反序列化器:

class OneOrManyJsonDeserializer<E> implements JsonDeserializer<List<E>> {

    private final Class<E> clazz;

    public OneOrManyJsonDeserializer(Class<E> clazz) {
        this.clazz = clazz;
    }

    @Override
    public List<E> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json instanceof JsonArray) {
            final JsonArray array = (JsonArray) json;
            final int size = array.size();
            if (size == 0) {
                return Collections.emptyList();
            }
            final List<E> suites = new ArrayList<>(size);
            for (int i = 0; i < size; i++) {
                suites.add(context.deserialize(array.get(i), clazz));
            }

            return suites;
        }

        E suite = context.deserialize(json, clazz);
        return Collections.singletonList(suite);
    }
}
在运行时需要

Class<E>才能正确反序列化给定JSON object。之后,让我们创建和自定义Gson实例:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;

import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class GsonApp {

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

        Type testCaseListType = new TypeToken<List<TestCase>>() {}.getType();
        Type testSuiteListType = new TypeToken<List<TestSuite>>() {}.getType();
        Gson gson = new GsonBuilder()
                .registerTypeAdapter(testCaseListType, new OneOrManyJsonDeserializer<>(TestCase.class))
                .registerTypeAdapter(testSuiteListType, new OneOrManyJsonDeserializer<>(TestSuite.class))
                .setPrettyPrinting()
                .create();

        TestResponse response = gson.fromJson(new FileReader(jsonFile), TestResponse.class);
        System.out.println(response);
    }
}

您可以看到,我们为每种one-to-many类型注册了两个实例。我们需要使用TypeToken来正确映射实例。

另请参阅:

版本2

在使用上述解决方案后,我想到了以下反序列化器:

class OneOrManyJsonDeserializer implements JsonDeserializer<List<?>> {

    @Override
    public List<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        final Type elementType = $Gson$Types.getCollectionElementType(typeOfT, List.class);

        if (json instanceof JsonArray) {
            final JsonArray array = (JsonArray) json;
            final int size = array.size();
            if (size == 0) {
                return Collections.emptyList();
            }

            final List<?> suites = new ArrayList<>(size);
            for (int i = 0; i < size; i++) {
                suites.add(context.deserialize(array.get(i), elementType));
            }

            return suites;
        }

        Object suite = context.deserialize(json, elementType);
        return Collections.singletonList(suite);
    }
}

我们不需要自定义它。使用$Gson$Types类,我们可以获取元素的类型并反序列化内部元素。简单用法:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.annotations.SerializedName;
import com.google.gson.internal.$Gson$Types;

import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class GsonApp {

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

        Gson gson = new GsonBuilder()
                .registerTypeAdapter(List.class, new OneOrManyJsonDeserializer())
                .setPrettyPrinting()
                .create();

        TestResponse response = gson.fromJson(new FileReader(jsonFile), TestResponse.class);
        System.out.println(response);
    }
}

上面的代码也应该对您有用。

答案 1 :(得分:0)

我认为您可以使用杰克逊。

ObjectMapper mapper = new ObjectMapper();
List<ChromeJsonModel> participantJsonList = mapper.readValue(jsonString, new TypeReference<List<ChromeJsonModel>>(){});

答案 2 :(得分:0)

在您json中,根元素是json对象:

{    <---- HERE YOU HAVE "OBJECT"

  "test-run": {
    "duration": 508.56199999999995,
    "result": "Passed",
    ...
   }

}

更改:

List<ChromeJsonModel> jsonModelList = (List<ChromeJsonModel>) ... ;

收件人:

ChromeJsonModel jsonModelList = (ChromeJsonModel) ... ;

您可以尝试在其中生成POJO: http://pojo.sodhanalibrary.com/