java枚举序列化可定制:jackson用@jsonvalue/@jsoncreator实现双向映射,gson用typeadapter精确控制,@jsonformat仅适用于简单别名,动态策略可通过@jsonview按场景切换。

Java枚举类默认序列化为名称字符串(如 STATUS_ACTIVE),但实际开发中常需输出更友好的值(如 "active")、带描述的结构(如 {"code": 1, "desc": "启用"}),或按不同场景动态适配。Jackson 和 Gson 都支持灵活定制,关键在于选对扩展点、避免全局污染、兼顾反序列化一致性。
用@JsonFormat指定简单别名(Jackson)
适用于只需将枚举名映射为固定字符串的轻量场景。通过 @JsonFormat 注解直接声明序列化后的值,无需额外类或配置。
- 在枚举类上加
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "active")不生效;正确用法是配合name属性: - 给每个枚举常量添加
@JsonProperty("active"),或统一在枚举类上用@JsonFormat(using = ...)(需自定义序列化器);最简方案是重写toString()并加@JsonValue:
public enum Status {
ACTIVE, INACTIVE;
@JsonValue
public String toValue() {
return name().toLowerCase();
}
}
序列化结果为 "active" 或 "inactive",反序列化时仍能按名称匹配。
用@JsonCreator + @JsonValue 构建双向映射(Jackson)
当枚举需携带元数据(如码值、中文描述)且要求 JSON 输入/输出结构一致时,推荐此方式。核心是让序列化走 @JsonValue 方法,反序列化走 @JsonCreator 静态工厂方法。
-
@JsonValue标记一个实例方法,返回要序列化的值(可为对象或字符串) -
@JsonCreator标记一个静态方法,接收 JSON 值并返回对应枚举实例 - 确保两者逻辑可逆:序列化输出的值,必须能被
@JsonCreator正确还原
public enum Role {
ADMIN(1, "管理员"),
USER(2, "普通用户");
private final int code;
private final String desc;
Role(int code, String desc) {
this.code = code;
this.desc = desc;
}
@JsonValue
public Map<string object> toJson() {
Map<string object> map = new HashMap();
map.put("code", code);
map.put("desc", desc);
return map;
}
@JsonCreator
public static Role fromJson(Map<string object> json) {
if (json == null) return null;
Integer code = (Integer) json.get("code");
for (Role r : values()) {
if (r.code == code) return r;
}
throw new IllegalArgumentException("Unknown role code: " + code);
}
}</string></string></string>
序列化得 {"code":1,"desc":"管理员"},反序列化也支持该结构输入。
Gson 中用 TypeAdapter 精确控制(Gson)
Gson 没有内置注解支持复杂枚举序列化,TypeAdapter 是最可控的方式。它分离序列化与反序列化逻辑,适合需要复用、或对接外部协议的场景。
- 继承
TypeAdapter<yourenum></yourenum>,重写write()和read() - 注册时使用
GsonBuilder.registerTypeAdapter(YourEnum.class, new YourEnumAdapter()) - 避免用
@SerializedName——它只改字段名,不改变枚举本身的序列化行为
public class RoleAdapter extends TypeAdapter<role> {
@Override
public void write(JsonWriter out, Role value) throws IOException {
if (value == null) {
out.nullValue();
} else {
out.beginObject();
out.name("code").value(value.getCode());
out.name("desc").value(value.getDesc());
out.endObject();
}
}
@Override
public Role read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
in.beginObject();
int code = 0;
while (in.hasNext()) {
String name = in.nextName();
if ("code".equals(name)) {
code = in.nextInt();
} else {
in.skipValue();
}
}
in.endObject();
return Role.fromCode(code);
}
}</role>
注册后,所有 Role 字段均按此规则处理,包括嵌套对象中的字段。
按上下文动态切换序列化策略(Jackson)
同一枚举在不同 API 接口可能需不同格式(如管理后台返回完整对象,移动端只返回 code)。Jackson 支持通过 @JsonView 或自定义 SerializerProvider 实现条件化序列化。
- 定义多个 View 类(如
public interface MobileView {}),在字段上标注@JsonView(MobileView.class) - 为枚举编写多个
StdSerializer子类,在serialize()中判断当前 View 并输出不同结构 - 注册时用
SimpleModule.addSerializer(new MobileRoleSerializer()),并在配置中启用 View 支持
这种方式保持枚举类干净,把格式逻辑外移,便于测试和复用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











