Skip to content

Allow JsonTransformingSerializer to take a nullable type #2980

@freya022

Description

@freya022

What is your use-case and why do you need this feature?
An API could accept strings that are nullable, but when non-null, must not be empty/blank, however, API users (such as forms in websites) can send empty/blank strings, which are invalid.
To prevent issues, I would like to map empty/blank strings to null before deserializing, I believe I can use JsonTransformingSerializer to do this like so:

internal class NullableStringSerializer : JsonTransformingSerializer<String>(String.serializer()) {

    override fun transformSerialize(element: JsonElement): JsonElement {
        TODO("Omitted for brievety")
    }

    override fun transformDeserialize(element: JsonElement): JsonElement {
        return when (element) {
            is JsonPrimitive if (element.isString && element.content.isBlank()) -> JsonNull
            else -> element
        }
    }
}

However this will throw Expected string value for a non-null key 'primitive', got null literal instead at element: $.primitive<EOL>JSON input: null]

I tried to reproduce a working sample by copying JsonTransformingSerializer's code, and I got it working by only adding .nullable on the serializer, like so:

internal class NullableStringSerializer : KSerializer<String?> {

    override val descriptor: SerialDescriptor = String.serializer().nullable.descriptor

    override fun deserialize(decoder: Decoder): String? {
        val input = decoder as JsonDecoder
        val element = input.decodeJsonElement()
        return input.json.decodeFromJsonElement(String.serializer().nullable, transformDeserialize(element))
    }

    override fun serialize(encoder: Encoder, value: String?) {
        TODO("Omitted for brievety")
    }
    
    private fun transformDeserialize(element: JsonElement): JsonElement {
        return when (element) {
            is JsonPrimitive if (element.isString && element.content.isBlank()) -> JsonNull
            else -> element
        }
    }
}

Describe the solution you'd like
I believe removing the Any bound on the type parameter would allow users to pass String.serializer().nullable, this should not require any further changes

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions