18
18
import static org .springframework .data .jpa .repository .query .QueryParsingToken .*;
19
19
20
20
import java .util .List ;
21
+ import java .util .regex .Pattern ;
21
22
22
23
import org .antlr .v4 .runtime .ParserRuleContext ;
24
+ import org .springframework .dao .InvalidDataAccessApiUsageException ;
23
25
import org .springframework .data .domain .Sort ;
26
+ import org .springframework .data .jpa .domain .JpaSort ;
24
27
import org .springframework .lang .Nullable ;
25
28
import org .springframework .util .Assert ;
26
29
@@ -56,8 +59,8 @@ String getQuery() {
56
59
abstract ParserRuleContext parse ();
57
60
58
61
/**
59
- * Create a string-based query using the original query with an @literal order by} added (or amended) based upon
60
- * {@link Sort}
62
+ * Generate a query using the original query with an @literal order by} clause added (or amended) based upon the
63
+ * provider {@link Sort} parameter.
61
64
*
62
65
* @param parsedQuery
63
66
* @param sort can be {@literal null}
@@ -69,7 +72,7 @@ String createQuery(ParserRuleContext parsedQuery, Sort sort) {
69
72
}
70
73
71
74
/**
72
- * Create a string -based count query using the original query.
75
+ * Generate a count -based query using the original query.
73
76
*
74
77
* @param parsedQuery
75
78
* @param countProjection
@@ -92,7 +95,8 @@ String projection(ParserRuleContext parsedQuery) {
92
95
}
93
96
94
97
/**
95
- * Create a {@link QueryParsingToken}-based query with an {@literal order by} applied/amended based upon {@link Sort}.
98
+ * Create a {@link QueryParsingToken}-based query with an {@literal order by} applied/amended based upon the
99
+ * {@link Sort} parameter.
96
100
*
97
101
* @param parsedQuery
98
102
* @param sort can be {@literal null}
@@ -108,25 +112,48 @@ String projection(ParserRuleContext parsedQuery) {
108
112
abstract List <QueryParsingToken > doCreateCountQuery (ParserRuleContext parsedQuery , @ Nullable String countProjection );
109
113
110
114
/**
111
- * Find the alias of the query's FROM clause
115
+ * Find the alias of the query's primary FROM clause
112
116
*
113
117
* @return can be {@literal null}
114
118
*/
115
119
abstract String findAlias (ParserRuleContext parsedQuery );
116
120
117
121
/**
118
- * Find the projection of the query's selection clause.
122
+ * Find the projection of the query's primary SELECT clause.
119
123
*
120
124
* @param parsedQuery
121
125
*/
122
126
abstract List <QueryParsingToken > doFindProjection (ParserRuleContext parsedQuery );
123
127
124
128
/**
125
- * Discern if the query has a new {@code com.example.Dto()} DTO constructor in the select clause.
129
+ * Discern if the query has a {@code new com.example.Dto()} DTO constructor in the select clause.
126
130
*
127
131
* @param parsedQuery
128
132
* @return Guaranteed to be {@literal true} or {@literal false}.
129
133
*/
130
134
abstract boolean hasConstructor (ParserRuleContext parsedQuery );
131
135
136
+ private static final Pattern PUNCTUATION_PATTERN = Pattern .compile (".*((?![._])[\\ p{Punct}|\\ s])" );
137
+
138
+ private static final String UNSAFE_PROPERTY_REFERENCE = "Sort expression '%s' must only contain property references or "
139
+ + "aliases used in the select clause; If you really want to use something other than that for sorting, please use "
140
+ + "JpaSort.unsafe(…)" ;
141
+
142
+ /**
143
+ * Check any given {@link JpaSort.JpaOrder#isUnsafe()} order for presence of at least one property offending the
144
+ * {@link #PUNCTUATION_PATTERN} and throw an {@link Exception} indicating potential unsafe order by expression.
145
+ *
146
+ * @param order
147
+ */
148
+ static void checkSortExpression (Sort .Order order ) {
149
+
150
+ if (order instanceof JpaSort .JpaOrder && ((JpaSort .JpaOrder ) order ).isUnsafe ()) {
151
+ return ;
152
+ }
153
+
154
+ if (PUNCTUATION_PATTERN .matcher (order .getProperty ()).find ()) {
155
+ throw new InvalidDataAccessApiUsageException (String .format (UNSAFE_PROPERTY_REFERENCE , order ));
156
+ }
157
+ }
158
+
132
159
}
0 commit comments