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

时间:2013-10-31 19:48:50

标签: java json gson

唯一的问题是我的对象包含一个枚举

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"}]

1 个答案:

答案 0 :(得分:2)

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

package stackoverflow.questions.q19715374;

import java.lang.reflect.Type;
import java.util.*;

import com.google.gson.*;

public class CustomSerializer implements JsonSerializer<Error> {


    @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<Integer, Error> map;

    static {
        map = new TreeMap<Integer, Error>();
        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<Error> {

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

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