Rohde Fischer
01/17/2025, 8:22 PM@Serializable
data class A<T>(
val a: T
)
class B
val x = A(B()) // B is not serializable
Rohde Fischer
01/17/2025, 8:34 PM@Serializable
class Wrapper(
val foo: A<B>,
)
I'm using kotlin 2.1 and kotlinx-serialization 1.8Michael Krussel
01/17/2025, 8:42 PMT
, than the serialization plugin cannot enforce anything when it is building the serializer for A
so it just has to assume that it will be serializable it tries to serialize it.
Then the val x = A(B())
is not being evaluated by the serialization plugin since it might be in a project that doesn't even apply the plugin, so it only processes classes with the @Serializable
annotation. Since T
is unbounded the normal complier has no problem with the type of x
. And x
is useable as long as you don't try to serialize it.
Now Wrapper
is not generic, so the plugin can build a serializer that is not generic and while trying to do that, it fails because it cannot pass the correct serializer for B
into `A`'s serializer.
I'm sure some of these details are wrongRohde Fischer
01/17/2025, 8:44 PMAyfri
01/17/2025, 8:53 PMRohde Fischer
01/17/2025, 9:03 PMAyfri
01/17/2025, 9:16 PMglureau
01/18/2025, 5:48 AMval b: Any = if (Random.nextBoolean()) B() else createAnotherObject()
val x = A(b)
checking runtime to ensure all branches are really serializable is very hard, and if even feasible may cost a lot of build time.
It sounds more reasonnable to write a linter on your side to detect unbounded generics or other cases you want to prevent. It won't be perfect.ephemient
01/22/2025, 5:19 AMJson.encodeToString(A.serializer(B.serializer()), x)
then you'd get compile-time errors if there types aren't serializable or don't matchRohde Fischer
01/24/2025, 8:45 AMdata class ApiError<T>(
val errorId: ErrorId,
val message: String,
val supplementaryData: T
)
where supplementary data can be any helpful data structure, e.g.,:
data class NucleotideError(
val characterGiven: Char,
val validCharacters: List<Char>,
)
that could for DNA be that:
{
"characterGiven": "Q",
"validCharacters": [
"A",
"T",
"C",
"G"
]
}
so everything is not encoded in a string and can be used with things like i18n frameworks etc.Rohde Fischer
01/24/2025, 8:46 AMT
to an @Serializable
open class
, but I haven't gotten around to checking that design path yetephemient
01/24/2025, 8:57 AMNucleotideError.serializer(ListSerializer(Char.serializer()))
yeah it's more annoying than allowing serializer<T>()
to pick the right one automatically, but it can't fail at runtimeRohde Fischer
01/24/2025, 9:13 AMcall.respond(error)
that can deal with all my ApiError
instancesephemient
01/24/2025, 9:14 AMRohde Fischer
01/24/2025, 9:17 AM