Skip to content

Commit 3eb9c4b

Browse files
committed
Fix parsing entity names in JPQL query with package names that contain reserved words.
Resolves: #3451 Original pull request: #3457
1 parent f3918d8 commit 3eb9c4b

File tree

5 files changed

+134
-48
lines changed

5 files changed

+134
-48
lines changed

spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4

+86-2
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ identification_variable
638638
;
639639

640640
constructor_name
641-
: state_field_path_expression
641+
: entity_name
642642
;
643643

644644
literal
@@ -720,7 +720,7 @@ collection_value_field
720720
;
721721

722722
entity_name
723-
: identification_variable ('.' identification_variable)* // Hibernate sometimes expands the entity name to FQDN when using named queries
723+
: reserved_word ('.' reserved_word)* // Hibernate sometimes expands the entity name to FQDN when using named queries
724724
;
725725

726726
result_variable
@@ -748,6 +748,90 @@ character_valued_input_parameter
748748
| input_parameter
749749
;
750750

751+
reserved_word
752+
: IDENTIFICATION_VARIABLE
753+
| f=(ABS
754+
|ALL
755+
|AND
756+
|ANY
757+
|AS
758+
|ASC
759+
|AVG
760+
|BETWEEN
761+
|BOTH
762+
|BY
763+
|CASE
764+
|CEILING
765+
|COALESCE
766+
|CONCAT
767+
|COUNT
768+
|CURRENT_DATE
769+
|CURRENT_TIME
770+
|CURRENT_TIMESTAMP
771+
|DATE
772+
|DATETIME
773+
|DELETE
774+
|DESC
775+
|DISTINCT
776+
|END
777+
|ELSE
778+
|EMPTY
779+
|ENTRY
780+
|ESCAPE
781+
|EXISTS
782+
|EXP
783+
|EXTRACT
784+
|FALSE
785+
|FETCH
786+
|FLOOR
787+
|FUNCTION
788+
|IN
789+
|INDEX
790+
|INNER
791+
|IS
792+
|KEY
793+
|LEFT
794+
|LENGTH
795+
|LIKE
796+
|LN
797+
|LOCAL
798+
|LOCATE
799+
|LOWER
800+
|MAX
801+
|MEMBER
802+
|MIN
803+
|MOD
804+
|NEW
805+
|NOT
806+
|NULL
807+
|NULLIF
808+
|OBJECT
809+
|OF
810+
|ON
811+
|OR
812+
|ORDER
813+
|OUTER
814+
|POWER
815+
|ROUND
816+
|SELECT
817+
|SET
818+
|SIGN
819+
|SIZE
820+
|SOME
821+
|SQRT
822+
|SUBSTRING
823+
|SUM
824+
|THEN
825+
|TIME
826+
|TRAILING
827+
|TREAT
828+
|TRIM
829+
|TRUE
830+
|TYPE
831+
|UPDATE
832+
|UPPER
833+
|VALUE)
834+
;
751835
/*
752836
Lexer rules
753837
*/

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java

+14-3
Original file line numberDiff line numberDiff line change
@@ -2331,7 +2331,7 @@ public List<JpaQueryParsingToken> visitConstructor_name(EqlParser.Constructor_na
23312331

23322332
List<JpaQueryParsingToken> tokens = new ArrayList<>();
23332333

2334-
tokens.addAll(visit(ctx.state_field_path_expression()));
2334+
tokens.addAll(visit(ctx.entity_name()));
23352335
NOSPACE(tokens);
23362336

23372337
return tokens;
@@ -2492,8 +2492,8 @@ public List<JpaQueryParsingToken> visitEntity_name(EqlParser.Entity_nameContext
24922492

24932493
List<JpaQueryParsingToken> tokens = new ArrayList<>();
24942494

2495-
ctx.identification_variable().forEach(identificationVariableContext -> {
2496-
tokens.addAll(visit(identificationVariableContext));
2495+
ctx.reserved_word().forEach(identificationVariableContext -> {
2496+
tokens.addAll(visitReserved_word(identificationVariableContext));
24972497
NOSPACE(tokens);
24982498
tokens.add(TOKEN_DOT);
24992499
});
@@ -2543,4 +2543,15 @@ public List<JpaQueryParsingToken> visitCharacter_valued_input_parameter(
25432543
return List.of();
25442544
}
25452545
}
2546+
2547+
@Override
2548+
public List<JpaQueryParsingToken> visitReserved_word(EqlParser.Reserved_wordContext ctx) {
2549+
if (ctx.IDENTIFICATION_VARIABLE() != null) {
2550+
return List.of(new JpaQueryParsingToken(ctx.IDENTIFICATION_VARIABLE()));
2551+
} else if (ctx.f != null) {
2552+
return List.of(new JpaQueryParsingToken(ctx.f));
2553+
} else {
2554+
return List.of();
2555+
}
2556+
}
25462557
}

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java

+20-12
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@
1818
import static org.assertj.core.api.Assertions.*;
1919
import static org.springframework.data.jpa.repository.query.JpaQueryParsingToken.*;
2020

21+
import java.util.stream.Stream;
22+
2123
import org.antlr.v4.runtime.CharStreams;
2224
import org.antlr.v4.runtime.CommonTokenStream;
2325
import org.junit.jupiter.api.Disabled;
2426
import org.junit.jupiter.api.Test;
2527
import org.junit.jupiter.params.ParameterizedTest;
28+
import org.junit.jupiter.params.provider.Arguments;
29+
import org.junit.jupiter.params.provider.MethodSource;
2630
import org.junit.jupiter.params.provider.ValueSource;
2731

2832
/**
@@ -55,6 +59,10 @@ private static String parseWithoutChanges(String query) {
5559
return render(new EqlQueryRenderer().visit(parsedQuery));
5660
}
5761

62+
static Stream<Arguments> reservedWords() {
63+
return Stream.of("abs", "exp", "any", "case", "else", "index", "time").map(Arguments::of);
64+
}
65+
5866
private void assertQuery(String query) {
5967

6068
String slimmedDownQuery = reduceWhitespace(query);
@@ -997,25 +1005,25 @@ void powerShouldBeLegalInAQuery() {
9971005
}
9981006

9991007
@ParameterizedTest // GH-3342
1000-
@ValueSource(strings = {
1001-
"select 1 from User u",
1002-
"select -1 from User u",
1003-
"select +1 from User u",
1004-
"select +1*-100 from User u",
1005-
"select count(u)*-0.7f from User u",
1008+
@ValueSource(strings = { "select 1 from User u", "select -1 from User u", "select +1 from User u",
1009+
"select +1*-100 from User u", "select count(u)*-0.7f from User u",
10061010
"select count(oi) + (-100) as perc from StockOrderItem oi",
1007-
"select p from Payment p where length(p.cardNumber) between +16 and -20"
1008-
})
1011+
"select p from Payment p where length(p.cardNumber) between +16 and -20" })
10091012
void signedLiteralShouldWork(String query) {
10101013
assertQuery(query);
10111014
}
10121015

10131016
@ParameterizedTest // GH-3342
1014-
@ValueSource(strings = {
1015-
"select -count(u) from User u",
1016-
"select +1*(-count(u)) from User u"
1017-
})
1017+
@ValueSource(strings = { "select -count(u) from User u", "select +1*(-count(u)) from User u" })
10181018
void signedExpressionsShouldWork(String query) {
10191019
assertQuery(query);
10201020
}
1021+
1022+
@ParameterizedTest // GH-3451
1023+
@MethodSource("reservedWords")
1024+
void entityNameWithPackageContainingReservedWord(String reservedWord) {
1025+
1026+
String source = "select new com.company.%s.thing.stuff.ClassName(e.id) from Experience e".formatted(reservedWord);
1027+
assertQuery(source);
1028+
}
10211029
}

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java

+7-15
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ private static String parseWithoutChanges(String query) {
6161
return render(new HqlQueryRenderer().visit(parsedQuery));
6262
}
6363

64-
public static Stream<Arguments> reservedWords() {
64+
static Stream<Arguments> reservedWords() {
6565
return Stream.of("abs", "exp", "any", "case", "else", "index", "time").map(Arguments::of);
6666
}
6767

@@ -1648,30 +1648,22 @@ group by extract(epoch from departureTime)
16481648
}
16491649

16501650
@ParameterizedTest // GH-3342
1651-
@ValueSource(strings = {
1652-
"select 1 from User",
1653-
"select -1 from User",
1654-
"select +1 from User",
1655-
"select +1*-100 from User",
1656-
"select count(u)*-0.7f from User u",
1657-
"select count(oi) + (-100) as perc from StockOrderItem oi",
1658-
"select p from Payment p where length(p.cardNumber) between +16 and -20"
1659-
})
1651+
@ValueSource(
1652+
strings = { "select 1 from User", "select -1 from User", "select +1 from User", "select +1*-100 from User",
1653+
"select count(u)*-0.7f from User u", "select count(oi) + (-100) as perc from StockOrderItem oi",
1654+
"select p from Payment p where length(p.cardNumber) between +16 and -20" })
16601655
void signedLiteralShouldWork(String query) {
16611656
assertQuery(query);
16621657
}
16631658

16641659
@ParameterizedTest // GH-3342
1665-
@ValueSource(strings = {
1666-
"select -count(u) from User u",
1667-
"select +1*(-count(u)) from User u"
1668-
})
1660+
@ValueSource(strings = { "select -count(u) from User u", "select +1*(-count(u)) from User u" })
16691661
void signedExpressionsShouldWork(String query) {
16701662
assertQuery(query);
16711663
}
16721664

16731665
@ParameterizedTest // GH-3451
1674-
@MethodSource({"reservedWords"})
1666+
@MethodSource("reservedWords")
16751667
void entityNameWithPackageContainingReservedWord(String reservedWord) {
16761668

16771669
String source = "select new com.company.%s.thing.stuff.ClassName(e.id) from Experience e".formatted(reservedWord);

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java

+7-16
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ private static String parseWithoutChanges(String query) {
6060
return render(new JpqlQueryRenderer().visit(parsedQuery));
6161
}
6262

63-
public static Stream<Arguments> reservedWords() {
63+
static Stream<Arguments> reservedWords() {
6464
return Stream.of("abs", "exp", "any", "case", "else", "index", "time").map(Arguments::of);
6565
}
6666

@@ -1006,35 +1006,26 @@ void powerShouldBeLegalInAQuery() {
10061006
}
10071007

10081008
@ParameterizedTest // GH-3342
1009-
@ValueSource(strings = {
1010-
"select 1 as value from User u",
1011-
"select -1 as value from User u",
1012-
"select +1 as value from User u",
1013-
"select +1*-100 as value from User u",
1014-
"select count(u)*-0.7f as value from User u",
1015-
"select count(oi) + (-100) as perc from StockOrderItem oi",
1016-
"select p from Payment p where length(p.cardNumber) between +16 and -20"
1017-
})
1009+
@ValueSource(strings = { "select 1 as value from User u", "select -1 as value from User u",
1010+
"select +1 as value from User u", "select +1*-100 as value from User u",
1011+
"select count(u)*-0.7f as value from User u", "select count(oi) + (-100) as perc from StockOrderItem oi",
1012+
"select p from Payment p where length(p.cardNumber) between +16 and -20" })
10181013
void signedLiteralShouldWork(String query) {
10191014
assertQuery(query);
10201015
}
10211016

10221017
@ParameterizedTest // GH-3342
1023-
@ValueSource(strings = {
1024-
"select -count(u) from User u",
1025-
"select +1*(-count(u)) from User u"
1026-
})
1018+
@ValueSource(strings = { "select -count(u) from User u", "select +1*(-count(u)) from User u" })
10271019
void signedExpressionsShouldWork(String query) {
10281020
assertQuery(query);
10291021
}
10301022

10311023
@ParameterizedTest // GH-3451
1032-
@MethodSource({"reservedWords"})
1024+
@MethodSource("reservedWords")
10331025
void entityNameWithPackageContainingReservedWord(String reservedWord) {
10341026

10351027
String source = "select new com.company.%s.thing.stuff.ClassName(e.id) from Experience e".formatted(reservedWord);
10361028
assertQuery(source);
10371029
}
10381030

1039-
10401031
}

0 commit comments

Comments
 (0)