
Jackson 默认将枚举序列化为 name() 字符串;若误加 @JsonFormat(shape = JsonFormat.Shape.OBJECT),则会转为 JSON 对象形式,需移除该注解并确保无其他干扰配置,即可输出如 "msgType": "HEARTBEAT" 的简洁字符串格式。
jackon 默认将枚举序列化为 `name()` 字符串;若误加 `@jsonformat(shape = jsonformat.shape.object)`,则会转为 json 对象形式,需移除该注解并确保无其他干扰配置,即可输出如 `"msgtype": "heartbeat"` 的简洁字符串格式。
在使用 Jackson 进行 JSON 序列化时,枚举类型的默认行为是调用其 name() 方法(即大写常量名),生成字符串形式的 JSON 字段值。例如,MsgType.HEARTBEAT 会被序列化为 "HEARTBEAT" —— 这正是你期望的结果。
但问题中的 @JsonFormat(shape = JsonFormat.Shape.OBJECT) 注解会强制 Jackson 将枚举视为普通 Java 对象,结合其字段(如 nr 和 value)生成嵌套 JSON 对象,导致输出不符合预期:
{
"msgType": {
"nr": 1,
"value": "heartbeat"
},
"msg": "test-msg"
}
✅ 正确做法:移除 @JsonFormat(shape = JsonFormat.Shape.OBJECT)
该注解仅在你需要自定义枚举的「对象式」序列化(如含多个属性的完整结构)时才启用。对于纯名称字符串输出,它不仅不必要,而且是根本性冲突源。
修正后的 MsgType 定义应简化为:
@Schema(implementation = MsgType.class) // OpenAPI 文档用途,不影响 Jackson 序列化
public enum MsgType {
HEARTBEAT(1, "heartbeat");
private final int nr;
private final String value;
MsgType(int nr, String value) {
this.nr = nr;
this.value = value;
}
// 可选:添加 getter 供反序列化或业务使用(非必需)
public int getNr() { return nr; }
public String getValue() { return value; }
}
此时,无需额外配置,ObjectMapper 即可按名称序列化:
WebSocketMsg resp = new WebSocketMsg(MsgType.HEARTBEAT, "balabala.....");
ObjectMapper objectMapper = new ObjectMapper();
String resultJson = objectMapper.writeValueAsString(resp);
// 输出:{"msgType":"HEARTBEAT","msg":"balabala....."}
⚠️ 注意事项:
- 若项目中全局配置了 SerializationFeature.WRITE_ENUMS_USING_TO_STRING 或 DeserializationFeature.READ_ENUMS_USING_TO_STRING,可能覆盖默认行为,请检查 ObjectMapper 配置;
- 如需对特定枚举统一使用 toString()(而非 name()),可添加 @JsonValue 到对应方法上,但本例中不推荐 —— name() 更符合语义且可逆;
- @Schema 来自 Springdoc/OpenAPI,仅用于 API 文档生成,不影响 Jackson 序列化逻辑,可安全保留。
总结:Jackson 枚举序列化的黄金法则——不加 @JsonFormat(shape = OBJECT),就默认用 name();加了,就变成对象。 精准控制的关键,在于理解注解意图并按需取舍。










