Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.2k views
in Technique[技术] by (71.8m points)

java - Jpa Stackoverflow exception in ManyToOne relation

I have sections inside which I can have subsections and inside them I can have deeper level of sections and further. Entity:

@Data
@Table(name = "section")
@Entity
@NoArgsConstructor
public class Section {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column
  private Long id;

  @Column private String title;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "parent_id")
  private Section parent;

  @JsonIgnore
  @OneToMany(fetch = FetchType.EAGER, mappedBy = "parent")
  private Set<Section> children;

  public Section(Long id, String title, Section parent) {
    this.id = id;
    this.title = title;
    this.parent = parent;
  }
}

I save all data in h2 database for testing purposes. Repository class:

@Repository
public interface SectionRepository extends JpaRepository<Section, Long> {
  List<Section> findAllByParentId(Long parentId);
}

What I have in h2:

enter image description here

I want to find only these sections which doesn't have parent(First two which have null in parent_id column). How I'm trying to do it:

Section about = new Section(null, "about", null);
Section production = new Section(null, "production", null);

sectionRepository.save(about);
sectionRepository.save(production);

Section subsectionOne = new Section(null, "subsectionOne", production); // without adding
Section subsectionTwo = new Section(null, "subsectionTwo", production); // these two subsections
                                 sectionRepository.save(subsectionOne); // and saving them to db
                                 sectionRepository.save(subsectionTwo); // I don't receive any error on findAllByParentId(null) method call

sectionRepository.findAllByParentId(null); // action
java.lang.StackOverflowError: null
    at org.h2.util.ParserUtil.getSaveTokenType(ParserUtil.java:592) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.read(Parser.java:5092) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.readIf(Parser.java:5011) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.readTerm(Parser.java:4306) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.readFactor(Parser.java:3343) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.readSum(Parser.java:3330) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.readConcat(Parser.java:3305) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.readCondition(Parser.java:3108) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.readExpression(Parser.java:3059) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parseSelectExpressions(Parser.java:2931) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parseSelect(Parser.java:2952) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parseQuerySub(Parser.java:2817) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parseSelectUnion(Parser.java:2649) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parseQuery(Parser.java:2620) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parsePrepared(Parser.java:868) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parse(Parser.java:843) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.parse(Parser.java:815) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.command.Parser.prepareCommand(Parser.java:738) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.engine.Session.prepareLocal(Session.java:657) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.engine.Session.prepareCommand(Session.java:595) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1235) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:76) ~[h2-1.4.200.jar:1.4.200]
    at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:352) ~[h2-1.4.200.jar:1.4.200]
    at com.zaxxer.hikari.pool.ProxyConnection.prepareStatement(ProxyConnection.java:337) ~[HikariCP-3.4.5.jar:na]
    at com.zaxxer.hikari.pool.HikariProxyConnection.prepareStatement(HikariProxyConnection.java) ~[HikariCP-3.4.5.jar:na]
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:149) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:176) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:151) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.prepareQueryStatement(AbstractLoadPlanBasedLoader.java:198) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:162) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:104) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:87) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:710) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:76) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2163) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:589) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:264) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:458) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at lv.sawex.core.sections.Section.hashCode(Section.java:10) ~[classes/:na]
    at lv.sawex.core.sections.Section.hashCode(Section.java:10) ~[classes/:na]
    at java.base/java.util.HashMap.hash(HashMap.java:339) ~[na:na]
    at java.base/java.util.HashMap.put(HashMap.java:607) ~[na:na]
    at java.base/java.util.HashSet.add(HashSet.java:220) ~[na:na]
    at java.base/java.util.AbstractCollection.addAll(AbstractCollection.java:352) ~[na:na]
    at org.hibernate.collection.internal.PersistentSet.endRead(PersistentSet.java:355) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection(CollectionLoadContext.java:239) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:224) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:198) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl.endLoading(CollectionReferenceInitializerImpl.java:154) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishLoadingCollections(AbstractRowReader.java:260) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:211) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:96) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:105) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:87) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:710) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:76) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2163) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:589) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:264) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:458) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at lv.sawex.core.sections.Section.hashCode(Section.java:10) ~[classes/:na]
    at lv.sawex.core.sections.Section.hashCode(Section.java:10) ~[classes/:na]
    at java.base/java.util.HashMap.hash(HashMap.java:339) ~[na:na]
    at java.base/java.util.HashMap.put(HashMap.java:607) ~[na:na]
    at java.base/java.util.HashSet.add(HashSet.java:220) ~[na:na]
    at java.base/java.util.AbstractCollection.addAll(AbstractCollection.java:352) ~[na:na]
    at org.hibernate.collection.internal.PersistentSet.endRead(PersistentSet.java:355) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection(CollectionLoadContext.java:239) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:224) ~[hibernate-core-5.4.25.Final.jar:5.4.25.Final]
    at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Judging by the stack trace and Lombok annotations used, the problem may be related to recursive invocation of hashCode(). Lombok's @Data will generate implementations for equals and hashCode methods, and by default these implementations will use all declared fields, including both parent and children in your case. This means that trying to calculate hash code for "production" entry will trigger calculations for "subsectionOne"/"subsectionTwo", leading back to "production" via parent property.

Excluding the set from hashCode implementation via adding @EqualsAndHashCode.Exclude to the children field should solve the issue


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...