唯一的事情是我的对象包含一个枚举
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<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
。
最后一点,虽然示例不同,但您可以将反序列化器和序列化器添加到构建器中。
关于java - 为什么 Java 不使用 GSON 将我的对象序列化为适当的 JSON 格式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19715374/