после нескольких часов попыток и поиска аналогичной проблемы я все еще не мог исправить проблему:
Я создаю приложение загрузки спринта (в Kotlin), которое использует JPA (а также спящий режим) и H2 (не думаю, что это актуально). Я хочу смоделировать отношения «многие ко многим» между классами User и Achievement (чтобы пользователь мог иметь несколько достижений, а достижение могло быть достигнуто несколькими пользователями). Вот классы моделей:
@Entity
data class User(
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
val id: Int = 0,
@Column(nullable = false)
val name: String,
@ManyToMany(cascade = [ CascadeType.PERSIST, CascadeType.MERGE ])
val achievements: MutableSet<Achievement> = HashSet()
)
@Entity
data class Achievement(
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
val id: Int = 0,
val key: String,
@ManyToMany(mappedBy = "achievements")
val users: MutableSet<User> = HashSet()
)
Эта модель работает нормально, поскольку я вижу следующие журналы:
Hibernate: create table achievement (id integer not null, key varchar(255), priority integer not null, category_id integer, primary key (id))
Hibernate: create table user (id integer not null, name varchar(255) not null, primary key (id))
Hibernate: create table user_achievements (users_id integer not null, achievements_id integer not null, primary key (users_id, achievements_id))
Затем я предварительно заполняю данные в @Service @Transactional следующим образом:
val achievement = Achievement(key = "SOME_ACHIEVEMENT_KEY")
achievementRepository.save(achievement)
val user = User(name = "John Doe")
userRepository.save(user)
и добавьте отношение:
val foundAchievement = achievementRepository.findById(achievementId)
val foundUser = userRepository.findById(userId)
foundAchievement.ifPresent { achievement ->
foundUser.ifPresent { user ->
user.achievements.add(achievement)
userRepository.save(user)
}
}
Если я сейчас попытаюсь получить доступ к данным, выполнив GET на одном из следующих URL-адресов:
http://localhost:8080/achievements/2/users
http://localhost:8080/users/3/achievements
Я получаю java.lang.StackOverflowError, и журналы показывают мне, что спящий режим снова и снова пытается запрашивать достижения и пользователей (бесконечный цикл до переполнения стека).
Итак, вот мои вопросы:





Хорошо, проблема заключалась в сочетании двунаправленного отношения и автоматически сгенерированных equals () и hashCode () Kotlin.
Поскольку я использовал класс данных Kotlin, он автоматически генерировал hashCode () и equals () для каждого свойства, определенного в основном конструкторе. Я взял аннотированные свойства @ManyToMany из основного конструктора, и проблема исчезла:
@Entity
data class Achievement(
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
val id: Int = 0,
val key: String
) {
@ManyToMany(mappedBy = "achievements")
val users: MutableSet<User> = HashSet()
}
@Entity
data class User(
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
val id: Int = 0,
@Column(nullable = false)
val name: String
) {
@ManyToMany(cascade = [CascadeType.PERSIST, CascadeType.MERGE])
val achievements: MutableSet<Achievement> = HashSet()
}