diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java index 91c949a0f..b3346562b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java @@ -5,7 +5,6 @@ import io.ebean.annotation.FetchPreference; import io.ebean.annotation.HistoryExclude; import io.ebean.annotation.Where; import io.ebean.bean.BeanCollection.ModifyListenMode; -import io.ebean.config.BeanNotRegisteredException; import io.ebean.config.NamingConvention; import io.ebean.config.TableName; import io.ebean.core.type.ScalarType; @@ -140,15 +139,15 @@ class AnnotationAssocManys extends AnnotationAssoc { JoinTable joinTable = get(prop, JoinTable.class); if (joinTable != null) { if (prop.isManyToMany()) { - // expected this readJoinTable(joinTable, prop); - } else { // OneToMany with @JoinTable prop.setO2mJoinTable(); readJoinTable(joinTable, prop); manyToManyDefaultJoins(prop); } + } else if (prop.isManyToMany()) { + checkSelfManyToMany(prop); } if (prop.getMappedBy() != null) { @@ -181,6 +180,12 @@ class AnnotationAssocManys extends AnnotationAssoc { } } + private void checkSelfManyToMany(DeployBeanPropertyAssocMany prop) { + if (prop.getTargetType().equals(descriptor.getBeanType())) { + throw new IllegalStateException("@ManyToMany mapping for " + prop.getFullBeanName() + " requires explicit @JoinTable with joinColumns & inverseJoinColumns. Refer issue #2157"); + } + } + @SuppressWarnings("unchecked") private void readElementCollection(DeployBeanPropertyAssocMany prop, ElementCollection elementCollection) { @@ -430,7 +435,6 @@ class AnnotationAssocManys extends AnnotationAssoc { } private void readToMany(ManyToMany propAnn, DeployBeanPropertyAssocMany manyProp) { - manyProp.setMappedBy(propAnn.mappedBy()); manyProp.setFetchType(propAnn.fetch()); setCascadeTypes(propAnn.cascade(), manyProp.getCascadeInfo()); @@ -442,7 +446,6 @@ class AnnotationAssocManys extends AnnotationAssoc { } private void readToOne(OneToMany propAnn, DeployBeanPropertyAssocMany manyProp) { - manyProp.setMappedBy(propAnn.mappedBy()); manyProp.setFetchType(propAnn.fetch()); setCascadeTypes(propAnn.cascade(), manyProp.getCascadeInfo()); diff --git a/ebean-core/src/test/java/org/tests/model/interfaces/SelfManyMany.java b/ebean-core/src/test/java/org/tests/model/interfaces/SelfManyMany.java new file mode 100644 index 000000000..6cfc52193 --- /dev/null +++ b/ebean-core/src/test/java/org/tests/model/interfaces/SelfManyMany.java @@ -0,0 +1,40 @@ +package org.tests.model.interfaces; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import java.util.List; + +@Entity +public class SelfManyMany { + + @Id + private long id; + + private final String name; + + @ManyToMany + // requires explicit @JoinTable + @JoinTable(name = "self_many_bridge", + joinColumns = @JoinColumn(name = "self_1_id"), + inverseJoinColumns = @JoinColumn(name = "self_2_id")) + private List related; + + public SelfManyMany(String name) { + this.name = name; + } + + public long getId() { + return id; + } + + public String getName() { + return name; + } + + public List getRelated() { + return related; + } +} diff --git a/ebean-core/src/test/java/org/tests/model/interfaces/TestSelfMany.java b/ebean-core/src/test/java/org/tests/model/interfaces/TestSelfMany.java new file mode 100644 index 000000000..e12c47cfd --- /dev/null +++ b/ebean-core/src/test/java/org/tests/model/interfaces/TestSelfMany.java @@ -0,0 +1,15 @@ +package org.tests.model.interfaces; + +import io.ebean.BaseTestCase; +import io.ebean.DB; +import org.junit.Test; + +public class TestSelfMany extends BaseTestCase { + + @Test + public void self_manyToMany() { + + SelfManyMany m = new SelfManyMany("1"); + DB.save(m); + } +}