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 .orm .test .annotations .generics ;
8+
9+ import java .util .List ;
10+
11+ import org .hibernate .metamodel .model .domain .ManagedDomainType ;
12+ import org .hibernate .query .sqm .tree .domain .SqmPath ;
13+
14+ import org .hibernate .testing .orm .junit .DomainModel ;
15+ import org .hibernate .testing .orm .junit .Jira ;
16+ import org .hibernate .testing .orm .junit .SessionFactory ;
17+ import org .hibernate .testing .orm .junit .SessionFactoryScope ;
18+ import org .junit .jupiter .api .AfterAll ;
19+ import org .junit .jupiter .api .BeforeAll ;
20+ import org .junit .jupiter .api .Test ;
21+
22+ import jakarta .persistence .Entity ;
23+ import jakarta .persistence .Id ;
24+ import jakarta .persistence .ManyToOne ;
25+ import jakarta .persistence .MappedSuperclass ;
26+ import jakarta .persistence .criteria .CriteriaBuilder ;
27+ import jakarta .persistence .criteria .CriteriaQuery ;
28+ import jakarta .persistence .criteria .Join ;
29+ import jakarta .persistence .criteria .Root ;
30+
31+ import static org .assertj .core .api .Assertions .assertThat ;
32+
33+ /**
34+ * @author Marco Belladelli
35+ */
36+ @ DomainModel ( annotatedClasses = {
37+ GenericMappedSuperclassNestedJoinTest .Selection .class ,
38+ GenericMappedSuperclassNestedJoinTest .SelectionProductRule .class ,
39+ GenericMappedSuperclassNestedJoinTest .SelectionProductRuleProductLink .class ,
40+
41+ } )
42+ @ SessionFactory
43+ @ Jira ( "https://hibernate.atlassian.net/browse/HHH-17606" )
44+ public class GenericMappedSuperclassNestedJoinTest {
45+ @ BeforeAll
46+ public void setUp (SessionFactoryScope scope ) {
47+ scope .inTransaction ( session -> {
48+ final Selection s1 = new Selection ();
49+ s1 .id = 1L ;
50+ s1 .ident = "s1" ;
51+ session .persist ( s1 );
52+ final SelectionProductRule s2 = new SelectionProductRule ();
53+ s2 .id = 2L ;
54+ s2 .ident = 2 ;
55+ s2 .parent = s1 ;
56+ session .persist ( s2 );
57+ final SelectionProductRuleProductLink s3 = new SelectionProductRuleProductLink ();
58+ s3 .id = 3L ;
59+ s3 .parent = s2 ;
60+ session .persist ( s3 );
61+ } );
62+ }
63+
64+ @ AfterAll
65+ public void tearDown (SessionFactoryScope scope ) {
66+ scope .inTransaction ( session -> {
67+ session .createMutationQuery ( "delete from SelectionProductRuleProductLink" ).executeUpdate ();
68+ session .createMutationQuery ( "delete from SelectionProductRule" ).executeUpdate ();
69+ session .createMutationQuery ( "delete from Selection" ).executeUpdate ();
70+ } );
71+ }
72+
73+ @ Test
74+ public void testSimpleGenericJoin (SessionFactoryScope scope ) {
75+ scope .inTransaction ( session -> {
76+ final List <Integer > resultList = session .createQuery (
77+ "select p1.ident from SelectionProductRuleProductLink s join s.parent p1" ,
78+ Integer .class
79+ ).getResultList ();
80+ assertThat ( resultList ).containsOnly ( 2 );
81+ } );
82+ }
83+
84+ @ Test
85+ public void testSimpleGenericJoinCriteria (SessionFactoryScope scope ) {
86+ scope .inTransaction ( session -> {
87+ final CriteriaBuilder cb = session .getCriteriaBuilder ();
88+ final CriteriaQuery <Integer > cq = cb .createQuery ( Integer .class );
89+ final Root <SelectionProductRuleProductLink > root = cq .from ( SelectionProductRuleProductLink .class );
90+ final Join <SelectionProductRuleProductLink , Object > parent = root .join ( "parent" );
91+ assertThat ( parent .getJavaType () ).isEqualTo ( SeqOrderLinkObjectWithUserContext .class );
92+ assertThat ( parent .getModel () ).isSameAs ( root .getModel ().getAttribute ( "parent" ) );
93+ assertThat ( ( (SqmPath <?>) parent ).getResolvedModel ().getBindableJavaType () )
94+ .isEqualTo ( SelectionProductRule .class );
95+ final List <Integer > resultList = session .createQuery ( cq .select ( parent .get ( "ident" ) ) ).getResultList ();
96+ assertThat ( resultList ).containsOnly ( 2 );
97+ } );
98+ }
99+
100+ @ Test
101+ public void testNestedGenericJoin (SessionFactoryScope scope ) {
102+ scope .inTransaction ( session -> {
103+ final List <String > resultList = session .createQuery (
104+ "select p2.ident from SelectionProductRuleProductLink s join s.parent p1 join p1.parent p2" ,
105+ String .class
106+ ).getResultList ();
107+ assertThat ( resultList ).containsOnly ( "s1" );
108+ } );
109+ }
110+
111+ @ Test
112+ public void testNestedGenericJoinCriteria (SessionFactoryScope scope ) {
113+ scope .inTransaction ( session -> {
114+ final CriteriaBuilder cb = session .getCriteriaBuilder ();
115+ final CriteriaQuery <String > cq = cb .createQuery ( String .class );
116+ final Root <SelectionProductRuleProductLink > root = cq .from ( SelectionProductRuleProductLink .class );
117+ final Join <SelectionProductRuleProductLink , ?> p1 = root .join ( "parent" );
118+ assertThat ( p1 .getJavaType () ).isEqualTo ( SeqOrderLinkObjectWithUserContext .class );
119+ assertThat ( p1 .getModel () ).isSameAs ( root .getModel ().getAttribute ( "parent" ) );
120+ assertThat ( ( (SqmPath <?>) p1 ).getResolvedModel ().getBindableJavaType () )
121+ .isEqualTo ( SelectionProductRule .class );
122+ final Join <Object , Object > p2 = p1 .join ( "parent" );
123+ assertThat ( p2 .getJavaType () ).isEqualTo ( SimpleObject .class );
124+ final ManagedDomainType <?> joinType = (ManagedDomainType <?>) ( (SqmPath <?>) p1 ).getReferencedPathSource ()
125+ .getSqmPathType ();
126+ assertThat ( p2 .getModel () ).isSameAs ( joinType .getAttribute ( "parent" ) );
127+ assertThat ( ( (SqmPath <?>) p2 ).getResolvedModel ().getBindableJavaType () )
128+ .isEqualTo ( Selection .class );
129+ final List <String > resultList = session .createQuery ( cq .select ( p2 .get ( "ident" ) ) ).getResultList ();
130+ assertThat ( resultList ).containsOnly ( "s1" );
131+ } );
132+ }
133+
134+ @ MappedSuperclass
135+ public static abstract class SimpleObject {
136+ @ Id
137+ protected Long id ;
138+ }
139+
140+ @ MappedSuperclass
141+ public abstract static class CommonLinkObject <T extends SimpleObject > extends SimpleObject {
142+ @ ManyToOne
143+ protected T parent ;
144+ }
145+
146+ @ MappedSuperclass
147+ public abstract static class SeqOrderLinkObject <T extends SimpleObject > extends CommonLinkObject <T > {
148+ }
149+
150+ @ MappedSuperclass
151+ public abstract static class SeqOrderLinkObjectWithUserContext <T extends SimpleObject >
152+ extends SeqOrderLinkObject <T > {
153+ }
154+
155+ @ Entity ( name = "Selection" )
156+ public static class Selection extends SimpleObject {
157+ private String ident ;
158+ }
159+
160+ @ Entity ( name = "SelectionProductRule" )
161+ public static class SelectionProductRule extends SeqOrderLinkObjectWithUserContext <Selection > {
162+ private Integer ident ;
163+ }
164+
165+ @ MappedSuperclass
166+ public abstract static class AbsProductRuleProductLink <T extends SeqOrderLinkObjectWithUserContext <?>>
167+ extends SimpleObject {
168+ @ ManyToOne
169+ protected T parent ;
170+ }
171+
172+ @ Entity ( name = "SelectionProductRuleProductLink" )
173+ public static class SelectionProductRuleProductLink extends AbsProductRuleProductLink <SelectionProductRule > {
174+ }
175+ }
0 commit comments