Kotlin - 数据类实体抛出 ***Error

Posted

技术标签:

【中文标题】Kotlin - 数据类实体抛出 ***Error【英文标题】:Kotlin - Data class entity throws ***Error 【发布时间】:2018-08-02 06:16:38 【问题描述】:

我尝试将 kotlin(版本 1.2.21)与 spring-boot(1.5.9.RELEASE)结合起来。我在使用带有 @Entity 注释的数据类时遇到了问题。我有问题的实体如下所示:

@Entity
@Table(name = "APP_USER")
data class AppUser(

    @Column(name = "USERNAME", unique = true)
    private val username: String,

    @Column(name = "PASSWORD")
    private val password: String,

    @Column(name = "IS_ACTIVE")
    val isActive: Boolean,

    @Column(name = "REGISTRATION_DATE_TIME")
    val registrationDateTime: LocalDateTime = SystemTimeManager.getSystemDateTime(),

    @OneToMany(mappedBy = "appUser", cascade = [CascadeType.ALL], fetch = FetchType.EAGER)
    val authorities: MutableSet<UserAuthority> = mutableSetOf()
) : EntityBase(), UserDetails 


   internal fun addRole(authority: UserAuthority) 
      this.authorities.add(authority)
   




@Entity
@Table(name = "USER_AUTHORITY")
data class UserAuthority(
    @ManyToOne
    @JoinColumn(name = "APP_USER_ID", nullable = false)
    val appUser: AppUser,

    @Column(name = "ROLE", length = 50, nullable = false)
    @Enumerated(value = EnumType.STRING)
    private val authority: Authority
) : EntityBase(), GrantedAuthority 

override fun getAuthority(): String 
    return authority.name
       

如您所见,我们在 AppUser 和 UserAuthority 之间有 @OneToMany 关系。现在我尝试添加一些这样的权限:

authoritiesCollection.forEach  appUser.addRole(UserAuthority(appUser, Authority.valueOf(it))) 

在执行期间,第一个权限总是正确地添加到 appUser,但是添加第二个权限会产生 ***Error 和堆栈跟踪

java.lang.***Error
at security.usermanagement.AppUser.hashCode(AppUser.kt)
at security.usermanagement.UserAuthority.hashCode(UserAuthority.kt)

如果我将这些类设为非数据,它会正常工作。我可能可以通过覆盖 hashcode 和 equals 方法来解决这个问题,但是我有很多实体,所以我真的不想这样做。

【问题讨论】:

【参考方案1】:

AppUserUserAuthority 之间存在循环依赖关系。处理hashCode时需要排除一个来打破循环依赖。

您可以通过将导致循环依赖的属性移动到数据类主体来修复它,这样这些属性就不会在自动生成的字段上使用。在这种情况下,它会将authorities 移动到AppUser 正文:

@Entity
@Table(name = "APP_USER")
data class AppUser(

        @Column(name = "USERNAME", unique = true)
        private val username: String,

        @Column(name = "PASSWORD")
        private val password: String,

        @Column(name = "IS_ACTIVE")
        val isActive: Boolean,

        @Column(name = "REGISTRATION_DATE_TIME")
        val registrationDateTime: LocalDateTime = SystemTimeManager.getSystemDateTime(),

) 
    @OneToMany(mappedBy = "appUser", cascade = [CascadeType.ALL], fetch = FetchType.EAGER)
    val authorities: MutableSet<String> = mutableSetOf()

    internal fun addRole(authority: String) 
        this.authorities.add(authority)
    


【讨论】:

不幸的是,它不起作用。可能是因为数据类不是由 lombok(由于 @Data 注释)仅由 kotlin 本身管理的。 更新了我的答案以避免使用来自 lombok 的 @EqualsAndHashCode 从技术上讲,这是一个正确的答案,但是正如我在问题中所说的那样,我确实有很多实体,其中许多实体具有循环依赖关系。所以我正在寻找某种注释或一些库,它们可以让我绕过覆盖每个实体的等于和哈希码。 我的错,根据数据类文档,如果您可以在类主体中声明一个属性,它将不会在自动生成的函数中使用。也许您可以尝试将 val authorities 移动到 AppUser 正文。 它正在工作,但是必须说明这个解决方案也有它的缺点。您将需要一个辅助构造函数或其他一些解决方案来初始化您从主构造函数中提取的参数,它在某种程度上是多余的,但冗余度较低,然后一遍又一遍地覆盖等于和哈希码。然而,最大的失望是您不再可以使用带有提取参数的复制方法。复制方法只能更改数据类主构造函数中的参数。

以上是关于Kotlin - 数据类实体抛出 ***Error的主要内容,如果未能解决你的问题,请参考以下文章

错误:惰性类的 Getter 不能是最终的 Kotlin Spring Boot

Room Kotlin 找不到字段的设置器

将 Kotlin 内联类作为实体字段的房间数据库

错误:实体类必须用@Entity注解

Spring not not null验证在kotlin中抛出HttpMessageNotReadableException而不是MethodArgumentNotValidException(示例代

如何使用数据类在 Kotlin 中解决“无法编写 JSON:无限递归 (***Error)”?