Home > Enterprise >  Why is this Spring (Kotlin) many to many relation created with hibernate using postgresql as db cras
Why is this Spring (Kotlin) many to many relation created with hibernate using postgresql as db cras

Time:02-02

I have two Entities: 1. Post. 2. Tag. They are implemented as follows:

@Entity(name = "Post")
@Table(name = "post")
data class Post(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,
var title: String,
@ManytToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER)
@Fetch(value= FetchMode.SELECT)
@JoinTable(name = "post_tag",
joinColumns = [JoinColumn(name = "post_id")],
inverseJoinColumns = [JoinColumn(name = "tag_id")],)
@JsonIgnoreProperties("posts")
var tags: Set<Tag> = mutableSetOf()
)


@Entity(name = "Tag")
@Table(name = "tag")
data class Tag(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,
val name: String,
@ManyToMany(mappedBy = "tags")
@JsonIgnoreProperties("tags")
var posts: Set<Post> = mutableSetOf(),
)

I can fill them with data, so I have data in every of the three tables.

But when I call for example postReository.getAll the below error is thrown: The warning line over 500 times, so it seems to be something recursive and after that the error and than the following StackOverflowError.

The intresting thing is when I use var tags: List<Tag> = mutableListOf() and var posts: List<Post> = mutableListOf(), instead of set, it is working. But I read using a set instead of a list is more performant.

So is it possible to make it running using set? Or what is the best practice to implement this in kotlin?

2022-02-01 20:51:03.585  WARN 44603 --- [nio-8080-exec-2] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@6cda6288<rs=HikariProxyResultSet@2079611130 wrapping org.postgresql.jdbc.PgResultSet@2f8e2b05>
2022-02-01 20:51:03.585  WARN 44603 --- [nio-8080-exec-2] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@2777867f<rs=HikariProxyResultSet@1686136316 wrapping org.postgresql.jdbc.PgResultSet@570a7adb>
2022-02-01 20:51:03.585  WARN 44603 --- [nio-8080-exec-2] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@68fb8c90<rs=HikariProxyResultSet@1899379583 wrapping org.postgresql.jdbc.PgResultSet@36f34489>

2022-02-01 20:51:03.592 ERROR 44603 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause

java.lang.StackOverflowError: null
at java.base/java.nio.ByteBuffer.limit(ByteBuffer.java:1529) ~[na:na]
at java.base/java.nio.MappedByteBuffer.limit(MappedByteBuffer.java:330) ~[na:na]
at java.base/java.nio.MappedByteBuffer.limit(MappedByteBuffer.java:73) ~[na:na]
at java.base/sun.nio.ch.Util$BufferCache.get(Util.java:172) ~[na:na]
at java.base/sun.nio.ch.Util.getTemporaryDirectBuffer(Util.java:232) ~[na:na]
at java.base/sun.nio.ch.NioSocketImpl.tryWrite(NioSocketImpl.java:394) ~[na:na]
at java.base/sun.nio.ch.NioSocketImpl.implWrite(NioSocketImpl.java:413) ~[na:na]
at java.base/sun.nio.ch.NioSocketImpl.write(NioSocketImpl.java:440) ~[na:na]
at java.base/sun.nio.ch.NioSocketImpl$2.write(NioSocketImpl.java:826) ~[na:na]
at java.base/java.net.Socket$SocketOutputStream.write(Socket.java:1035) ~[na:na]
at java.base/java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:81) ~[na:na]
at java.base/java.io.BufferedOutputStream.flush(BufferedOutputStream.java:142) ~[na:na]
at org.postgresql.core.PGStream.flush(PGStream.java:665) ~[postgresql-42.2.24.jre7.jar:42.2.24.jre7]
at org.postgresql.core.v3.QueryExecutorImpl.sendSync(QueryExecutorImpl.java:1482) ~[postgresql-42.2.24.jre7.jar:42.2.24.jre7]
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:320) ~[postgresql-42.2.24.jre7.jar:42.2.24.jre7]
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:481) ~[postgresql-42.2.24.jre7.jar:42.2.24.jre7]
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:401) ~[postgresql-42.2.24.jre7.jar:42.2.24.jre7]
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:164) ~[postgresql-42.2.24.jre7.jar:42.2.24.jre7]
at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:114) ~[postgresql-42.2.24.jre7.jar:42.2.24.jre7]
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52) ~[HikariCP-4.0.3.jar:na]
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java) ~[HikariCP-4.0.3.jar:na]
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:57) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.getResultSet(AbstractLoadPlanBasedLoader.java:390) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:163) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:104) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:87) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:710) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:76) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:99) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2163) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:589) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:264) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:458) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at com.bla.blabla.model.Post.hashCode(Post.kt) ~[main/:na]
at java.base/java.util.HashMap.hash(HashMap.java:338) ~[na:na]
at java.base/java.util.HashMap.put(HashMap.java:610) ~[na:na]
at java.base/java.util.HashSet.add(HashSet.java:221) ~[na:na]
at java.base/java.util.AbstractCollection.addAll(AbstractCollection.java:336) ~[na:na]
at java.base/java.util.AbstractCollection.addAll(AbstractCollection.java:336) ~[na:na]
at org.hibernate.collection.internal.PersistentSet.endRead(PersistentSet.java:355) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection(CollectionLoadContext.java:239) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:224) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:198) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl.endLoading(CollectionReferenceInitializerImpl.java:154) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishLoadingCollections(AbstractRowReader.java:253) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:211) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:96) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:105) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:87) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:710) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:76) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:99) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2163) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:589) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:264) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:458) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at com.bla.blabla.model.Tag.hashCode(Tag.kt) ~[main/:na]
at java.base/java.util.HashMap.hash(HashMap.java:338) ~[na:na]
at java.base/java.util.HashMap.put(HashMap.java:610) ~[na:na]
at java.base/java.util.HashSet.add(HashSet.java:221) ~[na:na]

Adding the following override function to each of the class bodies did the trick:

@Entity(name = "Post")
@Table(name = "post")
data class Post(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,
var title: String,
@ManytToMany(cascade = [CascadeType.ALL], fetch = 
FetchType.EAGER)
@Fetch(value= FetchMode.SELECT)
@JoinTable(name = "post_tag",
joinColumns = [JoinColumn(name = "post_id")],
inverseJoinColumns = [JoinColumn(name = "tag_id")],)
@JsonIgnoreProperties("posts")
var tags: Set<Tag> = mutableSetOf()
) {
override fun hashCode(): Int {
    return id.hashCode()
}
}


@Entity(name = "Tag")
@Table(name = "tag")
data class Tag(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,
val name: String,
@ManyToMany(mappedBy = "tags")
@JsonIgnoreProperties("tags")
var posts: Set<Post> = mutableSetOf(),
) {
override fun hashCode(): Int {
    return id.hashCode()
}
}

CodePudding user response:

The problem here is that determining the hashCode of the data class instance is leading to a stackoverflow error due to the bidirectional association (mutual references).

To avoid this you need to exclude the @ManyToMany properties from the hashCode method (e.g. by explicitly declaring hashCode on your own).

Property include/exclude on Kotlin data classes

  •  Tags:  
  • Related