如何 serialize/deserialize 使用 Gson 进行枚举
How to serialize/deserialize enum usin Gson
我需要serialize/deserialize一个特定的枚举:
public enum Status {
ONLINE("online"),
OFFLINE("offline"),
UNKNOWN("del") {
@Override
public String getStatusOld() {
return "off";
}
};
private final String name;
Status(String name) {
this.name = name;
}
public String getStatusOld() {
return name;
}
public String toString() {
return name;
}
public static Status typeOf(String name) {
if (!StringUtils.isEmpty(name)) {
for (Status type : values()) {
if (type.name.equalsIgnoreCase(name)) {
return type;
}
if (type.getStatusOld().equalsIgnoreCase(name)) {
return type;
}
}
}
throw new IllegalArgumentException("Unknown status type: " + name);
}
}
我的 POJO 如下所示:
public class User {
public String name;
public Status status;
...
}
并订购 serialize/deserialize 我的枚举 Status
我已经创建了自定义 serializer/deserializer:
public class GsonStatusEnumSerializer implements JsonSerializer<Status> {
@Override
public JsonElement serialize(Status status, Type type, JsonSerializationContext jsonSerializationContext) {
return new JsonPrimitive(status.toString());
}
}
public class GsonStatusEnumDeserializer implements JsonDeserializer<Status> {
@Override
public Status deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
if (jsonElement != null && jsonElement.isJsonPrimitive()) {
final String status = jsonElement.getAsString();
if (StringUtils.isNotBlank(status)) {
return Status.typeOf(status);
}
}
return null;
}
}
并且当我尝试序列化我的 User
class 并且 Status 的值为 UNKNOWN
时,Gson 没有使用我的自定义序列化程序来序列化用户的状态。
我发现它正在发生,因为如果 UNKNOWN
值具有不同的类型。
public static void main(String[] args) {
for (Status value : Status.values()) {
System.out.println("class = " + value.getClass() + ", value = " + value);
}
}
我得到的结果如下所示:
class = class com.test.Status, value = online
class = class com.test.Status, value = del
class = class com.test.Status, value = offline
我序列化User POJO的主要方法:
public static void main(String[] args) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(Status.class, new GsonStatusEnumDeserializer())
.registerTypeAdapter(Status.class, new GsonStatusEnumSerializer())
.create();
User user = new User();
user.name = "John";
user.status = Status.UNKNOWN;
String json = gson.toJson(user);
User user1 = gson.fromJson(json, User.class);
}
我得到一个例外:
Exception in thread "main" java.lang.IllegalArgumentException: Unknown process type: UNKNOWN
at com.test.Status.typeOf(Status.java:97)
at com.test.GsonStatusEnumDeserializer.deserialize(GsonStatusEnumDeserializer.java:22)
at com.test.GsonStatusEnumDeserializer.deserialize(GsonStatusEnumDeserializer.java:16)
我如何通过 Gson serialize/deserialize 它?
快速修复:如果您确实需要代码正常工作,请删除 UNKNOWN("del")
之后的大括号
我试过复制你的代码,但我不太明白你的一些决定背后的需要,所以如果这不适用,请提供额外的说明。有几点:
KISS:过度工程化
我认为您的很多代码都是不必要的,所以让 Keep It Stupid Simple 吧。我们可以将 Status 简化为:
状态枚举:
public enum Status {
ONLINE,
OFFLINE,
UNKNOWN
}
似乎对枚举的实际作用有些困惑。枚举实际上只是为了方便,标识符“ONLINE”、“OFFLINE”和“UNKNOWN”属于 Status 类型。要检查这一点,我们可以这样做:
for (Status value : Status.values()){
System.out.println(value.getClass().getName());
}
我们得到以下输出:
Status
Status
Status
Process finished with exit code 0
这意味着您不必将其转换为字符串并返回,并且您根本不需要自定义序列化器和反序列化器!
命名
我建议为您的变量和方法制定一致的命名约定。调用一个 class GsonStatusEnumSerializer
和另一个 GsonProcessTypeEnumDeserializer
(状态与过程)可能很难跟踪,并且在其他人看来它们没有逻辑连接。
在 Status 中,您有 ONLINE('online')
和 OFFLINE('offline')
,但 UNKNOWN('del')
,这可能是很多混乱的根源(尤其是当您覆盖 toString()
方法return“关闭”!)
封装
封装是面向对象编程的核心原则,通过 getter 和 setter 访问变量使代码更安全。
最终输出
public static void main(String[] args) {
Gson gson = new Gson();
User user = new User("John", Status.UNKNOWN);
String json = gson.toJson(user);
System.out.println(json);
User user1 = gson.fromJson(json, User.class);
System.out.println(user1.getName());
System.out.println(user1.getStatus());
}
运行 以上产生以下输出:
{"name":"John","status":"UNKNOWN"}
John
UNKNOWN
Process finished with exit code 0
祝您编码工作顺利:)
我已经找到了解决办法,我必须单独为这个类型添加一个序列化程序。
public static void main(String[] args) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(Status.class, new GsonStatusEnumDeserializer())
.registerTypeAdapter(Status.class, new GsonStatusEnumSerializer())
.registerTypeAdapter(Status.UNKNOWN.getClass(), new GsonStatusEnumSerializer())
.create();
User user = new User();
user.name = "John";
user.status = Status.UNKNOWN;
String json = gson.toJson(user);
User user1 = gson.fromJson(json, User.class);
}
我不喜欢这种方法,但它对我有用。
我需要serialize/deserialize一个特定的枚举:
public enum Status {
ONLINE("online"),
OFFLINE("offline"),
UNKNOWN("del") {
@Override
public String getStatusOld() {
return "off";
}
};
private final String name;
Status(String name) {
this.name = name;
}
public String getStatusOld() {
return name;
}
public String toString() {
return name;
}
public static Status typeOf(String name) {
if (!StringUtils.isEmpty(name)) {
for (Status type : values()) {
if (type.name.equalsIgnoreCase(name)) {
return type;
}
if (type.getStatusOld().equalsIgnoreCase(name)) {
return type;
}
}
}
throw new IllegalArgumentException("Unknown status type: " + name);
}
}
我的 POJO 如下所示:
public class User {
public String name;
public Status status;
...
}
并订购 serialize/deserialize 我的枚举 Status
我已经创建了自定义 serializer/deserializer:
public class GsonStatusEnumSerializer implements JsonSerializer<Status> {
@Override
public JsonElement serialize(Status status, Type type, JsonSerializationContext jsonSerializationContext) {
return new JsonPrimitive(status.toString());
}
}
public class GsonStatusEnumDeserializer implements JsonDeserializer<Status> {
@Override
public Status deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
if (jsonElement != null && jsonElement.isJsonPrimitive()) {
final String status = jsonElement.getAsString();
if (StringUtils.isNotBlank(status)) {
return Status.typeOf(status);
}
}
return null;
}
}
并且当我尝试序列化我的 User
class 并且 Status 的值为 UNKNOWN
时,Gson 没有使用我的自定义序列化程序来序列化用户的状态。
我发现它正在发生,因为如果 UNKNOWN
值具有不同的类型。
public static void main(String[] args) {
for (Status value : Status.values()) {
System.out.println("class = " + value.getClass() + ", value = " + value);
}
}
我得到的结果如下所示:
class = class com.test.Status, value = online
class = class com.test.Status, value = del
class = class com.test.Status, value = offline
我序列化User POJO的主要方法:
public static void main(String[] args) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(Status.class, new GsonStatusEnumDeserializer())
.registerTypeAdapter(Status.class, new GsonStatusEnumSerializer())
.create();
User user = new User();
user.name = "John";
user.status = Status.UNKNOWN;
String json = gson.toJson(user);
User user1 = gson.fromJson(json, User.class);
}
我得到一个例外:
Exception in thread "main" java.lang.IllegalArgumentException: Unknown process type: UNKNOWN
at com.test.Status.typeOf(Status.java:97)
at com.test.GsonStatusEnumDeserializer.deserialize(GsonStatusEnumDeserializer.java:22)
at com.test.GsonStatusEnumDeserializer.deserialize(GsonStatusEnumDeserializer.java:16)
我如何通过 Gson serialize/deserialize 它?
快速修复:如果您确实需要代码正常工作,请删除 UNKNOWN("del")
之后的大括号我试过复制你的代码,但我不太明白你的一些决定背后的需要,所以如果这不适用,请提供额外的说明。有几点:
KISS:过度工程化 我认为您的很多代码都是不必要的,所以让 Keep It Stupid Simple 吧。我们可以将 Status 简化为:
状态枚举:
public enum Status {
ONLINE,
OFFLINE,
UNKNOWN
}
似乎对枚举的实际作用有些困惑。枚举实际上只是为了方便,标识符“ONLINE”、“OFFLINE”和“UNKNOWN”属于 Status 类型。要检查这一点,我们可以这样做:
for (Status value : Status.values()){
System.out.println(value.getClass().getName());
}
我们得到以下输出:
Status
Status
Status
Process finished with exit code 0
这意味着您不必将其转换为字符串并返回,并且您根本不需要自定义序列化器和反序列化器!
命名
我建议为您的变量和方法制定一致的命名约定。调用一个 class GsonStatusEnumSerializer
和另一个 GsonProcessTypeEnumDeserializer
(状态与过程)可能很难跟踪,并且在其他人看来它们没有逻辑连接。
在 Status 中,您有 ONLINE('online')
和 OFFLINE('offline')
,但 UNKNOWN('del')
,这可能是很多混乱的根源(尤其是当您覆盖 toString()
方法return“关闭”!)
封装 封装是面向对象编程的核心原则,通过 getter 和 setter 访问变量使代码更安全。
最终输出
public static void main(String[] args) {
Gson gson = new Gson();
User user = new User("John", Status.UNKNOWN);
String json = gson.toJson(user);
System.out.println(json);
User user1 = gson.fromJson(json, User.class);
System.out.println(user1.getName());
System.out.println(user1.getStatus());
}
运行 以上产生以下输出:
{"name":"John","status":"UNKNOWN"}
John
UNKNOWN
Process finished with exit code 0
祝您编码工作顺利:)
我已经找到了解决办法,我必须单独为这个类型添加一个序列化程序。
public static void main(String[] args) {
Gson gson = new GsonBuilder()
.registerTypeAdapter(Status.class, new GsonStatusEnumDeserializer())
.registerTypeAdapter(Status.class, new GsonStatusEnumSerializer())
.registerTypeAdapter(Status.UNKNOWN.getClass(), new GsonStatusEnumSerializer())
.create();
User user = new User();
user.name = "John";
user.status = Status.UNKNOWN;
String json = gson.toJson(user);
User user1 = gson.fromJson(json, User.class);
}
我不喜欢这种方法,但它对我有用。