Spring(kotlin)控制器接收数据类的不可为空的参数为空
Posted
技术标签:
【中文标题】Spring(kotlin)控制器接收数据类的不可为空的参数为空【英文标题】:Spring (kotlin) controller receives non-nullable parameters of a data class as null 【发布时间】: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 参数。【问题讨论】:
【参考方案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,到目前为止它似乎表现还不错。因此,如果您可以请更新您的回复,以便我可以接受答案。以上是关于Spring(kotlin)控制器接收数据类的不可为空的参数为空的主要内容,如果未能解决你的问题,请参考以下文章
错误:惰性类的 Getter 不能是最终的 Kotlin Spring Boot
使用 spring boot、kotlin 和 junit 进行休息控制器单元测试