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

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

import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.util.LinkedHashMap; public class Example { private LinkedHashMap 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(); General.put(VERSION, "0.1"); LinkedHashMap Range = new LinkedHashMap(); 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); } } 

我希望得到以下输出:

 {"General":{"Version":"0.1","Range":{"Start_Time":"now","End_Time":"never"}}} 

但是调用函数toJSON()返回

 {"General":{"Version":"0.1","Range":{}}} 

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

Nishant的答案之所以有效,是因为Gson的默认构造函数可以为默认情况下启用所有类型的东西,否则你必须手动使用GsonBuilder。

来自JavaDocs :

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

  • toJson方法生成的JSON是紧凑的表示forms。 这意味着删除了所有不需要的空白区域。 您可以使用GsonBuilder.setPrettyPrinting()更改此行为。
  • 生成的JSON省略了所有null的字段。 请注意,由于数组是有序列表,因此数组中的空值保持不变。 此外,如果字段不为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(); } 

尝试这个:

 Gson gson = new Gson(); System.out.println(gson.toJson(General)); 

不确定你是否还在寻找解决方案,这对我有用:

 import java.util.LinkedHashMap; import com.google.common.collect.ImmutableMap; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class Example { // private static LinkedHashMap General; private ImmutableMap 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() { LinkedHashMap Range = new LinkedHashMap(); Range.put(START_TIME, "now"); Range.put(END_TIME, "never"); // General.put(RANGE, Range); General = ImmutableMap.of(VERSION, "0.1", RANGE, Range); } public String toJSON() { // Gson gson = new GsonBuilder().serializeNulls().create(); Gson gson = new Gson(); return gson.toJson(this); } } 

返回:{“常规”:{“版本”:“0.1”,“范围”:{“Start_Time”:“now”,“End_Time”:“never”}}}


显然你可以在这里使用ImmutableMap.copyOf(your_hashmap)

一个更简单的替代方案是使用Jackson而不是GSON,嵌套地图的序列化开箱即用:

  LinkedHashMap general; general = new LinkedHashMap(); general.put("Version", "0.1"); LinkedHashMap Range = new LinkedHashMap(); Range.put("Start_Time", "now"); Range.put("End_Time", "never"); general.put("Range", Range); // Serialize the map to json using Jackson ByteArrayOutputStream os = new ByteArrayOutputStream(); new org.codehaus.jackson.map.ObjectMapper().writer().writeValue(os, general); String json = os.toString(); os.close(); System.out.println(json); 

输出:

{ “版本”: “0.1”, “范围”:{ “START_TIME”: “现在”, “END_TIME”: “从来没有”}}