8000 HHH-6686 fix JQL exception in face of 'empty' · hibernate/hibernate-orm@23ebc38 · GitHub
[go: up one dir, main page]

Skip to content

Commit 23ebc38

Browse files
Nathan Xusebersole
Nathan Xu
authored andcommitted
HHH-6686 fix JQL exception in face of 'empty'
1 parent 69ffd8e commit 23ebc38

File tree

3 files changed

+108
-10
lines changed

3 files changed

+108
-10
lines changed

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

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import org.hibernate.QueryException;
1919
import org.hibernate.hql.internal.antlr.HqlBaseParser;
2020
import org.hibernate.hql.internal.antlr.HqlTokenTypes;
21-
import org.hibernate.hql.internal.ast.util.ASTPrinter;
2221
import org.hibernate.hql.internal.ast.util.ASTUtil;
2322
import org.hibernate.hql.internal.ast.util.TokenPrinters;
2423
import org.hibernate.internal.CoreLogging;
@@ -116,7 +115,7 @@ public ParseErrorHandler getParseErrorHandler() {
116115
* @param token The token.
117116
* @param ex The recognition exception.
118117
*
119-
* @return AST - The new AST.
118+
* @return The new AST.
120119
*
121120
* @throws antlr.RecognitionException if the substitution was not possible.
122121
* @throws antlr.TokenStreamException if the substitution was not possible.
@@ -159,7 +158,7 @@ public AST handleIdentifierError(Token token, RecognitionException ex)
159158
*
160159
* @param x The sub tree to transform, the parent is assumed to be NOT.
161160
*
162-
* @return AST - The equivalent sub-tree.
161+
* @return The equivalent sub-tree.
163162
*/
164163
@Override
165164
public AST negateNode(AST x) {
@@ -286,7 +285,7 @@ public AST negateNode(AST x) {
286285
*
287286
* @param x The equality expression.
288287
*
289-
* @return AST - The clean sub-tree.
288+
* @return The clean sub-tree.
290289
*/
291290
@Override
292291
public AST processEqualityExpression(AST x) {
@@ -348,6 +347,10 @@ private AST processIsEmpty(AST node, boolean negated) {
348347
private AST createSubquery(AST node) {
349348
AST ast = ASTUtil.createParent( astFactory, RANGE, "RANGE", node );
350349
ast = ASTUtil.createParent( astFactory, FROM, "from", ast );
350+
351+
AST alias = ASTUtil.createSibling( astFactory, ALIAS, "_", node );
352+
ASTUtil.insertChild( ASTUtil.createSibling( astFactory, SELECT, "select", ast ), astFactory.create(IDENT, alias.getText() ) );
353+
351354
ast = ASTUtil.createParent( astFactory, SELECT_FROM, "SELECT_FROM", ast );
352355
ast = ASTUtil.createParent( astFactory, QUERY, "QUERY", ast );
353356
return ast;
@@ -489,12 +492,12 @@ protected void registerTreat(AST pathToTreat, AST treatAs) {
489492
LOG.debugf( "Registering discovered request to treat(%s as %s)", path, subclassName );
490493

491494
if ( treatMap == null ) {
492-
treatMap = new HashMap<String, Set<String>>();
495+
treatMap = new HashMap<>();
493496
}
494497

495498
Set<String> subclassNames = treatMap.get( path );
496499
if ( subclassNames == null ) {
497-
subclassNames = new HashSet<String>();
500+
subclassNames = new HashSet<>();
498501
treatMap.put( path, subclassNames );
499502
}
500503
subclassNames.add( subclassName );
@@ -512,11 +515,11 @@ private String toPathText(AST node) {
512515
}
513516

514517
public Map<String, Set<String>> getTreatMap() {
515-
return treatMap == null ? Collections.<String, Set<String>>emptyMap() : treatMap;
518+
return treatMap == null ? Collections.emptyMap() : treatMap;
516519
}
517520

518521
public static void panic() {
519-
//overriden to avoid System.exit
522+
//overridden to avoid System.exit
520523
throw new QueryException( "Parser: panic" );
521524
}
522525
}

hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/paths/PluralAttributeExpressionsTest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ public void testCollectionIsEmptyCriteria() {
7272

7373
@Test
7474
@TestForIssue( jiraKey = "HHH-11225" )
75-
@FailureExpected( jiraKey = "HHH-6686")
7675
public void testElementMapIsEmptyHql() {
7776
doInJPA( this::entityManagerFactory, entityManager -> {
7877
entityManager.createQuery( "select m from MapEntity m where m.localized is empty" ).getResultList();
@@ -81,7 +80,6 @@ public void testElementMapIsEmptyHql() {
8180

8281
@Test
8382
@TestForIssue( jiraKey = "HHH-11225" )
84-
@FailureExpected( jiraKey = "HHH-6686")
8583
public void testElementMapIsEmptyCriteria() {
8684
doInJPA( this::entityManagerFactory, entityManager -> {
8785
final HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) entityManager.getCriteriaBuilder();
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package org.hibernate.query;
2+
3+
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
4+
import org.hibernate.testing.TestForIssue;
5+
import org.junit.Test;
6+
7+
import javax.persistence.*;
8+
import java.util.*;
9+
import java.util.stream.Collectors;
10+
11+
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
12+
import static org.junit.Assert.assertEquals;
13+
14+
/**
15+
* @author Nathan Xu
16+
*/
17+
@TestForIssue(jiraKey = "HHH-6686")
18+
public class IsEmptyJQLTest extends BaseEntityManagerFunctionalTestCase {
19+
20+
private Long personWithoutNicknameId = 1L;
21+
private Long personaWithSingleNicknameId = 2L;
22+
private Long personWithMultipleNicknamesId = 3L;
23+
24+
@Override
25+
public Class<?>[] getAnnotatedClasses() {
26+
return new Class[] { Person.class };
27+
}
28+
29+
@Test
30+
public void testJQLContainingEmpty() {
31+
List<Person> personWithNicknames = doInJPA( this::entityManagerFactory, entityManager -> {
32+
return entityManager.createQuery(
33+
"select p from Person p where p.nicknames is not empty", Person.class )
34+
.getResultList();
35+
});
36+
37+
assertEquals( new HashSet<>( Arrays.asList(personaWithSingleNicknameId, personWithMultipleNicknamesId)),
38+
personWithNicknames.stream().map( Person::getId ).collect( Collectors.toSet() ));
39+
40+
List<Person> personWithOutNickname = doInJPA( this::entityManagerFactory, entityManager -> {
41+
return entityManager.createQuery(
42+
"select p from Person p where p.nicknames is empty", Person.class )
43+
.getResultList();
44+
});
45+
46+
assertEquals( Collections.singleton(personWithoutNicknameId),
47+
personWithOutNickname.stream().map( Person::getId ).collect( Collectors.toSet() ));
48+
}
49+
50+
@Override
51+
protected void afterEntityManagerFactoryBuilt() {
52+
doInJPA( this::entityManagerFactory, entityManager -> {
53+
Person personaWithoutNickname = new Person();
54+
personaWithoutNickname.setId(personWithoutNicknameId);
55+
56+
Person personaWithSingleNickname = new Person();
57+
personaWithSingleNickname.getNicknames().add( "nickname" );
58+
personaWithSingleNickname.setId(personaWithSingleNicknameId);
59+
60+
Person personWithMultipleNicknames = new Person();
61+
personWithMultipleNicknames.getNicknames().addAll( Arrays.asList( "nickName1", "nickName2" ) );
62+
personWithMultipleNicknames.setId(personWithMultipleNicknamesId);
63+
64+
entityManager.persist( personaWithoutNickname );
65+
entityManager.persist( personaWithSingleNickname );
66+
entityManager.persist( personWithMultipleNicknames );
67+
} );
68+
}
69+
70+
@Entity(name = "Person")
71+
public static class Person {
72+
73+
@Id
74+
private Long id;
75+
76+
@ElementCollection
77+
private List<String> nicknames = new ArrayList<>();
78+
79+
public Long getId() {
80+
return id;
81+
}
82+
83+
public void setId(Long id) {
84+
this.id = id;
85+
}
86+
87+
public List<String> getNicknames() {
88+
return nicknames;
89+
}
90+
91+
public void setNicknames(List<String> nicknames) {
92+
this.nicknames = nicknames;
93+
}
94+
}
95+
}
96+
97+

0 commit comments

Comments
 (0)
0