【问题标题】:Kotlin Spring Data JPA - Declared non-null type is NULLKotlin Spring Data JPA - 声明的非空类型为 NULL
【发布时间】:2021-09-11 19:08:44
【问题描述】:

使用 Kotlin、Spring Data JPA 和 Hibernate。 考虑以下 JPA 实体:

@Entity
@Table(name = "applications")
class Application(

    @Column(name = "name", nullable = false)
    var name: String,

    @Column(name = "version", nullable = false)
    var version: String,

) {

    @Id
    @SequenceGenerator(name = "seq_gen_application_id", sequenceName = "seq_application_id")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_gen_application_id")
    @Column(name = "id", unique = true, nullable = false)
    var id: Long? = null

    @Embedded
    var/val k8s: K8s = K8s()

    @Embeddable
    class K8s {
        @Column(name = "k8s_image")
        var image: String? = null
    }
}

从语言级别的角度来看,Application.k8s 属性永远不会为空。所以访问 k8s 属性而不进行任何空检查应该是安全的。

例如,使用经典 CrudRepository 中的 findAll() 函数:

@Repository
interface ApplicationRepository : CrudRepository<Application, Long>

我将获得Application 实例的列表,其中非空k8s 属性 null(如果k8s.image 为空)。

当您访问属性k8s 时,这将在运行时导致NullPointerException,即使它不应该(感谢Kotlin 的空安全机制)。所以它非常令人困惑,并可能导致意想不到的错误。我猜这可能是由一些 Hibernate 互操作性问题引起的? Hibernate发现embeddable类中的所有字段都是null,所以它使用反射将其设置为null?

解决方案 1:

k8s 属性(和其他嵌入式实体)始终声明为可为空,这将强制进行额外的空检查。

解决方案 2:

@Embedded
var k8s: K8s = K8s()
   get() = if (field == null) K8s() else field

这也令人困惑,因为对不可为空的类型进行了空检查。所以它会生成一个编译器警告: Condition 'field == null' is always 'false'

解决方案 3: 声明一个具有虚拟属性的辅助类,以确保总有一些东西永远不会为空。

@Embeddable
@MappedSuperclass
open class NonNullEmbeddable {
    @Formula("0")
    private var internalNonNullProperty: Int = 0
}

用法:

class K8s : NonNullEmbeddable() {
    @Column(name = "k8s_image")
    var image: String? = null
}

有什么想法吗?这是错误还是预期行为?

如果Application 实体来自 Java 代码 (https://kotlinlang.org/docs/java-interop.html#null-safety-and-platform-types),我会理解。但是由于Application被声明为Kotlin类,感觉就错了。

【问题讨论】:

标签: hibernate kotlin spring-data-jpa nullpointerexception null


【解决方案1】:

这是根据 JPA 规范,当 @Embeddable 上的所有字段为空时,@Embeddable 本身将设置为空。

这是对还是错是另一个讨论的话题,但这就是 JPA 定义可嵌入对象的方式。您正试图偏离规范,这通常不是一个好的方向。

也许您想要一些不同于可嵌入概念的东西?

【讨论】:

    猜你喜欢
    • 2020-01-27
    • 2017-05-06
    • 2018-09-04
    • 2022-01-01
    • 2017-05-01
    • 2011-08-25
    • 2020-04-09
    • 1970-01-01
    • 2020-11-06
    相关资源
    最近更新 更多