Retrofit 在不可为空的字符串上返回 null (Kotlin)

Posted

技术标签:

【中文标题】Retrofit 在不可为空的字符串上返回 null (Kotlin)【英文标题】:Retrofit returns null on a non-nullable String (Kotlin) 【发布时间】:2020-09-11 11:53:45 【问题描述】:

当我遇到这个问题时,我正在用 android 开发一个应用程序,我真的不知道这是一个已知的错误还是我应该提交错误报告。代码如下:

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!")

本地服务器代码(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))
        
    

结果是:

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

上面的代码是我为测试这种行为而做的一个例子,但是当我第一次意识到这个“错误”出现在 Android 应用程序中时,我得到了 NullPointerException,我不明白为什么。

该应用程序正在使用远程节点服务器,并且发生了同样的事情。 Capture showing the linter thinks this can't be possible

如果这是一个错误,我应该将其报告给 Kotlin 还是 Retrofit?

【问题讨论】:

在您的客户端代码中,您有不可为空的 val msg2:String,但您从 ktor 发送 null。这就是问题 是的,我知道,这是有意测试我描述的行为。问题是 Kotlin 字符串不应该为空,根据定义,如果它没有声明为字符串? (如图所示),但在这个例子中它是可能的。我想这是 Java 到 Kotlin 字符串转换的问题,但我仍然不明白这是怎么可能的。我的意思是,如果发生这种情况,不应该提前抛出异常吗? 是的,不可为空的字符串不应为空,因此当 gson 强制尝试将 null 解析为不可为空的字符串时会出现运行时异常。在编译时一切都很好,因为代码中没有任何地方可以将 null 传递给非 null 变量。但是如果你在运行时将 null 放入非 null 变量中,那么编译器就无法检查,对吧? 是的,我希望 gson 会抛出异常,但事实并非如此。它只是以某种方式将 null 解析为字符串 所以,总而言之,这不是改造、kotlin 和 gson 中的错误。如果这就是您要查找的全部内容,则会引发异常。如果您正在寻找一些解决方法,那么您必须更具体。 【参考方案1】:

我想我已经找到了答案,虽然我认为这是由语言保证的。

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

【讨论】:

以上是关于Retrofit 在不可为空的字符串上返回 null (Kotlin)的主要内容,如果未能解决你的问题,请参考以下文章

错误无法为不可为空的类型返回 null:父 MyModelType 中的“字符串”(/createMyModelType/id)

错误:主体可能正常完成,导致返回“null”,但返回类型是不可为空的类型

错误:不能为不可为空的 postgres 返回 null

GraphQL 查询返回错误“不能为不可为空的字段返回 null”

Schema graphql 错误给出“不能为不可为空的字段 Organisation.id 返回 null”为啥?

无法为不可为空的字段返回 null,调试器不显示 null [重复]