In compose type safe navigation, I am trying to pa...
# compose
n
In compose type safe navigation, I am trying to pass a nullable data class to a screen route class, I am using serializableType generic fun to create typeMap and pass it to the Route class, with isNullableAllowed as true
Copy code
inline fun <reified T : Any> serializableType(
    isNullableAllowed: Boolean = false,
    json: Json = Json,
) = object : NavType<T>(isNullableAllowed = isNullableAllowed) {
    override fun get(bundle: Bundle, key: String) =
        bundle.getString(key)?.let<String, T>(json::decodeFromString)

    override fun parseValue(value: String): T = json.decodeFromString(value)

    override fun serializeAsValue(value: T): String = json.encodeToString(value)

    override fun put(bundle: Bundle, key: String, value: T) {
        bundle.putString(key, json.encodeToString(value))
    }
}
but still I am getting this error,
Copy code
java.lang.IllegalArgumentException: Route companyname.data.model.Route.PartValidation could not find any NavType for argument validation of type companyname.domain.model.ValidationItem? - typeMap received was {companyname.domain.model.ValidationItem (Kotlin reflection is not available)=nav_type}
s
You say nullable is allowed, but the type is
T : Any
and none of the function signatures seem to allow for
T
to be null. In contrast, I am copy-pasting our implementation of this here:
Copy code
@Suppress("NOTHING_TO_INLINE")
internal data class JsonSerializableNullableNavType<T : Any?>(
  private val serializer: KSerializer<T?>,
) : NavType<T?>(isNullableAllowed = true) {
  override fun put(bundle: Bundle, key: String, value: T?) {
    bundle.putString(key, value?.encodedAsString())
  }

  override fun get(bundle: Bundle, key: String): T? {
    val data = bundle.getString(key) ?: return null
    return parseValue(data)
  }

  override fun serializeAsValue(value: T?): String {
    if (value == null) return "null"
    return Uri.encode(value.encodedAsString())
  }

  override fun parseValue(value: String): T? {
    if (value == "null") return null
    return value.decodedFromString()
  }

  private inline fun T.encodedAsString(): String = Json.encodeToString(serializer, this)

  private inline fun String.decodedFromString(): T? = Json.decodeFromString(serializer, this)
}
Where the nullability is marked explicitly in the function signatures.
Unrelated to your question, but you might also want to Uri.encode inside your
serializeAsValue
as specified in the docs https://developer.android.com/guide/navigation/design/kotlin-dsl#custom-types