将Json数组映射到Java模型 [英] Mapping Json Array to Java Models

查看:92
本文介绍了将Json数组映射到Java模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个复杂的json,如此处

I have a complex json as in here

我正在尝试将其映射到模型类"ChromeJsonModel"中,例如:

I am trying to map this in my model class 'ChromeJsonModel' like :

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

但是我收到以下错误.

Expected BEGIN_ARRAY but was BEGIN_OBJECT

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

Any reason why and where am I going wrong?

推荐答案

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

You have very complex JSON payload where the same property could have one JSON object or JSON array of objects. Gson does not handle this case by default and we need to implement custom deserialiser for this kind of one-or-many properties. Below I created simple POJO model which represents your JSON payload:

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属性.让我们为这些属性实现自定义反序列化器:

As you can see test-suite and test-case are List-es properties. Let's implement custom deserialiser for these properties:

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实例:

Class<E> is required in runtime to deserialise properly given JSON object. After that, let's create and customise Gson instance:

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来正确映射实例.

As, you can see, we registered two instances for each one-to-many types. We need to use TypeToken to have correct mapping of our instances.

另请参阅:

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

After playing with above solution I came up with below deserialiser:

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类,我们可以获取元素的类型并反序列化内部元素.简单用法:

We do not need to customise it. Using $Gson$Types class we can get type of element and deserialise internal element. Simple usage:

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

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

Above code should also work for you.

这篇关于将Json数组映射到Java模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆