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