Dariusz Kuc

    Dariusz Kuc

    1 year ago
    hello 👋 by any chance anyone tried conditional serialization of fields based on some condition? (I tried using custom filter as was suggested here -> https://www.baeldung.com/jackson-serialize-field-custom-criteria but with no luck). See thread for code
    sealed class OptionalInput<out T> {
        /**
         * Represents missing/undefined value.
         */
        object Undefined : OptionalInput<Nothing>() {
            override fun toString() = "UNDEFINED"
        }
    
        /**
         * Wrapper holding explicitly specified value including NULL.
         */
        class Defined<out U> @JsonCreator constructor(@JsonValue val value: U?) : OptionalInput<U>() {
            override fun toString(): String = "Defined(value=$value)"
        }
    }
    
    @JsonFilter(value = "optionalInputFilter")
    data class InputObject(
        val name: OptionalInput<String>,
        val value: OptionalInput<Int>
    )
    
    class OptionalInputFilter : SimpleBeanPropertyFilter() {
        override fun serializeAsField(
            pojo: Any?,
            jgen: JsonGenerator,
            provider: SerializerProvider,
            writer: PropertyWriter
        ) {
            if (pojo is OptionalInput.Undefined) { // pojo is an instance of InputObject, this does not get invoked for fields
                writer.serializeAsOmittedField(pojo, jgen, provider)
            } else {
                writer.serializeAsField(pojo, jgen, provider)
            }
        }
    }
    
    val mapper = jacksonObjectMapper()
    val filters = SimpleFilterProvider().addFilter("optionalInputFilter", OptionalInputFilter())
    
    val notSpecified = InputObject(name = OptionalInput.Defined("123"), value = OptionalInput.Undefined)
    println("not specified: ${mapper.writer(filters).writeValueAsString(notSpecified)}"). // prints out: not specified: {"name":"123","value":{}}
    if I use custom serializer instead
    override fun serialize(value: OptionalInput<*>, gen: JsonGenerator, serializers: SerializerProvider) {
        when (value) {
            is OptionalInput.Undefined -> return
            is OptionalInput.Defined -> {
                if (value.value == null) {
                    serializers.defaultNullValueSerializer.serialize(value.value, gen, serializers)
                } else {
                    serializers.findValueSerializer(value.value::class.java).serialize(value.value, gen, serializers)
                }
            }
        }
    }
    I end up with invalid
    { "name": "123", "value" }
    if anyone else is looking for solution, custom serializer works fine when you set serialization policy to omit empty
    val mapper = jacksonObjectMapper()
    mapper.setSerializationInclusion(Include.NON_EMPTY)