我尝试将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,但是添加第二个权限会产生带有堆栈跟踪的StackOverflowError
java.lang.StackOverflowError
at security.usermanagement.AppUser.hashCode(AppUser.kt)
at security.usermanagement.UserAuthority.hashCode(UserAuthority.kt)
如果我使这些类非数据,它可以正常工作。我可能可以通过重写hashcode和equals方法解决这个问题,但是我有很多实体,所以我真的不愿意。
答案 0 :(得分:5)
AppUser
和UserAuthority
之间存在循环依赖关系。在处理hashCode时,您需要排除一个以打破循环依赖。
您可以通过将导致de循环依赖的属性移动到数据类主体来修复它,这样就不会在自动生成的字段上使用这些属性。在这种情况下,它会将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)
}
}