Skip to content

Commit 88a0afc

Browse files
yrodiereSanne
authored andcommitted
HHH-13295 Test @EmbeddedId + @mapsid targeting a derived entity
1 parent 7906a27 commit 88a0afc

File tree

1 file changed

+227
-0
lines changed

1 file changed

+227
-0
lines changed
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
6+
*/
7+
package org.hibernate.test.ecid;
8+
9+
import static org.assertj.core.api.Assertions.assertThat;
10+
import static org.hibernate.test.util.SchemaUtil.getColumnNames;
11+
12+
import java.io.Serializable;
13+
import java.util.ArrayList;
14+
import java.util.List;
15+
import javax.persistence.Column;
16+
import javax.persistence.Embeddable;
17+
import javax.persistence.EmbeddedId;
18+
import javax.persistence.Entity;
19+
import javax.persistence.FetchType;
20+
import javax.persistence.Id;
21+
import javax.persistence.Inheritance;
22+
import javax.persistence.InheritanceType;
23+
import javax.persistence.ManyToOne;
24+
import javax.persistence.MapsId;
25+
import javax.persistence.OneToMany;
26+
import javax.persistence.Table;
27+
28+
import org.hibernate.testing.TestForIssue;
29+
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
30+
import org.junit.Test;
31+
32+
/**
33+
* Test that bootstrap doesn't throw an exception
34+
* when an entity has an {@link EmbeddedId} and a {@link MapsId} that references a derived identity.
35+
* <p>
36+
* This test used to fail on bootstrap with the following error:
37+
* <p>
38+
* java.util.NoSuchElementException
39+
* at java.base/java.util.ArrayList$Itr.next(ArrayList.java:1000)
40+
* at org.hibernate.cfg.annotations.TableBinder.linkJoinColumnWithValueOverridingNameIfImplicit(TableBinder.java:714)
41+
* at org.hibernate.cfg.PkDrivenByDefaultMapsIdSecondPass.doSecondPass(PkDrivenByDefaultMapsIdSecondPass.java:37)
42+
* at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1693)
43+
* at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1650)
44+
* at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:295)
45+
* at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:86)
46+
* at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:479)
47+
* at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:85)
48+
* at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:709)
49+
* at org.hibernate.testing.junit4.BaseCoreFunctionalTestCase.buildSessionFactory(BaseCoreFunctionalTestCase.java:125)
50+
* at org.hibernate.testing.junit4.BaseCoreFunctionalTestCase.buildSessionFactory(BaseCoreFunctionalTestCase.java:110)
51+
* at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
52+
* at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
53+
* at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
54+
* at java.base/java.lang.reflect.Method.invoke(Method.java:566)
55+
* at org.hibernate.testing.junit4.TestClassMetadata.performCallbackInvocation(TestClassMetadata.java:205)
56+
*/
57+
@TestForIssue(jiraKey = "HHH-13295")
58+
public class EmbeddedIdWithMapsIdTargetingDerivedEntityTest extends BaseNonConfigCoreFunctionalTestCase {
59+
60+
@Override
61+
protected Class<?>[] getAnnotatedClasses() {
62+
return new Class[] { Attendance.class, AttendanceId.class, Lecture.class, Student.class, User.class };
63+
}
64+
65+
@Test
66+
public void metadataTest() {
67+
assertThat( getColumnNames( "attendance", metadata() ) )
68+
// Just check we're using @MapsId; otherwise the test wouldn't be able to reproduce HHH-13295.
69+
.containsExactlyInAnyOrder( "student_id", "lecture_id" );
70+
}
71+
72+
// The main goal of the test is to check that bootstrap doesn't throw an exception,
73+
// but it feels wrong to have a test class with just an empty test method,
74+
// so just check that persisting/loading works correctly.
75+
@Test
76+
public void smokeTest() {
77+
inTransaction( s -> {
78+
Lecture lecture = new Lecture( 1L );
79+
s.persist( lecture );
80+
Student student = new Student( 2L );
81+
s.persist( student );
82+
Attendance attendance = new Attendance( lecture, student );
83+
student.getAttendances().add( attendance );
84+
lecture.getAttendances().add( attendance );
85+
s.persist( attendance );
86+
} );
87+
88+
inTransaction( s -> {
89+
Attendance attendance = s.get( Attendance.class, new AttendanceId( 1L, 2L ) );
90+
assertThat( attendance.getId() )
91+
.extracting( AttendanceId::getLectureId )
92+
.isEqualTo( 1L );
93+
assertThat( attendance.getId() )
94+
.extracting( AttendanceId::getStudentId )
95+
.isEqualTo( 2L );
96+
assertThat( attendance.getLecture() )
97+
.extracting( Lecture::getId )
98+
.isEqualTo( 1L );
99+
assertThat( attendance.getStudent() )
100+
.extracting( Student::getId )
101+
.isEqualTo( 2L );
102+
} );
103+
}
104+
105+
@Entity
106+
@Table(name = "attendance")
107+
public static class Attendance {
108+
@EmbeddedId
109+
private AttendanceId id;
110+
111+
@ManyToOne(fetch = FetchType.LAZY)
112+
@MapsId("lectureId")
113+
private Lecture lecture;
114+
115+
@ManyToOne(fetch = FetchType.LAZY)
116+
@MapsId("studentId")
117+
private Student student;
118+
119+
Attendance() {
120+
}
121+
122+
public Attendance(Lecture lecture, Student student) {
123+
this.id = new AttendanceId( lecture.getId(), student.getId() );
124+
this.lecture = lecture;
125+
this.student = student;
126+
}
127+
128+
public AttendanceId getId() {
129+
return id;
130+
}
131+
132+
public Lecture getLecture() {
133+
return lecture;
134+
}
135+
136+
public Student getStudent() {
137+
return student;
138+
}
139+
}
140+
141+
@Embeddable
142+
public static class AttendanceId implements Serializable {
143+
@Column
144+
private Long lectureId;
145+
146+
@Column
147+
private Long studentId;
148+
149+
AttendanceId() {
150+
}
151+
152+
public AttendanceId(Long lectureId, Long studentId) {
153+
this.lectureId = lectureId;
154+
this.studentId = studentId;
155+
}
156+
157+
public Long getLectureId() {
158+
return lectureId;
159+
}
160+
161+
public Long getStudentId() {
162+
return studentId;
163+
}
164+
}
165+
166+
@Entity
167+
@Table(name = "users")
168+
@Inheritance(strategy = InheritanceType.JOINED)
169+
public static abstract class User {
170+
@Id
171+
private Long id;
172+
173+
User() {
174+
}
175+
176+
public User(Long id) {
177+
this.id = id;
178+
}
179+
180+
public Long getId() {
181+
return id;
182+
}
183+
}
184+
185+
@Entity
186+
@Table(name = "student")
187+
public static class Student extends User {
188+
@OneToMany(mappedBy = "student", fetch = FetchType.LAZY)
189+
private List<Attendance> attendances = new ArrayList<>();
190+
191+
Student() {
192+
}
193+
194+
public Student(Long id) {
195+
super( id );
196+
}
197+
198+
public List<Attendance> getAttendances() {
199+
return attendances;
200+
}
201+
}
202+
203+
@Entity
204+
@Table(name = "lecture")
205+
public static class Lecture {
206+
@Id
207+
private Long id;
208+
209+
@OneToMany(mappedBy = "lecture", fetch = FetchType.LAZY)
210+
private List<Attendance> attendances = new ArrayList<>();
211+
212+
Lecture() {
213+
}
214+
215+
public Lecture(Long id) {
216+
this.id = id;
217+
}
218+
219+
public Long getId() {
220+
return id;
221+
}
222+
223+
public List<Attendance> getAttendances() {
224+
return attendances;
225+
}
226+
}
227+
}

0 commit comments

Comments
 (0)