Hristijan
10/17/2024, 7:47 AM@OptIn(InternalSerializationApi::class)
@ExperimentalSerializationApi
fun <T : Any> encodeDataToString(
data: T,
) : String {
val serializer: KSerializer<out T> = data::class.serializer()
return Json.encodeToString(serializer, data)
}
why is the data::class.serializer
an out variance of the type, Json.encodeToString(serializer, data)
screams of an error expecting data to be CapturedType(out T)
the only way to fix this error is by casting it to a non outer variance
val serializer = data::class.serializer() as KSerializer<T>
i’ve tried inline and reified, still same issue, only casting has fixed it, am I missing something?phldavies
10/17/2024, 9:45 AMphldavies
10/17/2024, 9:47 AMserializer<T>
helper to obtain the serializerHristijan
10/17/2024, 9:58 AMval serializer = serializer<T>()
val result = Json.encodeToString(serializer, data)
then it crashes, of course the function is inlined and type is reified
kotlinx.serialization.SerializationException: Serializer for class 'kotlin.Any' is not found.
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied
phldavies
10/17/2024, 10:09 AMAny
phldavies
10/17/2024, 10:13 AMencodeDataToString
the parameter is likely inferred as Any
(or explicitly typed as Any
)Hristijan
10/17/2024, 10:14 AMDataEvent<*> -> encodeDataToString(event.value)
phldavies
10/17/2024, 10:25 AMDataEvent
can hold using a sealed hierarchy - in which case you can use the root of that sealed hierarchy as the type argument.
Alternatively, if you know the types which will need serializing, you can create a SerializersModule
with the required types provided, and use a contextual lookup (assuming no type-arguments are required as you won't know them from the DataEvent<*>
projection)phldavies
10/17/2024, 10:35 AMHristijan
10/17/2024, 12:26 PMval serializer = data::class.serializer() as KSerializer<T>
was just wondering why I need explicit casting from <out T>
to <T>
phldavies
10/17/2024, 12:50 PM::class
returns KClass<out T>
as that's the variance that can be guaranteed. I strongly suggest against using KClass<T>.serializer()
though as (from the docs):
This method uses platform-specific reflection available for the given erased KClass and it is not recommended to use this method for anything, but last-ditch resort, e. g. when all type info is lost, your application has crashed and it is the final attempt to log or send some serializable data.
phldavies
10/17/2024, 12:51 PMHristijan
10/17/2024, 1:14 PMserializer<T>
because the data can come from any module, it can be any type, as long as it’s serializable i can process it
// Finds destination within _graph including its children and
// generates a route filled with args based on the serializable object.
// Throws if destination with `route` is not found
@OptIn(InternalSerializationApi::class)
private fun <T : Any> generateRouteFilled(route: T): String {
val id = route::class.serializer().generateHashCode()
val destination = graph.findDestinationComprehensive(id, true)
// throw immediately if destination is not found within the graph
requireNotNull(destination) {
"Destination with route ${route::class.simpleName} cannot be found " +
"in navigation graph $_graph"
}
return generateRouteWithArgs(
route,
// get argument typeMap
destination.arguments.mapValues { it.value.type }
)
}