I try to combine kotlin (version 1.2.21) with spring-boot (1.5.9.RELEASE). I have encountered a problem using data class with @Entity annotation. My problematic entities look like this:
@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
}
}
As you see, we have here @OneToMany relation between AppUser and UserAuthority. Now I try to add few authorities like this:
authoritiesCollection.forEach { appUser.addRole(UserAuthority(appUser, Authority.valueOf(it))) }
During execution first authority is always correctly added to appUser, however adding second authority produces StackOverflowError with a stacktrace
java.lang.StackOverflowError
at security.usermanagement.AppUser.hashCode(AppUser.kt)
at security.usermanagement.UserAuthority.hashCode(UserAuthority.kt)
If I make these class non data it works as it should. I probably can fix this by overriding hashcode and equals methods however I have many entities so I really rather not.
Increase Thread Stack Size (-Xss) Increasing the stack size can be useful, for example, when the program involves calling a large number of methods or using lots of local variables. This will set the thread's stack size to 4 mb which should prevent the JVM from throwing a java. lang. StackOverflowError .
A stack overflow is a type of buffer overflow error that occurs when a computer program tries to use more memory space in the call stack than has been allocated to that stack.
The most common cause of StackOverFlowError is excessively deep or infinite recursion.
You have a circular dependency between AppUser
and UserAuthority
. You need to exclude one to break the circular dependency when processing the hashCode.
You can fix it by moving the properties that cause de circular dependency to the data class body, that way those properties won't be used on the autogenerated fields. In this case, it would be moving authorities
to the AppUser
body:
@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)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With