Jackson 的 @JsonFormat 不生效

发表于 2023-02-02

问题描述

系统中自定义了全局的序列化器,然后有部分需要指定序列化格式,但是使用注解并没有生效。

我在字段上使用 Jackson 的 @JsonFormat(pattern = "yyyy-MM") ,但是序列化时全走了了全局的序列化器 JsonSerializer<LocalDateTime>

代码详情

通过继承 JsonSerializer<LocalDateTime> 实现了全局格式化。

public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {

    public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (null != value) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            gen.writeString(formatter.format(value));
        }
    }
}

ObjectMapper 注入 LocalDateTimeSerializer

// 全局的 ObjectMapper mapper
JavaTimeModule timeModule = new JavaTimeModule();
timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
mapper.registerModule(timeModule);

在具体的字段上使用了 @JsonFormat(pattern = "yyyy-MM-dd") 自定义格式。

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createdTime;

结果是,@JsonFormat(pattern = "yyyy-MM-dd") 无效,全部转成了 yyyy-MM-dd HH:mm:ss 格式。

解决问题

针对 @JsonFormat(pattern = "yyyy-MM-dd") 做一定的特殊处理。

将自定义的序列化器 LocalDateTimeSerializer 实现一下 ContextualSerializer 接口并实现 createContextual 方法。

public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> implements ContextualSerializer {

    private String pattern = "yyyy-MM-dd HH:mm:ss";

    @Override
    public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (null != value) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            gen.writeString(formatter.format(value));
        }
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
        AnnotationMap annotated = property.getMember().getAllAnnotations();
        JsonFormat jsonFormat = annotated.get(JsonFormat.class);
        if (jsonFormat != null && jsonFormat.pattern() != null) {
            // 为 JsonFormat 创建一个单独的序列化器
            LocalDateTimeSerializer datetimeSerializer = new LocalDateTimeSerializer();
            datetimeSerializer.pattern = jsonFormat.pattern();
            return datetimeSerializer;
        }
        return this;
    }
}