首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何序列化/反序列化enum Gson

如何序列化/反序列化enum Gson
EN

Stack Overflow用户
提问于 2021-10-08 09:47:21
回答 2查看 378关注 0票数 1

我需要序列化/反序列化一个特定的枚举:

代码语言:javascript
运行
复制
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看起来如下:

代码语言:javascript
运行
复制
public class User {
    public String name;
    public Status status;
    ...
}

为了序列化/反序列化我的枚举Status,我创建了自定义序列化程序/反序列化器:

代码语言:javascript
运行
复制
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类并且状态有值UNKNOWN时,我的自定义序列化程序没有被Gson用于序列化用户的状态。我发现发生这种情况是因为万一UNKNOWN值有不同的类型。

代码语言:javascript
运行
复制
public static void main(String[] args) {
    for (Status value : Status.values()) {
            System.out.println("class = " + value.getClass() + ", value = " + value);
        }
}

我得到的结果如下:

代码语言:javascript
运行
复制
class = class com.test.Status, value = online
class = class com.test.Status$2, value = del
class = class com.test.Status, value = offline

我用于序列化用户POJO的主要方法:

代码语言:javascript
运行
复制
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);
}

我得到一个例外:

代码语言:javascript
运行
复制
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序列化/反序列化它?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-10-08 11:18:23

我已经找到了解决方案,我必须为这种类型分别添加一个序列化程序。

代码语言:javascript
运行
复制
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);
}

我不喜欢这种方法,但它对我有用。

票数 1
EN

Stack Overflow用户

发布于 2021-10-08 11:03:00

快速修复:如果您确实需要代码工作,在未知(“del”)之后移除大括号

我试图复制您的代码,但我不太理解您的一些决定背后的需要,所以如果这不适用,请提供更多的说明。这里有几点:

KISS:关于工程,我认为很多代码都是不必要的,所以让我们保持愚蠢的简单吧。我们可以将状态简化为:

地位枚举:

代码语言:javascript
运行
复制
public enum Status {
    ONLINE,
    OFFLINE,
    UNKNOWN
}

现在看来,对于enum到底在做什么有一些困惑。Enum只是为了方便起见,标识符“联机”、“脱机”和“未知”都是类型状态。为了检查这一点,我们可以这样做:

代码语言:javascript
运行
复制
for (Status value : Status.values()){
    System.out.println(value.getClass().getName());
}

我们得到以下输出:

代码语言:javascript
运行
复制
Status
Status
Status

Process finished with exit code 0

这意味着您不必将其转换为字符串和返回,而且根本不需要自定义序列化程序和反序列化程序!

命名

我建议为您的变量和方法设置一个一致的命名约定。调用一个类GsonStatusEnumSerializer和另一个GsonProcessTypeEnumDeserializer (status )可能很难跟踪,而且对其他人来说,它们似乎没有逻辑上的关联。

在状态下,您有ONLINE('online')OFFLINE('offline'),但是有UNKNOWN('del'),这可能是许多混乱的根源(特别是当您重写toString()方法返回“off”时!)

Encapsulation封装是面向对象编程的核心原则,可以通过getter和setter访问变量,从而使代码更安全。

最终输出

代码语言:javascript
运行
复制
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());
    }

运行上面的输出将产生以下结果:

代码语言:javascript
运行
复制
{"name":"John","status":"UNKNOWN"}
John
UNKNOWN

Process finished with exit code 0

祝您的编码工作好运:)

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69493871

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档