Jackson枚举序列化:基于名称而非下标

小豆丁 16天前 ⋅ 15 阅读
聊天记录
头像

jackson对枚举的序列化和反序列化,是根据枚举名称还是枚举位置下标

头像

这是一个很好的问题!Jackson对枚举的默认行为是:

默认行为

序列化:基于枚举的名称(name()),而不是下标(ordinal())

反序列化:基于枚举的名称进行匹配

示例说明

JAVA
public enum Status {
    PENDING,    // ordinal=0
    APPROVED,   // ordinal=1  
    REJECTED    // ordinal=2
}

public class Order {
    private Status status;
    
    // getter/setter
}

序列化示例

JAVA
Order order = new Order();
order.setStatus(Status.APPROVED);

// 序列化结果为:{"status": "APPROVED"}
// 而不是 {"status": 1}
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(order);

反序列化示例

JAVA
String json = "{\"status\": \"APPROVED\"}";
Order order = mapper.readValue(json, Order.class);
// order.getStatus() = Status.APPROVED

如何改变默认行为

1. 使用下标(ordinal)进行序列化/反序列化

JAVA
public enum Status {
    PENDING,    // 0
    APPROVED,   // 1
    REJECTED    // 2
}

// 全局配置使用ordinal
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX, true);
mapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, false);

// 序列化结果:{"status": 1}

2. 在枚举字段上使用注解

JAVA
public class Order {
    @JsonFormat(shape = JsonFormat.Shape.NUMBER)
    private Status status;  // 序列化为数字
}

3. 使用@JsonValue和@JsonCreator自定义

JAVA
public enum Status {
    PENDING("P"), 
    APPROVED("A"),
    REJECTED("R");
    
    private String code;
    
    Status(String code) { this.code = code; }
    
    @JsonValue  // 序列化时使用code
    public String getCode() { return code; }
    
    @JsonCreator  // 反序列化时根据code查找
    public static Status fromCode(String code) {
        return Arrays.stream(Status.values())
            .filter(s -> s.code.equals(code))
            .findFirst()
            .orElse(null);
    }
}

// 序列化结果:{"status": "A"}
// 可以从 {"status": "A"} 反序列化

推荐做法

  1. 默认使用名称:更易读,枚举顺序变化时不影响现有数据
  2. 避免使用ordinal:如果枚举顺序改变,会导致数据不一致
  3. 考虑向前兼容:使用自定义代码值比依赖名称或下标更稳定

总结:Jackson默认使用枚举名称,这是最安全、最可读的方式。

全部评论: 0

    我有话说: