You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在父级对象中自定义Jackson对部分枚举属性的序列化

问题:在特定返回结构中自定义枚举序列化逻辑(避免全局影响)

背景

我定义了一个泛型记录EnumJson,用来向前端传递带描述的枚举值:

public record EnumJson<E extends Enum<E>>(E value, String description) {
}

还有一个接口的返回结构Enums,会单次返回多种不同枚举的列表(实际结构更复杂):

public record Enums(
  List<YesNo> yesNo, 
  List<RedBlue> redBlue, 
  List<UpDown> upDown, ...) {
}

需求是:多数枚举用Jackson默认的Enum.name()序列化即可,但少数枚举(比如UpDown)需要自定义序列化逻辑,而且希望直接在Enums这个返回结构层面控制,比如像这样给泛型参数加注解实现:

public record Enums(
  List<YesNo> yesNo, 
  List<RedBlue> redBlue, 
  List<@SomeInstructionToCustomizeSerialization UpDown> upDown, ...) {
}

目前我临时复制了EnumJson得到SpecialEnumJson,在其中给value字段加了序列化注解:

public record SpecialEnumJson<E extends Enum<E>>(@JsonSerialize(...) E value, String description) {
}

但我觉得这个方案不够优雅,希望有更优的实现。

注意:给少数枚举添加自定义@JsonValue注解的方案不适用,因为会影响它们在整个应用中的序列化逻辑。


更优解决方案

方案1:直接在泛型参数上使用@JsonSerialize注解

不需要复制EnumJson,直接在Enums中需要自定义序列化的枚举列表的泛型参数上标注@JsonSerialize,指定对应的序列化器即可,仅影响当前字段的序列化行为,不会全局改变枚举的序列化逻辑。

步骤1:编写自定义序列化器

比如针对UpDown枚举写一个序列化器:

public class UpDownSerializer extends StdSerializer<UpDown> {
    protected UpDownSerializer() {
        super(UpDown.class);
    }

    @Override
    public void serialize(UpDown value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        // 这里写你的自定义序列化逻辑,比如返回枚举的自定义编码、描述等
        gen.writeString(value.getCustomCode());
    }
}

步骤2:在Enums中应用注解

直接在List的泛型参数上添加序列化注解:

public record Enums(
    List<YesNo> yesNo,
    List<RedBlue> redBlue,
    List<@JsonSerialize(using = UpDownSerializer.class) UpDown> upDown
) {}

这样Jackson在序列化这个upDown列表时,会使用你指定的序列化器处理每个UpDown枚举实例,而其他枚举还是用默认逻辑,完全满足需求,也不需要额外定义重复的SpecialEnumJson。

方案2:自定义注解+上下文序列化器(扩展性更强)

如果有多个枚举需要不同的自定义序列化,且希望注解更语义化,可以自定义一个专门用于泛型参数的注解,配合Jackson的ContextualSerializer实现更灵活的控制。

步骤1:自定义注解

@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomEnumSerialize {
    Class<? extends JsonSerializer<?>> serializer();
}

步骤2:实现上下文序列化器

写一个通用的枚举序列化器,能根据注解选择具体的实现:

public class ContextualEnumSerializer extends StdSerializer<Enum<?>> implements ContextualSerializer {
    private JsonSerializer<?> delegateSerializer;

    public ContextualEnumSerializer() {
        super(Enum.class);
    }

    private ContextualEnumSerializer(JsonSerializer<?> delegateSerializer) {
        super(Enum.class);
        this.delegateSerializer = delegateSerializer;
    }

    @Override
    public void serialize(Enum<?> value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if (delegateSerializer != null) {
            delegateSerializer.serialize(value, gen, provider);
        } else {
            // 默认用Enum.name()序列化
            gen.writeString(value.name());
        }
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        if (property != null) {
            // 获取泛型参数上的CustomEnumSerialize注解
            AnnotatedType annotatedType = property.getMember().getAnnotatedType();
            CustomEnumSerialize annotation = annotatedType.getAnnotation(CustomEnumSerialize.class);
            if (annotation != null) {
                try {
                    JsonSerializer<?> serializer = annotation.serializer().getDeclaredConstructor().newInstance();
                    return new ContextualEnumSerializer(serializer);
                } catch (Exception e) {
                    throw new JsonMappingException(property.getMember().getAnnotated(), "Failed to instantiate serializer", e);
                }
            }
        }
        return this;
    }
}

步骤3:全局注册序列化器

在Jackson的ObjectMapper中注册这个上下文序列化器:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Enum.class, new ContextualEnumSerializer());
mapper.registerModule(module);

步骤4:在Enums中使用自定义注解

public record Enums(
    List<YesNo> yesNo,
    List<RedBlue> redBlue,
    List<@CustomEnumSerialize(serializer = UpDownSerializer.class) UpDown> upDown
) {}

这个方案适合有大量自定义序列化需求的场景,注解更语义化,扩展性更好,但配置稍复杂。


内容的提问来源于stack exchange,提问作者Werner de Groot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 16:30:03