如何使用GSON序列化地图的地图?

asm*_*ier 11 java json map gson

我想使用GSON将下面的Example类序列化为JSON.

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.LinkedHashMap;

public class Example
{
    private LinkedHashMap<String,Object> General;

    private static final String VERSION="Version";
    private static final String RANGE="Range";
    private static final String START_TIME="Start_Time";
    private static final String END_TIME="End_Time";

    public Example() {
        General = new LinkedHashMap<String,Object>();
        General.put(VERSION, "0.1");

        LinkedHashMap<String,String> Range = new LinkedHashMap<String, String>();
        Range.put(START_TIME, "now");
        Range.put(END_TIME, "never");

        General.put(RANGE, Range);
    }

    public String toJSON() {
        Gson gson = new GsonBuilder().serializeNulls().create();
        return gson.toJson(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望得到以下输出:

{"General":{"Version":"0.1","Range":{"Start_Time":"now","End_Time":"never"}}}
Run Code Online (Sandbox Code Playgroud)

但是调用函数会toJSON()返回

{"General":{"Version":"0.1","Range":{}}}
Run Code Online (Sandbox Code Playgroud)

似乎GSON无法在Map中序列化RangeMap General.这是GSON的限制还是我在这里做错了什么?

Sea*_*oyd 9

Nishant的答案之所以能够解决,是因为Gson的默认构造函数支持默认情况下所有类型的东西,否则你必须手动使用GsonBuilder.

来自JavaDocs:

使用默认配置构造Gson对象.默认配置具有以下设置:

  • toJson方法生成的JSON是紧凑的表示形式.这意味着删除了所有不需要的空白区域.您可以使用GsonBuilder.setPrettyPrinting()更改此行为.
  • 生成的JSON省略了所有空字段.请注意,由于数组是有序列表,因此数组中的空值保持不变.此外,如果字段不为null,但其生成的JSON为空,则保留该字段.您可以通过设置GsonBuilder.serializeNulls()将Gson配置为序列化空值.
  • Gson为Enums,Map,java.net.URL,java.net.URI,java.util.Locale,java.util.Date,java.math.BigDecimal和java.math.BigInteger类提供默认序列化和反序列化.如果您希望更改默认表示,可以通过GsonBuilder.registerTypeAdapter(Type,Object)注册类型适配器来实现.
  • 默认日期格式与java.text.DateFormat.DEFAULT相同.此格式忽略序列化期间日期的毫秒部分.您可以通过调用GsonBuilder.setDateFormat(int)或GsonBuilder.setDateFormat(String)来更改此设置.
  • 默认情况下,Gson会忽略com.google.gson.annotations.Expose注释.您可以通过GsonBuilder.excludeFieldsWithoutExposeAnnotation()使Gson仅对通过此批注标记的字段进行序列化/反序列化.
  • 默认情况下,Gson会忽略com.google.gson.annotations.Since注释.您可以通过GsonBuilder.setVersion(double)启用Gson来使用此批注.
  • 输出Json的默认字段命名策略与Java中的相同.因此,Java类字段versionNumber将在Json中作为"versionNumber @"输出.应用相同的规则将传入的Json映射到Java类.您可以通过GsonBuilder.setFieldNamingPolicy(FieldNamingPolicy)更改此策略.
  • 默认情况下,Gson从序列化和反序列化的考虑中排除瞬态或静态字段.您可以通过GsonBuilder.excludeFieldsWithModifiers(int)更改此行为.

好的,现在我明白了问题所在.默认的Map序列化程序,如您所料,不支持嵌套映射.正如您在DefaultTypeAdapters的源代码片段中看到的那样(特别是如果您使用调试器),变量childGenericType被设置java.lang.Object为某种神秘原因的类型,因此永远不会分析该值的运行时类型.

我猜两种解决方案:

  1. 实现自己的Map serializer/deserializer
  2. 使用更复杂的方法版本,如下所示:

    public String toJSON(){
        final Gson gson = new Gson();
        final JsonElement jsonTree = gson.toJsonTree(General, Map.class);
        final JsonObject jsonObject = new JsonObject();
        jsonObject.add("General", jsonTree);
        return jsonObject.toString();
    }
    
    Run Code Online (Sandbox Code Playgroud)