问题描述
使用 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
属性应该是安全的。
例如,使用经典 findAll()
中的 CrudRepository
函数:
@Repository
interface ApplicationRepository : CrudRepository<Application,Long>
我会得到一个 Application
实例列表,其中非空的 k8s
属性 is null
(如果 k8s.image
为空) .
当您访问属性 NullPointerException
时,这将在运行时导致 k8s
,即使它不应该(感谢 Kotlin 的空安全机制)。所以它非常令人困惑,并可能导致意想不到的错误。我猜这可能是由一些 Hibernate 互操作性问题引起的? Hibernate 发现 embeddable 类中的所有字段都是空的,所以它使用反射将其设置为空?
解决方案 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 类,所以感觉是错误的。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)