I haven't worked with annotations much in Java or ...
# getting-started
s
I haven't worked with annotations much in Java or Kotlin. I've come across a bug, that I believe is in generated code.
Copy code
@Serializable
data class FooInput {
    val id: OptionalInput<@Serializable(with = UUIDSerializer::class) UUID> = OptionalInput.Undefined
}
How does the annotation in the type parameter work? It seems like it's discarded which causes the bug, but kotlinx.serialization looks a bit like magic to me.
d
What's the bug?
Is optional input marked serialisable?
The serializer tries to inspect the properties of UUID which raises an exception.
specifically
java.lang.IllegalAccessException: class kotlin.reflect.jvm.internal.calls.CallerImpl$FieldGetter cannot access a member of class java.util.UUID (in module java.base) with modifiers "private final"
d
You can't use that annotation the way you have. The custom serialiser for optional input doesn't support it.
The compiler plugin will try and inject the uuid serialiser into the optional input serialiser ctor and fail.
s
Yeah, makes sense. That code I pasted is generated by the gradle plugin
Is it obvious how that should work and I'm not understanding, or should I wait for the maintainers of the graphql library to look at it and come up with a solution?
d
No, I don't see how that is supposed to work. It needs fixing.
e
it should work if you define a serializer that accepts the type, for example
Copy code
class TypedOptionalInputSerializer<T : Any>(
    private val delegate: KSerializer<T>
) : KSerializer<OptionalInput<T>> {
    override val descriptor: SerialDescriptor = delegate.descriptor.nullable

    override fun serialize(encoder: Encoder, value: OptionalInput<T>) {
        encoder.encodeNullableSerializableValue(
            delegate,
            when (value) {
                is OptionalInput.Undefined -> null
                is OptionalInput.Defined -> value.value
            }
        )
    }

    override fun deserialize(decoder: Decoder): OptionalInput<T> =
        OptionalInput.Defined(decoder.decodeNullableSerializableValue(delegate.nullable))
}

@Serializable
data class FooInput {
    val id: @Serializable(with = TypedOptionalInputSerializer::class) OptionalInput<@Serializable(with = UUIDSerializer::class) UUID> = OptionalInput.Undefined
}
(untested but something along those lines)
their default OptionalInput serializer only works reasonably for primitives and Map/List of…, and otherwise falls back to reflection; I think it's a terrible idea but not my project 🤷
s
Thanks. That looks promising. Would it be possible for TypedOptionalInputSerializer to have a default delegate of AnyKSerializer so it falls back to the current behavior? I guess I can try to work our a set of changes for this. Thanks again for your help