我想使用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); } }
我期望得到以下输出:
{"General":{"Version":"0.1","Range":{"Start_Time":"now","End_Time":"never"}}}
但是调用函数toJSON()返回
toJSON()
{"General":{"Version":"0.1","Range":{}}}
看来GSON无法在Map Range内序列化Map General。这是GSON的限制,还是我在这里做错了?
Range
General
Nishant的答案之所以起作用,是因为Gson的默认构造函数默认启用了所有东西,否则您将不得不使用GsonBuilder手动启用它们。
从JavaDocs:
使用默认配置构造一个Gson对象。默认配置具有以下设置: * toJson方法生成的JSON以紧凑形式表示。这意味着将删除所有不需要的空格。您可以使用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注释。您可以允许Gson通过GsonBuilder.setVersion(double)使用此注释。 * 输出Json的默认字段命名策略与Java中的相同。因此,Java类字段versionNumber在Json中将作为“ versionNumber @”输出。相同的规则也适用于将传入的Json映射到Java类。您可以通过GsonBuilder.setFieldNamingPolicy(FieldNamingPolicy)更改此策略。 * 默认情况下,Gson在进行序列化和反序列化时不考虑瞬态或静态字段。您可以通过GsonBuilder.excludeFieldsWithModifiers(int)更改此行为。
使用默认配置构造一个Gson对象。默认配置具有以下设置:
* toJson方法生成的JSON以紧凑形式表示。这意味着将删除所有不需要的空格。您可以使用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注释。您可以允许Gson通过GsonBuilder.setVersion(double)使用此注释。 * 输出Json的默认字段命名策略与Java中的相同。因此,Java类字段versionNumber在Json中将作为“ versionNumber @”输出。相同的规则也适用于将传入的Json映射到Java类。您可以通过GsonBuilder.setFieldNamingPolicy(FieldNamingPolicy)更改此策略。 * 默认情况下,Gson在进行序列化和反序列化时不考虑瞬态或静态字段。您可以通过GsonBuilder.excludeFieldsWithModifiers(int)更改此行为。
好的,现在我看到了问题所在。如您所料,默认的Map序列化程序不支持嵌套映射。正如您从DefaultTypeAdapters的此源代码片段中看到的(尤其是如果您使用调试器进行调试),由于某种神秘的原因,该变量childGenericType被设置为类型java.lang.Object,因此永远不会分析该值的运行时类型。
childGenericType
java.lang.Object
我猜有两种解决方案:
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();
}