Skip to content

枚举型(enum)字段的序列化

🏷️ JSON C# Java

Java

默认情况下枚举字段会序列为字符型,值为枚举字段的名字(即 Enum<E extends Enum<E>>name() 方法的返回值)。

jackson 中可以通过设置 SerializationFeature.WRITE_ENUMS_USING_TO_STRINGSerializationFeature.WRITE_ENUMS_USING_INDEX 来改变默认的枚举型序列化结果。默认情况下这两个设置均为 false,可以通过如下方式设置:

java
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
mapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX, true);
return mapper.writeValueAsString(obj);

WRITE_ENUMS_USING_TO_STRING 设置为 true , 将序列化为 Enum.toString() 的返回值。而 Enum.toString() 方法可以重写。

WRITE_ENUMS_USING_INDEX 设置为 true 则序列化为 Enum.ordinal() 的返回值(及该枚举值的索引),这时值是 Integer 型。另外 Enum.ordinal() 不可以重写。

两个同时设置为 true 时, WRITE_ENUMS_USING_INDEX 拥有较高的优先级。

java
/**
 * Feature that determines standard serialization mechanism used for
 * Enum values: if enabled, return value of <code>Enum.toString()</code>
 * is used; if disabled, return value of <code>Enum.name()</code> is used.
 *<p>
 * Note: this feature should usually have same value
 * as {@link DeserializationFeature#READ_ENUMS_USING_TO_STRING}.
 *<p>
 * Feature is disabled by default.
 */
WRITE_ENUMS_USING_TO_STRING(false),

/**
 * Feature that determines whethere Java Enum values are serialized
 * as numbers (true), or textual values (false). If textual values are
 * used, other settings are also considered.
 * If this feature is enabled,
 *  return value of <code>Enum.ordinal()</code>
 * (an integer) will be used as the serialization.
 *<p>
 * Note that this feature has precedence over {@link #WRITE_ENUMS_USING_TO_STRING},
 * which is only considered if this feature is set to false.
 *<p>
 * Feature is disabled by default.
 */
WRITE_ENUMS_USING_INDEX(false),

下为一个 enum 型的示例:

java
public enum LogLevel {
    /**
     * 异常
     */
    Error("Error", 1),
    /**
     * 警告
     */
    Warn("Warn", 2),
    /**
     * 消息
     */
    Info("Info", 3),
    /**
     * 调试
     */
    Debug("Debug", 4),
    /**
     * 跟踪
     */
    Trace("Trace", 5);

    private String name;
    private int index;

    LogLevel(String name, int index) {
        this.name = name;
        this.index = index;
    }

    public String getName() {
        return name;
    }

    public LogLevel valueOf(int value) {
        switch (value) {
            case 1:
                return LogLevel.Error;
            case 2:
                return LogLevel.Warn;
            case 3:
                return LogLevel.Info;
            case 4:
                return LogLevel.Debug;
            case 5:
                return LogLevel.Trace;
            default:
                return LogLevel.Info;
        }
    }

//    // Error: java: LogLevel 中的 ordinal() 无法覆盖 java.lang.Enum 中的 ordinal()
//    @Override
//    public int ordinal() {
//        return this.index;
//    }

    @Override
    public String toString() {
        return String.valueOf(this.index);
    }
}

C#

C# 中默认序列化为对应的整形值。如果需要序列化为字符串则需要使用 JsonConverter 特性。

csharp
/// <summary>
/// 日志级别
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public LogLevel Level { get; set; } = LogLevel.Info;

保持 Java & C# 中序列化结果一致

Java 和 C# 中枚举型最大的不同就是:Java 中不能指定索引值,只能从零开始;C# 中默认也是从零开始,但是可以手动指定每个的索引值。

统一序列化成数字

虽然 Java 中 将 WRITE_ENUMS_USING_TO_STRING 设置为 true,然后再重写 ToString 方法可以将其序列化成指定的索引值,但其类型是 String,而不是 C# 中默认的整形。

统一序列化成名字(推荐)

在 C# 中将其序列化为字符串,这样就可以和 Java 中的默认方法一致了。

参考

  1. Java enum 的用法详解
  2. Newtonsoft.Json 序列化 Enum 类型