I have a retrofit api interface with a method that looks like this:
@GET("/data")
suspend fun getData(): DataDto?
The server in this instance is returning a 200, and the json response body is null
(bare string, no quotes).
This results in an exception:
java.util.concurrent.ExecutionException: kotlinx.serialization.json.internal.JsonDecodingException: Unexpected JSON token at offset 0: Expected start of the object '{', but had 'n' instead at path: $
JSON input: null
I don't think I change the backend at this point. Is there any way to get this to work?
I'm using kotlin 2.0.0, kotlinx.serialization gradle plugin 2.0.0, and kotlinx-serialization-json 1.7.1.
My json config looks like this:
@OptIn(ExperimentalSerializationApi::class)
@Singleton
@Provides
fun provideJson(): Json = Json {
allowTrailingComma = true
encodeDefaults = true
explicitNulls = false
ignoreUnknownKeys = true
prettyPrint = true
isLenient = true
}
I've tried with explicitNulls set to both true and false, makes no difference.
After going down several different rabbit holes, I finally looked at the json.asConverterFactory(contentType)
source. There's a FormatString
class, that has a method like this:
override fun <T> fromResponseBody(
loader: DeserializationStrategy<T>,
body: ResponseBody
): T {
val string = body.string()
return format.decodeFromString(loader, string)
}
This takes a string, decodes it, and returns an instance of T - it doesn't allow a "null" response - it always expects an object. It requires copying a fair bit of code, and modifying things to accept a T?, and a very small change to the fromResponseBody method to check the string
value for "null" before forwarding it on to the decodeFromString
.
So now I can do json.asNullableConverterFactory(contentType)
, and it works as intended.