为什么使用GSON的Java没有将我的对象序列化为适当的JSON格式?

唯一的事情是我的对象包括枚举

class A { String id; Error error; } enum Error { int code; String message; // constructor that defines the intake of code and message INVALID(0,"Does not exist"), SERVER_ERROR(1,"Server error"); } 

如何使用gson序列化以获取此JSON字符串?

 [{id:"123",error {code:"0",message:"Does not exist"}] 

默认情况下,Gson不会为您提供所需的JSON字符串,您必须使用特定的序列化程序自定义Gson。 这里是:

 package stackoverflow.questions.q19715374; import java.lang.reflect.Type; import java.util.*; import com.google.gson.*; public class CustomSerializer implements JsonSerializer { @Override public JsonElement serialize(Error error, Type typeOfSrc, JsonSerializationContext context) { if (error == null) return null; else { JsonObject jo = new JsonObject(); jo.add("code", new JsonPrimitive(error.code)); jo.add("message", new JsonPrimitive(error.message)); return jo; } } } 

以及如何使用它。

 public static void main(String[] args) { A a = new A(); a.id="XX"; a.error = Error.INVALID; Gson defaultGson = new Gson(); System.out.println("With default Gson: "+defaultGson.toJson(a)); GsonBuilder gb = new GsonBuilder(); gb.registerTypeAdapter(Error.class, new CustomSerializer()); Gson customGson = gb.create(); System.out.println("With custom Gson: "+ customGson.toJson(a)); } 

这是执行结果:

 With default Gson: {"id":"XX","error":"INVALID"} With custom Gson: {"id":"XX","error":{"code":0,"message":"Does not exist"}} 

请注意您发布的JSON无效,需要冒号。

为什么? (如果你愿意,你可以跳过)

您还询问了为什么序列化枚举值的名称而不是其“属性”。 答案很简单,Gson的默认行为是使用EnumTypeAdapter 。 此类减少枚举的序列化以打印输出枚举值的名称和反序列化以从其名称获取枚举值。

因此,如果要序列化枚举的属性,则必须使用我向您展示的自定义序列化程序。 要从使用自定义序列化程序生成的Json反序列化,还需要一个自定义反序列化器,将代码(在本例中)映射到枚举值。

编辑如果要为此案例编写反序列化器,则需要像这样更改Error

 public enum Error { INVALID(0, "Does not exist"), SERVER_ERROR(1, "Server error"); int code; String message; private Error(int code, String message) { this.code = code; this.message = message; } static private Map map; static { map = new TreeMap(); map.put(INVALID.code, INVALID); map.put(SERVER_ERROR.code, SERVER_ERROR); } public static Error getByCode(int code) { return map.get(code); } } 

然后解串器很简单。

 public class CustomDeserializer implements JsonDeserializer { public Error deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { if (json == null) return null; else { JsonElement e = json.getAsJsonObject().get("code"); if (e == null || e instanceof JsonNull) return null; int code = e.getAsInt(); return Error.getByCode(code); } } } 

这是如何配置Gson使用它:

  GsonBuilder gb2 = new GsonBuilder(); gb2.registerTypeAdapter(Error.class, new CustomDeserializer()); Gson customGson2 = gb2.create(); String jsonTest1 = "{\"id\":\"AA\",\"error\":{\"code\":1}}"; String jsonTest2 = "{\"id\":\"BB\"}"; String jsonTest3 = "{\"id\":\"CC\",\"error\":{\"code\":42, \"message\":\"This is the answer\"}}"; System.out.println("Deserialize test 1: "+ customGson2.fromJson(jsonTest1, A.class)); System.out.println("Deserialize test 2: "+ customGson2.fromJson(jsonTest2, A.class)); System.out.println("Deserialize test 3: "+ customGson2.fromJson(jsonTest3, A.class)); 

这可以得到这个结果:

 Deserialize test 1: A [id=AA, error=SERVER_ERROR] Deserialize test 2: A [id=BB, error=null] Deserialize test 3: A [id=CC, error=null] 

我假设代码是枚举的唯一(替代)标识符,因此可以省略消息字段。 请注意,如果代码为null或未找到,则会出现null Error

最后一点,虽然示例不同,但您可以将反序列化器和序列化器都添加到构建器中。