jackson-databind icon indicating copy to clipboard operation
jackson-databind copied to clipboard

@JsonFormat (and other annotations) is ignored after adding custom serializer to specified type

Open hetot opened this issue 1 year ago • 1 comments

Search before asking

  • [x] I searched in the issues and found nothing similar.

Describe the bug

Problem: I wanted to change default pattern of formatting for OffsetDateTime (only if the field is not annotated with @JsonFormat)

Solution: I realized custom serializer which extends JsonSerializer<OffsetDateTime>. I also implemented ContextualSerializer in order to define is field annotated or not, all annotated fields will be passed to default serializer. I made custom modifier (exteded BeanSerializerModifier) to get and pass default serializer to my custom serializer.

I tested my serializer with unannotated OffsetDateTime fields and default format is working. But when I tried fields with @JsonFormat(pattern=...), I realized that defaultSerializer has ignored the pattern and used its default one but I expected pattern which is defined in @JsonFormat

Version Information

2.15.4

Reproduction

Custom Serializer:

class CustomOffsetDateTimeSerializer(
    private val defaultSerializer: JsonSerializer<*>,
    private val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern(defaultPattern),
) : JsonSerializer<OffsetDateTime>(), ContextualSerializer {
    companion object {
        private const val defaultPattern = "yyyy-MM-dd'T'HH:mm"
    }

    override fun serialize(
        value: OffsetDateTime,
        jsonGenerator: JsonGenerator,
        serializerProvider: SerializerProvider?,
    ) {
        jsonGenerator.writeString(formatter.format(value))
    }

    override fun createContextual(
        prov: SerializerProvider?,
        property: BeanProperty?,
    ): JsonSerializer<*> {
        if (property?.getAnnotation(JsonFormat::class.java) != null) {
            return defaultSerializer
        }

        return CustomOffsetDateTimeSerializer(defaultSerializer)
    }
}

Custom Modifier:

class CustomOffsetDateTimeModifier : BeanSerializerModifier() {
    override fun modifySerializer(
        config: SerializationConfig?,
        beanDesc: BeanDescription,
        serializer: JsonSerializer<*>,
    ): JsonSerializer<*> {
        if (beanDesc.beanClass == OffsetDateTime::class.java) {
            return CustomOffsetDateTimeSerializer(serializer)
        }
        return super.modifySerializer(config, beanDesc, serializer)
    }
}

Expected behavior

No response

Additional context

No response

hetot avatar Sep 24 '24 12:09 hetot

2.15.4 is not the latest so please make sure to verify with 2.17.2 or 2.18.0-rc1. Ideally before filing issue :)

Also looks like reproduction is in Kotlin so I may need to move to Kotlin module (although might be easy enough to translate to plain Java to keep here).

Also: code is not complete enough as reproduction: would need code to show configuration, calls to serialize.

cowtowncoder avatar Sep 25 '24 15:09 cowtowncoder

Cannot reproduce: would need changes requested to re-open or re-file.

cowtowncoder avatar Nov 07 '24 22:11 cowtowncoder