Skip to content

Allow JsonTransformingSerializer to take a nullable type #2980

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
freya022 opened this issue Apr 11, 2025 · 1 comment
Closed

Allow JsonTransformingSerializer to take a nullable type #2980

freya022 opened this issue Apr 11, 2025 · 1 comment
Labels

Comments

@freya022
Copy link

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

@freya022
Copy link
Author

freya022 commented Apr 11, 2025

I just realized this was already fixed by #2911 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant