【问题标题】:Spring (kotlin) controller receives non-nullable parameters of a data class as nullSpring(kotlin)控制器接收数据类的不可为空的参数为空
【发布时间】:2019-04-09 08:21:14
【问题描述】:

我遇到了一个我不知道如何处理的意外错误。

我有一个这样的数据类:

data class Payload (
  @SerializedName("id")
  var id: String
  @SerializedName("type")
  var type: String,
  @SerializedName("data")
  var data: String
)

还有一个像这样的简单 Spring 控制器:

@PostMapping("/some-endpoint")
fun dataHandler(@RequestBody payload: Payload): String{
    when (payload.type){
        "someType" -> {
            val result = try {
                gson.fromJson(payload.data, payloadData::class.java)
            } catch (e: Exception){
                throw BadDataException("Bad Data")
            }
            payloadProcessor.process(result, payload.id) // NPE here
        }
        "otherType" -> {
            doSomethingElseHere()
        }
    }
}

当执行到达 payloadProcessor.process 时,会发生空指针异常,因为 id 显然为空。另一方面,对象已创建,其余两个值似乎已正确填充。 如果我添加一个检查空值的 if 语句,ide 会抱怨负载属性永远不会为空,将 if 语句标记为冗余,但实际上并非如此。 我的印象是 null 安全属性是……嗯…… null 安全的。至少我希望在构造对象后会发生空指针异常。

我的问题是:

  • Spring 如何创建这样的对象
  • 为什么在对象构造时没有检测到这一点
  • “Kotlin”的处理方式是什么,因为我不想在一个假定为 null 的安全对象中检查 null 参数。

【问题讨论】:

    标签: spring spring-boot kotlin nullpointerexception kotlin-null-safety


    【解决方案1】:

    问题在于 Gson,而不是 Spring。 Gson 是为与 Java 一起使用而设计的,Java 没有*可空类型和不可空类型之间的区别,因此 Gson 无论如何都会很乐意分配一个空值。

    不幸的是,这里没有神奇的解决方案。您可以编写自己的TypeAdapter,它在构建数据类之前显式检查空值,但如果您有很多类,那将变得非常重复。或者,您可以创建自己的 TypeAdapterFactory 并使用 Kotlin 的反射库来检查哪些类型可以为空,哪些不能,但这会对性能和依赖关系产生各种影响。

    * 有可空性注解(@Nonnull、@Nullable),但 Gson 不检查它们。

    【讨论】:

    • 感谢您的意见。我考虑过这一点,但在我的情况下,nullPointerException 不在 gson.fromJson() 生成的对象上,而是在接收到的对象本身的属性上。事实上,gson 的工作是作为 payload.data 不为空。但是 payload.id 是。
    • 是的,当 Gson 反序列化您的数据时,它会将 null 分配给 result.id 字段,因为在 Java 中 String 可以为空。在您尝试使用result.id 的值之前不会出现错误,因为它是null
    • 为了清楚起见,我说的是@RequestBody payload: Payload,而不是result = gson.fromJson(payload.data, payloadData::class.java),gson 正在转换数据属性whish 分配给结果。我不是 gson 专家,但 gson 如何影响有效载荷?该对象已经构建,仅由 gson 用于创建 payloadData 对象。我没有对有效载荷本身进行任何修改,只是读取它的属性。
    • 啊,我明白了。我假设 payload 正在从网络请求中反序列化,它是否可以在内部使用 Gson 进行反序列化并在那里使用 null 值?
    • spring内部使用gson吗?还是它使用类似的反序列化机制?这也是我的同事们提出的建议,也是我所怀疑的,但我真的很想有一个具体的理由,以便我将来避免类似的陷阱。我已经编写了自己的 typeAdapter,到目前为止它似乎表现还不错。因此,如果您可以请更新您的回复,以便我可以接受答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-17
    • 2018-12-24
    • 1970-01-01
    • 1970-01-01
    • 2015-07-25
    相关资源
    最近更新 更多