1

I was developing an app in android when I encountered this problem that I don't really know if it's a known bug or if I should file a bug report. Here's the code:

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET

data class Status(val msg: String, val integer: Int, val msg2:String)

interface API {

  @GET("/json/gson")
  suspend fun gson(): Status
}

val gsonApiCalls = Retrofit.Builder()
  .addConverterFactory(GsonConverterFactory.create())
  .baseUrl("http://localhost:8080")
  .build()
  .create(API::class.java)

suspend fun main(){

  val result = gsonApiCalls.gson()
  println(result)
  result.msg2?.let(::println) ?: println("Null result!")
}

The local server code (Ktor):

import io.ktor.application.*
import io.ktor.response.*
import io.ktor.request.*
import io.ktor.routing.*
import io.ktor.http.*
import io.ktor.gson.*
import io.ktor.features.*

fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)

data class StandardResponse(val msg: String, val integer: Int, val msg2:String?)

@Suppress("unused") // Referenced in application.conf
@kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
    install(ContentNegotiation) {
        gson {
        }
    }

    routing {
        get("/") {
            call.respondText("HELLO WORLD!", contentType = ContentType.Text.Plain)
        }

        get("/json/gson") {
            call.respond(StandardResponse("Hello",34, null))
        }
    }
}

And the result is:

Status(msg=Hello, integer=34, msg2=null)
Null result!

The code above is an example I made for testing this behaviour but the first time I realised this "bug" was in the android app when I got a NullPointerException, and I didn't understand why.

The app was using a remote node server and the same thing happens. Capture showing the linter thinks this can't be possible

If this is a bug, should I report this to Kotlin or Retrofit?

SaRoKu
  • 21
  • 4
  • In your client code, you have non-nullable `val msg2:String` but you're sending `null` from ktor. That's the problem – denvercoder9 May 24 '20 at 22:31
  • Yes, I know, this is intentional to test the behaviour I describe. The problem is that a Kotlin String shouldn't be able to be null, by definition if it's not declared as String? (and as shown in the picture), but in this example it is possible somehow. I guess this is a problem with Java to Kotlin String conversion but I still don't understand how it is possible. I mean, shouldn't an exception be thrown earlier if this happens? – SaRoKu May 24 '20 at 23:13
  • Yes, non-nullable string shouldn't be null and hence the runtime exception when gson forcefully tries to parse null into non-nullable string. At compile time it's all fine because there is nowhere in the code you're passing null into non-null variable. But if you put null into non-null variable at runtime, then the compiler can't check that, right? – denvercoder9 May 24 '20 at 23:25
  • Yes, I would expect gson to throw an exception but it doesn't. It just parses the null into the String somehow – SaRoKu May 24 '20 at 23:29
  • So, to conclude, this isn't a bug in retrofit, kotlin and gson. There was an exception thrown, if that's all you're looking for. If you are looking for some workaround then you'll have to be more specific. – denvercoder9 May 24 '20 at 23:57
  • No, there wasn't any exception thrown, that's the problem. I'm not looking for a workaround I'm just trying to figure out how is this possible. – SaRoKu May 25 '20 at 00:01
  • Write your own custom converter/adapter or use jackson which has support for kotlin's default values in constructors https://stackoverflow.com/questions/40297407/how-do-you-make-jackson-use-kotlin-default-params-for-missing-values – denvercoder9 May 25 '20 at 00:08

1 Answers1

1

I think I've found the answer, although I thought this was guaranteed by the language.

Why Kotlin data classes can have nulls in non-nullable fields with Gson?

SaRoKu
  • 21
  • 4