如何用Java在Gson中表示混合数据类型的Json对象

时间:2016-01-23 22:36:53

标签: java json gson

我将一些Json序列化为Java对象时遇到了一些困难。如您所见,Json位包含顶级元素args,其中包含一个对象列表,其中包含String作为键和混合值的值。我在Java源文件中尝试了一些创造性的东西:

的Json

{
    "args": {
        "all": {
            "expectCliArgs": true
        },
        "Prog3a": {
            "expectedNumberOfCliArgs": 2,
            "expectedErrorMessage": "Usage: java Prog3a infilename searchword"
        },
        "Prog3b": {
            "expectedNumberOfCliArgs": 2,
            "expectedErrorMessage": "Usage: java Prog3b infileName outfileName"
        },
        "Prog3c": {
            "expectedNumberOfCliArgs": 1,
            "expectedErrorMessage": "Usage: java Prog3c infileName"
        }
    }
}

爪哇

protected class Args {
    public Map<String, Set<Map<String, Object>>> map = new HashMap<>(); // no dice
}

protected class Args {
    public Map<String, Set<Map<String, ?>>> map = new HashMap<>(); // no dice
}

我可能需要custom serializer吗?

更新 我试着在课堂上做以下几点(按照答案):

private Map<String, Set<ExpectedArgs>> args = new HashMap<>();

protected class ExpectedArgs {
    public Boolean expectCliArgs;
    public Integer expectedNumberOfCliArgs;
    public String expectedArgsErrorMessage;
}

但现在好像Gson抱怨我的Json文件的语法:

Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 847
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:176)
    at com.google.gson.Gson.fromJson(Gson.java:803)
    at com.google.gson.Gson.fromJson(Gson.java:768)
    at com.google.gson.Gson.fromJson(Gson.java:717)
    at com.google.gson.Gson.fromJson(Gson.java:689)
    at javaGrader.config.ParseConfig.convertJsonToObject(ParseConfig.java:72)
    at javaGrader.config.ParseConfig.parseConfig(ParseConfig.java:34)
    at javaGrader.JavaGrader.main(JavaGrader.java:60)
Disconnected from the target VM, address: '127.0.0.1:62344', transport: 'socket'
Caused by: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 847
    at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:338)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:79)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:60)
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:187)
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:93)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:172)
    ... 7 more

我在我的Json文件中设置了一些断点,看起来“args”对象是导致胃灼热的对象。作为参考,这里是full Json filejava Config classthe class where Gson runs。看起来Gson将我的对象与数组混淆。

Col 847是:

searchword"},"Prog3b":{
             ^

有什么想法吗?

Gson error

更新2 我对变量的签名不正确:

private Map<String, Set<ExpectedArgs>> args = new HashMap<>();  // wrong
private Map<String, ExpectedArgs> args = new HashMap<>(); // right

1 个答案:

答案 0 :(得分:2)

我会为包含两组字段的内部对象定义一个类,如下所示:

public static class ExpectedArgs {
    public Boolean expectCliArgs;
    public Integer expectedNumberOfCliArgs;
    public String expectedErrorMessage;
}

(注意我在这里故意使用BooleanInteger而不是booleanint,这样您就可以通过测试{{{{}}来判断该字段是否已设置1}}。)

然后你可以像这样定义外部类:

null

最后,您可以将JSON反序列化为public static class Data { public Map<String, ExpectedArgs> args; }

的实例
Data

此代码为您的示例JSON输出以下内容:

String json = "...";

Gson gson = new Gson();

Data data = gson.fromJson(json, Data.class);

data.args.forEach((key, value) -> {
    System.out.println(key);
    System.out.println(value.expectCliArgs);
    System.out.println(value.expectedNumberOfCliArgs);
    System.out.println(value.expectedErrorMessage);
    System.out.println();
});