Skip to content

Commit 8c1174f

Browse files
committed
Fix parsing entity names in JPQL query with package names that contain reserved words.
Resolves: spring-projects#3451 Original pull request: spring-projects#3457
1 parent 6a2510d commit 8c1174f

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
/**
@@ -53,6 +57,10 @@ private static String parseWithoutChanges(String query) {
5357
return render(new EqlQueryRenderer().visit(parsedQuery));
5458
}
5559

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

5866
String slimmedDownQuery = reduceWhitespace(query);
@@ -995,25 +1003,25 @@ void powerShouldBeLegalInAQuery() {
9951003
}
9961004

9971005
@ParameterizedTest // GH-3342
998-
@ValueSource(strings = {
999-
"select 1 from User u",
1000-
"select -1 from User u",
1001-
"select +1 from User u",
1002-
"select +1*-100 from User u",
1003-
"select count(u)*-0.7f from User u",
1006+
@ValueSource(strings = { "select 1 from User u", "select -1 from User u", "select +1 from User u",
1007+
"select +1*-100 from User u", "select count(u)*-0.7f from User u",
10041008
"select count(oi) + (-100) as perc from StockOrderItem oi",
1005-
"select p from Payment p where length(p.cardNumber) between +16 and -20"
1006-
})
1009+
"select p from Payment p where length(p.cardNumber) between +16 and -20" })
10071010
void signedLiteralShouldWork(String query) {
10081011
assertQuery(query);
10091012
}
10101013

10111014
@ParameterizedTest // GH-3342
1012-
@ValueSource(strings = {
1013-
"select -count(u) from User u",
1014-
"select +1*(-count(u)) from User u"
1015-
})
1015+
@ValueSource(strings = { "select -count(u) from User u", "select +1*(-count(u)) from User u" })
10161016
void signedExpressionsShouldWork(String query) {
10171017
assertQuery(query);
10181018
}
1019+
1020+
@ParameterizedTest // GH-3451
1021+
@MethodSource("reservedWords")
1022+
void entityNameWithPackageContainingReservedWord(String reservedWord) {
1023+
1024+
String source = "select new com.company.%s.thing.stuff.ClassName(e.id) from Experience e".formatted(reservedWord);
1025+
assertQuery(source);
1026+
}
10191027
}

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

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

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

@@ -1646,30 +1646,22 @@ group by extract(epoch from departureTime)
16461646
}
16471647

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

16621657
@ParameterizedTest // GH-3342
1663-
@ValueSource(strings = {
1664-
"select -count(u) from User u",
1665-
"select +1*(-count(u)) from User u"
1666-
})
1658+
@ValueSource(strings = { "select -count(u) from User u", "select +1*(-count(u)) from User u" })
16671659
void signedExpressionsShouldWork(String query) {
16681660
assertQuery(query);
16691661
}
16701662

16711663
@ParameterizedTest // GH-3451
1672-
@MethodSource({"reservedWords"})
1664+
@MethodSource("reservedWords")
16731665
void entityNameWithPackageContainingReservedWord(String reservedWord) {
16741666

16751667
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
@@ -58,7 +58,7 @@ private static String parseWithoutChanges(String query) {
5858
return render(new JpqlQueryRenderer().visit(parsedQuery));
5959
}
6060

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

@@ -1004,35 +1004,26 @@ void powerShouldBeLegalInAQuery() {
10041004
}
10051005

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

10201015
@ParameterizedTest // GH-3342
1021-
@ValueSource(strings = {
1022-
"select -count(u) from User u",
1023-
"select +1*(-count(u)) from User u"
1024-
})
1016+
@ValueSource(strings = { "select -count(u) from User u", "select +1*(-count(u)) from User u" })
10251017
void signedExpressionsShouldWork(String query) {
10261018
assertQuery(query);
10271019
}
10281020

10291021
@ParameterizedTest // GH-3451
1030-
@MethodSource({"reservedWords"})
1022+
@MethodSource("reservedWords")
10311023
void entityNameWithPackageContainingReservedWord(String reservedWord) {
10321024

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

1037-
10381029
}

0 commit comments

Comments
 (0)