Skip to content

Commit f09a337

Browse files
committed
HHH-5465 - HQL left join fetch of an element collection following a left join fetch of a one-to-one relationship causes NullPointerException
1 parent 4c47ba1 commit f09a337

File tree

6 files changed

+143
-83
lines changed

6 files changed

+143
-83
lines changed

hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/SelectClause.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/*
22
* Hibernate, Relational Persistence for Idiomatic Java
33
*
4-
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
4+
* Copyright (c) 2008, 2013, Red Hat Inc. or third-party contributors as
55
* indicated by the @author tags or express copyright attribution
66
* statements applied by the authors. All third-party contributions are
7-
* distributed under license by Red Hat Middleware LLC.
7+
* distributed under license by Red Hat Inc.
88
*
99
* This copyrighted material is made available to anyone wishing to use, modify,
1010
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,7 +20,6 @@
2020
* Free Software Foundation, Inc.
2121
* 51 Franklin Street, Fifth Floor
2222
* Boston, MA 02110-1301 USA
23-
*
2423
*/
2524
package org.hibernate.hql.internal.ast.tree;
2625
import java.util.ArrayList;
@@ -139,7 +138,7 @@ public void initializeExplicitSelectClause(FromClause fromClause) throws Semanti
139138
// NOTE: This must be done *before* invoking setScalarColumnText() because setScalarColumnText()
140139
// changes the AST!!!
141140
SelectExpression[] selectExpressions = collectSelectExpressions();
142-
141+
143142
for ( int i = 0; i < selectExpressions.length; i++ ) {
144143
SelectExpression selectExpression = selectExpressions[i];
145144

@@ -176,14 +175,14 @@ public void initializeExplicitSelectClause(FromClause fromClause) throws Semanti
176175
if ( !getWalker().isShallowQuery() ) {
177176
// add the fetched entities
178177
List fromElements = fromClause.getProjectionList();
179-
178+
180179
ASTAppender appender = new ASTAppender( getASTFactory(), this ); // Get ready to start adding nodes.
181180
int size = fromElements.size();
182181

183182
Iterator iterator = fromElements.iterator();
184183
for ( int k = 0; iterator.hasNext(); k++ ) {
185184
FromElement fromElement = ( FromElement ) iterator.next();
186-
185+
187186
if ( fromElement.isFetch() ) {
188187
FromElement origin = null;
189188
if ( fromElement.getRealOrigin() == null ) {
@@ -226,7 +225,7 @@ public void initializeExplicitSelectClause(FromClause fromClause) throws Semanti
226225
}
227226
}
228227
}
229-
228+
230229
// generate id select fragment and then property select fragment for
231230
// each expression, just like generateSelectFragments().
232231
renderNonScalarSelects( collectSelectExpressions(), fromClause );
@@ -326,7 +325,7 @@ public void initializeDerivedSelectClause(FromClause fromClause) throws Semantic
326325

327326
private void addCollectionFromElement(FromElement fromElement) {
328327
if ( fromElement.isFetch() ) {
329-
if ( fromElement.isCollectionJoin() || fromElement.getQueryableCollection() != null ) {
328+
if ( fromElement.getQueryableCollection() != null ) {
330329
String suffix;
331330
if (collectionFromElements==null) {
332331
collectionFromElements = new ArrayList();
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.hibernate.test.collection.set.hhh8206;
1+
package org.hibernate.test.collection.basic;
22

33
import java.io.Serializable;
44
import java.util.HashSet;
@@ -7,13 +7,10 @@
77
import javax.persistence.CollectionTable;
88
import javax.persistence.ElementCollection;
99
import javax.persistence.Entity;
10-
import javax.persistence.FetchType;
1110
import javax.persistence.GeneratedValue;
1211
import javax.persistence.GenerationType;
1312
import javax.persistence.Id;
1413
import javax.persistence.JoinColumn;
15-
import javax.persistence.ManyToMany;
16-
import javax.persistence.OneToMany;
1714
import javax.persistence.Table;
1815

1916
@Entity
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
package org.hibernate.test.collection.set.hhh8206;
1+
package org.hibernate.test.collection.basic;
22

33
import java.io.Serializable;
4-
import java.util.Set;
54
import javax.persistence.*;
65

76
@Embeddable
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
5+
* indicated by the @author tags or express copyright attribution
6+
* statements applied by the authors. All third-party contributions are
7+
* distributed under license by Red Hat Inc.
8+
*
9+
* This copyrighted material is made available to anyone wishing to use, modify,
10+
* copy, or redistribute it subject to the terms and conditions of the GNU
11+
* Lesser General Public License, as published by the Free Software Foundation.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15+
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16+
* for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public License
19+
* along with this distribution; if not, write to:
20+
* Free Software Foundation, Inc.
21+
* 51 Franklin Street, Fifth Floor
22+
* Boston, MA 02110-1301 USA
23+
*/
24+
package org.hibernate.test.collection.basic;
25+
26+
import java.util.HashSet;
27+
import java.util.Set;
28+
29+
import org.hibernate.Session;
30+
31+
import org.junit.Assert;
32+
import org.junit.Test;
33+
34+
import org.hibernate.testing.FailureExpected;
35+
import org.hibernate.testing.TestForIssue;
36+
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
37+
38+
public class JoinFetchElementCollectionTest extends BaseCoreFunctionalTestCase {
39+
@Override
40+
protected Class<?>[] getAnnotatedClasses() {
41+
return new Class[] {Contact.class, EmailAddress.class, User.class};
42+
}
43+
44+
@Test
45+
@TestForIssue(jiraKey = "HHH-8206")
46+
@FailureExpected(jiraKey = "HHH-8206", message = "This is not explicitly supported, however should arguably throw an exception")
47+
public void testJoinFetchesByPath() {
48+
Set<EmailAddress> emailAddresses = new HashSet<EmailAddress>();
49+
emailAddresses.add( new EmailAddress( "test1@test.com" ) );
50+
emailAddresses.add( new EmailAddress( "test2@test.com" ) );
51+
emailAddresses.add( new EmailAddress( "test3@test.com" ) );
52+
53+
{
54+
// Session 1: Insert a user with email addresses but no emailAddresses2
55+
Session session = openSession();
56+
session.beginTransaction();
57+
58+
User user = new User();
59+
user.setName( "john" );
60+
Contact contact = new Contact();
61+
contact.setName( "John Doe" );
62+
contact.setEmailAddresses( emailAddresses );
63+
contact = (Contact) session.merge( contact );
64+
user.setContact( contact );
65+
user = (User) session.merge( user );
66+
67+
session.getTransaction().commit();
68+
session.close();
69+
}
70+
{
71+
// Session 2: Retrieve the user object and check if the sets have the expected values
72+
Session session = openSession();
73+
session.beginTransaction();
74+
final String qry = "SELECT user "
75+
+ "FROM User user "
76+
+ "LEFT OUTER JOIN FETCH user.contact "
77+
+ "LEFT OUTER JOIN FETCH user.contact.emailAddresses2 "
78+
+ "LEFT OUTER JOIN FETCH user.contact.emailAddresses";
79+
User user = (User) session.createQuery( qry ).uniqueResult();
80+
session.getTransaction().commit();
81+
session.close();
82+
83+
Assert.assertEquals( emailAddresses, user.getContact().getEmailAddresses() );
84+
Assert.assertTrue( user.getContact().getEmailAddresses2().isEmpty() );
85+
}
86+
87+
}
88+
89+
@Test
90+
@TestForIssue(jiraKey = "HHH-5465")
91+
public void testJoinFetchElementCollection() {
92+
Set<EmailAddress> emailAddresses = new HashSet<EmailAddress>();
93+
emailAddresses.add( new EmailAddress( "test1@test.com" ) );
94+
emailAddresses.add( new EmailAddress( "test2@test.com" ) );
95+
emailAddresses.add( new EmailAddress( "test3@test.com" ) );
96+
97+
{
98+
// Session 1: Insert a user with email addresses but no emailAddresses2
99+
Session session = openSession();
100+
session.beginTransaction();
101+
102+
User user = new User();
103+
user.setName( "john" );
104+
Contact contact = new Contact();
105+
contact.setName( "John Doe" );
106+
contact.setEmailAddresses( emailAddresses );
107+
contact = (Contact) session.merge( contact );
108+
user.setContact( contact );
109+
user = (User) session.merge( user );
110+
111+
session.getTransaction().commit();
112+
session.close();
113+
}
114+
{
115+
// Session 2: Retrieve the user object and check if the sets have the expected values
116+
Session session = openSession();
117+
session.beginTransaction();
118+
final String qry = "SELECT user "
119+
+ "FROM User user "
120+
+ "LEFT OUTER JOIN FETCH user.contact c "
121+
+ "LEFT OUTER JOIN FETCH c.emailAddresses2 "
122+
+ "LEFT OUTER JOIN FETCH c.emailAddresses";
123+
User user = (User) session.createQuery( qry ).uniqueResult();
124+
session.getTransaction().commit();
125+
session.close();
126+
127+
Assert.assertEquals( emailAddresses, user.getContact().getEmailAddresses() );
128+
Assert.assertTrue( user.getContact().getEmailAddresses2().isEmpty() );
129+
}
130+
131+
}
132+
133+
}

hibernate-core/src/test/java/org/hibernate/test/collection/set/hhh8206/User.java renamed to hibernate-core/src/test/java/org/hibernate/test/collection/basic/User.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
1-
package org.hibernate.test.collection.set.hhh8206;
1+
package org.hibernate.test.collection.basic;
22

33
import java.io.Serializable;
4-
import java.util.HashSet;
5-
import java.util.Set;
64
import javax.persistence.Basic;
7-
import javax.persistence.CollectionTable;
8-
import javax.persistence.ElementCollection;
95
import javax.persistence.Entity;
10-
import javax.persistence.FetchType;
116
import javax.persistence.GeneratedValue;
127
import javax.persistence.GenerationType;
138
import javax.persistence.Id;
149
import javax.persistence.JoinColumn;
15-
import javax.persistence.ManyToMany;
1610
import javax.persistence.ManyToOne;
17-
import javax.persistence.OneToMany;
1811
import javax.persistence.Table;
1912

2013
@Entity

hibernate-core/src/test/java/org/hibernate/test/collection/set/hhh8206/JoinFetchElementCollectionTest.java

Lines changed: 0 additions & 61 deletions
This file was deleted.

0 commit comments

Comments
 (0)