parserFactoryFunction, Function parseFunction) {
+ P parser = getParser(query, lexerFactoryFunction, parserFactoryFunction);
+
+ parser.getInterpreter().setPredictionMode(PredictionMode.SLL);
+ parser.setErrorHandler(new BailErrorStrategy() {
+ @Override
+ public void reportError(Parser recognizer, RecognitionException e) {
+
+ // avoid BadJpqlGrammarException creation in the first pass.
+ // recover(…) is going to handle cancellation.
+ }
+ });
+
+ try {
+
+ return parseFunction.apply(parser);
+ } catch (BadJpqlGrammarException | ParseCancellationException e) {
+
+ parser = getParser(query, lexerFactoryFunction, parserFactoryFunction);
+ // fall back to LL(*)-based parsing
+ parser.getInterpreter().setPredictionMode(PredictionMode.LL);
+
+ return parseFunction.apply(parser);
+ }
+ }
+
+ private static
P getParser(String query, Function lexerFactoryFunction,
+ Function parserFactoryFunction) {
+
Lexer lexer = lexerFactoryFunction.apply(CharStreams.fromString(query));
P parser = parserFactoryFunction.apply(new CommonTokenStream(lexer));
- configureParser(query, lexer, parser);
+ String grammar = lexer.getGrammarFileName();
+ int dot = grammar.lastIndexOf('.');
+ if (dot != -1) {
+ grammar = grammar.substring(0, dot);
+ }
+
+ configureParser(query, grammar.toUpperCase(), lexer, parser);
- return parseFunction.apply(parser);
+ return parser;
}
/**
- * Apply common configuration (SLL prediction for performance, our own error listeners).
+ * Apply common configuration.
*
* @param query
* @param lexer
* @param parser
*/
- static void configureParser(String query, Lexer lexer, Parser parser) {
+ static void configureParser(String query, String grammar, Lexer lexer, Parser parser) {
- BadJpqlGrammarErrorListener errorListener = new BadJpqlGrammarErrorListener(query);
+ BadJpqlGrammarErrorListener errorListener = new BadJpqlGrammarErrorListener(query, grammar);
lexer.removeErrorListeners();
lexer.addErrorListener(errorListener);
- parser.getInterpreter().setPredictionMode(PredictionMode.SLL);
-
parser.removeErrorListeners();
parser.addErrorListener(errorListener);
}
@@ -136,6 +177,13 @@ public static JpaQueryEnhancer forEql(DeclaredQuery query) {
return EqlQueryParser.parseQuery(query.getQueryString());
}
+ /**
+ * @return the parser context (AST) representing the parsed query.
+ */
+ ParserRuleContext getContext() {
+ return context;
+ }
+
/**
* Checks if the select clause has a new constructor instantiation in the JPA query.
*
@@ -180,7 +228,7 @@ public Set getJoinAliases() {
*/
@Override
public DeclaredQuery getQuery() {
- throw new UnsupportedOperationException();
+ return DeclaredQuery.of(applySorting(Sort.unsorted()), false);
}
/**
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java
index 82482cd99c..35a680c8fe 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryFactory.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryFactory.java
index a998e1a086..82babfb9e4 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryFactory.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java
index 136a16b271..6d25af839a 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -181,11 +181,9 @@ protected RepositoryQuery resolveQuery(JpaQueryMethod method, QueryRewriter quer
getCountQuery(method, namedQueries, em), queryRewriter, valueExpressionDelegate);
}
- RepositoryQuery query = NamedQuery.lookupFrom(method, em);
+ RepositoryQuery query = NamedQuery.lookupFrom(method, em, queryRewriter);
- return query != null //
- ? query //
- : NO_QUERY;
+ return query != null ? query : NO_QUERY;
}
@Nullable
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java
index 885b989bbe..97b6390d22 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,6 @@
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@@ -70,20 +69,10 @@ public class JpaQueryMethod extends QueryMethod {
* Persistence Specification: Persistent Fields and Properties - Paragraph starting with
* "Collection-valued persistent...".
*/
- private static final Set> NATIVE_ARRAY_TYPES;
+ private static final Set> NATIVE_ARRAY_TYPES = Set.of(byte[].class, Byte[].class, char[].class,
+ Character[].class);
private static final StoredProcedureAttributeSource storedProcedureAttributeSource = StoredProcedureAttributeSource.INSTANCE;
- static {
-
- Set> types = new HashSet<>();
- types.add(byte[].class);
- types.add(Byte[].class);
- types.add(char[].class);
- types.add(Character[].class);
-
- NATIVE_ARRAY_TYPES = Collections.unmodifiableSet(types);
- }
-
private final QueryExtractor extractor;
private final Method method;
private final Class> returnType;
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethodFactory.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethodFactory.java
index 24326fe0ae..a5b5213127 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethodFactory.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethodFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaResultConverters.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaResultConverters.java
index 03c9d82adb..06382e5e9b 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaResultConverters.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaResultConverters.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlCountQueryTransformer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlCountQueryTransformer.java
index 2adac83e9b..eaecd6e73d 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlCountQueryTransformer.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlCountQueryTransformer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -100,6 +100,10 @@ private QueryRendererBuilder getDistinctCountSelection(QueryTokenStream selectio
if (countSelection.requiresPrimaryAlias()) {
// constructor
+ if (primaryFromAlias == null) {
+ throw new IllegalStateException(
+ "Primary alias must be set for DISTINCT count selection using constructor expressions");
+ }
nested.append(QueryTokens.token(primaryFromAlias));
} else {
// keep all the select items to distinct against
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryIntrospector.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryIntrospector.java
index 20551ff366..52162e791c 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryIntrospector.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryIntrospector.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java
index f743d50669..52455ebe14 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
import org.springframework.data.jpa.repository.query.JpqlParser.NullsPrecedenceContext;
import org.springframework.data.jpa.repository.query.JpqlParser.Reserved_wordContext;
import org.springframework.data.jpa.repository.query.QueryRenderer.QueryRendererBuilder;
+import org.springframework.util.CollectionUtils;
/**
* An ANTLR {@link org.antlr.v4.runtime.tree.ParseTreeVisitor} that renders a JPQL query without making any changes.
@@ -694,7 +695,7 @@ public QueryTokenStream visitAggregate_expression(JpqlParser.Aggregate_expressio
builder.append(QueryTokens.expression(ctx.DISTINCT()));
}
- builder.appendInline(visit(ctx.state_valued_path_expression()));
+ builder.appendInline(visit(ctx.simple_select_expression()));
builder.append(TOKEN_CLOSE_PAREN);
} else if (ctx.COUNT() != null) {
@@ -703,13 +704,8 @@ public QueryTokenStream visitAggregate_expression(JpqlParser.Aggregate_expressio
if (ctx.DISTINCT() != null) {
builder.append(QueryTokens.expression(ctx.DISTINCT()));
}
- if (ctx.identification_variable() != null) {
- builder.appendInline(visit(ctx.identification_variable()));
- } else if (ctx.state_valued_path_expression() != null) {
- builder.appendInline(visit(ctx.state_valued_path_expression()));
- } else if (ctx.single_valued_object_path_expression() != null) {
- builder.appendInline(visit(ctx.single_valued_object_path_expression()));
- }
+
+ builder.appendInline(visit(ctx.simple_select_expression()));
builder.append(TOKEN_CLOSE_PAREN);
} else if (ctx.function_invocation() != null) {
builder.append(visit(ctx.function_invocation()));
@@ -1078,8 +1074,8 @@ public QueryTokenStream visitIn_expression(JpqlParser.In_expressionContext ctx)
QueryRendererBuilder builder = QueryRenderer.builder();
- if (ctx.state_valued_path_expression() != null) {
- builder.appendExpression(visit(ctx.state_valued_path_expression()));
+ if (ctx.string_expression() != null) {
+ builder.appendExpression(visit(ctx.string_expression()));
}
if (ctx.type_discriminator() != null) {
builder.appendExpression(visit(ctx.type_discriminator()));
@@ -1113,8 +1109,18 @@ public QueryTokenStream visitIn_item(JpqlParser.In_itemContext ctx) {
if (ctx.literal() != null) {
return visit(ctx.literal());
+ } else if (ctx.string_expression() != null) {
+ return visit(ctx.string_expression());
+ } else if (ctx.boolean_literal() != null) {
+ return visit(ctx.boolean_literal());
+ } else if (ctx.numeric_literal() != null) {
+ return visit(ctx.numeric_literal());
+ } else if (ctx.date_time_timestamp_literal() != null) {
+ return visit(ctx.date_time_timestamp_literal());
} else if (ctx.single_valued_input_parameter() != null) {
return visit(ctx.single_valued_input_parameter());
+ } else if (ctx.conditional_expression() != null) {
+ return visit(ctx.conditional_expression());
}
return QueryTokenStream.empty();
@@ -1263,115 +1269,174 @@ public QueryTokenStream visitAll_or_any_expression(JpqlParser.All_or_any_express
}
@Override
- public QueryTokenStream visitComparison_expression(JpqlParser.Comparison_expressionContext ctx) {
+ public QueryTokenStream visitStringComparison(JpqlParser.StringComparisonContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
- if (!ctx.string_expression().isEmpty()) {
+ builder.appendInline(visit(ctx.string_expression(0)));
+ builder.append(visit(ctx.comparison_operator()));
- builder.appendExpression(visit(ctx.string_expression(0)));
- builder.appendExpression(visit(ctx.comparison_operator()));
+ if (ctx.string_expression(1) != null) {
+ builder.append(visit(ctx.string_expression(1)));
+ } else {
+ builder.append(visit(ctx.all_or_any_expression()));
+ }
- if (ctx.string_expression(1) != null) {
- builder.appendExpression(visit(ctx.string_expression(1)));
- } else {
- builder.appendExpression(visit(ctx.all_or_any_expression()));
- }
- } else if (!ctx.boolean_expression().isEmpty()) {
+ return builder;
+ }
- builder.appendInline(visit(ctx.boolean_expression(0)));
- builder.append(QueryTokens.ventilated(ctx.op));
+ @Override
+ public QueryTokenStream visitBooleanComparison(JpqlParser.BooleanComparisonContext ctx) {
- if (ctx.boolean_expression(1) != null) {
- builder.appendExpression(visit(ctx.boolean_expression(1)));
- } else {
- builder.appendExpression(visit(ctx.all_or_any_expression()));
- }
- } else if (!ctx.enum_expression().isEmpty()) {
+ QueryRendererBuilder builder = QueryRenderer.builder();
- builder.appendInline(visit(ctx.enum_expression(0)));
- builder.append(QueryTokens.ventilated(ctx.op));
+ builder.appendInline(visit(ctx.boolean_expression(0)));
+ builder.append(QueryTokens.ventilated(ctx.op));
- if (ctx.enum_expression(1) != null) {
- builder.appendExpression(visit(ctx.enum_expression(1)));
- } else {
- builder.appendExpression(visit(ctx.all_or_any_expression()));
- }
- } else if (!ctx.datetime_expression().isEmpty()) {
+ if (ctx.boolean_expression(1) != null) {
+ builder.append(visit(ctx.boolean_expression(1)));
+ } else {
+ builder.append(visit(ctx.all_or_any_expression()));
+ }
- builder.appendExpression(visit(ctx.datetime_expression(0)));
- builder.appendExpression(visit(ctx.comparison_operator()));
+ return builder;
+ }
- if (ctx.datetime_expression(1) != null) {
- builder.appendExpression(visit(ctx.datetime_expression(1)));
- } else {
- builder.appendExpression(visit(ctx.all_or_any_expression()));
- }
- } else if (!ctx.entity_expression().isEmpty()) {
+ @Override
+ public QueryTokenStream visitDirectBooleanCheck(JpqlParser.DirectBooleanCheckContext ctx) {
+ return visit(ctx.boolean_expression());
+ }
- builder.appendInline(visit(ctx.entity_expression(0)));
- builder.append(QueryTokens.ventilated(ctx.op));
+ @Override
+ public QueryTokenStream visitEnumComparison(JpqlParser.EnumComparisonContext ctx) {
- if (ctx.entity_expression(1) != null) {
- builder.appendExpression(visit(ctx.entity_expression(1)));
- } else {
- builder.appendExpression(visit(ctx.all_or_any_expression()));
- }
- } else if (!ctx.arithmetic_expression().isEmpty()) {
+ QueryRendererBuilder builder = QueryRenderer.builder();
- builder.appendExpression(visit(ctx.arithmetic_expression(0)));
- builder.appendExpression(visit(ctx.comparison_operator()));
+ builder.appendInline(visit(ctx.enum_expression(0)));
+ builder.append(QueryTokens.ventilated(ctx.op));
- if (ctx.arithmetic_expression(1) != null) {
- builder.appendExpression(visit(ctx.arithmetic_expression(1)));
- } else {
- builder.appendExpression(visit(ctx.all_or_any_expression()));
- }
- } else if (!ctx.entity_type_expression().isEmpty()) {
+ if (ctx.enum_expression(1) != null) {
+ builder.append(visit(ctx.enum_expression(1)));
+ } else {
+ builder.append(visit(ctx.all_or_any_expression()));
+ }
- builder.appendInline(visit(ctx.entity_type_expression(0)));
- builder.append(QueryTokens.ventilated(ctx.op));
- builder.appendExpression(visit(ctx.entity_type_expression(1)));
+ return builder;
+ }
+
+ @Override
+ public QueryTokenStream visitDatetimeComparison(JpqlParser.DatetimeComparisonContext ctx) {
+
+ QueryRendererBuilder builder = QueryRenderer.builder();
+
+ builder.appendInline(visit(ctx.datetime_expression(0)));
+ builder.append(QueryTokens.ventilated(ctx.comparison_operator().op));
+
+ if (ctx.datetime_expression(1) != null) {
+ builder.append(visit(ctx.datetime_expression(1)));
+ } else {
+ builder.append(visit(ctx.all_or_any_expression()));
}
return builder;
}
+ @Override
+ public QueryTokenStream visitEntityComparison(JpqlParser.EntityComparisonContext ctx) {
+
+ QueryRendererBuilder builder = QueryRenderer.builder();
+
+ builder.appendExpression(visit(ctx.entity_expression(0)));
+ builder.append(QueryTokens.expression(ctx.op));
+
+ if (ctx.entity_expression(1) != null) {
+ builder.append(visit(ctx.entity_expression(1)));
+ } else {
+ builder.append(visit(ctx.all_or_any_expression()));
+ }
+
+ return builder;
+ }
+
+ @Override
+ public QueryTokenStream visitArithmeticComparison(JpqlParser.ArithmeticComparisonContext ctx) {
+
+ QueryRendererBuilder builder = QueryRenderer.builder();
+
+ builder.append(visit(ctx.arithmetic_expression(0)));
+ builder.append(visit(ctx.comparison_operator()));
+
+ if (ctx.arithmetic_expression(1) != null) {
+ builder.append(visit(ctx.arithmetic_expression(1)));
+ } else {
+ builder.append(visit(ctx.all_or_any_expression()));
+ }
+
+ return builder;
+ }
+
+ @Override
+ public QueryTokenStream visitEntityTypeComparison(JpqlParser.EntityTypeComparisonContext ctx) {
+
+ QueryRendererBuilder builder = QueryRenderer.builder();
+
+ builder.appendInline(visit(ctx.entity_type_expression(0)));
+ builder.append(QueryTokens.ventilated(ctx.op));
+ builder.append(visit(ctx.entity_type_expression(1)));
+
+ return builder;
+ }
+
+ @Override
+ public QueryTokenStream visitRegexpComparison(JpqlParser.RegexpComparisonContext ctx) {
+
+ QueryRendererBuilder builder = QueryRenderer.builder();
+
+ builder.appendExpression(visit(ctx.string_expression()));
+ builder.append(QueryTokens.expression(ctx.REGEXP()));
+ builder.appendExpression(visit(ctx.string_literal()));
+
+ return builder;
+ }
+
@Override
public QueryTokenStream visitComparison_operator(JpqlParser.Comparison_operatorContext ctx) {
- return QueryRenderer.from(QueryTokens.token(ctx.op));
+ return QueryRendererBuilder.from(QueryTokens.ventilated(ctx.op));
}
@Override
public QueryTokenStream visitArithmetic_expression(JpqlParser.Arithmetic_expressionContext ctx) {
+ QueryRendererBuilder builder = QueryRenderer.builder();
+
if (ctx.arithmetic_expression() != null) {
- QueryRendererBuilder builder = QueryRenderer.builder();
builder.append(visit(ctx.arithmetic_expression()));
- builder.append(QueryTokens.ventilated(ctx.op));
+ builder.append(QueryTokens.expression(ctx.op));
builder.append(visit(ctx.arithmetic_term()));
- return builder;
} else {
- return visit(ctx.arithmetic_term());
+ builder.append(visit(ctx.arithmetic_term()));
}
+
+ return builder;
}
@Override
public QueryTokenStream visitArithmetic_term(JpqlParser.Arithmetic_termContext ctx) {
+ QueryRendererBuilder builder = QueryRenderer.builder();
+
if (ctx.arithmetic_term() != null) {
- QueryRendererBuilder builder = QueryRenderer.builder();
builder.appendInline(visit(ctx.arithmetic_term()));
builder.append(QueryTokens.ventilated(ctx.op));
builder.append(visit(ctx.arithmetic_factor()));
-
- return builder;
} else {
- return visit(ctx.arithmetic_factor());
+ builder.append(visit(ctx.arithmetic_factor()));
}
+
+ return builder;
}
@Override
@@ -1382,8 +1447,7 @@ public QueryTokenStream visitArithmetic_factor(JpqlParser.Arithmetic_factorConte
if (ctx.op != null) {
builder.append(QueryTokens.token(ctx.op));
}
-
- builder.append(visit(ctx.arithmetic_primary()));
+ builder.appendInline(visit(ctx.arithmetic_primary()));
return builder;
}
@@ -1410,6 +1474,10 @@ public QueryTokenStream visitArithmetic_primary(JpqlParser.Arithmetic_primaryCon
builder.append(visit(ctx.aggregate_expression()));
} else if (ctx.case_expression() != null) {
builder.append(visit(ctx.case_expression()));
+ } else if (ctx.arithmetic_cast_function() != null) {
+ builder.append(visit(ctx.arithmetic_cast_function()));
+ } else if (ctx.type_cast_function() != null) {
+ builder.append(visit(ctx.type_cast_function()));
} else if (ctx.function_invocation() != null) {
builder.append(visit(ctx.function_invocation()));
} else if (ctx.subquery() != null) {
@@ -1439,6 +1507,10 @@ public QueryTokenStream visitString_expression(JpqlParser.String_expressionConte
builder.append(visit(ctx.aggregate_expression()));
} else if (ctx.case_expression() != null) {
builder.append(visit(ctx.case_expression()));
+ } else if (ctx.string_cast_function() != null) {
+ builder.append(visit(ctx.string_cast_function()));
+ } else if (ctx.type_cast_function() != null) {
+ builder.append(visit(ctx.type_cast_function()));
} else if (ctx.function_invocation() != null) {
builder.append(visit(ctx.function_invocation()));
} else if (ctx.subquery() != null) {
@@ -1783,6 +1855,62 @@ public QueryTokenStream visitTrim_specification(JpqlParser.Trim_specificationCon
}
}
+ @Override
+ public QueryTokenStream visitArithmetic_cast_function(JpqlParser.Arithmetic_cast_functionContext ctx) {
+
+ QueryRendererBuilder builder = QueryRenderer.builder();
+
+ builder.append(QueryTokens.token(ctx.CAST()));
+ builder.append(TOKEN_OPEN_PAREN);
+ builder.appendExpression(visit(ctx.string_expression()));
+ if (ctx.AS() != null) {
+ builder.append(QueryTokens.expression(ctx.AS()));
+ }
+ builder.append(QueryTokens.token(ctx.f));
+ builder.append(TOKEN_CLOSE_PAREN);
+
+ return builder;
+ }
+
+ @Override
+ public QueryTokenStream visitType_cast_function(JpqlParser.Type_cast_functionContext ctx) {
+
+ QueryRendererBuilder builder = QueryRenderer.builder();
+
+ builder.append(QueryTokens.token(ctx.CAST()));
+ builder.append(TOKEN_OPEN_PAREN);
+ builder.appendExpression(visit(ctx.scalar_expression()));
+ if (ctx.AS() != null) {
+ builder.append(QueryTokens.expression(ctx.AS()));
+ }
+ builder.appendInline(visit(ctx.identification_variable()));
+
+ if (!CollectionUtils.isEmpty(ctx.numeric_literal())) {
+
+ builder.append(TOKEN_OPEN_PAREN);
+ builder.appendInline(QueryTokenStream.concat(ctx.numeric_literal(), this::visit, TOKEN_COMMA));
+ builder.append(TOKEN_CLOSE_PAREN);
+ }
+ builder.append(TOKEN_CLOSE_PAREN);
+
+ return builder;
+ }
+
+ @Override
+ public QueryTokenStream visitString_cast_function(JpqlParser.String_cast_functionContext ctx) {
+
+ QueryRendererBuilder builder = QueryRenderer.builder();
+
+ builder.append(QueryTokens.token(ctx.CAST()));
+ builder.append(TOKEN_OPEN_PAREN);
+ builder.appendExpression(visit(ctx.scalar_expression()));
+ builder.append(QueryTokens.expression(ctx.AS()));
+ builder.append(QueryTokens.token(ctx.STRING()));
+ builder.append(TOKEN_CLOSE_PAREN);
+
+ return builder;
+ }
+
@Override
public QueryTokenStream visitFunction_invocation(JpqlParser.Function_invocationContext ctx) {
@@ -1842,16 +1970,7 @@ public QueryTokenStream visitDatetime_part(JpqlParser.Datetime_partContext ctx)
@Override
public QueryTokenStream visitFunction_arg(JpqlParser.Function_argContext ctx) {
-
- if (ctx.literal() != null) {
- return visit(ctx.literal());
- } else if (ctx.state_valued_path_expression() != null) {
- return visit(ctx.state_valued_path_expression());
- } else if (ctx.input_parameter() != null) {
- return visit(ctx.input_parameter());
- } else {
- return visit(ctx.scalar_expression());
- }
+ return visit(ctx.simple_select_expression());
}
@Override
@@ -2049,7 +2168,16 @@ public QueryTokenStream visitEntity_type_literal(JpqlParser.Entity_type_literalC
@Override
public QueryTokenStream visitEscape_character(JpqlParser.Escape_characterContext ctx) {
- return QueryRenderer.from(QueryTokens.expression(ctx.CHARACTER()));
+
+ if (ctx.CHARACTER() != null) {
+ return QueryRenderer.from(QueryTokens.expression(ctx.CHARACTER()));
+ } else if (ctx.character_valued_input_parameter() != null) {
+ return visit(ctx.character_valued_input_parameter());
+ } else if (ctx.string_literal() != null) {
+ return visit(ctx.string_literal());
+ }
+
+ return QueryTokenStream.empty();
}
@Override
@@ -2108,21 +2236,36 @@ public QueryTokenStream visitSubtype(JpqlParser.SubtypeContext ctx) {
@Override
public QueryTokenStream visitCollection_valued_field(JpqlParser.Collection_valued_fieldContext ctx) {
+ if (ctx.reserved_word() != null) {
+ return visit(ctx.reserved_word());
+ }
return visit(ctx.identification_variable());
}
@Override
public QueryTokenStream visitSingle_valued_object_field(JpqlParser.Single_valued_object_fieldContext ctx) {
+
+ if (ctx.reserved_word() != null) {
+ return visit(ctx.reserved_word());
+ }
return visit(ctx.identification_variable());
}
@Override
public QueryTokenStream visitState_field(JpqlParser.State_fieldContext ctx) {
+
+ if (ctx.reserved_word() != null) {
+ return visit(ctx.reserved_word());
+ }
return visit(ctx.identification_variable());
}
@Override
public QueryTokenStream visitCollection_value_field(JpqlParser.Collection_value_fieldContext ctx) {
+
+ if (ctx.reserved_word() != null) {
+ return visit(ctx.reserved_word());
+ }
return visit(ctx.identification_variable());
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlSortedQueryTransformer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlSortedQueryTransformer.java
index a545171bbf..2b65552fd1 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlSortedQueryTransformer.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlSortedQueryTransformer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/KeysetScrollDelegate.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/KeysetScrollDelegate.java
index 2942fa0bce..7fb9f3659c 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/KeysetScrollDelegate.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/KeysetScrollDelegate.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/KeysetScrollSpecification.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/KeysetScrollSpecification.java
index 6047c164ca..40aa051983 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/KeysetScrollSpecification.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/KeysetScrollSpecification.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/Meta.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/Meta.java
index 79b6d7e0bd..53790bcf4f 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/Meta.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/Meta.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java
index 659c04c7de..eeed1593fa 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,11 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.provider.QueryExtractor;
+import org.springframework.data.jpa.repository.QueryRewriter;
import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.QueryCreationException;
import org.springframework.data.repository.query.RepositoryQuery;
@@ -53,11 +57,12 @@ final class NamedQuery extends AbstractJpaQuery {
private final boolean namedCountQueryIsPresent;
private final Lazy declaredQuery;
private final QueryParameterSetter.QueryMetadataCache metadataCache;
+ private final QueryRewriter queryRewriter;
/**
* Creates a new {@link NamedQuery}.
*/
- private NamedQuery(JpaQueryMethod method, EntityManager em) {
+ private NamedQuery(JpaQueryMethod method, EntityManager em, QueryRewriter queryRewriter) {
super(method, em);
@@ -65,12 +70,14 @@ private NamedQuery(JpaQueryMethod method, EntityManager em) {
this.countQueryName = method.getNamedCountQueryName();
QueryExtractor extractor = method.getQueryExtractor();
this.countProjection = method.getCountQueryProjection();
+ this.queryRewriter = queryRewriter;
Parameters, ?> parameters = method.getParameters();
if (parameters.hasSortParameter()) {
- throw new IllegalStateException(String.format("Finder method %s is backed by a NamedQuery and must "
- + "not contain a sort parameter as we cannot modify the query; Use @Query instead", method));
+ throw new IllegalStateException(String.format("Query method %s is backed by a NamedQuery and must "
+ + "not contain a sort parameter as we cannot modify the query; Use @%s(value=…) instead to apply sorting or remove the 'Sort' parameter.",
+ method, method.isNativeQuery() ? "NativeQuery" : "Query"));
}
this.namedCountQueryIsPresent = hasNamedQuery(em, countQueryName);
@@ -85,14 +92,14 @@ private NamedQuery(JpaQueryMethod method, EntityManager em) {
if (parameters.hasPageableParameter()) {
LOG.warn(String.format(
- "Finder method %s is backed by a NamedQuery but contains a Pageable parameter; Sorting delivered via this Pageable will not be applied",
- method));
+ "Query method %s is backed by a NamedQuery but contains a Pageable parameter; Sorting delivered via this Pageable will not be applied; Use @%s(value=…) instead to apply sorting.",
+ method, method.isNativeQuery() ? "NativeQuery" : "Query"));
}
String queryString = extractor.extractQueryString(query);
- // TODO: Detect whether a named query is a native one.
- this.declaredQuery = Lazy.of(() -> DeclaredQuery.of(queryString, query.toString().contains("NativeQuery")));
+ this.declaredQuery = Lazy
+ .of(() -> DeclaredQuery.of(queryString, method.isNativeQuery() || query.toString().contains("NativeQuery")));
this.metadataCache = new QueryParameterSetter.QueryMetadataCache();
}
@@ -126,14 +133,15 @@ static boolean hasNamedQuery(EntityManager em, String queryName) {
*
* @param method must not be {@literal null}.
* @param em must not be {@literal null}.
+ * @param queryRewriter must not be {@literal null}.
*/
@Nullable
- public static RepositoryQuery lookupFrom(JpaQueryMethod method, EntityManager em) {
+ public static RepositoryQuery lookupFrom(JpaQueryMethod method, EntityManager em, QueryRewriter queryRewriter) {
String queryName = method.getNamedQueryName();
if (LOG.isDebugEnabled()) {
- LOG.debug(String.format("Looking up named query %s", queryName));
+ LOG.debug(String.format("Looking up named query '%s'", queryName));
}
if (!hasNamedQuery(em, queryName)) {
@@ -141,12 +149,14 @@ public static RepositoryQuery lookupFrom(JpaQueryMethod method, EntityManager em
}
if (method.isScrollQuery()) {
- throw QueryCreationException.create(method, "Scroll queries are not supported using String-based queries");
+ throw QueryCreationException.create(method, String.format(
+ "Scroll queries are not supported using String-based queries as we cannot rewrite the query string. Use @%s(value=…) instead.",
+ method.isNativeQuery() ? "NativeQuery" : "Query"));
}
- RepositoryQuery query = new NamedQuery(method, em);
+ RepositoryQuery query = new NamedQuery(method, em, queryRewriter);
if (LOG.isDebugEnabled()) {
- LOG.debug(String.format("Found named query %s", queryName));
+ LOG.debug(String.format("Found named query '%s'", queryName));
}
return query;
}
@@ -184,6 +194,7 @@ protected TypedQuery doCreateCountQuery(JpaParametersParameterAccessor acc
} else {
String countQueryString = declaredQuery.get().deriveCountQuery(countProjection).getQueryString();
+ countQueryString = potentiallyRewriteQuery(countQueryString, accessor.getSort(), accessor.getPageable());
cacheKey = countQueryString;
countQuery = em.createQuery(countQueryString, Long.class);
}
@@ -219,4 +230,20 @@ protected Class> getTypeToRead(ReturnedType returnedType) {
? null //
: super.getTypeToRead(returnedType);
}
+
+ /**
+ * Use the {@link QueryRewriter}, potentially rewrite the query, using relevant {@link Sort} and {@link Pageable}
+ * information.
+ *
+ * @param originalQuery
+ * @param sort
+ * @param pageable
+ * @return
+ */
+ private String potentiallyRewriteQuery(String originalQuery, Sort sort, Pageable pageable) {
+
+ return pageable.isPaged() //
+ ? queryRewriter.rewrite(originalQuery, pageable) //
+ : queryRewriter.rewrite(originalQuery, sort);
+ }
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NativeJpaQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NativeJpaQuery.java
index 61c4c6ef19..9221cc3807 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NativeJpaQuery.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/NativeJpaQuery.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -93,8 +93,15 @@ private Class> getTypeToQueryFor(ReturnedType returnedType) {
return result;
}
- return returnedType.isProjecting() && !getMetamodel().isJpaManaged(returnedType.getReturnedType()) //
- ? Tuple.class
- : result;
+ if (returnedType.isProjecting()) {
+
+ if (returnedType.getReturnedType().isInterface()) {
+ return Tuple.class;
+ }
+
+ return returnedType.getReturnedType();
+ }
+
+ return result;
}
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java
index 78fc9531ee..7a49f584a1 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinderFactory.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinderFactory.java
index e5122e93d3..21a715e07f 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinderFactory.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinderFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinding.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinding.java
index 493f474f6f..e5cffccaf6 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinding.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinding.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -156,6 +156,10 @@ public Object prepare(@Nullable Object valueToBind) {
*/
public boolean bindsTo(ParameterBinding other) {
+ if (getIdentifier().equals(other.getIdentifier())) {
+ return true;
+ }
+
if (identifier.hasName() && other.identifier.hasName()) {
if (identifier.getName().equals(other.identifier.getName())) {
return true;
@@ -503,6 +507,16 @@ static Expression ofExpression(ValueExpression expression) {
return new Expression(expression);
}
+ /**
+ * Creates a {@link MethodInvocationArgument} object for {@code name}
+ *
+ * @param name the parameter name from the method invocation.
+ * @return {@link MethodInvocationArgument} object for {@code name}.
+ */
+ static MethodInvocationArgument ofParameter(String name) {
+ return ofParameter(name, null);
+ }
+
/**
* Creates a {@link MethodInvocationArgument} object for {@code name} and {@code position}. Either the name or the
* position must be given.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterMetadataProvider.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterMetadataProvider.java
index 213e641a5c..b99f1b93f9 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterMetadataProvider.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParameterMetadataProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParsedQueryIntrospector.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParsedQueryIntrospector.java
index fc34eb9b6f..cab53a6e9f 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParsedQueryIntrospector.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ParsedQueryIntrospector.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/PartTreeJpaQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/PartTreeJpaQuery.java
index 1d0923f26d..a1246ac056 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/PartTreeJpaQuery.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/PartTreeJpaQuery.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/Procedure.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/Procedure.java
index 6e6a825259..9ebbe5f2a8 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/Procedure.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/Procedure.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ProcedureParameter.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ProcedureParameter.java
index e86a59151a..0cef0b0a0f 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ProcedureParameter.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ProcedureParameter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2024 the original author or authors.
+ * Copyright 2021-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancer.java
index 55c168a4f5..1367fa6cad 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancer.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java
index c40ab11f66..5a2853cb1a 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetter.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetter.java
index a05a34052b..727f61cc81 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetter.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactory.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactory.java
index 38247f92db..c45c3d8aa3 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactory.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -240,10 +240,13 @@ public QueryParameterSetter create(ParameterBinding binding, DeclaredQuery decla
BindingIdentifier identifier = mia.identifier();
- if (declaredQuery.hasNamedParameter()) {
+ if (declaredQuery.hasNamedParameter() && identifier.hasName()) {
parameter = findParameterForBinding(parameters, identifier.getName());
- } else {
+ } else if (identifier.hasPosition()) {
parameter = findParameterForBinding(parameters, identifier.getPosition() - 1);
+ } else {
+ // this can happen when a query uses parameters in ORDER BY and the COUNT query just needs to drop a binding.
+ parameter = null;
}
return parameter == null //
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRenderer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRenderer.java
index 1bdde97beb..3039ef735a 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRenderer.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRenderer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,6 +38,7 @@
*
*
* @author Mark Paluch
+ * @author Christoph Strobl
*/
abstract class QueryRenderer implements QueryTokenStream {
@@ -243,7 +244,7 @@ String render() {
for (QueryRenderer queryRenderer : nested) {
if (lastAppended != null && (lastExpression || queryRenderer.isExpression()) && !builder.isEmpty()
- && !lastAppended.endsWith(" ")) {
+ && (!lastAppended.endsWith(" ") && !lastAppended.endsWith("("))) {
builder.append(' ');
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRewriterProvider.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRewriterProvider.java
index b3abe97552..85e6d34aa2 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRewriterProvider.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryRewriterProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryToken.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryToken.java
index 9b3c798f15..ac67b8bf0d 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryToken.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryToken.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTokenStream.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTokenStream.java
index 233711d797..c91fddb0e4 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTokenStream.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTokenStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTokens.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTokens.java
index 80df0b3300..90295f3776 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTokens.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTokens.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,6 +46,7 @@ class QueryTokens {
static final QueryToken TOKEN_OPEN_SQUARE_BRACKET = token("[");
static final QueryToken TOKEN_CLOSE_SQUARE_BRACKET = token("]");
static final QueryToken TOKEN_COLON = token(":");
+ static final QueryToken TOKEN_DASH = token("-");
static final QueryToken TOKEN_QUESTION_MARK = token("?");
static final QueryToken TOKEN_OPEN_BRACE = token("{");
static final QueryToken TOKEN_CLOSE_BRACE = token("}");
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTransformers.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTransformers.java
index 46bdc36003..a76749bc69 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTransformers.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryTransformers.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -71,6 +71,42 @@ static CountSelectionTokenStream create(QueryTokenStream selection) {
return new CountSelectionTokenStream(target, containsNew);
}
+ /**
+ * Filter constructor expression and return the selection list of the constructor.
+ *
+ * @return the selection list of the constructor without {@code NEW}, class name, and the first level of
+ * parentheses.
+ * @since 3.5.2
+ */
+ public CountSelectionTokenStream withoutConstructorExpression() {
+
+ if (!requiresPrimaryAlias()) {
+ return this;
+ }
+
+ List target = new ArrayList<>(size());
+ int nestingLevel = 0;
+
+ for (QueryToken token : this) {
+
+ if (token.equals(TOKEN_OPEN_PAREN)) {
+ nestingLevel++;
+ continue;
+ }
+
+ if (token.equals(TOKEN_CLOSE_PAREN)) {
+ nestingLevel--;
+ continue;
+ }
+
+ if (nestingLevel > 0) {
+ target.add(token);
+ }
+ }
+
+ return new CountSelectionTokenStream(target, requiresPrimaryAlias());
+ }
+
@Override
public Iterator iterator() {
return tokens.iterator();
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java
index 3c06c7079b..97506ef9df 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -99,7 +99,7 @@ public abstract class QueryUtils {
public static final String COUNT_QUERY_STRING = "select count(%s) from %s x";
public static final String DELETE_ALL_QUERY_STRING = "delete from %s x";
- public static final String DELETE_ALL_QUERY_BY_ID_STRING = "delete from %s x where %s in :ids";
+ public static final String DELETE_ALL_QUERY_BY_ID_STRING = "delete from %s x where x.%s in :ids";
// Used Regex/Unicode categories (see https://www.unicode.org/reports/tr18/#General_Category_Property):
// Z Separator
@@ -202,17 +202,15 @@ public abstract class QueryUtils {
// any function call including parameters within the brackets
builder.append("\\w+\\s*\\([\\w\\.,\\s'=:;\\\\?]+\\)");
// the potential alias
- builder.append("\\s+[as|AS]+\\s+(([\\w\\.]+))");
+ builder.append("\\s+(?:as)+\\s+([\\w\\.]+)");
- FUNCTION_PATTERN = compile(builder.toString());
+ FUNCTION_PATTERN = compile(builder.toString(), CASE_INSENSITIVE);
builder = new StringBuilder();
- builder.append("\\s+"); // at least one space
builder.append("[^\\s\\(\\)]+"); // No white char no bracket
- builder.append("\\s+[as|AS]+\\s+(([\\w\\.]+))"); // the potential alias
-
- FIELD_ALIAS_PATTERN = compile(builder.toString());
+ builder.append("\\s+(?:as)+\\s+([\\w\\.]+)"); // the potential alias
+ FIELD_ALIAS_PATTERN = compile(builder.toString(), CASE_INSENSITIVE);
}
/**
@@ -399,7 +397,7 @@ static Set getOuterJoinAliases(String query) {
* @param query a {@literal String} containing a query. Must not be {@literal null}.
* @return a {@literal Set} containing all found aliases. Guaranteed to be not {@literal null}.
*/
- private static Set getFieldAliases(String query) {
+ static Set getFieldAliases(String query) {
Set result = new HashSet<>();
Matcher matcher = FIELD_ALIAS_PATTERN.matcher(query);
@@ -889,7 +887,7 @@ private static T getAnnotationProperty(Attribute, ?> attribute, String pro
}
/**
- * Returns an existing join for the given attribute if one already exists or creates a new one if not.
+ * Returns an existing (fetch) join for the given attribute if one already exists or creates a new one if not.
*
* @param from the {@link From} to get the current joins from.
* @param attribute the {@link Attribute} to look for in the current joins.
@@ -898,6 +896,13 @@ private static T getAnnotationProperty(Attribute, ?> attribute, String pro
*/
private static Join, ?> getOrCreateJoin(From, ?> from, String attribute, JoinType joinType) {
+ for (Fetch, ?> fetch : from.getFetches()) {
+
+ if (fetch instanceof Join, ?> join && join.getAttribute().getName().equals(attribute)) {
+ return join;
+ }
+ }
+
for (Join, ?> join : from.getJoins()) {
if (join.getAttribute().getName().equals(attribute)) {
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ScrollDelegate.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ScrollDelegate.java
index 359dfb6ea2..7fbe146bb4 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ScrollDelegate.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ScrollDelegate.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java
index 16fa3c30e0..f2634c1620 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,13 +40,13 @@ final class SimpleJpaQuery extends AbstractStringBasedJpaQuery {
*
* @param method must not be {@literal null}
* @param em must not be {@literal null}
- * @param countQueryString
+ * @param sourceQuery the original source query, must not be {@literal null} or empty.
* @param queryRewriter must not be {@literal null}
* @param valueExpressionDelegate must not be {@literal null}
*/
- public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, @Nullable String countQueryString,
+ public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, @Nullable String sourceQuery,
QueryRewriter queryRewriter, ValueExpressionDelegate valueExpressionDelegate) {
- this(method, em, method.getRequiredAnnotatedQuery(), countQueryString, queryRewriter, valueExpressionDelegate);
+ this(method, em, method.getRequiredAnnotatedQuery(), sourceQuery, queryRewriter, valueExpressionDelegate);
}
/**
@@ -54,21 +54,20 @@ public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, @Nullable String
*
* @param method must not be {@literal null}
* @param em must not be {@literal null}
- * @param queryString must not be {@literal null} or empty
+ * @param sourceQuery the original source query, must not be {@literal null} or empty
* @param countQueryString
* @param queryRewriter
* @param valueExpressionDelegate must not be {@literal null}
*/
- public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, String queryString, @Nullable String countQueryString, QueryRewriter queryRewriter,
- ValueExpressionDelegate valueExpressionDelegate) {
+ public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, String sourceQuery, @Nullable String countQueryString,
+ QueryRewriter queryRewriter, ValueExpressionDelegate valueExpressionDelegate) {
- super(method, em, queryString, countQueryString, queryRewriter, valueExpressionDelegate);
+ super(method, em, sourceQuery, countQueryString, queryRewriter, valueExpressionDelegate);
- validateQuery(getQuery().getQueryString(), "Validation failed for query for method %s", method);
+ validateQuery(getQuery(), "Query '%s' validation failed for method %s", method);
if (method.isPageQuery()) {
- validateQuery(getCountQuery().getQueryString(),
- String.format("Count query validation failed for method %s", method));
+ validateQuery(getCountQuery(), "Count query '%s' validation failed for method %s", method);
}
}
@@ -78,29 +77,20 @@ public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, String queryStrin
* @param query
* @param errorMessage
*/
- private void validateQuery(String query, String errorMessage, Object... arguments) {
+ private void validateQuery(DeclaredQuery query, String errorMessage, JpaQueryMethod method) {
if (getQueryMethod().isProcedureQuery()) {
return;
}
- EntityManager validatingEm = null;
-
- try {
- validatingEm = getEntityManager().getEntityManagerFactory().createEntityManager();
- validatingEm.createQuery(query);
-
+ String queryString = query.getQueryString();
+ try (EntityManager validatingEm = getEntityManager().getEntityManagerFactory().createEntityManager()) {
+ validatingEm.createQuery(queryString);
} catch (RuntimeException e) {
// Needed as there's ambiguities in how an invalid query string shall be expressed by the persistence provider
- // https://java.net/projects/jpa-spec/lists/jsr338-experts/archive/2012-07/message/17
- throw new IllegalArgumentException(String.format(errorMessage, arguments), e);
-
- } finally {
-
- if (validatingEm != null) {
- validatingEm.close();
- }
+ // https://download.oracle.com/javaee-archive/jpa-spec.java.net/users/2012/07/0404.html
+ throw new IllegalArgumentException(errorMessage.formatted(queryString, method), e);
}
}
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributeSource.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributeSource.java
index 770c946f64..2616c3d796 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributeSource.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributeSource.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributes.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributes.java
index 2acc5f83c1..e7ef76a3eb 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributes.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributes.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureJpaQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureJpaQuery.java
index 54d6b0b24a..8ff29f4ba2 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureJpaQuery.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StoredProcedureJpaQuery.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java
index 471ede0403..3e5c7fe733 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/StringQuery.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -73,6 +74,15 @@ class StringQuery implements DeclaredQuery {
* @param query must not be {@literal null} or empty.
*/
public StringQuery(String query, boolean isNative) {
+ this(query, isNative, it -> {});
+ }
+
+ /**
+ * Creates a new {@link StringQuery} from the given JPQL query.
+ *
+ * @param query must not be {@literal null} or empty.
+ */
+ private StringQuery(String query, boolean isNative, Consumer> parameterPostProcessor) {
Assert.hasText(query, "Query must not be null or empty");
@@ -87,6 +97,8 @@ public StringQuery(String query, boolean isNative) {
this.usesJdbcStyleParameters = queryMeta.usesJdbcStyleParameters;
this.queryEnhancer = QueryEnhancerFactory.forQuery(this);
+ parameterPostProcessor.accept(this.bindings);
+
boolean hasNamedParameters = false;
for (ParameterBinding parameterBinding : getParameterBindings()) {
if (parameterBinding.getIdentifier().hasName() && parameterBinding.getOrigin().isMethodArgument()) {
@@ -117,15 +129,29 @@ public List getParameterBindings() {
@Override
public DeclaredQuery deriveCountQuery(@Nullable String countQueryProjection) {
- StringQuery stringQuery = new StringQuery(this.queryEnhancer.createCountQueryFor(countQueryProjection), //
- this.isNative);
+ // need to copy expression bindings from the declared to the derived query as JPQL query derivation only sees
+ // JPA parameter markers and not the original expressions anymore.
- if (this.hasParameterBindings() && !this.getParameterBindings().equals(stringQuery.getParameterBindings())) {
- stringQuery.getParameterBindings().clear();
- stringQuery.getParameterBindings().addAll(this.bindings);
- }
+ return new StringQuery(this.queryEnhancer.createCountQueryFor(countQueryProjection), //
+ this.isNative, derivedBindings -> {
+
+ // need to copy expression bindings from the declared to the derived query as JPQL query derivation only sees
+ // JPA
+ // parameter markers and not the original expressions anymore.
+ if (this.hasParameterBindings() && !this.getParameterBindings().equals(derivedBindings)) {
+
+ for (ParameterBinding binding : bindings) {
- return stringQuery;
+ Predicate identifier = binding::bindsTo;
+ Predicate notCompatible = Predicate.not(binding::isCompatibleWith);
+
+ // replace incompatible bindings
+ if (derivedBindings.removeIf(it -> identifier.test(it) && notCompatible.test(it))) {
+ derivedBindings.add(binding);
+ }
+ }
+ }
+ });
}
@Override
@@ -179,7 +205,7 @@ enum ParameterBindingParser {
INSTANCE;
private static final String EXPRESSION_PARAMETER_PREFIX = "__$synthetic$__";
- public static final String POSITIONAL_OR_INDEXED_PARAMETER = "\\?(\\d*+(?![#\\w]))";
+ public static final String POSITIONAL_OR_INDEXED_PARAMETER = "\\?(\\d*+(?![\\&\\|#\\w]))";
// .....................................................................^ not followed by a hash or a letter.
// .................................................................^ zero or more digits.
// .............................................................^ start with a question mark.
@@ -243,8 +269,7 @@ String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(String que
}
ValueExpressionQueryRewriter.ParsedQuery parsedQuery = createSpelExtractor(query,
- parametersShouldBeAccessedByIndex,
- greatestParameterIndex);
+ parametersShouldBeAccessedByIndex, greatestParameterIndex);
String resultingQuery = parsedQuery.getQueryString();
Matcher matcher = PARAMETER_BINDING_PATTERN.matcher(resultingQuery);
@@ -269,7 +294,9 @@ String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(String que
Integer parameterIndex = getParameterIndex(parameterIndexString);
String match = matcher.group(0);
- if (JDBC_STYLE_PARAM.matcher(match).find()) {
+ Matcher jdbcStyleMatcher = JDBC_STYLE_PARAM.matcher(match);
+
+ if (jdbcStyleMatcher.find()) {
queryMeta.usesJdbcStyleParameters = true;
}
@@ -350,8 +377,7 @@ String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(String que
}
private static ValueExpressionQueryRewriter.ParsedQuery createSpelExtractor(String queryWithSpel,
- boolean parametersShouldBeAccessedByIndex,
- int greatestParameterIndex) {
+ boolean parametersShouldBeAccessedByIndex, int greatestParameterIndex) {
/*
* If parameters need to be bound by index, we bind the synthetic expression parameters starting from position of the greatest discovered index parameter in order to
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadata.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadata.java
index ae738974b1..4b0b7bacaf 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadata.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadata.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java
index 246e82dcd6..135d3c6e44 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/DefaultJpaContext.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/DefaultJpaContext.java
index e6e51b991d..220ac48587 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/DefaultJpaContext.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/DefaultJpaContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/DefaultQueryHints.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/DefaultQueryHints.java
index bbf5b12a9a..228251d4f2 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/DefaultQueryHints.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/DefaultQueryHints.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,11 +15,11 @@
*/
package org.springframework.data.jpa.repository.support;
+import jakarta.persistence.EntityManager;
+
import java.util.Optional;
import java.util.function.BiConsumer;
-import jakarta.persistence.EntityManager;
-
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.query.Jpa21Utils;
import org.springframework.data.jpa.repository.query.JpaEntityGraph;
@@ -99,7 +99,7 @@ private QueryHints getFetchGraphs() {
return Optionals
.mapIfAllPresent(entityManager, metadata.getEntityGraph(),
(em, graph) -> Jpa21Utils.getFetchGraphHint(em, getEntityGraph(graph), information.getJavaType()))
- .orElse(new MutableQueryHints());
+ .orElseGet(MutableQueryHints::new);
}
private JpaEntityGraph getEntityGraph(EntityGraph entityGraph) {
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/EntityGraphFactory.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/EntityGraphFactory.java
index 97bf993818..5308fa64b8 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/EntityGraphFactory.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/EntityGraphFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2024 the original author or authors.
+ * Copyright 2021-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistrarPostProcessor.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistrarPostProcessor.java
index a3344c2c94..4d84dfc0d4 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistrarPostProcessor.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistrarPostProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryByPredicate.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryByPredicate.java
index 9ed0a0ce3e..e19e7bf0e2 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryByPredicate.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryByPredicate.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2024 the original author or authors.
+ * Copyright 2021-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -132,7 +132,7 @@ public FetchableFluentQuery project(Collection properties) {
@Override
public R oneValue() {
- List> results = createSortedAndProjectedQuery() //
+ List> results = createSortedAndProjectedQuery(this.sort) //
.limit(2) // Never need more than 2 values
.fetch();
@@ -146,7 +146,7 @@ public R oneValue() {
@Override
public R firstValue() {
- List> results = createSortedAndProjectedQuery() //
+ List> results = createSortedAndProjectedQuery(this.sort) //
.limit(1) // Never need more than 1 value
.fetch();
@@ -155,7 +155,11 @@ public R firstValue() {
@Override
public List all() {
- return convert(createSortedAndProjectedQuery().fetch());
+ return all(this.sort);
+ }
+
+ private List all(Sort sort) {
+ return convert(createSortedAndProjectedQuery(sort).fetch());
}
@Override
@@ -168,13 +172,13 @@ public Window scroll(ScrollPosition scrollPosition) {
@Override
public Page page(Pageable pageable) {
- return pageable.isUnpaged() ? new PageImpl<>(all()) : readPage(pageable);
+ return pageable.isUnpaged() ? new PageImpl<>(all(pageable.getSortOr(this.sort))) : readPage(pageable);
}
@Override
public Stream stream() {
- return createSortedAndProjectedQuery() //
+ return createSortedAndProjectedQuery(this.sort) //
.stream() //
.map(getConversionFunction());
}
@@ -189,7 +193,7 @@ public boolean exists() {
return existsOperation.apply(predicate);
}
- private AbstractJPAQuery, ?> createSortedAndProjectedQuery() {
+ private AbstractJPAQuery, ?> createSortedAndProjectedQuery(Sort sort) {
AbstractJPAQuery, ?> query = finder.apply(sort);
@@ -206,6 +210,7 @@ public boolean exists() {
private Page readPage(Pageable pageable) {
+ Sort sort = pageable.getSortOr(this.sort);
AbstractJPAQuery, ?> query = pagedFinder.apply(sort, pageable);
if (!properties.isEmpty()) {
@@ -214,7 +219,8 @@ private Page readPage(Pageable pageable) {
List paginatedResults = convert(query.fetch());
- return PageableExecutionUtils.getPage(paginatedResults, pageable, () -> countOperation.apply(predicate));
+ return PageableExecutionUtils.getPage(paginatedResults, withSort(pageable, sort),
+ () -> countOperation.apply(predicate));
}
private List convert(List> resultList) {
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryBySpecification.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryBySpecification.java
index 08659af984..4c9f2b501d 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryBySpecification.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryBySpecification.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2024 the original author or authors.
+ * Copyright 2021-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -89,8 +89,14 @@ public FetchableFluentQuery sortBy(Sort sort) {
Assert.notNull(sort, "Sort must not be null");
- return new FetchableFluentQueryBySpecification<>(spec, entityType, resultType, this.sort.and(sort), limit,
- properties, finder, scroll, countOperation, existsOperation, entityManager, projectionFactory);
+ Sort sort1 = this.sort.and(sort);
+
+ if (this.sort == sort1) {
+ return this;
+ }
+
+ return new FetchableFluentQueryBySpecification<>(spec, entityType, resultType, sort1, limit, properties, finder,
+ scroll, countOperation, existsOperation, entityManager, projectionFactory);
}
@Override
@@ -98,8 +104,8 @@ public FetchableFluentQuery limit(int limit) {
Assert.isTrue(limit >= 0, "Limit must not be negative");
- return new FetchableFluentQueryBySpecification<>(spec, entityType, resultType, sort, limit,
- properties, finder, scroll, countOperation, existsOperation, entityManager, projectionFactory);
+ return new FetchableFluentQueryBySpecification<>(spec, entityType, resultType, sort, limit, properties, finder,
+ scroll, countOperation, existsOperation, entityManager, projectionFactory);
}
@Override
@@ -124,7 +130,7 @@ public FetchableFluentQuery project(Collection properties) {
@Override
public R oneValue() {
- List> results = createSortedAndProjectedQuery() //
+ List> results = createSortedAndProjectedQuery(this.sort) //
.setMaxResults(2) // Never need more than 2 values
.getResultList();
@@ -138,7 +144,7 @@ public R oneValue() {
@Override
public R firstValue() {
- List> results = createSortedAndProjectedQuery() //
+ List> results = createSortedAndProjectedQuery(this.sort) //
.setMaxResults(1) // Never need more than 1 value
.getResultList();
@@ -147,7 +153,11 @@ public R firstValue() {
@Override
public List all() {
- return convert(createSortedAndProjectedQuery().getResultList());
+ return all(this.sort);
+ }
+
+ private List all(Sort sort) {
+ return convert(createSortedAndProjectedQuery(sort).getResultList());
}
@Override
@@ -160,13 +170,13 @@ public Window scroll(ScrollPosition scrollPosition) {
@Override
public Page page(Pageable pageable) {
- return pageable.isUnpaged() ? new PageImpl<>(all()) : readPage(pageable);
+ return pageable.isUnpaged() ? new PageImpl<>(all(pageable.getSortOr(this.sort))) : readPage(pageable);
}
@Override
public Stream stream() {
- return createSortedAndProjectedQuery() //
+ return createSortedAndProjectedQuery(this.sort) //
.getResultStream() //
.map(getConversionFunction());
}
@@ -181,7 +191,7 @@ public boolean exists() {
return existsOperation.apply(spec);
}
- private TypedQuery createSortedAndProjectedQuery() {
+ private TypedQuery createSortedAndProjectedQuery(Sort sort) {
TypedQuery query = finder.apply(sort);
@@ -198,7 +208,8 @@ private TypedQuery createSortedAndProjectedQuery() {
private Page readPage(Pageable pageable) {
- TypedQuery pagedQuery = createSortedAndProjectedQuery();
+ Sort sort = pageable.getSortOr(this.sort);
+ TypedQuery pagedQuery = createSortedAndProjectedQuery(sort);
if (pageable.isPaged()) {
pagedQuery.setFirstResult(PageableUtils.getOffsetAsInteger(pageable));
@@ -207,7 +218,7 @@ private Page readPage(Pageable pageable) {
List paginatedResults = convert(pagedQuery.getResultList());
- return PageableExecutionUtils.getPage(paginatedResults, pageable, () -> countOperation.apply(spec));
+ return PageableExecutionUtils.getPage(paginatedResults, withSort(pageable, sort), () -> countOperation.apply(spec));
}
private List convert(List resultList) {
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FluentQuerySupport.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FluentQuerySupport.java
index 5917a119f5..27fd7d6b68 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FluentQuerySupport.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/FluentQuerySupport.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2024 the original author or authors.
+ * Copyright 2021-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,8 @@
import java.util.function.Function;
import org.springframework.core.convert.support.DefaultConversionService;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Sort;
import org.springframework.data.projection.ProjectionFactory;
@@ -49,7 +51,7 @@ abstract class FluentQuerySupport {
protected final ProjectionFactory projectionFactory;
FluentQuerySupport(Class resultType, Sort sort, int limit, @Nullable Collection properties,
- Class entityType, ProjectionFactory projectionFactory) {
+ Class entityType, ProjectionFactory projectionFactory) {
this.resultType = resultType;
this.sort = sort;
@@ -87,6 +89,15 @@ final Function getConversionFunction(Class inputType, Class tar
return o -> DefaultConversionService.getSharedInstance().convert(o, targetType);
}
+ Pageable withSort(Pageable pageable, Sort sort) {
+
+ if (pageable instanceof PageRequest pr && pageable.getSort() != sort) {
+ return pr.withSort(sort);
+ }
+
+ return pageable;
+ }
+
interface ScrollQueryFactory {
Query createQuery(Sort sort, ScrollPosition scrollPosition);
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformation.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformation.java
index 096bd77d21..98828424ab 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformation.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformation.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformationSupport.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformationSupport.java
index 00c9f7f27d..6d8c0ba8dc 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformationSupport.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaEntityInformationSupport.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaEvaluationContextExtension.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaEvaluationContextExtension.java
index 79b7b10de0..f635a221a4 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaEvaluationContextExtension.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaEvaluationContextExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2024 the original author or authors.
+ * Copyright 2019-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformation.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformation.java
index 9979fc773b..9293454649 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformation.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformation.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformation.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformation.java
index ed0b4644ec..aaaff2050c 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformation.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformation.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryConfigurationAware.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryConfigurationAware.java
index d5b497f9a2..b8d6e2a587 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryConfigurationAware.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryConfigurationAware.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java
index 7ecd163244..e14658773b 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBean.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBean.java
index f75f45a8d1..86f2f14d6c 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBean.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryImplementation.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryImplementation.java
index d3a5b1c5fe..006b39a689 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryImplementation.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryImplementation.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/MutableQueryHints.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/MutableQueryHints.java
index 4a1e7443b6..46b7a7c77d 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/MutableQueryHints.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/MutableQueryHints.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2024 the original author or authors.
+ * Copyright 2020-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QueryHintValue.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QueryHintValue.java
index c32b40f767..0d01e738a8 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QueryHintValue.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QueryHintValue.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2024 the original author or authors.
+ * Copyright 2020-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QueryHints.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QueryHints.java
index 17e6d01725..8afea10892 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QueryHints.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QueryHints.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/Querydsl.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/Querydsl.java
index 0ade24f133..d895d4717a 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/Querydsl.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/Querydsl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -108,12 +108,11 @@ public JPQLQuery applyPagination(Pageable pageable, JPQLQuery query) {
Assert.notNull(pageable, "Pageable must not be null");
Assert.notNull(query, "JPQLQuery must not be null");
- if (pageable.isUnpaged()) {
- return query;
- }
+ if (pageable.isPaged()) {
- query.offset(pageable.getOffset());
- query.limit(pageable.getPageSize());
+ query.offset(pageable.getOffset());
+ query.limit(pageable.getPageSize());
+ }
return applySorting(pageable.getSort(), query);
}
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaPredicateExecutor.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaPredicateExecutor.java
index c16f95c0a1..7b31a6ce5c 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaPredicateExecutor.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaPredicateExecutor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
import java.util.function.Function;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
+import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.KeysetScrollPosition;
import org.springframework.data.domain.OffsetScrollPosition;
import org.springframework.data.domain.Page;
@@ -41,6 +42,7 @@
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.querydsl.QSort;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
+import org.springframework.data.repository.query.FluentQuery;
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.lang.Nullable;
@@ -75,6 +77,12 @@
*/
public class QuerydslJpaPredicateExecutor implements QuerydslPredicateExecutor, JpaRepositoryConfigurationAware {
+ private static final String PREDICATE_MUST_NOT_BE_NULL = "Predicate must not be null";
+ private static final String ORDER_SPECIFIERS_MUST_NOT_BE_NULL = "Order specifiers must not be null";
+ private static final String SORT_MUST_NOT_BE_NULL = "Sort must not be null";
+ private static final String PAGEABLE_MUST_NOT_BE_NULL = "Pageable must not be null";
+ private static final String QUERY_FUNCTION_MUST_NOT_BE_NULL = "Query function must not be null";
+
private final JpaEntityInformation entityInformation;
private final EntityPath path;
private final Querydsl querydsl;
@@ -116,7 +124,7 @@ public void setProjectionFactory(ProjectionFactory projectionFactory) {
@Override
public Optional findOne(Predicate predicate) {
- Assert.notNull(predicate, "Predicate must not be null");
+ Assert.notNull(predicate, PREDICATE_MUST_NOT_BE_NULL);
try {
return Optional.ofNullable(createQuery(predicate).select(path).limit(2).fetchOne());
@@ -128,7 +136,7 @@ public Optional findOne(Predicate predicate) {
@Override
public List findAll(Predicate predicate) {
- Assert.notNull(predicate, "Predicate must not be null");
+ Assert.notNull(predicate, PREDICATE_MUST_NOT_BE_NULL);
return createQuery(predicate).select(path).fetch();
}
@@ -136,8 +144,8 @@ public List findAll(Predicate predicate) {
@Override
public List findAll(Predicate predicate, OrderSpecifier>... orders) {
- Assert.notNull(predicate, "Predicate must not be null");
- Assert.notNull(orders, "Order specifiers must not be null");
+ Assert.notNull(predicate, PREDICATE_MUST_NOT_BE_NULL);
+ Assert.notNull(orders, ORDER_SPECIFIERS_MUST_NOT_BE_NULL);
return executeSorted(createQuery(predicate).select(path), orders);
}
@@ -145,8 +153,8 @@ public List findAll(Predicate predicate, OrderSpecifier>... orders) {
@Override
public List findAll(Predicate predicate, Sort sort) {
- Assert.notNull(predicate, "Predicate must not be null");
- Assert.notNull(sort, "Sort must not be null");
+ Assert.notNull(predicate, PREDICATE_MUST_NOT_BE_NULL);
+ Assert.notNull(sort, SORT_MUST_NOT_BE_NULL);
return executeSorted(createQuery(predicate).select(path), sort);
}
@@ -154,7 +162,7 @@ public List findAll(Predicate predicate, Sort sort) {
@Override
public List findAll(OrderSpecifier>... orders) {
- Assert.notNull(orders, "Order specifiers must not be null");
+ Assert.notNull(orders, ORDER_SPECIFIERS_MUST_NOT_BE_NULL);
return executeSorted(createQuery(new Predicate[0]).select(path), orders);
}
@@ -162,8 +170,8 @@ public List findAll(OrderSpecifier>... orders) {
@Override
public Page findAll(Predicate predicate, Pageable pageable) {
- Assert.notNull(predicate, "Predicate must not be null");
- Assert.notNull(pageable, "Pageable must not be null");
+ Assert.notNull(predicate, PREDICATE_MUST_NOT_BE_NULL);
+ Assert.notNull(pageable, PAGEABLE_MUST_NOT_BE_NULL);
final JPQLQuery> countQuery = createCountQuery(predicate);
JPQLQuery query = querydsl.applyPagination(pageable, createQuery(predicate).select(path));
@@ -175,8 +183,8 @@ public Page findAll(Predicate predicate, Pageable pageable) {
@Override
public R findBy(Predicate predicate, Function, R> queryFunction) {
- Assert.notNull(predicate, "Predicate must not be null");
- Assert.notNull(queryFunction, "Query function must not be null");
+ Assert.notNull(predicate, PREDICATE_MUST_NOT_BE_NULL);
+ Assert.notNull(queryFunction, QUERY_FUNCTION_MUST_NOT_BE_NULL);
Function> finder = sort -> {
AbstractJPAQuery, ?> select = (AbstractJPAQuery, ?>) createQuery(predicate).select(path);
@@ -239,7 +247,14 @@ public R findBy(Predicate predicate, Function) fluentQuery);
+ R result = queryFunction.apply((FetchableFluentQuery) fluentQuery);
+
+ if (result instanceof FluentQuery>) {
+ throw new InvalidDataAccessApiUsageException(
+ "findBy(…) queries must result a query result and not the FluentQuery object to ensure that queries are executed within the scope of the findBy(…) method");
+ }
+
+ return result;
}
@Override
@@ -260,7 +275,7 @@ public boolean exists(Predicate predicate) {
*/
protected AbstractJPAQuery, ?> createQuery(Predicate... predicate) {
- Assert.notNull(predicate, "Predicate must not be null");
+ Assert.notNull(predicate, PREDICATE_MUST_NOT_BE_NULL);
AbstractJPAQuery, ?> query = doCreateQuery(getQueryHints().withFetchGraphs(entityManager), predicate);
CrudMethodMetadata metadata = getRepositoryMethodMetadata();
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaRepository.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaRepository.java
index 0f32999b14..129d56f6e9 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaRepository.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QuerydslRepositorySupport.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QuerydslRepositorySupport.java
index a140b734b0..09c43e198b 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QuerydslRepositorySupport.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QuerydslRepositorySupport.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java
index bf2faea2f4..3ee2c7736f 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,6 +42,7 @@
import java.util.function.BiConsumer;
import java.util.function.Function;
+import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.KeysetScrollPosition;
import org.springframework.data.domain.OffsetScrollPosition;
@@ -62,6 +63,7 @@
import org.springframework.data.jpa.support.PageableUtils;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
+import org.springframework.data.repository.query.FluentQuery;
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.data.util.ProxyUtils;
@@ -100,7 +102,11 @@ public class SimpleJpaRepository implements JpaRepositoryImplementation entityInformation;
private final EntityManager entityManager;
@@ -190,7 +196,7 @@ public void deleteById(ID id) {
@SuppressWarnings("unchecked")
public void delete(T entity) {
- Assert.notNull(entity, "Entity must not be null");
+ Assert.notNull(entity, ENTITY_MUST_NOT_BE_NULL);
if (entityInformation.isNew(entity)) {
return;
@@ -490,8 +496,8 @@ public long delete(@Nullable Specification spec) {
@Override
public R findBy(Specification spec, Function, R> queryFunction) {
- Assert.notNull(spec, "Specification must not be null");
- Assert.notNull(queryFunction, "Query function must not be null");
+ Assert.notNull(spec, SPECIFICATION_MUST_NOT_BE_NULL);
+ Assert.notNull(queryFunction, QUERY_FUNCTION_MUST_NOT_BE_NULL);
return doFindBy(spec, getDomainClass(), queryFunction);
}
@@ -499,8 +505,8 @@ public R findBy(Specification spec, Function R doFindBy(Specification spec, Class domainClass,
Function, R> queryFunction) {
- Assert.notNull(spec, "Specification must not be null");
- Assert.notNull(queryFunction, "Query function must not be null");
+ Assert.notNull(spec, SPECIFICATION_MUST_NOT_BE_NULL);
+ Assert.notNull(queryFunction, QUERY_FUNCTION_MUST_NOT_BE_NULL);
ScrollQueryFactory scrollFunction = (sort, scrollPosition) -> {
@@ -530,7 +536,14 @@ private R doFindBy(Specification spec, Class domainClass,
FetchableFluentQueryBySpecification, T> fluentQuery = new FetchableFluentQueryBySpecification<>(spec, domainClass,
finder, scrollDelegate, this::count, this::exists, this.entityManager, getProjectionFactory());
- return queryFunction.apply((FetchableFluentQuery) fluentQuery);
+ R result = queryFunction.apply((FetchableFluentQuery) fluentQuery);
+
+ if (result instanceof FluentQuery>) {
+ throw new InvalidDataAccessApiUsageException(
+ "findBy(…) queries must result a query result and not the FluentQuery object to ensure that queries are executed within the scope of the findBy(…) method");
+ }
+
+ return result;
}
@Override
@@ -589,8 +602,8 @@ public Page findAll(Example example, Pageable pageable) {
@Override
public R findBy(Example example, Function, R> queryFunction) {
- Assert.notNull(example, "Example must not be null");
- Assert.notNull(queryFunction, "Query function must not be null");
+ Assert.notNull(example, EXAMPLE_MUST_NOT_BE_NULL);
+ Assert.notNull(queryFunction, QUERY_FUNCTION_MUST_NOT_BE_NULL);
ExampleSpecification spec = new ExampleSpecification<>(example, escapeCharacter);
Class probeType = example.getProbeType();
@@ -617,7 +630,7 @@ public long count(@Nullable Specification spec) {
@Transactional
public S save(S entity) {
- Assert.notNull(entity, "Entity must not be null");
+ Assert.notNull(entity, ENTITY_MUST_NOT_BE_NULL);
if (entityInformation.isNew(entity)) {
entityManager.persist(entity);
@@ -710,7 +723,6 @@ protected Page readPage(TypedQuery query, final Class dom
* @param pageable must not be {@literal null}.
*/
protected TypedQuery getQuery(@Nullable Specification spec, Pageable pageable) {
-
return getQuery(spec, getDomainClass(), pageable.getSort());
}
@@ -723,7 +735,6 @@ protected TypedQuery getQuery(@Nullable Specification spec, Pageable pagea
*/
protected TypedQuery getQuery(@Nullable Specification spec, Class domainClass,
Pageable pageable) {
-
return getQuery(spec, domainClass, pageable.getSort());
}
@@ -990,7 +1001,7 @@ private static class ExampleSpecification implements Specification {
*/
ExampleSpecification(Example example, EscapeCharacter escapeCharacter) {
- Assert.notNull(example, "Example must not be null");
+ Assert.notNull(example, EXAMPLE_MUST_NOT_BE_NULL);
Assert.notNull(escapeCharacter, "EscapeCharacter must not be null");
this.example = example;
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessor.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessor.java
index 8415d67959..324c37f327 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessor.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/support/MergingPersistenceUnitManager.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/support/MergingPersistenceUnitManager.java
index e2703107cc..c3c7fc384f 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/support/MergingPersistenceUnitManager.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/support/MergingPersistenceUnitManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/support/PageableUtils.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/support/PageableUtils.java
index c50a8f98aa..fab11c139a 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/support/PageableUtils.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/support/PageableUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/BeanDefinitionUtils.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/BeanDefinitionUtils.java
index 80403737d5..a5c181ee0b 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/BeanDefinitionUtils.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/BeanDefinitionUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/HibernateProxyDetector.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/HibernateProxyDetector.java
index 6969cfb4a5..149742c0b7 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/HibernateProxyDetector.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/HibernateProxyDetector.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2024 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/JpaMetamodel.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/JpaMetamodel.java
index f10b69c61a..fc2cb71ae2 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/JpaMetamodel.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/JpaMetamodel.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/JpaMetamodelCacheCleanup.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/JpaMetamodelCacheCleanup.java
index df17d56ade..c9c3e70447 100644
--- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/JpaMetamodelCacheCleanup.java
+++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/util/JpaMetamodelCacheCleanup.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2024 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/AntlrVersionTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/AntlrVersionTests.java
index c694587167..7c18f5d466 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/AntlrVersionTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/AntlrVersionTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/QueryByExamplePredicateBuilderUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/QueryByExamplePredicateBuilderUnitTests.java
index 0cd7169d04..544644ef81 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/QueryByExamplePredicateBuilderUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/QueryByExamplePredicateBuilderUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.springframework.data.jpa.convert;
import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import static org.springframework.data.domain.Example.*;
@@ -23,6 +24,7 @@
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Join;
+import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
@@ -39,6 +41,8 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@@ -47,6 +51,7 @@
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.ExampleMatcher.GenericPropertyMatcher;
+import org.springframework.data.domain.ExampleMatcher.MatchMode;
import org.springframework.data.jpa.repository.query.EscapeCharacter;
import org.springframework.util.ObjectUtils;
@@ -57,6 +62,7 @@
* @author Mark Paluch
* @author Oliver Gierke
* @author Jens Schauder
+ * @author Arnaud Lecointre
*/
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
@@ -271,6 +277,21 @@ void likePatternsGetEscapedEnding() {
verify(cb, times(1)).like(any(Expression.class), eq("%f\\\\o\\_o"), eq('\\'));
}
+ @ParameterizedTest(name = "Matching {0} on association should join using JoinType.{1} ") // GH-3763
+ @CsvSource({ "ALL, INNER", "ANY, LEFT" })
+ void matchingAssociationShouldUseTheCorrectJoinType(MatchMode matchMode, JoinType expectedJoinType) {
+
+ Person person = new Person();
+ person.father = new Person();
+
+ ExampleMatcher matcher = matchMode == MatchMode.ALL ? ExampleMatcher.matchingAll() : ExampleMatcher.matchingAny();
+ Example example = of(person, matcher);
+
+ QueryByExamplePredicateBuilder.getPredicate(root, cb, example, EscapeCharacter.DEFAULT);
+
+ verify(root, times(1)).join("father", expectedJoinType);
+ }
+
@SuppressWarnings("unused")
static class Person {
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/threeten/DateTimeSample.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/threeten/DateTimeSample.java
index 7743c9868c..579c430b83 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/threeten/DateTimeSample.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/threeten/DateTimeSample.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/threeten/Jsr310JpaConvertersIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/threeten/Jsr310JpaConvertersIntegrationTests.java
index 5ef388138e..ff76fbd718 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/threeten/Jsr310JpaConvertersIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/threeten/Jsr310JpaConvertersIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/threeten/Jsr310JpaConvertersUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/threeten/Jsr310JpaConvertersUnitTests.java
index 92a31cec4a..a1daf39d27 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/threeten/Jsr310JpaConvertersUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/convert/threeten/Jsr310JpaConvertersUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/JpaSortTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/JpaSortTests.java
index 53d3d0df21..dac929f40d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/JpaSortTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/JpaSortTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/SpecificationUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/SpecificationUnitTests.java
index aeb0c819ea..994f597cf0 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/SpecificationUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/SpecificationUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -45,11 +45,12 @@
* @author Jens Schauder
* @author Mark Paluch
* @author Daniel Shuy
+ * @author Peter Aisher
*/
-@SuppressWarnings("serial")
+@SuppressWarnings("removal")
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
-class SpecificationUnitTests implements Serializable {
+class SpecificationUnitTests {
private Specification spec;
@Mock(serializable = true) Root root;
@@ -120,7 +121,7 @@ void orConcatenatesNullSpecToSpec() {
}
@Test // GH-1943
- public void allOfConcatenatesNull() {
+ void allOfConcatenatesNull() {
Specification specification = Specification.allOf(null, spec, null);
@@ -129,7 +130,7 @@ public void allOfConcatenatesNull() {
}
@Test // GH-1943
- public void anyOfConcatenatesNull() {
+ void anyOfConcatenatesNull() {
Specification specification = Specification.anyOf(null, spec, null);
@@ -138,7 +139,7 @@ public void anyOfConcatenatesNull() {
}
@Test // GH-1943
- public void emptyAllOfReturnsEmptySpecification() {
+ void emptyAllOfReturnsEmptySpecification() {
Specification specification = Specification.allOf();
@@ -147,7 +148,7 @@ public void emptyAllOfReturnsEmptySpecification() {
}
@Test // GH-1943
- public void emptyAnyOfReturnsEmptySpecification() {
+ void emptyAnyOfReturnsEmptySpecification() {
Specification specification = Specification.anyOf();
@@ -163,7 +164,7 @@ void specificationsShouldBeSerializable() {
assertThat(specification).isNotNull();
- @SuppressWarnings("unchecked")
+ @SuppressWarnings({ "unchecked", "deprecation" })
Specification transferredSpecification = (Specification) deserialize(serialize(specification));
assertThat(transferredSpecification).isNotNull();
@@ -178,7 +179,7 @@ void complexSpecificationsShouldBeSerializable() {
assertThat(specification).isNotNull();
- @SuppressWarnings("unchecked")
+ @SuppressWarnings({ "unchecked", "deprecation" })
Specification transferredSpecification = (Specification) deserialize(serialize(specification));
assertThat(transferredSpecification).isNotNull();
@@ -206,7 +207,6 @@ void orCombinesSpecificationsInOrder() {
Predicate secondPredicate = mock(Predicate.class);
Specification first = ((root1, query1, criteriaBuilder) -> firstPredicate);
-
Specification second = ((root1, query1, criteriaBuilder) -> secondPredicate);
first.or(second).toPredicate(root, query, builder);
@@ -214,6 +214,15 @@ void orCombinesSpecificationsInOrder() {
verify(builder).or(firstPredicate, secondPredicate);
}
+ @Test // GH-3849, GH-4023
+ void notWithNullPredicate() {
+
+ Specification notSpec = Specification.not(Specification.where(null));
+
+ assertThat(notSpec.toPredicate(root, query, builder)).isNull();
+ verifyNoInteractions(builder);
+ }
+
static class SerializableSpecification implements Serializable, Specification {
@Override
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AbstractAnnotatedAuditable.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AbstractAnnotatedAuditable.java
index 82adedca45..e3e2ee3472 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AbstractAnnotatedAuditable.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AbstractAnnotatedAuditable.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AbstractMappedType.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AbstractMappedType.java
index 60a37337b0..801b3fd9c9 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AbstractMappedType.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AbstractMappedType.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Account.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Account.java
index 856611e95f..787c4bd64f 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Account.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Account.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Address.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Address.java
index 468a3ba193..e5db7bfddf 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Address.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Address.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AnnotatedAuditableUser.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AnnotatedAuditableUser.java
index cbb435fbc2..44bcc91e6f 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AnnotatedAuditableUser.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AnnotatedAuditableUser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableEmbeddable.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableEmbeddable.java
index 2cb8553073..40563a3f52 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableEmbeddable.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableEmbeddable.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableEntity.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableEntity.java
index 8cb2b861c8..730fe36d20 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableEntity.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableEntity.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableRole.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableRole.java
index 9fa9442b30..bfc17a68d2 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableRole.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableRole.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableUser.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableUser.java
index e69864c553..65d4e6e2ad 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableUser.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditableUser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditorAwareStub.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditorAwareStub.java
index 2ef54a1ff6..00124d98db 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditorAwareStub.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/AuditorAwareStub.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Book.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Book.java
index e66c26ffab..e30fd93869 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Book.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Book.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Child.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Child.java
index 05673e35b0..f3df1a4fe2 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Child.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Child.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ConcreteType1.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ConcreteType1.java
index 90be74aeb7..28fb4e588f 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ConcreteType1.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ConcreteType1.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ConcreteType2.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ConcreteType2.java
index 356cc35d52..a30d7b4140 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ConcreteType2.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ConcreteType2.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/CustomAbstractPersistable.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/CustomAbstractPersistable.java
index aa136318aa..dd3fd70449 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/CustomAbstractPersistable.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/CustomAbstractPersistable.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Customer.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Customer.java
index 72d01a6267..f8442a9ae4 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Customer.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Customer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Dummy.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Dummy.java
index e30afcd084..bb8bfe638a 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Dummy.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Dummy.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmbeddedIdExampleDepartment.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmbeddedIdExampleDepartment.java
index 043457222a..a7aa1b9dfc 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmbeddedIdExampleDepartment.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmbeddedIdExampleDepartment.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmbeddedIdExampleEmployee.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmbeddedIdExampleEmployee.java
index 0368411310..218c1f6e01 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmbeddedIdExampleEmployee.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmbeddedIdExampleEmployee.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmbeddedIdExampleEmployeePK.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmbeddedIdExampleEmployeePK.java
index 1b5e49bef7..393bb6b668 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmbeddedIdExampleEmployeePK.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmbeddedIdExampleEmployeePK.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmployeeWithName.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmployeeWithName.java
index ee4f273f10..4668ed04de 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmployeeWithName.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EmployeeWithName.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EntityWithAssignedId.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EntityWithAssignedId.java
index 3204f31995..4226b8bb67 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EntityWithAssignedId.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/EntityWithAssignedId.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2024 the original author or authors.
+ * Copyright 2019-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/IdClassExampleDepartment.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/IdClassExampleDepartment.java
index 2539184afb..7db4bf3486 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/IdClassExampleDepartment.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/IdClassExampleDepartment.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/IdClassExampleEmployee.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/IdClassExampleEmployee.java
index 18df94dcec..6ad0aeb024 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/IdClassExampleEmployee.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/IdClassExampleEmployee.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/IdClassExampleEmployeePK.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/IdClassExampleEmployeePK.java
index 142c75b5f9..fd730da59d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/IdClassExampleEmployeePK.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/IdClassExampleEmployeePK.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Invoice.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Invoice.java
index 2f5381f494..a0458759f6 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Invoice.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Invoice.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2024 the original author or authors.
+ * Copyright 2020-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/InvoiceItem.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/InvoiceItem.java
index 1ff39954df..c791359af3 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/InvoiceItem.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/InvoiceItem.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2024 the original author or authors.
+ * Copyright 2020-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Item.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Item.java
index 1625c2a794..7a01bdf620 100755
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Item.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Item.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ItemId.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ItemId.java
index 774c609c97..b58f92d049 100755
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ItemId.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ItemId.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ItemSite.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ItemSite.java
index b5da989a14..f5ad83e344 100755
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ItemSite.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ItemSite.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ItemSiteId.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ItemSiteId.java
index c691ac8f50..4d838de5e6 100755
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ItemSiteId.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/ItemSiteId.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/MailMessage.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/MailMessage.java
index 08d5975559..065e9ec59b 100755
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/MailMessage.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/MailMessage.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/MailSender.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/MailSender.java
index a15de9c1f1..00fffaa244 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/MailSender.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/MailSender.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/MailUser.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/MailUser.java
index 49911d316a..16d5b2dbcd 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/MailUser.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/MailUser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Order.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Order.java
index c9146c1bf6..2c544945b7 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Order.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Order.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/OrmXmlEntity.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/OrmXmlEntity.java
index b18eb9f18b..48ba2cdeb2 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/OrmXmlEntity.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/OrmXmlEntity.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Owner.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Owner.java
index 7661f038a1..820fc189fd 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Owner.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Owner.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/OwnerContainer.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/OwnerContainer.java
index 177b8b48ba..f726ca86c1 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/OwnerContainer.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/OwnerContainer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Parent.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Parent.java
index b0a00f0ace..4b9e57c4fe 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Parent.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Parent.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithIdClass.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithIdClass.java
index 5b6d1277d9..08a31a09bf 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithIdClass.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithIdClass.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithIdClassPK.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithIdClassPK.java
index 5f7a6ffa43..0dcef9e938 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithIdClassPK.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithIdClassPK.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithSingleIdClass.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithSingleIdClass.java
index 38305b4b90..cefd449fc9 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithSingleIdClass.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithSingleIdClass.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2024 the original author or authors.
+ * Copyright 2021-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithSingleIdClassPK.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithSingleIdClassPK.java
index e405b3c4ba..6466fd1dd8 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithSingleIdClassPK.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PersistableWithSingleIdClassPK.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2024 the original author or authors.
+ * Copyright 2021-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PrimitiveVersionProperty.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PrimitiveVersionProperty.java
index c3531adacc..694f896df8 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PrimitiveVersionProperty.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/PrimitiveVersionProperty.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Role.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Role.java
index f9518a8fbc..101a784ee2 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Role.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Role.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleEntity.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleEntity.java
index 8fe586d843..3fafe176f1 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleEntity.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleEntity.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleEntityPK.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleEntityPK.java
index c46143f81d..2ad2f36f3f 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleEntityPK.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleEntityPK.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithPrimitiveId.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithPrimitiveId.java
index a84c1409f5..f1047f1d4f 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithPrimitiveId.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithPrimitiveId.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithTimestampVersion.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithTimestampVersion.java
index 7dc7d4ab59..3b17fb3a59 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithTimestampVersion.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/SampleWithTimestampVersion.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Site.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Site.java
index 996561cdf4..591f4da96e 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Site.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/Site.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/User.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/User.java
index b3e1b4dea2..fafd6fca4a 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/User.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/User.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/UserSpecifications.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/UserSpecifications.java
index 3b4d0cbbcd..304dcb5607 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/UserSpecifications.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/UserSpecifications.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/UserWithOptionalField.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/UserWithOptionalField.java
index b4029f4717..cdfb9a3bfc 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/UserWithOptionalField.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/UserWithOptionalField.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/UserWithOptionalFieldRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/UserWithOptionalFieldRepository.java
index 348b4433c6..c2ead4cdf7 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/UserWithOptionalFieldRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/UserWithOptionalFieldRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/VersionedUser.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/VersionedUser.java
index 5e5927e1e4..58ff336205 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/VersionedUser.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/sample/VersionedUser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AbstractAttributeConverterIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AbstractAttributeConverterIntegrationTests.java
index c5a088ddec..34fb8b1bf4 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AbstractAttributeConverterIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AbstractAttributeConverterIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AnnotationAuditingBeanFactoryPostProcessorUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AnnotationAuditingBeanFactoryPostProcessorUnitTests.java
index 39160aee50..94702362a0 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AnnotationAuditingBeanFactoryPostProcessorUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AnnotationAuditingBeanFactoryPostProcessorUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingBeanFactoryPostProcessorUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingBeanFactoryPostProcessorUnitTests.java
index e34cec061d..c5ed0d79df 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingBeanFactoryPostProcessorUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingBeanFactoryPostProcessorUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingEntityListenerTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingEntityListenerTests.java
index e95c8b0542..674fef7bf9 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingEntityListenerTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingEntityListenerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingEntityWithEmbeddableListenerTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingEntityWithEmbeddableListenerTests.java
index 2887bb4dd3..6701ddc4b9 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingEntityWithEmbeddableListenerTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingEntityWithEmbeddableListenerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingNamespaceUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingNamespaceUnitTests.java
index 2835201104..510793ad72 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingNamespaceUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/AuditingNamespaceUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/QueryByExampleWithOptionalEmptyTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/QueryByExampleWithOptionalEmptyTests.java
index d5711367ef..21c04b3145 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/QueryByExampleWithOptionalEmptyTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/domain/support/QueryByExampleWithOptionalEmptyTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/EclipseLinkMetamodelIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/EclipseLinkMetamodelIntegrationTests.java
index 93ff873092..e3cf795046 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/EclipseLinkMetamodelIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/EclipseLinkMetamodelIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/HibernateMetamodelIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/HibernateMetamodelIntegrationTests.java
index 284287c990..6ecaceccbc 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/HibernateMetamodelIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/HibernateMetamodelIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/HibernateTestUtils.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/HibernateTestUtils.java
index 82efcfadd3..02d29a7673 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/HibernateTestUtils.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/HibernateTestUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/MetamodelIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/MetamodelIntegrationTests.java
index 2f48b244b4..c821dd76a5 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/MetamodelIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/MetamodelIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/OpenJpaMetamodelIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/OpenJpaMetamodelIntegrationTests.java
index 8e437f6473..16983f0f88 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/OpenJpaMetamodelIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/infrastructure/OpenJpaMetamodelIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContextIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContextIntegrationTests.java
index 3ed9eaf357..4e2d3c32ea 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContextIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContextIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContextUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContextUnitTests.java
index ff83c9672e..03962c2aa6 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContextUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContextUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImplUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImplUnitTests.java
index e7d42e9e76..ef3af850a1 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImplUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/mapping/JpaPersistentPropertyImplUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/provider/PersistenceProviderIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/provider/PersistenceProviderIntegrationTests.java
index b28943e2d5..0f27bd1422 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/provider/PersistenceProviderIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/provider/PersistenceProviderIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/provider/PersistenceProviderUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/provider/PersistenceProviderUnitTests.java
index bcb9582bc6..ba7c3abed7 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/provider/PersistenceProviderUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/provider/PersistenceProviderUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/AbstractPersistableIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/AbstractPersistableIntegrationTests.java
index 67ce3cfa50..bad12168d4 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/AbstractPersistableIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/AbstractPersistableIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CrudMethodMetadataUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CrudMethodMetadataUnitTests.java
index 76c7e95662..52e217bb71 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CrudMethodMetadataUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CrudMethodMetadataUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CustomAbstractPersistableIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CustomAbstractPersistableIntegrationTests.java
index 46353534a1..a5ac1bd413 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CustomAbstractPersistableIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CustomAbstractPersistableIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CustomEclipseLinkJpaVendorAdapter.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CustomEclipseLinkJpaVendorAdapter.java
index 124fff7adb..6919ba545d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CustomEclipseLinkJpaVendorAdapter.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CustomEclipseLinkJpaVendorAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CustomHsqlHibernateJpaVendorAdaptor.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CustomHsqlHibernateJpaVendorAdaptor.java
index 2957ab2e87..359bda9b5e 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CustomHsqlHibernateJpaVendorAdaptor.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/CustomHsqlHibernateJpaVendorAdaptor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkEntityGraphRepositoryMethodsIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkEntityGraphRepositoryMethodsIntegrationTests.java
index e0d21dc716..74820a58a2 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkEntityGraphRepositoryMethodsIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkEntityGraphRepositoryMethodsIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkNamespaceUserRepositoryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkNamespaceUserRepositoryTests.java
index a93fb5336b..ad61aa2f55 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkNamespaceUserRepositoryTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkNamespaceUserRepositoryTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkParentRepositoryIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkParentRepositoryIntegrationTests.java
index 06d1575fd5..796e14be8a 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkParentRepositoryIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkParentRepositoryIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkQueryByExampleIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkQueryByExampleIntegrationTests.java
index afea59666d..1f0e5e1300 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkQueryByExampleIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkQueryByExampleIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkRepositoryWithCompositeKeyIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkRepositoryWithCompositeKeyIntegrationTests.java
index 82ca0c59a9..a2f1bbb5db 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkRepositoryWithCompositeKeyIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkRepositoryWithCompositeKeyIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkStoredProcedureIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkStoredProcedureIntegrationTests.java
index e3ff3d5c07..71a583ebc1 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkStoredProcedureIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkStoredProcedureIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkUserRepositoryFinderTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkUserRepositoryFinderTests.java
index 99343adb99..75cfa39d82 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkUserRepositoryFinderTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EclipseLinkUserRepositoryFinderTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EntityGraphRepositoryMethodsIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EntityGraphRepositoryMethodsIntegrationTests.java
index 1086577a21..7191b85a4d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EntityGraphRepositoryMethodsIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EntityGraphRepositoryMethodsIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EntityWithAssignedIdIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EntityWithAssignedIdIntegrationTests.java
index 10a84ed886..05e6714895 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EntityWithAssignedIdIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/EntityWithAssignedIdIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2024 the original author or authors.
+ * Copyright 2019-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/GreetingsFrom.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/GreetingsFrom.java
index 247944ccd0..3e31f95ffb 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/GreetingsFrom.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/GreetingsFrom.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/HibernateRepositoryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/HibernateRepositoryTests.java
new file mode 100644
index 0000000000..5f965f203e
--- /dev/null
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/HibernateRepositoryTests.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.jpa.repository;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.assertj.core.api.Assumptions.*;
+
+import jakarta.persistence.EntityManager;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.FilterType;
+import org.springframework.context.annotation.ImportResource;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.domain.sample.Role;
+import org.springframework.data.jpa.domain.sample.User;
+import org.springframework.data.jpa.provider.PersistenceProvider;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.data.jpa.repository.sample.RoleRepository;
+import org.springframework.data.jpa.repository.sample.UserRepository;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Hibernate-specific repository tests.
+ *
+ * @author Mark Paluch
+ */
+@ExtendWith(SpringExtension.class)
+@ContextConfiguration()
+@Transactional
+class HibernateRepositoryTests {
+
+ @Autowired UserRepository userRepository;
+ @Autowired RoleRepository roleRepository;
+ @Autowired CteUserRepository cteUserRepository;
+ @Autowired EntityManager em;
+
+ PersistenceProvider provider;
+ User dave;
+ User carter;
+ User oliver;
+ Role drummer;
+ Role guitarist;
+ Role singer;
+
+ @BeforeEach
+ void setUp() {
+ provider = PersistenceProvider.fromEntityManager(em);
+
+ assumeThat(provider).isEqualTo(PersistenceProvider.HIBERNATE);
+ roleRepository.deleteAll();
+ userRepository.deleteAll();
+
+ drummer = roleRepository.save(new Role("DRUMMER"));
+ guitarist = roleRepository.save(new Role("GUITARIST"));
+ singer = roleRepository.save(new Role("SINGER"));
+
+ dave = userRepository.save(new User("Dave", "Matthews", "dave@dmband.com", singer));
+ carter = userRepository.save(new User("Carter", "Beauford", "carter@dmband.com", singer, drummer));
+ oliver = userRepository.save(new User("Oliver August", "Matthews", "oliver@dmband.com"));
+ }
+
+ @Test // GH-3726
+ void testQueryWithCTE() {
+
+ Page result = cteUserRepository.findWithCTE(PageRequest.of(0, 1));
+ assertThat(result.getTotalElements()).isEqualTo(3);
+ }
+
+ @ImportResource({ "classpath:infrastructure.xml" })
+ @Configuration
+ @EnableJpaRepositories(basePackageClasses = HibernateRepositoryTests.class, considerNestedRepositories = true,
+ includeFilters = @ComponentScan.Filter(
+ classes = { CteUserRepository.class, UserRepository.class, RoleRepository.class },
+ type = FilterType.ASSIGNABLE_TYPE))
+ static class TestConfig {}
+
+ interface CteUserRepository extends CrudRepository {
+
+ /*
+ WITH entities AS (
+ SELECT
+ e.id as id,
+ e.number as number
+ FROM TestEntity e
+ )
+ SELECT new com.example.demo.Result('X', c.id, c.number)
+ FROM entities c
+ */
+
+ @Query("""
+ WITH cte_select AS (select u.firstname as firstname, u.lastname as lastname from User u)
+ SELECT new org.springframework.data.jpa.repository.UserExcerptDto(c.firstname, c.lastname)
+ FROM cte_select c
+ """)
+ Page findWithCTE(Pageable page);
+
+ }
+
+}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/JavaConfigUserRepositoryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/JavaConfigUserRepositoryTests.java
index b1aeb29c3a..d87b9e152c 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/JavaConfigUserRepositoryTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/JavaConfigUserRepositoryTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/MappedTypeRepositoryIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/MappedTypeRepositoryIntegrationTests.java
index 1a33ab4bc2..42428a19f2 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/MappedTypeRepositoryIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/MappedTypeRepositoryIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/NamespaceUserRepositoryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/NamespaceUserRepositoryTests.java
index a37117e848..5c99719d12 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/NamespaceUserRepositoryTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/NamespaceUserRepositoryTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/ORMInfrastructureTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/ORMInfrastructureTests.java
index 98bd534a78..5cbb6a96bb 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/ORMInfrastructureTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/ORMInfrastructureTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaEntityGraphRepositoryMethodsIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaEntityGraphRepositoryMethodsIntegrationTests.java
index 22390b7682..c42ae99579 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaEntityGraphRepositoryMethodsIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaEntityGraphRepositoryMethodsIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaNamespaceUserRepositoryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaNamespaceUserRepositoryTests.java
index cfe023d9c6..a69fb9e35c 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaNamespaceUserRepositoryTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaNamespaceUserRepositoryTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaParentRepositoryIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaParentRepositoryIntegrationTests.java
index 5cf9bc4917..d94ed598c0 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaParentRepositoryIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaParentRepositoryIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaRepositoryWithCompositeKeyIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaRepositoryWithCompositeKeyIntegrationTests.java
index e3c8eeb334..c6acc17b33 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaRepositoryWithCompositeKeyIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaRepositoryWithCompositeKeyIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaStoredProcedureIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaStoredProcedureIntegrationTests.java
index 993cb32a04..6984b99e27 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaStoredProcedureIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaStoredProcedureIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaUserRepositoryFinderTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaUserRepositoryFinderTests.java
index d53d6bd531..d1e1b01f66 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaUserRepositoryFinderTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/OpenJpaUserRepositoryFinderTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/ParentRepositoryIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/ParentRepositoryIntegrationTests.java
index 6b85895950..7b53e6669b 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/ParentRepositoryIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/ParentRepositoryIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/QueryByExampleIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/QueryByExampleIntegrationTests.java
index a5302d9506..fa9de5e26f 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/QueryByExampleIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/QueryByExampleIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
*/
package org.springframework.data.jpa.repository;
-import static org.assertj.core.api.Assertions.*;
+import static org.assertj.core.api.Assertions.assertThat;
import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaBuilder;
@@ -23,21 +23,27 @@
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
+import java.util.List;
+
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
+import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.jpa.convert.QueryByExamplePredicateBuilder;
import org.springframework.data.jpa.domain.sample.Role;
+import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.repository.sample.RoleRepository;
+import org.springframework.data.jpa.repository.sample.UserRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Greg Turnquist
+ * @author Christoph Strobl
* @since 3.0
*/
@ExtendWith(SpringExtension.class)
@@ -45,7 +51,8 @@
@Transactional
class QueryByExampleIntegrationTests {
- @Autowired RoleRepository repository;
+ @Autowired RoleRepository roleRepository;
+ @Autowired UserRepository userRepository;
@Autowired EntityManager em;
private Role drummer;
@@ -55,14 +62,14 @@ class QueryByExampleIntegrationTests {
@BeforeEach
void setUp() {
- drummer = repository.save(new Role("drummer"));
- guitarist = repository.save(new Role("guitarist"));
- singer = repository.save(new Role("singer"));
+ drummer = roleRepository.save(new Role("drummer"));
+ guitarist = roleRepository.save(new Role("guitarist"));
+ singer = roleRepository.save(new Role("singer"));
}
@AfterEach
void clearUp() {
- repository.deleteAll();
+ roleRepository.deleteAll();
}
@Test // GH-2283
@@ -81,6 +88,39 @@ void queryByExampleWithNoPredicatesShouldHaveNoWhereClause() {
// then
assertThat(predicate).isNull();
- assertThat(repository.findAll(example)).containsExactlyInAnyOrder(drummer, guitarist, singer);
+ assertThat(roleRepository.findAll(example)).containsExactlyInAnyOrder(drummer, guitarist, singer);
+ }
+
+ @Test // GH-3763
+ void usesAnyMatchOnJoins() {
+
+ User manager = new User("mighty", "super user", "msu@u.io");
+
+ userRepository.save(manager);
+
+ User dave = new User();
+ dave.setFirstname("dave");
+ dave.setLastname("matthews");
+ dave.setEmailAddress("d@dmb.com");
+ dave.addRole(singer);
+
+ User carter = new User();
+ carter.setFirstname("carter");
+ carter.setLastname("beaufort");
+ carter.setEmailAddress("c@dmb.com");
+ carter.addRole(drummer);
+ carter.addRole(singer);
+ carter.setManager(manager);
+
+ userRepository.saveAllAndFlush(List.of(dave, carter));
+
+ User probe = new User();
+ probe.setLastname(dave.getLastname());
+ probe.setManager(manager);
+
+ Example example = Example.of(probe,
+ ExampleMatcher.matchingAny().withIgnorePaths("id", "createdAt", "age", "active", "emailAddress",
+ "secondaryEmailAddress", "colleagues", "address", "binaryData", "attributes", "dateOfBirth"));
+ assertThat(userRepository.findAll(example)).containsExactly(dave, carter);
}
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RedeclaringRepositoryMethodsTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RedeclaringRepositoryMethodsTests.java
index b8b1f54511..c4f5c4e30d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RedeclaringRepositoryMethodsTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RedeclaringRepositoryMethodsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RepositoryWithCompositeKeyTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RepositoryWithCompositeKeyTests.java
index 64b51acb1c..20613cc1d6 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RepositoryWithCompositeKeyTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RepositoryWithCompositeKeyTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RepositoryWithIdClassKeyTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RepositoryWithIdClassKeyTests.java
index b0cbec6b44..5cc0f45ce0 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RepositoryWithIdClassKeyTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RepositoryWithIdClassKeyTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RoleRepositoryIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RoleRepositoryIntegrationTests.java
index 2a8f849823..5fc3573d64 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RoleRepositoryIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/RoleRepositoryIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/SPR8954Tests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/SPR8954Tests.java
index f731ca2c66..f2a0042a32 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/SPR8954Tests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/SPR8954Tests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/SimpleJpaParameterBindingTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/SimpleJpaParameterBindingTests.java
index bc11790d8e..efe754ad7b 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/SimpleJpaParameterBindingTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/SimpleJpaParameterBindingTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/StoredProcedureIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/StoredProcedureIntegrationTests.java
index 93615637f5..8cc377e059 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/StoredProcedureIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/StoredProcedureIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserExcerptDto.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserExcerptDto.java
new file mode 100644
index 0000000000..dad70a9a2c
--- /dev/null
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserExcerptDto.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.jpa.repository;
+
+/**
+ * Hibernate is still a bit picky on records so let's use a class, just in case.
+ *
+ * @author Christoph Strobl
+ */
+public class UserExcerptDto {
+
+ private String firstname;
+ private String lastname;
+
+ public UserExcerptDto(String firstname, String lastname) {
+ this.firstname = firstname;
+ this.lastname = lastname;
+ }
+
+ public String getFirstname() {
+ return firstname;
+ }
+
+ public void setFirstname(String firstname) {
+ this.firstname = firstname;
+ }
+
+ public String getLastname() {
+ return lastname;
+ }
+
+ public void setLastname(String lastname) {
+ this.lastname = lastname;
+ }
+}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java
index 259420a09a..7d8f721c5c 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryFinderTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryStoredProcedureIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryStoredProcedureIntegrationTests.java
index de57832f7a..1f158fa4fd 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryStoredProcedureIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryStoredProcedureIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java
index 225336983e..016300697c 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,6 +42,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.function.Function;
import java.util.stream.IntStream;
import java.util.stream.Stream;
@@ -67,9 +68,11 @@
import org.springframework.data.jpa.domain.sample.Role;
import org.springframework.data.jpa.domain.sample.SpecialUser;
import org.springframework.data.jpa.domain.sample.User;
+import org.springframework.data.jpa.repository.sample.NameOnlyRecord;
import org.springframework.data.jpa.repository.sample.SampleEvaluationContextExtension.SampleSecurityContextHolder;
import org.springframework.data.jpa.repository.sample.UserRepository;
import org.springframework.data.jpa.repository.sample.UserRepository.NameOnly;
+import org.springframework.data.jpa.util.DisabledOnHibernate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.transaction.annotation.Transactional;
@@ -2353,6 +2356,14 @@ void findByFluentExampleWithSorting() {
assertThat(users).containsExactly(thirdUser, firstUser, fourthUser);
}
+ @Test // GH-3294
+ void findByFluentFailsReturningFluentQuery() {
+
+ User prototype = new User();
+ assertThatExceptionOfType(InvalidDataAccessApiUsageException.class)
+ .isThrownBy(() -> repository.findBy(of(prototype), Function.identity()));
+ }
+
@Test // GH-2294
void findByFluentExampleFirstValue() {
@@ -2423,6 +2434,24 @@ void findByFluentExamplePage() {
assertThat(page1.getContent()).containsExactly(fourthUser);
}
+ @Test // GH-3762
+ void findByFluentExamplePageSortOverride() {
+
+ flushTestUsers();
+
+ User prototype = new User();
+ prototype.setFirstname("v");
+
+ Example userProbe = of(prototype, matching().withIgnorePaths("age", "createdAt", "active")
+ .withMatcher("firstname", GenericPropertyMatcher::contains));
+
+ Page page = repository.findBy(userProbe, //
+ q -> q.sortBy(Sort.by("firstname")).page(PageRequest.of(0, 2, Sort.by(DESC, "firstname"))));
+
+ assertThat(page.getContent()).containsExactly(fourthUser, firstUser);
+ assertThat(repository.findAll(page.nextPageable())).containsExactly(secondUser, thirdUser);
+ }
+
@Test // GH-2294
void findByFluentExampleWithInterfaceBasedProjection() {
@@ -2450,13 +2479,13 @@ void findByFluentExampleWithInterfaceBasedProjectionUsingSpEL() {
prototype.setFirstname("v");
List users = repository.findBy(
- of(prototype,
- matching().withIgnorePaths("age", "createdAt", "active").withMatcher("firstname",
- GenericPropertyMatcher::contains)), //
- q -> q.as(UserProjectionUsingSpEL.class).all());
+ of(prototype,
+ matching().withIgnorePaths("age", "createdAt", "active").withMatcher("firstname",
+ GenericPropertyMatcher::contains)), //
+ q -> q.as(UserProjectionUsingSpEL.class).all());
assertThat(users).extracting(UserProjectionUsingSpEL::hello)
- .contains(new GreetingsFrom().groot(firstUser.getFirstname()));
+ .contains(new GreetingsFrom().groot(firstUser.getFirstname()));
}
@Test // GH-2294
@@ -2678,6 +2707,18 @@ void findByFluentSpecificationPage() {
assertThat(page1.getContent()).containsExactly(fourthUser);
}
+ @Test // GH-3762
+ void findByFluentSpecificationSortOverridePage() {
+
+ flushTestUsers();
+
+ Page page = repository.findBy(userHasFirstnameLike("v"),
+ q -> q.sortBy(Sort.by("firstname")).page(PageRequest.of(0, 2, Sort.by(DESC, "firstname"))));
+
+ assertThat(page.getContent()).containsExactly(fourthUser, firstUser);
+ assertThat(repository.findAll(page.nextPageable())).containsExactly(secondUser, thirdUser);
+ }
+
@Test // GH-2274
void findByFluentSpecificationWithInterfaceBasedProjection() {
@@ -2979,6 +3020,20 @@ void supportsInterfaceProjectionsWithNativeQueries() {
assertThat(result.getLastname()).isEqualTo(user.getLastname());
}
+ @Test // GH-2757
+ @DisabledOnHibernate("6.2")
+ void supportsRecordsWithNativeQueries() {
+
+ flushTestUsers();
+
+ User user = repository.findAll().get(0);
+
+ NameOnlyRecord result = repository.findRecordProjectionByNativeQuery(user.getId());
+
+ assertThat(result.firstname()).isEqualTo(user.getFirstname());
+ assertThat(result.lastname()).isEqualTo(user.getLastname());
+ }
+
@Test // DATAJPA-1248
void supportsProjectionsWithNativeQueriesAndCamelCaseProperty() {
@@ -3044,22 +3099,36 @@ void handlesColonsFollowedByIntegerInStringLiteral() {
assertThat(users).extracting(User::getId).containsExactly(expected.getId());
}
- @Disabled("ORDER BY CASE appears to be a Hibernate-only feature")
- @Test // DATAJPA-1233
+ @Test // DATAJPA-1233, GH-3756
void handlesCountQueriesWithLessParametersSingleParam() {
- // repository.findAllOrderedBySpecialNameSingleParam("Oliver", PageRequest.of(2, 3));
+
+ flushTestUsers();
+
+ Page result = repository.findAllOrderedByNamedParam("Oliver", PageRequest.of(0, 3));
+
+ assertThat(result.getContent()).containsExactly(firstUser, fourthUser, thirdUser);
+ assertThat(result.getTotalElements()).isEqualTo(4);
+
+ result = repository.findAllOrderedByIndexedParam("Oliver", PageRequest.of(0, 3));
+
+ assertThat(result.getContent()).containsExactly(firstUser, fourthUser, thirdUser);
+ assertThat(result.getTotalElements()).isEqualTo(4);
}
- @Disabled("ORDER BY CASE appears to be a Hibernate-only feature")
- @Test // DATAJPA-1233
+ @Test // DATAJPA-1233, GH-3756
void handlesCountQueriesWithLessParametersMoreThanOne() {
- // repository.findAllOrderedBySpecialNameMultipleParams("Oliver", "x", PageRequest.of(2, 3));
- }
- @Disabled("ORDER BY CASE appears to be a Hibernate-only feature")
- @Test // DATAJPA-1233
- void handlesCountQueriesWithLessParametersMoreThanOneIndexed() {
- // repository.findAllOrderedBySpecialNameMultipleParamsIndexed("x", "Oliver", PageRequest.of(2, 3));
+ flushTestUsers();
+
+ Page result = repository.findAllOrderedBySpecialNameMultipleParams("Oliver", "x", PageRequest.of(0, 3));
+
+ assertThat(result.getContent()).containsExactly(firstUser, fourthUser, thirdUser);
+ assertThat(result.getTotalElements()).isEqualTo(4);
+
+ result = repository.findAllOrderedBySpecialNameMultipleParamsIndexed("x", "Oliver", PageRequest.of(0, 3));
+
+ assertThat(result.getContent()).containsExactly(firstUser, fourthUser, thirdUser);
+ assertThat(result.getTotalElements()).isEqualTo(4);
}
// DATAJPA-928
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/aot/JpaRuntimeHintsUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/aot/JpaRuntimeHintsUnitTests.java
index bce5b13fcd..9f7f6b5f0e 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/aot/JpaRuntimeHintsUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/aot/JpaRuntimeHintsUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/CdiExtensionIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/CdiExtensionIntegrationTests.java
index 1d44e9bf86..e04c20790e 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/CdiExtensionIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/CdiExtensionIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/EntityManagerFactoryProducer.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/EntityManagerFactoryProducer.java
index a00c0d43b5..d293674d49 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/EntityManagerFactoryProducer.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/EntityManagerFactoryProducer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/JpaQueryRewriterWithCdiIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/JpaQueryRewriterWithCdiIntegrationTests.java
index 30d6a7b85d..92994cfef3 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/JpaQueryRewriterWithCdiIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/JpaQueryRewriterWithCdiIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/JpaRepositoryExtensionUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/JpaRepositoryExtensionUnitTests.java
index 3b76bc9a05..7c8b6c8d94 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/JpaRepositoryExtensionUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/JpaRepositoryExtensionUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/Person.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/Person.java
index a889375381..007de3b9c9 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/Person.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/Person.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/PersonDB.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/PersonDB.java
index c91f3f97bb..abb7b5e6fd 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/PersonDB.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/PersonDB.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/PersonRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/PersonRepository.java
index 72b4956aba..eb8468db45 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/PersonRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/PersonRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedCdiConfiguration.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedCdiConfiguration.java
index 67e387afbb..ad47eda044 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedCdiConfiguration.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedCdiConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedUserRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedUserRepository.java
index 2d41f76bf6..d43704a813 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedUserRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedUserRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedUserRepositoryBean.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedUserRepositoryBean.java
index 779fa370ea..7a34f07fb4 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedUserRepositoryBean.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedUserRepositoryBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedUserRepositoryCustom.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedUserRepositoryCustom.java
index e4d49f78a0..ed789c32ca 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedUserRepositoryCustom.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedCustomizedUserRepositoryCustom.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedEntityManagerProducer.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedEntityManagerProducer.java
index 5a2a045bb1..093b5afc16 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedEntityManagerProducer.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedEntityManagerProducer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedFragment.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedFragment.java
index f379d09c1b..4702152d9b 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedFragment.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2024 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedFragmentBean.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedFragmentBean.java
index 6ff85427b4..54ce392031 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedFragmentBean.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedFragmentBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2024 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedPersonRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedPersonRepository.java
index a9fc2fe9a3..487121fc7a 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedPersonRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/QualifiedPersonRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/RepositoryConsumer.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/RepositoryConsumer.java
index f9ff0fa711..2833ea63b0 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/RepositoryConsumer.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/RepositoryConsumer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/SamplePersonRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/SamplePersonRepository.java
index 5e99a709a4..559370d8fe 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/SamplePersonRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/SamplePersonRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/SamplePersonRepositoryCustom.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/SamplePersonRepositoryCustom.java
index 072332f0fb..66a910a882 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/SamplePersonRepositoryCustom.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/SamplePersonRepositoryCustom.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/SamplePersonRepositoryImpl.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/SamplePersonRepositoryImpl.java
index 4e14a00ea4..ed7ef43cdd 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/SamplePersonRepositoryImpl.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/SamplePersonRepositoryImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/Transactional.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/Transactional.java
index ddc35d77bc..d50e810b25 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/Transactional.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/Transactional.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/TransactionalInterceptor.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/TransactionalInterceptor.java
index 1e9813df95..51d2bc3b29 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/TransactionalInterceptor.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/TransactionalInterceptor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/UnqualifiedEntityManagerProducer.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/UnqualifiedEntityManagerProducer.java
index d18edec881..43eded0a81 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/UnqualifiedEntityManagerProducer.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/UnqualifiedEntityManagerProducer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/UnqualifiedPersonRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/UnqualifiedPersonRepository.java
index 47677d70ac..fb7a4dd096 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/UnqualifiedPersonRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/UnqualifiedPersonRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/UserDB.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/UserDB.java
index d89737beb0..93f14563c7 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/UserDB.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/cdi/UserDB.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AbstractAuditingViaJavaConfigRepositoriesTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AbstractAuditingViaJavaConfigRepositoriesTests.java
index 7a5fb05c0d..5285ed2e3e 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AbstractAuditingViaJavaConfigRepositoriesTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AbstractAuditingViaJavaConfigRepositoriesTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AbstractRepositoryConfigTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AbstractRepositoryConfigTests.java
index 8d6baca3e3..64da44a6a0 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AbstractRepositoryConfigTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AbstractRepositoryConfigTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AllowNestedRepositoriesRepositoryConfigTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AllowNestedRepositoriesRepositoryConfigTests.java
index 6110e02b1c..edae851478 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AllowNestedRepositoriesRepositoryConfigTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AllowNestedRepositoriesRepositoryConfigTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AuditingBeanDefinitionParserTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AuditingBeanDefinitionParserTests.java
index 14edf2c213..b739493a23 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AuditingBeanDefinitionParserTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/AuditingBeanDefinitionParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/CustomRepositoryFactoryConfigTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/CustomRepositoryFactoryConfigTests.java
index 9dc0b3d0fc..02f2f2a1fe 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/CustomRepositoryFactoryConfigTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/CustomRepositoryFactoryConfigTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/DefaultAuditingViaJavaConfigRepositoriesTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/DefaultAuditingViaJavaConfigRepositoriesTests.java
index 69206bb28e..5e40224732 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/DefaultAuditingViaJavaConfigRepositoriesTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/DefaultAuditingViaJavaConfigRepositoriesTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/ExplicitAuditingViaJavaConfigRepositoriesTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/ExplicitAuditingViaJavaConfigRepositoriesTests.java
index cc3ff4e612..d0c5fd06f4 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/ExplicitAuditingViaJavaConfigRepositoriesTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/ExplicitAuditingViaJavaConfigRepositoriesTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/InfrastructureConfig.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/InfrastructureConfig.java
index 8542911649..4fdaad1022 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/InfrastructureConfig.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/InfrastructureConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/InspectionClassLoaderUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/InspectionClassLoaderUnitTests.java
index beb61ed5ad..0b3da373e5 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/InspectionClassLoaderUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/InspectionClassLoaderUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2024 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaAuditingRegistrarUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaAuditingRegistrarUnitTests.java
index 623f3d5249..504ac40d24 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaAuditingRegistrarUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaAuditingRegistrarUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoriesRegistrarIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoriesRegistrarIntegrationTests.java
index d6b550f0ea..8d4a11955e 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoriesRegistrarIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoriesRegistrarIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoriesRegistrarUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoriesRegistrarUnitTests.java
index 3c293e245b..3b68b30365 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoriesRegistrarUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoriesRegistrarUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigDefinitionParserTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigDefinitionParserTests.java
index 09751277d3..2cbadc8275 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigDefinitionParserTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigDefinitionParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtensionUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtensionUnitTests.java
index 54ca71d9f7..df4e2097e5 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtensionUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtensionUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryRegistrationAotProcessorUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryRegistrationAotProcessorUnitTests.java
index ef9011e437..714abc2afa 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryRegistrationAotProcessorUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryRegistrationAotProcessorUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/NestedRepositoriesJavaConfigTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/NestedRepositoriesJavaConfigTests.java
index 2cf100c402..7384a64cb6 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/NestedRepositoriesJavaConfigTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/NestedRepositoriesJavaConfigTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/QueryLookupStrategyTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/QueryLookupStrategyTests.java
index 7ea61726f6..22cb434931 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/QueryLookupStrategyTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/QueryLookupStrategyTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/RepositoriesJavaConfigTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/RepositoriesJavaConfigTests.java
index 688e5471a8..bb40ccfc01 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/RepositoriesJavaConfigTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/RepositoriesJavaConfigTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/RepositoryAutoConfigTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/RepositoryAutoConfigTests.java
index a6eada978a..f08f7bb2ee 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/RepositoryAutoConfigTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/RepositoryAutoConfigTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/RepositoryConfigTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/RepositoryConfigTests.java
index 10977363f9..722e137690 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/RepositoryConfigTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/RepositoryConfigTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/TypeFilterConfigTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/TypeFilterConfigTests.java
index b8e35ce52b..56b449f9b6 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/TypeFilterConfigTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/config/TypeFilterConfigTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepository.java
index e9c53f287a..00fe7c6aa1 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactory.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactory.java
index ab6b76002b..d898522b32 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactory.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactoryBean.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactoryBean.java
index 09a702b6f0..b2c13f48dc 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactoryBean.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactoryBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericRepository.java
index b39c31c296..b5d8b10b8e 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/UserCustomExtendedRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/UserCustomExtendedRepository.java
index dd537e7155..1606e832f8 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/UserCustomExtendedRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/custom/UserCustomExtendedRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/generics/EclipseLinkGenericsIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/generics/EclipseLinkGenericsIntegrationTests.java
index e7725e53e6..9c3019106f 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/generics/EclipseLinkGenericsIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/generics/EclipseLinkGenericsIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/generics/GenericsIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/generics/GenericsIntegrationTests.java
index 364bcbfa7f..ce40a725bc 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/generics/GenericsIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/generics/GenericsIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/MySqlStoredProcedureIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/MySqlStoredProcedureIntegrationTests.java
index b248e809f6..5366736fc9 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/MySqlStoredProcedureIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/MySqlStoredProcedureIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/PostgresStoredProcedureIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/PostgresStoredProcedureIntegrationTests.java
index b3c76d25b1..af07eb0013 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/PostgresStoredProcedureIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/PostgresStoredProcedureIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/PostgresStoredProcedureNullHandlingIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/PostgresStoredProcedureNullHandlingIntegrationTests.java
index 98783a9c28..c5fba7eff7 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/PostgresStoredProcedureNullHandlingIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/PostgresStoredProcedureNullHandlingIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/StoredProcedureConfigSupport.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/StoredProcedureConfigSupport.java
index 0b8ef1f9cd..998245126b 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/StoredProcedureConfigSupport.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/procedures/StoredProcedureConfigSupport.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/projections/ProjectionJoinIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/projections/ProjectionJoinIntegrationTests.java
index 1c952765e6..d0bdce94bd 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/projections/ProjectionJoinIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/projections/ProjectionJoinIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2024 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/projections/ProjectionsIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/projections/ProjectionsIntegrationTests.java
index f744dd540d..9abc3716e0 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/projections/ProjectionsIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/projections/ProjectionsIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractJpaQueryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractJpaQueryTests.java
index 1f7db3cc42..8728e03229 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractJpaQueryTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractJpaQueryTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryIntegrationTests.java
index 9cb74dcaa0..6590db4022 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryUnitTests.java
index b2e6ba4fce..d9073be331 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQueryUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/BadJpqlGrammarExceptionUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/BadJpqlGrammarExceptionUnitTests.java
new file mode 100644
index 0000000000..16766673fc
--- /dev/null
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/BadJpqlGrammarExceptionUnitTests.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.jpa.repository.query;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for {@link BadJpqlGrammarException}.
+ *
+ * @author Mark Paluch
+ */
+class BadJpqlGrammarExceptionUnitTests {
+
+ @Test // GH-3757
+ void shouldContainOriginalText() {
+
+ assertThatExceptionOfType(BadJpqlGrammarException.class)
+ .isThrownBy(() -> JpaQueryEnhancer.HqlQueryParser
+ .parseQuery("SELECT e FROM Employee e WHERE FOO(x).bar RESPECTING NULLS"))
+ .withMessageContaining("no viable alternative")
+ .withMessageContaining("SELECT e FROM Employee e WHERE FOO(x).bar *RESPECTING NULLS")
+ .withMessageContaining("Bad HQL grammar [SELECT e FROM Employee e WHERE FOO(x).bar RESPECTING NULLS]");
+ }
+
+ @Test // GH-3757
+ void shouldReportExtraneousInput() {
+
+ assertThatExceptionOfType(BadJpqlGrammarException.class)
+ .isThrownBy(() -> JpaQueryEnhancer.HqlQueryParser.parseQuery("select * from User group by name"))
+ .withMessageContaining("extraneous input '*'")
+ .withMessageContaining("Bad HQL grammar [select * from User group by name]");
+ }
+
+ @Test // GH-3757
+ void shouldReportMismatchedInput() {
+
+ assertThatExceptionOfType(BadJpqlGrammarException.class)
+ .isThrownBy(() -> JpaQueryEnhancer.HqlQueryParser.parseQuery("SELECT AVG(m.price) AS m.avg FROM Magazine m"))
+ .withMessageContaining("mismatched input '.'").withMessageContaining("expecting one of the following tokens:")
+ .withMessageContaining("EXCEPT")
+ .withMessageContaining("Bad HQL grammar [SELECT AVG(m.price) AS m.avg FROM Magazine m]");
+ }
+
+}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/CollectionUtilsUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/CollectionUtilsUnitTests.java
index dd488b1ac5..9ab7aa87da 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/CollectionUtilsUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/CollectionUtilsUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/CustomNonBindableJpaParametersIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/CustomNonBindableJpaParametersIntegrationTests.java
index 724f0e1bf7..50ca107e95 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/CustomNonBindableJpaParametersIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/CustomNonBindableJpaParametersIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2024 the original author or authors.
+ * Copyright 2019-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/DefaultQueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/DefaultQueryEnhancerUnitTests.java
index da2bb066ac..43a87c8282 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/DefaultQueryEnhancerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/DefaultQueryEnhancerUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/DefaultQueryUtilsUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/DefaultQueryUtilsUnitTests.java
index cf3eb4867c..0e6b4a577c 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/DefaultQueryUtilsUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/DefaultQueryUtilsUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkJpa21UtilsTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkJpa21UtilsTests.java
index bd97fbb600..19a2701e0e 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkJpa21UtilsTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkJpa21UtilsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkMetaAnnotatedQueryMethodIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkMetaAnnotatedQueryMethodIntegrationTests.java
index df7b27f9d9..bf8e408d52 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkMetaAnnotatedQueryMethodIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkMetaAnnotatedQueryMethodIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkParameterMetadataProviderIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkParameterMetadataProviderIntegrationTests.java
index c89f75309f..1e253c5acb 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkParameterMetadataProviderIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkParameterMetadataProviderIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkQueryUtilsIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkQueryUtilsIntegrationTests.java
index f70c7186f7..ce1b95d90e 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkQueryUtilsIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkQueryUtilsIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,11 +15,25 @@
*/
package org.springframework.data.jpa.repository.query;
+import static org.assertj.core.api.Assertions.*;
+
+import jakarta.persistence.criteria.CriteriaBuilder;
+import jakarta.persistence.criteria.CriteriaQuery;
+import jakarta.persistence.criteria.Path;
+import jakarta.persistence.criteria.Root;
+
+import org.junit.jupiter.api.Test;
+
+import org.springframework.data.jpa.domain.sample.User;
+import org.springframework.data.mapping.PropertyPath;
import org.springframework.test.context.ContextConfiguration;
/**
+ * EclipseLink variant of {@link QueryUtilsIntegrationTests}.
+ *
* @author Oliver Gierke
* @author Jens Schauder
+ * @author Mark Paluch
*/
@ContextConfiguration("classpath:eclipselink.xml")
class EclipseLinkQueryUtilsIntegrationTests extends QueryUtilsIntegrationTests {
@@ -28,4 +42,25 @@ int getNumberOfJoinsAfterCreatingAPath() {
return 1;
}
+ @Test // GH-2756
+ @Override
+ void prefersFetchOverJoin() {
+
+ CriteriaBuilder builder = em.getCriteriaBuilder();
+ CriteriaQuery query = builder.createQuery(User.class);
+ Root from = query.from(User.class);
+ from.fetch("https://github.com/manager");
+ from.join("manager");
+
+ PropertyPath managerFirstname = PropertyPath.from("manager.firstname", User.class);
+ PropertyPath managerLastname = PropertyPath.from("manager.lastname", User.class);
+
+ QueryUtils.toExpressionRecursively(from, managerLastname);
+ Path expr = (Path) QueryUtils.toExpressionRecursively(from, managerFirstname);
+
+ assertThat(expr.getParentPath()).hasFieldOrPropertyWithValue("isFetch", true);
+ assertThat(from.getFetches()).hasSize(1);
+ assertThat(from.getJoins()).hasSize(1);
+ }
+
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlComplianceTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlComplianceTests.java
index bbfbffe1ab..2ec5f229a1 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlComplianceTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlComplianceTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,9 +17,8 @@
import static org.assertj.core.api.Assertions.*;
-import org.antlr.v4.runtime.CharStreams;
-import org.antlr.v4.runtime.CommonTokenStream;
import org.junit.jupiter.api.Test;
+
import org.springframework.data.jpa.repository.query.QueryRenderer.TokenRenderer;
/**
@@ -40,14 +39,9 @@ class EqlComplianceTests {
*/
private static String parseWithoutChanges(String query) {
- EqlLexer lexer = new EqlLexer(CharStreams.fromString(query));
- EqlParser parser = new EqlParser(new CommonTokenStream(lexer));
-
- parser.addErrorListener(new BadJpqlGrammarErrorListener(query));
-
- EqlParser.StartContext parsedQuery = parser.start();
+ JpaQueryEnhancer.EqlQueryParser parser = JpaQueryEnhancer.EqlQueryParser.parseQuery(query);
- return TokenRenderer.render(new EqlQueryRenderer().visit(parsedQuery));
+ return TokenRenderer.render(new EqlQueryRenderer().visit(parser.getContext()));
}
private void assertQuery(String query) {
@@ -78,6 +72,7 @@ void selectClause() {
assertQuery("SELECT COUNT(e) FROM Employee e");
assertQuery("SELECT MAX(e.salary) FROM Employee e");
+ assertQuery("select sum(i.size.foo.bar.new) from Item i");
assertQuery("SELECT NEW com.acme.reports.EmpReport(e.firstName, e.lastName, e.salary) FROM Employee e");
}
@@ -348,8 +343,11 @@ void specialOperators() {
assertQuery("SELECT toDo FROM Employee e JOIN e.toDoList toDo WHERE INDEX(toDo) = 1");
assertQuery("SELECT p FROM Employee e JOIN e.priorities p WHERE KEY(p) = 'high'");
assertQuery("SELECT e FROM Employee e WHERE SIZE(e.managedEmployees) < 2");
+ assertQuery("SELECT e FROM Employee e WHERE SIZE(e.managedEmployees.new) < 2");
assertQuery("SELECT e FROM Employee e WHERE e.managedEmployees IS EMPTY");
+ assertQuery("SELECT e FROM Employee e WHERE e.managedEmployee.size.new IS EMPTY");
assertQuery("SELECT e FROM Employee e WHERE 'write code' MEMBER OF e.responsibilities");
+ assertQuery("SELECT e FROM Employee e WHERE 'write code' MEMBER OF e.responsibilities.size");
assertQuery("SELECT p FROM Project p WHERE TYPE(p) = LargeProject");
/**
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlParserQueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlParserQueryEnhancerUnitTests.java
index 241a5310b5..8895fc4c19 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlParserQueryEnhancerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlParserQueryEnhancerUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java
index 91a4bb761e..ded1101a54 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,14 +19,13 @@
import java.util.stream.Stream;
-import org.antlr.v4.runtime.CharStreams;
-import org.antlr.v4.runtime.CommonTokenStream;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
+
import org.springframework.data.jpa.repository.query.QueryRenderer.TokenRenderer;
/**
@@ -37,6 +36,7 @@
*
* @author Greg Turnquist
* @author Christoph Strobl
+ * @author Mark Paluch
*/
class EqlQueryRendererTests {
@@ -47,14 +47,9 @@ class EqlQueryRendererTests {
*/
private static String parseWithoutChanges(String query) {
- EqlLexer lexer = new EqlLexer(CharStreams.fromString(query));
- EqlParser parser = new EqlParser(new CommonTokenStream(lexer));
-
- parser.addErrorListener(new BadJpqlGrammarErrorListener(query));
-
- EqlParser.StartContext parsedQuery = parser.start();
+ JpaQueryEnhancer.EqlQueryParser parser = JpaQueryEnhancer.EqlQueryParser.parseQuery(query);
- return TokenRenderer.render(new EqlQueryRenderer().visit(parsedQuery));
+ return TokenRenderer.render(new EqlQueryRenderer().visit(parser.getContext()));
}
static Stream reservedWords() {
@@ -343,6 +338,15 @@ OR TREAT(e AS Contractor).hours > 100
""");
}
+ @Test // GH-3024, GH-3863
+ void casting() {
+
+ assertQuery("""
+ select cast(i as string) from Item i where cast(i.date as date) <= cast(:currentDateTime as date)
+ """);
+ assertQuery("SELECT e FROM Employee e WHERE CAST(e.salary NUMERIC(10, 2)) > 0.0");
+ }
+
@Test
void pathExpressionsNamedParametersExample() {
@@ -560,6 +564,18 @@ WHERE TYPE(e) IN :empTypes
""");
}
+ @Test
+ void inClauseWithFunctionAndLiterals() {
+
+ assertQuery("""
+ select f from FooEntity f where upper(f.name) IN ('Y', 'Basic', 'Remit')
+ """);
+ assertQuery(
+ """
+ select count(f) from FooEntity f where f.status IN (com.example.eql_bug_check.entity.FooStatus.FOO, com.example.eql_bug_check.entity.FooStatus.BAR)
+ """);
+ }
+
@Test
void notEqualsForTypeShouldWork() {
@@ -590,6 +606,14 @@ SELECT c.country, COUNT(c)
GROUP BY c.country
HAVING COUNT(c) > 30
""");
+
+ assertQuery("""
+ SELECT COUNT(f)
+ FROM FooEntity f
+ WHERE f.name IN ('Y', 'Basic', 'Remit')
+ AND f.size = 10
+ HAVING COUNT(f) > 0
+ """);
}
@Test
@@ -928,6 +952,14 @@ void findOrdersThatHaveProductNamedByAParameter() {
""");
}
+ @Test // GH-4013
+ void minMaxFunctionsShouldWork() {
+ assertQuery("SELECT MAX(e.age), e.address.city FROM Employee e");
+ assertQuery("SELECT MAX(1), e.address.city FROM Employee e");
+ assertQuery("SELECT MAX(MIN(MOD(e.salary, 10))), e.address.city FROM Employee e");
+ assertQuery("SELECT MIN(MOD(e.salary, 10)), e.address.city FROM Employee e");
+ }
+
@Test // GH-2982
void floorShouldBeValidEntityName() {
@@ -1032,6 +1064,14 @@ void signedExpressionsShouldWork(String query) {
assertQuery(query);
}
+ @Test // GH-3873
+ void escapeClauseShouldWork() {
+ assertQuery("select t.name from SomeDbo t where t.name LIKE :name escape '\\\\'");
+ assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE '\\\\'");
+ assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE ?1");
+ assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE :param");
+ }
+
@ParameterizedTest // GH-3451
@MethodSource("reservedWords")
void entityNameWithPackageContainingReservedWord(String reservedWord) {
@@ -1046,4 +1086,15 @@ void lateralShouldBeAValidParameter() {
assertQuery("select e from Employee e where e.lateral = :_lateral");
assertQuery("select te from TestEntity te where te.lateral = :lateral");
}
+
+ @Test // GH-3834
+ void reservedWordsShouldWork() {
+
+ assertQuery("select ie from ItemExample ie left join ie.object io where io.externalId = :externalId");
+ assertQuery("select ie.object from ItemExample ie left join ie.object io where io.externalId = :externalId");
+ assertQuery("select ie from ItemExample ie left join ie.object io where io.object = :externalId");
+ assertQuery("select ie from ItemExample ie where ie.status = com.app.domain.object.Status.UP");
+ assertQuery("select f from FooEntity f where upper(f.name) IN :names");
+ assertQuery("select f from FooEntity f where f.size IN :sizes");
+ }
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryTransformerTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryTransformerTests.java
index a85214f43d..3c1fec2ed3 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryTransformerTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryTransformerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlSpecificationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlSpecificationTests.java
index b6ed4fc8b8..bff45ec75d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlSpecificationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlSpecificationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,10 +17,9 @@
import static org.assertj.core.api.Assertions.*;
-import org.antlr.v4.runtime.CharStreams;
-import org.antlr.v4.runtime.CommonTokenStream;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+
import org.springframework.data.jpa.repository.query.QueryRenderer.TokenRenderer;
/**
@@ -37,14 +36,9 @@ class EqlSpecificationTests {
private static String parseWithoutChanges(String query) {
- EqlLexer lexer = new EqlLexer(CharStreams.fromString(query));
- EqlParser parser = new EqlParser(new CommonTokenStream(lexer));
-
- parser.addErrorListener(new BadJpqlGrammarErrorListener(query));
-
- EqlParser.StartContext parsedQuery = parser.start();
+ JpaQueryEnhancer.EqlQueryParser parser = JpaQueryEnhancer.EqlQueryParser.parseQuery(query);
- return TokenRenderer.render(new EqlQueryRenderer().visit(parsedQuery));
+ return TokenRenderer.render(new EqlQueryRenderer().visit(parser.getContext()));
}
private void assertQuery(String query) {
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EscapeCharacterUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EscapeCharacterUnitTests.java
index 418fbff3e0..ca16538f7d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EscapeCharacterUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EscapeCharacterUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2024 the original author or authors.
+ * Copyright 2019-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java
index d651db1393..049773d450 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -97,25 +97,13 @@ void shouldDetectBindParameterCountCorrectlyWithJDBCStyleParameters() {
assertThat(query.getParameterBindings()).hasSize(8);
}
- @Test
- void shouldDetectComplexNativeQueriesWithSpelAsNonNative() {
-
- StringQuery query = new ExpressionBasedStringQuery(
- "select n from #{#entityName} n where (LOWER(n.name) LIKE LOWER(NULLIF(text(concat('%',?#{#networkRequest.name},'%')), '')) OR ?#{#networkRequest.name} IS NULL )"
- + "AND (LOWER(n.server) LIKE LOWER(NULLIF(text(concat('%',?#{#networkRequest.server},'%')), '')) OR ?#{#networkRequest.server} IS NULL)"
- + "AND (n.createdAt >= ?#{#networkRequest.createdTime.startDateTime}) AND (n.createdAt <=?#{#networkRequest.createdTime.endDateTime})"
- + "AND (n.updatedAt >= ?#{#networkRequest.updatedTime.startDateTime}) AND (n.updatedAt <=?#{#networkRequest.updatedTime.endDateTime})",
- metadata, PARSER, true);
-
- assertThat(query.isNativeQuery()).isFalse();
- }
+ @Test // GH-3979
+ void shouldExpandExpressionUsingNativeQueries() {
- @Test
- void shouldDetectSimpleNativeQueriesWithSpelAsNonNative() {
-
- StringQuery query = new ExpressionBasedStringQuery("select n from #{#entityName} n", metadata, PARSER, true);
+ StringQuery query = new ExpressionBasedStringQuery("select n.* from #{#entityName} n", metadata, PARSER, true);
- assertThat(query.isNativeQuery()).isFalse();
+ assertThat(query.isNativeQuery()).isTrue();
+ assertThat(query.getQueryString()).isEqualTo("select n.* from User n");
}
@Test
@@ -177,7 +165,7 @@ void indexedExpressionsShouldCreateLikeBindings() {
}
@Test
- public void doesTemplatingWhenEntityNameSpelIsPresent() {
+ void doesTemplatingWhenEntityNameSpelIsPresent() {
StringQuery query = new ExpressionBasedStringQuery("select #{#entityName + 'Hallo'} from #{#entityName} u",
metadata, PARSER, false);
@@ -186,7 +174,7 @@ public void doesTemplatingWhenEntityNameSpelIsPresent() {
}
@Test
- public void doesNoTemplatingWhenEntityNameSpelIsNotPresent() {
+ void doesNoTemplatingWhenEntityNameSpelIsNotPresent() {
StringQuery query = new ExpressionBasedStringQuery("select #{#entityName + 'Hallo'} from User u", metadata,
PARSER, false);
@@ -195,7 +183,7 @@ public void doesNoTemplatingWhenEntityNameSpelIsNotPresent() {
}
@Test
- public void doesTemplatingWhenEntityNameSpelIsPresentForBindParameter() {
+ void doesTemplatingWhenEntityNameSpelIsPresentForBindParameter() {
StringQuery query = new ExpressionBasedStringQuery("select u from #{#entityName} u where name = :#{#something}",
metadata, PARSER, false);
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserQueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserQueryEnhancerUnitTests.java
index 7d57ed37ad..ef7b269115 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserQueryEnhancerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserQueryEnhancerUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserUnitTests.java
index 62f194ea66..fb56b657f3 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java
index 8a23e279cd..d064fd4d3e 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,8 +19,6 @@
import java.util.stream.Stream;
-import org.antlr.v4.runtime.CharStreams;
-import org.antlr.v4.runtime.CommonTokenStream;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -37,6 +35,8 @@
*
* @author Greg Turnquist
* @author Christoph Strobl
+ * @author Mark Paluch
+ * @author Yannick Brandt
* @since 3.1
*/
class HqlQueryRendererTests {
@@ -48,14 +48,9 @@ class HqlQueryRendererTests {
*/
private static String parseWithoutChanges(String query) {
- HqlLexer lexer = new HqlLexer(CharStreams.fromString(query));
- HqlParser parser = new HqlParser(new CommonTokenStream(lexer));
+ JpaQueryEnhancer.HqlQueryParser parser = JpaQueryEnhancer.HqlQueryParser.parseQuery(query);
- parser.addErrorListener(new BadJpqlGrammarErrorListener(query));
-
- HqlParser.StartContext parsedQuery = parser.start();
-
- QueryTokenStream tokens = new HqlQueryRenderer().visit(parsedQuery);
+ QueryTokenStream tokens = new HqlQueryRenderer().visit(parser.getContext());
return QueryRenderer.from(tokens).render();
}
@@ -178,6 +173,180 @@ void pathExpressionSyntaxExample1() {
""");
}
+ @Test // GH-3711
+ void entityTypeReference() {
+
+ assertQuery("""
+ SELECT TYPE(e)
+ FROM Employee e
+ """);
+
+ assertQuery("""
+ SELECT TYPE(?0)
+ FROM Employee e
+ """);
+ }
+
+ @Test // GH-3711
+ void entityIdReference() {
+
+ assertQuery("""
+ SELECT ID(e)
+ FROM Employee e
+ """);
+
+ assertQuery("""
+ SELECT ID(e).foo
+ FROM Employee e
+ """);
+ }
+
+ @Test // GH-3711
+ void entityNaturalIdReference() {
+
+ assertQuery("""
+ SELECT NATURALID(e)
+ FROM Employee e
+ """);
+
+ assertQuery("""
+ SELECT NATURALID(e).foo
+ FROM Employee e
+ """);
+ }
+
+ @Test // GH-3711
+ void entityVersionReference() {
+
+ assertQuery("""
+ SELECT VERSION(e)
+ FROM Employee e
+ """);
+ }
+
+ @Test // GH-3711
+ void treatedNavigablePath() {
+
+ assertQuery("""
+ SELECT TREAT(e as Integer).foo
+ FROM Employee e
+ """);
+ }
+
+ @Test // GH-3711
+ void collectionValueNavigablePath() {
+
+ assertQuery("""
+ SELECT ELEMENT(e)
+ FROM Employee e
+ """);
+
+ assertQuery("""
+ SELECT ELEMENT(e).foo
+ FROM Employee e
+ """);
+
+ assertQuery("""
+ SELECT VALUE(e)
+ FROM Employee e
+ """);
+
+ assertQuery("""
+ SELECT VALUE(e).foo
+ FROM Employee e
+ """);
+ }
+
+ @Test // GH-3711
+ void mapKeyNavigablePath() {
+
+ assertQuery("""
+ SELECT KEY(e)
+ FROM Employee e
+ """);
+
+ assertQuery("""
+ SELECT KEY(e).foo
+ FROM Employee e
+ """);
+
+ assertQuery("""
+ SELECT INDEX(e)
+ FROM Employee e
+ """);
+ }
+
+ @Test // GH-3711
+ void toOneFkReference() {
+
+ assertQuery("""
+ SELECT FK(e)
+ FROM Employee e
+ """);
+
+ assertQuery("""
+ SELECT FK(e.foo)
+ FROM Employee e
+ """);
+ }
+
+ @Test // GH-3711
+ void indexedPathAccessFragment() {
+
+ assertQuery("""
+ SELECT e.names[0]
+ FROM Employee e
+ """);
+
+ assertQuery("""
+ SELECT e.payments[1].id
+ FROM Employee e
+ """);
+
+ assertQuery("""
+ SELECT some_function()[0]
+ FROM Employee e
+ """);
+
+ assertQuery("""
+ SELECT some_function()[1].id
+ FROM Employee e
+ """);
+ }
+
+ @Test // GH-3711
+ void slicedPathAccessFragment() {
+
+ assertQuery("""
+ SELECT e.names[0:1]
+ FROM Employee e
+ """);
+
+ assertQuery("""
+ SELECT e.payments[1:2].id
+ FROM Employee e
+ """);
+
+ assertQuery("""
+ SELECT some_function()[0:1]
+ FROM Employee e
+ """);
+
+ assertQuery("""
+ SELECT some_function()[1:2].id
+ FROM Employee e
+ """);
+ }
+
+ @Test // GH-3711
+ void functionPathContinuation() {
+
+ assertQuery("""
+ SELECT some_function().foo
+ FROM Employee e
+ """);
+ }
+
@Test
void joinsExample1() {
@@ -298,7 +467,7 @@ void fromClauseDowncastingExample1() {
assertQuery("""
SELECT b.name, b.ISBN
FROM Order o JOIN TREAT(o.product AS Book) b
- """);
+ """);
}
@Test
@@ -307,7 +476,7 @@ void fromClauseDowncastingExample2() {
assertQuery("""
SELECT e FROM Employee e JOIN TREAT(e.projects AS LargeProject) lp
WHERE lp.budget > 1000
- """);
+ """);
}
/**
@@ -322,7 +491,7 @@ void fromClauseDowncastingExample3_SPEC_BUG() {
WHERE TREAT(p AS LargeProject).budget > 1000
OR TREAT(p AS SmallProject).name LIKE 'Persist%'
OR p.description LIKE "cost overrun"
- """);
+ """);
}
@Test
@@ -333,7 +502,7 @@ void fromClauseDowncastingExample3fixed() {
WHERE TREAT(p AS LargeProject).budget > 1000
OR TREAT(p AS SmallProject).name LIKE 'Persist%'
OR p.description LIKE 'cost overrun'
- """);
+ """);
}
@Test
@@ -343,7 +512,7 @@ void fromClauseDowncastingExample4() {
SELECT e FROM Employee e
WHERE TREAT(e AS Exempt).vacationDays > 10
OR TREAT(e AS Contractor).hours > 100
- """);
+ """);
}
@Test
@@ -407,7 +576,7 @@ void allExample() {
WHERE emp.salary > ALL (SELECT m.salary
FROM Manager m
WHERE m.department = emp.department)
- """);
+ """);
}
@Test
@@ -419,7 +588,7 @@ void existsSubSelectExample2() {
WHERE EXISTS (SELECT spouseEmp
FROM Employee spouseEmp
WHERE spouseEmp = emp.spouse)
- """);
+ """);
}
@Test
@@ -487,7 +656,7 @@ void updateCaseExample1() {
WHEN e.rating = 2 THEN e.salary * 1.05
ELSE e.salary * 1.01
END
- """);
+ """);
}
@Test
@@ -500,7 +669,7 @@ void updateCaseExample2() {
WHEN 2 THEN e.salary * 1.05
ELSE e.salary * 1.01
END
- """);
+ """);
}
@Test
@@ -540,7 +709,7 @@ void theRest() {
SELECT e
FROM Employee e
WHERE TYPE(e) IN (Exempt, Contractor)
- """);
+ """);
}
@Test
@@ -622,6 +791,18 @@ HAVING COUNT(o) >= 5
""");
}
+ @Test
+ void shouldRenderHavingWithFunction() {
+
+ assertQuery("""
+ SELECT COUNT(f)
+ FROM FooEntity f
+ WHERE f.name IN ('Y', 'Basic', 'Remit')
+ AND f.size = 10
+ HAVING COUNT(f) > 0
+ """);
+ }
+
@Test
void theRest8() {
@@ -1495,6 +1676,20 @@ void orderByWithNullsFirstOrLastShouldWork() {
});
}
+ @Test // GH-3882
+ void shouldSupportLimitOffset() {
+
+ assertQuery("SELECT si from StockItem si order by si.id LIMIT 10 OFFSET 10 FETCH FIRST 10 ROWS ONLY");
+ assertQuery("SELECT si from StockItem si order by si.id LIMIT ? OFFSET ? FETCH FIRST ? ROWS ONLY");
+ assertQuery("SELECT si from StockItem si order by si.id LIMIT :l OFFSET :o");
+ assertQuery("SELECT si from StockItem si LIMIT :l OFFSET :o");
+ assertQuery("SELECT si from StockItem si order by si.id LIMIT :l");
+ assertQuery("SELECT si from StockItem si order by si.id OFFSET 1");
+ assertQuery("SELECT si from StockItem si LIMIT 1");
+ assertQuery("SELECT si from StockItem si OFFSET 1");
+ assertQuery("SELECT si from StockItem si FETCH FIRST 1 ROWS ONLY");
+ }
+
@Test // GH-2964
void roundFunctionShouldWorkLikeAnyOtherFunction() {
@@ -1508,6 +1703,22 @@ select round(count(ri) * 100 / max(ri.receipt.positions), 0) as perc
});
}
+ @Test // GH-3711
+ void ceilingFunctionShouldWork() {
+ assertQuery("select ceiling(1.5) from Element a");
+ }
+
+ @Test // GH-3711
+ void lnFunctionShouldWork() {
+ assertQuery("select ln(7.5) from Element a");
+ }
+
+ @Test // GH-4013
+ void minMaxFunctionsShouldWork() {
+ assertQuery("SELECT MAX(MIN(MOD(e.salary, 10))), e.address.city FROM Employee e");
+ assertQuery("SELECT MIN(MOD(e.salary, 10)), e.address.city FROM Employee e");
+ }
+
@Test // GH-2981
void cteWithClauseShouldWork() {
@@ -1519,6 +1730,31 @@ WITH maxId AS (select max(sr.snapshot.id) snapshotId from SnapshotReference sr
""");
}
+ @Test // GH-4012
+ void cteWithSearch() {
+
+ assertQuery("""
+ WITH Tree AS (SELECT o.uuid AS test_uuid FROM DemoEntity o)
+ SEARCH BREADTH FIRST BY foo ASC NULLS FIRST, bar DESC NULLS LAST SET baz
+ SELECT test_uuid FROM Tree
+ """);
+ }
+
+ @Test // GH-4012
+ void cteWithCycle() {
+
+ assertQuery("""
+ WITH Tree AS (SELECT o.uuid AS test_uuid FROM DemoEntity o) CYCLE test_uuid SET circular TO true DEFAULT false
+ SELECT test_uuid FROM Tree
+ """);
+
+ assertQuery(
+ """
+ WITH Tree AS (SELECT o.uuid AS test_uuid FROM DemoEntity o) CYCLE test_uuid SET circular TO true DEFAULT false USING bar
+ SELECT test_uuid FROM Tree
+ """);
+ }
+
@Test // GH-2982
void floorShouldBeValidEntityName() {
@@ -1551,9 +1787,52 @@ void castFunctionWithFqdnShouldWork() {
assertQuery("SELECT o FROM Order o WHERE CAST(:userId AS java.util.UUID) IS NULL OR o.user.id = :userId");
}
- @Test // GH-3025
- void durationLiteralsShouldWork() {
- assertQuery("SELECT ce.id FROM CalendarEvent ce WHERE (ce.endDate - ce.startDate) > 5 MINUTE");
+ @ParameterizedTest // GH-3025
+ @ValueSource(strings = { "YEAR", "MONTH", "DAY", "WEEK", "QUARTER", "HOUR", "MINUTE", "SECOND", "NANOSECOND",
+ "NANOSECOND", "EPOCH" })
+ void durationLiteralsShouldWork(String dtField) {
+
+ assertQuery("SELECT ce.id FROM CalendarEvent ce WHERE (ce.endDate - ce.startDate) > 5 %s".formatted(dtField));
+ assertQuery(
+ "SELECT ce.id FROM CalendarEvent ce WHERE ce.text LIKE :text GROUP BY year(cd.date) HAVING (ce.endDate - ce.startDate) > 5 %s"
+ .formatted(dtField));
+ assertQuery("SELECT ce.id as id, cd.startDate + 5 %s AS summedDate FROM CalendarEvent ce".formatted(dtField));
+ }
+
+ @Test // GH-3739
+ void dateTimeLiterals() {
+
+ assertQuery("SELECT e FROM Employee e WHERE e.startDate = {d'2012-01-03'}");
+ assertQuery("SELECT e FROM Employee e WHERE e.startTime = {t'09:00:00'}");
+ assertQuery("SELECT e FROM Employee e WHERE e.version = {ts'2012-01-03 09:00:00'}");
+ assertQuery("SELECT e FROM Employee e WHERE e.version = {ts'something weird'}");
+ assertQuery("SELECT e FROM Employee e WHERE e.version = {ts2012-01-03 09:00:00+1}");
+ assertQuery("SELECT e FROM Employee e WHERE e.version = {ts2012-01-03 09:00:00-1}");
+ assertQuery("SELECT e FROM Employee e WHERE e.version = {ts2012-01-03 09:00:00+1:00}");
+ assertQuery("SELECT e FROM Employee e WHERE e.version = {ts2012-01-03 09:00:00-1:00}");
+
+ assertQuery("SELECT e FROM Employee e WHERE e.version = OFFSET DATETIME 2012-01-03 09:00:00+1:01");
+ assertQuery("SELECT e FROM Employee e WHERE e.version = OFFSET DATETIME 2012-01-03 09:00:00-1:01");
+ }
+
+ @Test
+ void literals() {
+
+ assertQuery("SELECT e FROM Employee e WHERE e.name = 'Bob'");
+ assertQuery("SELECT e FROM Employee e WHERE e.names = [e.firstName, e.lastName]");
+ assertQuery("SELECT e FROM Employee e WHERE e.id = 1234");
+ assertQuery("SELECT e FROM Employee e WHERE e.id = 1234L");
+ assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14F");
+ assertQuery("SELECT s FROM Stat s WHERE s.ratio > 3.14e32D");
+ assertQuery("SELECT e FROM Employee e WHERE e.active = TRUE");
+ assertQuery("SELECT e FROM Employee e WHERE e.gender = org.acme.Gender.MALE");
+ assertQuery("UPDATE Employee e SET e.manager = NULL WHERE e.manager = :manager");
+ }
+
+ @ParameterizedTest // GH-3711
+ @ValueSource(strings = { "1", "1_000", "1L", "1_000L", "1bi", "1.1f", "2.2d", "2.2bd" })
+ void numberLiteralsShouldWork(String literal) {
+ assertQuery(String.format("SELECT %s FROM User u where u.id = %s", literal, literal));
}
@Test // GH-3025
@@ -1567,6 +1846,9 @@ void binaryLiteralsShouldWork() {
@Test // GH-3040
void escapeClauseShouldWork() {
assertQuery("select t.name from SomeDbo t where t.name LIKE :name escape '\\\\'");
+ assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE '\\\\'");
+ assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE ?1");
+ assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE :param");
}
@Test // GH-3062, GH-3056
@@ -1662,6 +1944,23 @@ group by extract(epoch from departureTime)
""");
}
+ @Test // GH-3757
+ void arithmeticDate() {
+
+ assertQuery("SELECT a FROM foo a WHERE (cast(a.createdAt as date) - CURRENT_DATE()) BY day - 2 = 0");
+ assertQuery("SELECT a FROM foo a WHERE (cast(a.createdAt as date) - CURRENT_DATE()) BY day - 2 = 0");
+ assertQuery("SELECT a FROM foo a WHERE (cast(a.createdAt as date)) BY day - 2 = 0");
+
+ assertQuery("SELECT f.start BY DAY - 2 FROM foo f");
+ assertQuery("SELECT f.start - 1 minute FROM foo f");
+
+ assertQuery("SELECT f FROM foo f WHERE (cast(f.start as date) - CURRENT_DATE()) BY day - 2 = 0");
+ assertQuery("SELECT 1 week - 1 day FROM foo f");
+ assertQuery("SELECT f.birthday - local date day FROM foo f");
+ assertQuery("SELECT local datetime - f.birthday FROM foo f");
+ assertQuery("SELECT (1 year) by day FROM foo f");
+ }
+
@ParameterizedTest // GH-3342
@ValueSource(
strings = { "select 1 from User", "select -1 from User", "select +1 from User", "select +1 * -100 from User",
@@ -1684,4 +1983,13 @@ void entityNameWithPackageContainingReservedWord(String reservedWord) {
String source = "select new com.company.%s.thing.stuff.ClassName(e.id) from Experience e".formatted(reservedWord);
assertQuery(source);
}
+
+ @Test
+ void reservedWordsShouldWork() {
+
+ assertQuery("select ie from ItemExample ie left join ie.object io where io.externalId = :externalId");
+ assertQuery("select ie.object from ItemExample ie left join ie.object io where io.externalId = :externalId");
+ assertQuery("select ie from ItemExample ie left join ie.object io where io.object = :externalId");
+ assertQuery("select ie from ItemExample ie where ie.status = com.app.domain.object.Status.UP");
+ }
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java
index 482b02db47..40a8c4dc7a 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,6 +41,7 @@
*
* @author Greg Turnquist
* @author Christoph Strobl
+ * @author Mark Paluch
*/
class HqlQueryTransformerTests {
@@ -86,13 +87,11 @@ void nullFirstLastSorting() {
assertThat(createQueryFor(original, Sort.unsorted())).isEqualTo(original);
- assertThat(createQueryFor(original, Sort.by(Order.desc("lastName").nullsLast())))
- .startsWith(original)
- .endsWithIgnoringCase("e.lastName DESC NULLS LAST");
+ assertThat(createQueryFor(original, Sort.by(Order.desc("lastName").nullsLast()))).startsWith(original)
+ .endsWithIgnoringCase("e.lastName DESC NULLS LAST");
- assertThat(createQueryFor(original, Sort.by(Order.desc("lastName").nullsFirst())))
- .startsWith(original)
- .endsWithIgnoringCase("e.lastName DESC NULLS FIRST");
+ assertThat(createQueryFor(original, Sort.by(Order.desc("lastName").nullsFirst()))).startsWith(original)
+ .endsWithIgnoringCase("e.lastName DESC NULLS FIRST");
}
@Test
@@ -151,6 +150,24 @@ void applyCountToAlreadySortedQuery() {
assertThat(results).isEqualTo("SELECT count(e) FROM Employee e where e.name = :name");
}
+ @Test // GH-3726
+ void shouldCreateCountQueryForCTE() {
+
+ // given
+ var original = """
+ WITH cte_select AS (select u.firstname as firstname, u.lastname as lastname from User u)
+ SELECT new org.springframework.data.jpa.repository.sample.UserExcerptDto(c.firstname, c.lastname)
+ FROM cte_select c
+ """;
+
+ // when
+ var results = createCountQueryFor(original);
+
+ // then
+ assertThat(results).isEqualToIgnoringWhitespace(
+ "WITH cte_select AS (select u.firstname as firstname, u.lastname as lastname from User u) SELECT count(*) FROM cte_select c");
+ }
+
@Test
void multipleAliasesShouldBeGathered() {
@@ -166,6 +183,12 @@ void multipleAliasesShouldBeGathered() {
@Test
void createsCountQueryCorrectly() {
+
+ assertCountQuery("SELECT id FROM Person", "SELECT count(id) FROM Person");
+ assertCountQuery("SELECT p.id FROM Person p", "SELECT count(p) FROM Person p");
+ assertCountQuery("SELECT id FROM Person p", "SELECT count(id) FROM Person p");
+ assertCountQuery("SELECT id, name FROM Person", "SELECT count(*) FROM Person");
+ assertCountQuery("SELECT id, name FROM Person p", "SELECT count(p) FROM Person p");
assertCountQuery(QUERY, COUNT_QUERY);
}
@@ -188,6 +211,9 @@ void createsCountQueryForConstructorQueries() {
assertCountQuery("select distinct new com.example.User(u.name) from User u where u.foo = ?1",
"select count(distinct u) from User u where u.foo = ?1");
+
+ assertCountQuery("select distinct new com.example.User(name, lastname) from User where foo = ?1",
+ "select count(distinct name, lastname) from User where foo = ?1");
}
@Test
@@ -539,7 +565,7 @@ WITH maxId AS(select max(sr.snapshot.id) snapshotId from SnapshotReference sr
""");
assertThat(countQuery).startsWith("WITH maxId AS (select max(sr.snapshot.id) snapshotId from SnapshotReference sr")
- .endsWith("select count(m) from maxId m join SnapshotReference sr on sr.snapshot.id = m.snapshotId");
+ .endsWith("select count(*) from maxId m join SnapshotReference sr on sr.snapshot.id = m.snapshotId");
}
@Test // GH-3504
@@ -893,7 +919,7 @@ void queryParserPicksCorrectAliasAmidstMultipleAlises() {
assertThat(alias("select u from User as u left join u.roles as r")).isEqualTo("u");
}
- @Test // GH-2032
+ @Test // GH-2032, GH-3792
void countQueryShouldWorkEvenWithoutExplicitAlias() {
assertCountQuery("FROM BookError WHERE portal = :portal",
@@ -924,7 +950,7 @@ where exists (
and iu = u
)
and ct.id = :teamId
- """, relationshipName, joinAlias, joinAlias));
+ """, relationshipName, joinAlias, joinAlias));
}
static Stream queriesWithReservedWordsAsIdentifiers() {
@@ -933,7 +959,6 @@ static Stream queriesWithReservedWordsAsIdentifiers() {
Arguments.of("right", "rt"), //
Arguments.of("left", "lt"), //
Arguments.of("outer", "ou"), //
- Arguments.of("full", "full"), //
Arguments.of("inner", "inr"));
}
@@ -1040,8 +1065,7 @@ select max(id), col
""", """
delete MyEntity AS mes
where mes.col = 'test'
- """
- }) // GH-2977, GH-3649
+ """ }) // GH-2977, GH-3649
void isSubqueryThrowsException(String query) {
assertThat(createQueryFor(query, Sort.unsorted())).isEqualToIgnoringWhitespace(query);
}
@@ -1090,18 +1114,20 @@ void aliasesShouldNotOverlapWithSortProperties() {
"SELECT t3 FROM Test3 t3 JOIN t3.test2 x WHERE x.id = :test2Id order by t3.testDuplicateColumnName desc");
}
- @Test // GH-3269
+ @Test // GH-3269, GH-3689
void createsCountQueryUsingAliasCorrectly() {
- assertCountQuery("select distinct 1 as x from Employee", "select count(distinct 1) from Employee AS __");
- assertCountQuery("SELECT DISTINCT abc AS x FROM T", "SELECT count(DISTINCT abc) FROM T AS __");
- assertCountQuery("select distinct a as x, b as y from Employee", "select count(distinct a, b) from Employee AS __");
+ assertCountQuery("select distinct 1 as x from Employee", "select count(distinct 1) from Employee");
+ assertCountQuery("SELECT DISTINCT abc AS x FROM T", "SELECT count(DISTINCT abc) FROM T");
+ assertCountQuery("select distinct a as x, b as y from Employee", "select count(distinct a, b) from Employee");
assertCountQuery("select distinct sum(amount) as x from Employee GROUP BY n",
- "select count(distinct sum(amount)) from Employee AS __ GROUP BY n");
+ "select count(distinct sum(amount)) from Employee GROUP BY n");
assertCountQuery("select distinct a, b, sum(amount) as c, d from Employee GROUP BY n",
- "select count(distinct a, b, sum(amount), d) from Employee AS __ GROUP BY n");
+ "select count(distinct a, b, sum(amount), d) from Employee GROUP BY n");
assertCountQuery("select distinct a, count(b) as c from Employee GROUP BY n",
- "select count(distinct a, count(b)) from Employee AS __ GROUP BY n");
+ "select count(distinct a, count(b)) from Employee GROUP BY n");
+ assertCountQuery("select distinct substring(e.firstname, 1, position('a' in e.lastname)) as x from from Employee",
+ "select count(distinct substring(e.firstname, 1, position('a' in e.lastname))) from from Employee");
}
@Test // GH-3427
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlSpecificationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlSpecificationTests.java
index 62efc2fdc2..be05e3fceb 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlSpecificationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlSpecificationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,10 +17,11 @@
import static org.assertj.core.api.Assertions.*;
-import org.antlr.v4.runtime.CharStreams;
-import org.antlr.v4.runtime.CommonTokenStream;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
import org.springframework.data.jpa.repository.query.QueryRenderer.TokenRenderer;
/**
@@ -31,6 +32,8 @@
* IMPORTANT: Purely verifies the parser without any transformations.
*
* @author Greg Turnquist
+ * @author Mark Paluch
+ * @author Christoph Strobl
* @since 3.1
*/
class HqlSpecificationTests {
@@ -39,14 +42,9 @@ class HqlSpecificationTests {
private static String parseWithoutChanges(String query) {
- HqlLexer lexer = new HqlLexer(CharStreams.fromString(query));
- HqlParser parser = new HqlParser(new CommonTokenStream(lexer));
-
- parser.addErrorListener(new BadJpqlGrammarErrorListener(query));
+ JpaQueryEnhancer.HqlQueryParser parser = JpaQueryEnhancer.HqlQueryParser.parseQuery(query);
- HqlParser.StartContext parsedQuery = parser.start();
-
- return TokenRenderer.render(new HqlQueryRenderer().visit(parsedQuery));
+ return TokenRenderer.render(new HqlQueryRenderer().visit(parser.getContext()));
}
private void assertQuery(String query) {
@@ -331,6 +329,213 @@ OR TREAT(e AS Contractor).hours > 100
""");
}
+ @ParameterizedTest // GH-3689
+ @ValueSource(strings = { "RESPECT NULLS", "IGNORE NULLS" })
+ void generic(String nullHandling) {
+
+ // not in the official documentation but supported in the grammar.
+ assertQuery("""
+ SELECT e FROM Employee e
+ WHERE FOO(x).bar %s
+ """.formatted(nullHandling));
+ }
+
+ @Test // GH-3689
+ void size() {
+
+ assertQuery("""
+ SELECT e FROM Employee e
+ WHERE SIZE(x) > 1
+ """);
+
+ assertQuery("""
+ SELECT e FROM Employee e
+ WHERE SIZE(e.skills) > 1
+ """);
+ }
+
+ @Test // GH-3689
+ void collectionAggregate() {
+
+ assertQuery("""
+ SELECT e FROM Employee e
+ WHERE MAXELEMENT(foo) > MINELEMENT(bar)
+ """);
+
+ assertQuery("""
+ SELECT e FROM Employee e
+ WHERE MININDEX(foo) > MAXINDEX(bar)
+ """);
+ }
+
+ @Test // GH-3689
+ void trunc() {
+
+ assertQuery("""
+ SELECT e FROM Employee e
+ WHERE TRUNC(x) = TRUNCATE(y)
+ """);
+
+ assertQuery("""
+ SELECT e FROM Employee e
+ WHERE TRUNC(e, 'foo') = TRUNCATE(e, 'bar')
+ """);
+
+ assertQuery("""
+ SELECT e FROM Employee e
+ WHERE TRUNC(e, 'YEAR') = TRUNCATE(LOCAL DATETIME, 'YEAR')
+ """);
+ }
+
+ @ParameterizedTest // GH-3689
+ @ValueSource(strings = { "YEAR", "MONTH", "DAY", "WEEK", "QUARTER", "HOUR", "MINUTE", "SECOND", "NANOSECOND",
+ "NANOSECOND", "EPOCH" })
+ void trunc(String truncation) {
+
+ assertQuery("""
+ SELECT e FROM Employee e
+ WHERE TRUNC(e, %1$s) = TRUNCATE(e, %1$s)
+ """.formatted(truncation));
+ }
+
+ @Test // GH-3689
+ void format() {
+
+ assertQuery("""
+ SELECT e FROM Employee e
+ WHERE FORMAT(x AS 'yyyy') = FORMAT(e.hiringDate AS 'yyyy')
+ """);
+
+ assertQuery("""
+ SELECT e FROM Employee e
+ WHERE e.hiringDate = format(LOCAL DATETIME as 'yyyy-MM-dd')
+ """);
+
+ assertQuery("""
+ SELECT e FROM Employee e
+ WHERE e.hiringDate = format(LOCAL_DATE() as 'yyyy-MM-dd')
+ """);
+ }
+
+ @Test // GH-3689
+ void collate() {
+
+ assertQuery("""
+ SELECT e FROM Employee e
+ WHERE COLLATE(x AS ucs_basic) = COLLATE(e.name AS ucs_basic)
+ """);
+ }
+
+ @Test // GH-3689
+ void substring() {
+
+ assertQuery("select substring(c.number, 1, 2) " + //
+ "from Call c");
+
+ assertQuery("select substring(c.number, 1) " + //
+ "from Call c");
+
+ assertQuery("select substring(c.number, 1, position('/0' in c.number)) " + //
+ "from Call c");
+
+ assertQuery("select substring(c.number FROM 1 FOR 2) " + //
+ "from Call c");
+
+ assertQuery("select substring(c.number FROM 1) " + //
+ "from Call c");
+
+ assertQuery("select substring(c.number FROM 1 FOR position('/0' in c.number)) " + //
+ "from Call c");
+
+ assertQuery("select substring(c.number FROM 1) AS shortNumber " + //
+ "from Call c");
+ }
+
+ @Test // GH-3689
+ void overlay() {
+
+ assertQuery("select OVERLAY(c.number PLACING 1 FROM 2) " + //
+ "from Call c ");
+
+ assertQuery("select OVERLAY(p.number PLACING 1 FROM 2 FOR 3) " + //
+ "from Call c ");
+ }
+
+ @Test // GH-3689
+ void pad() {
+
+ assertQuery("select PAD(c.number WITH 1 LEADING) " + //
+ "from Call c ");
+
+ assertQuery("select PAD(c.number WITH 1 TRAILING) " + //
+ "from Call c ");
+
+ assertQuery("select PAD(c.number WITH 1 LEADING '0') " + //
+ "from Call c ");
+
+ assertQuery("select PAD(c.number WITH 1 TRAILING '0') " + //
+ "from Call c ");
+ }
+
+ @Test // GH-3689
+ void position() {
+
+ assertQuery("select POSITION(c.number IN 'foo') " + //
+ "from Call c ");
+
+ assertQuery("select POSITION(c.number IN 'foo') + 1 AS pos " + //
+ "from Call c ");
+ }
+
+ @Test // GH-3689
+ void currentDateFunctions() {
+
+ assertQuery("select CURRENT DATE, CURRENT_DATE() " + //
+ "from Call c ");
+
+ assertQuery("select CURRENT TIME, CURRENT_TIME() " + //
+ "from Call c ");
+
+ assertQuery("select CURRENT TIMESTAMP, CURRENT_TIMESTAMP() " + //
+ "from Call c ");
+
+ assertQuery("select INSTANT, CURRENT_INSTANT() " + //
+ "from Call c ");
+
+ assertQuery("select LOCAL DATE, LOCAL_DATE() " + //
+ "from Call c ");
+
+ assertQuery("select LOCAL TIME, LOCAL_TIME() " + //
+ "from Call c ");
+
+ assertQuery("select LOCAL DATETIME, LOCAL_DATETIME() " + //
+ "from Call c ");
+
+ assertQuery("select OFFSET DATETIME, OFFSET_DATETIME() " + //
+ "from Call c ");
+
+ assertQuery("select OFFSET DATETIME AS offsetDatetime, OFFSET_DATETIME() AS offset_datetime " + //
+ "from Call c ");
+ }
+
+ @Test // GH-3689
+ void cube() {
+
+ assertQuery("select CUBE(foo), CUBE(foo, bar) " + //
+ "from Call c ");
+
+ assertQuery("select c.callerId from Call c GROUP BY CUBE(state, province)");
+ }
+
+ @Test // GH-3689
+ void rollup() {
+
+ assertQuery("select ROLLUP(foo), ROLLUP(foo, bar) " + //
+ "from Call c ");
+
+ assertQuery("select c.callerId from Call c GROUP BY ROLLUP(state, province)");
+ }
+
@Test
void pathExpressionsNamedParametersExample() {
@@ -383,6 +588,80 @@ WHERE EXISTS (SELECT spouseEmp
""");
}
+ @Test // GH-3689
+ void everyAll() {
+
+ assertQuery("""
+ SELECT DISTINCT emp
+ FROM Employee emp
+ WHERE EVERY (SELECT spouseEmp
+ FROM Employee spouseEmp) > 1
+ """);
+
+ assertQuery("""
+ SELECT DISTINCT emp
+ FROM Employee emp
+ WHERE ALL (SELECT spouseEmp
+ FROM Employee spouseEmp) > 1
+ """);
+
+ assertQuery("""
+ SELECT DISTINCT emp
+ FROM Employee emp
+ WHERE ALL (foo > 1) OVER (PARTITION BY bar)
+ """);
+
+ assertQuery("""
+ SELECT DISTINCT emp
+ FROM Employee emp
+ WHERE ALL VALUES (foo) > 1
+ """);
+
+ assertQuery("""
+ SELECT DISTINCT emp
+ FROM Employee emp
+ WHERE ALL ELEMENTS (foo) > 1
+ """);
+ }
+
+ @Test // GH-3689
+ void anySome() {
+
+ assertQuery("""
+ SELECT DISTINCT emp
+ FROM Employee emp
+ WHERE ANY (SELECT spouseEmp
+ FROM Employee spouseEmp) > 1
+ """);
+
+ assertQuery("""
+ SELECT DISTINCT emp
+ FROM Employee emp
+ WHERE SOME (SELECT spouseEmp
+ FROM Employee spouseEmp) > 1
+ """);
+
+ assertQuery("""
+ SELECT DISTINCT emp
+ FROM Employee emp
+ WHERE ANY (foo > 1) OVER (PARTITION BY bar)
+ """);
+
+ assertQuery("""
+ SELECT DISTINCT emp
+ FROM Employee emp
+ WHERE ANY VALUES (foo) > 1
+ """);
+ }
+
+ @Test // GH-3689
+ void listAgg() {
+
+ assertQuery("select listagg(p.number, ', ') within group (order by p.type, p.number) " + //
+ "from Phone p " + //
+ "group by p.person");
+ }
+
@Test
void allExample() {
@@ -461,16 +740,13 @@ WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit) = TRUE
""");
}
- @Test // GH-3628
- void functionInvocationWithIsBoolean() {
-
- assertQuery("""
- from RoleTmpl where find_in_set(:appId, appIds) is true
- """);
+ @ParameterizedTest // GH-3628
+ @ValueSource(strings = { "is true", "is not true", "is false", "is not false" })
+ void functionInvocationWithIsBoolean(String booleanComparison) {
assertQuery("""
- from RoleTmpl where find_in_set(:appId, appIds) is false
- """);
+ from RoleTmpl where find_in_set(:appId, appIds) %s
+ """.formatted(booleanComparison));
}
@Test
@@ -845,20 +1121,36 @@ void booleanPredicate() {
""");
}
- @Test // GH-3628
- void distinctFromPredicate() {
+ @ParameterizedTest // GH-3628
+ @ValueSource(strings = { "IS DISTINCT FROM", "IS NOT DISTINCT FROM" })
+ void distinctFromPredicate(String distinctFrom) {
assertQuery("""
SELECT c
FROM Customer c
- WHERE c.orders IS DISTINCT FROM c.payments
- """);
+ WHERE c.orders %s c.payments
+ """.formatted(distinctFrom));
assertQuery("""
SELECT c
FROM Customer c
- WHERE c.orders IS NOT DISTINCT FROM c.payments
- """);
+ WHERE c.orders %s c.payments
+ """.formatted(distinctFrom));
+
+ assertQuery("""
+ SELECT c
+ FROM Customer c
+ GROUP BY c.lastname
+ HAVING c.orders %s c.payments
+ """.formatted(distinctFrom));
+
+ assertQuery("""
+ SELECT c
+ FROM Customer c
+ WHERE EXISTS (SELECT c2
+ FROM Customer c2
+ WHERE c2.orders %s c.orders)
+ """.formatted(distinctFrom));
}
@Test
@@ -983,6 +1275,29 @@ void theRest38() {
""");
}
+ @Test // GH-3689
+ void insertQueries() {
+
+ assertQuery("insert Person (id, name) values (100L, 'Jane Doe')");
+
+ assertQuery("insert Person (id, name) values " + //
+ "(101L, 'J A Doe III'), " + //
+ "(102L, 'J X Doe'), " + //
+ "(103L, 'John Doe, Jr')");
+
+ assertQuery("insert into Partner (id, name) " + //
+ "select p.id, p.name from Person p ");
+
+ assertQuery("INSERT INTO AggregationPrice (range, price, type) " + "VALUES (:range, :price, :priceType) "
+ + "ON CONFLICT (range) DO UPDATE SET price = :price, type = :priceType");
+
+ assertQuery("INSERT INTO AggregationPrice (range, price, type) " + "VALUES (:range, :price, :priceType) "
+ + "ON CONFLICT ON CONSTRAINT foo DO UPDATE SET price = :price, type = :priceType");
+
+ assertQuery("INSERT INTO AggregationPrice (range, price, type) " + "VALUES (:range, :price, :priceType) "
+ + "ON CONFLICT ON CONSTRAINT foo DO NOTHING");
+ }
+
@Test
void hqlQueries() {
@@ -1000,15 +1315,7 @@ void hqlQueries() {
assertQuery("update versioned Person " + //
"set name = :newName " + //
"where name = :oldName");
- assertQuery("insert Person (id, name) " + //
- "values (100L, 'Jane Doe')");
- assertQuery("insert Person (id, name) " + //
- "values (101L, 'J A Doe III'), " + //
- "(102L, 'J X Doe'), " + //
- "(103L, 'John Doe, Jr')");
- assertQuery("insert into Partner (id, name) " + //
- "select p.id, p.name " + //
- "from Person p ");
+
assertQuery("select p " + //
"from Person p " + //
"where p.name like 'Joe'");
@@ -1104,9 +1411,6 @@ void hqlQueries() {
assertQuery("select concat(p.number, ' : ', cast(c.duration as string)) " + //
"from Call c " + //
"join c.phone p");
- assertQuery("select substring(p.number, 1, 2) " + //
- "from Call c " + //
- "join c.phone p");
assertQuery("select upper(p.name) " + //
"from Person p ");
assertQuery("select lower(p.name) " + //
@@ -1315,7 +1619,7 @@ void hqlQueries() {
assertQuery("select longest.duration " + //
"from Phone p " + //
"left join lateral (" + //
- " select c.duration as duration " + //
+ "select c.duration as duration " + //
" from p.calls c" + //
" order by c.duration desc" + //
" limit 1 " + //
@@ -1435,9 +1739,6 @@ void hqlQueries() {
"from Call c " + //
"join c.phone p " + //
"group by p.number");
- assertQuery("select listagg(p.number, ', ') within group (order by p.type, p.number) " + //
- "from Phone p " + //
- "group by p.person");
assertQuery("select sum(c.duration) " + //
"from Call c ");
assertQuery("select p.name, sum(c.duration) " + //
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerUnitTests.java
index a41b54193c..5ce7b0d31f 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@
* @author Geoffrey Deremetz
* @author Christoph Strobl
*/
-public class JSqlParserQueryEnhancerUnitTests extends QueryEnhancerTckTests {
+class JSqlParserQueryEnhancerUnitTests extends QueryEnhancerTckTests {
@Override
QueryEnhancer createQueryEnhancer(DeclaredQuery declaredQuery) {
@@ -51,6 +51,22 @@ void shouldApplySorting() {
assertThat(sql).isEqualTo("SELECT e FROM Employee e ORDER BY e.foo ASC, e.bar ASC");
}
+ @Test // GH-3707
+ void countQueriesShouldConsiderPrimaryTableAlias() {
+
+ QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.of("""
+ SELECT DISTINCT a.*, b.b1
+ FROM TableA a
+ JOIN TableB b ON a.b = b.b
+ LEFT JOIN TableC c ON b.c = c.c
+ ORDER BY b.b1, a.a1, a.a2
+ """, true));
+
+ String sql = enhancer.createCountQueryFor();
+
+ assertThat(sql).startsWith("SELECT count(DISTINCT a.*) FROM TableA a");
+ }
+
@Override
@ParameterizedTest // GH-2773
@MethodSource("jpqlCountQueries")
@@ -241,4 +257,17 @@ static Stream mergeStatementWorksSource() {
null));
}
+ @Test // GH-3869
+ void shouldWorkWithParenthesedSelect() {
+
+ String query = "(SELECT is_contained_in(:innerId, :outerId))";
+
+ StringQuery stringQuery = new StringQuery(query, true);
+ QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
+
+ assertThat(stringQuery.getQueryString()).isEqualTo(query);
+ assertThat(stringQuery.getAlias()).isNull();
+ assertThat(queryEnhancer.getProjection()).isEqualTo("is_contained_in(:innerId, :outerId)");
+ }
+
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/Jpa21UtilsTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/Jpa21UtilsTests.java
index f09d50be0e..aebad09360 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/Jpa21UtilsTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/Jpa21UtilsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -50,6 +50,7 @@
* @author Mark Paluch
* @author Jens Schauder
* @author Krzysztof Krason
+ * @author Christoph Strobl
*/
@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:application-context.xml")
@@ -166,6 +167,15 @@ void errorsOnUnknownProperties() {
em.createEntityGraph(User.class)));
}
+ @Test // GH-3682
+ void allowsEmptyGraph() {
+
+ EntityGraph graph = em.createEntityGraph(User.class);
+ Jpa21Utils.configureFetchGraphFrom(new JpaEntityGraph("User.NoNamedEntityGraphAvailable", EntityGraphType.FETCH, new String[0]), graph);
+
+ Assertions.assertThat(graph.getAttributeNodes()).isEmpty();
+ }
+
/**
* Lookup the {@link AttributeNode} with given {@literal nodeName} in the root of the given {@literal graph}.
*/
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/Jpa21UtilsUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/Jpa21UtilsUnitTests.java
index 4885869be9..fab642d505 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/Jpa21UtilsUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/Jpa21UtilsUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaCountQueryCreatorIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaCountQueryCreatorIntegrationTests.java
index 3835426aba..9afcf27d56 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaCountQueryCreatorIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaCountQueryCreatorIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaParametersUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaParametersUnitTests.java
index ea851bb4fe..c798acd8ac 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaParametersUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaParametersUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryEnhancerUnitTests.java
new file mode 100644
index 0000000000..a11ba9ffdf
--- /dev/null
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryEnhancerUnitTests.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.jpa.repository.query;
+
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+/**
+ * Unit tests for {@link JpaQueryEnhancer}.
+ *
+ * @author Mark Paluch
+ */
+class JpaQueryEnhancerUnitTests {
+
+ @ParameterizedTest // GH-3997
+ @MethodSource("queryEnhancers")
+ void shouldRemoveCommentsFromJpql(Function enhancerFunction) {
+
+ QueryEnhancer enhancer = enhancerFunction
+ .apply(DeclaredQuery.of("SELECT /* foo */ some_alias FROM /* some other */ table_name some_alias", false));
+
+ assertThat(enhancer.getQuery().getQueryString())
+ .isEqualToIgnoringCase("SELECT some_alias FROM table_name some_alias");
+
+ enhancer = enhancerFunction.apply(DeclaredQuery.of("""
+ SELECT /* multi
+ line
+ comment
+ */ some_alias FROM /* some other */ table_name some_alias
+ """, false));
+
+ assertThat(enhancer.getQuery().getQueryString())
+ .isEqualToIgnoringCase("SELECT some_alias FROM table_name some_alias");
+ }
+
+ static Stream> queryEnhancers() {
+ return Stream.of(JpaQueryEnhancer::forHql, JpaQueryEnhancer::forEql, JpaQueryEnhancer::forJpql);
+ }
+}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java
index da57f6a899..6d93f6ae9f 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java
index 7a27c1bfc6..a8205cea35 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -163,7 +163,7 @@ void namedQueryWithSortShouldThrowIllegalStateException() throws NoSuchMethodExc
assertThatIllegalStateException()
.isThrownBy(() -> strategy.resolveQuery(method, metadata, projectionFactory, namedQueries))
.withMessageContaining(
- "is backed by a NamedQuery and must not contain a sort parameter as we cannot modify the query; Use @Query instead");
+ "is backed by a NamedQuery and must not contain a sort parameter as we cannot modify the query; Use @Query(value=…) instead to apply sorting or remove the 'Sort' parameter.");
}
@Test // GH-2018
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java
index 4d54b1950d..93f01a109c 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryRewriteIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryRewriteIntegrationTests.java
index 4c504e8cc9..9637785e39 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryRewriteIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryRewriteIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,8 +19,10 @@
import static org.assertj.core.api.Assertions.entry;
import java.util.HashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -31,6 +33,7 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ImportResource;
+import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@@ -44,7 +47,7 @@
import org.springframework.test.context.junit.jupiter.SpringExtension;
/**
- * Unit tests for repository with {@link Query} and {@link QueryRewrite}.
+ * Unit tests for repository with {@link Query} and {@link QueryRewriter}.
*
* @author Greg Turnquist
* @author Krzysztof Krason
@@ -60,10 +63,12 @@ class JpaQueryRewriteIntegrationTests {
static final String REWRITTEN_QUERY = "rewritten query";
static final String SORT = "sort";
static Map results = new HashMap<>();
+ static Set queries = new LinkedHashSet<>();
@BeforeEach
void setUp() {
results.clear();
+ repository.deleteAll();
}
@Test
@@ -77,15 +82,15 @@ void nativeQueryShouldHandleRewrites() {
entry(SORT, Sort.unsorted().toString()));
}
- @Test
+ @Test // GH-3801
void nonNativeQueryShouldHandleRewrites() {
- repository.findByNonNativeQuery("Matthews");
+ repository.save(new User("D", "A", "foo@bar"));
- assertThat(results).containsExactly( //
- entry(ORIGINAL_QUERY, "select original_user_alias from User original_user_alias"), //
- entry(REWRITTEN_QUERY, "select rewritten_user_alias from User rewritten_user_alias"), //
- entry(SORT, Sort.unsorted().toString()));
+ repository.findByNonNativeQuery("Matthews", PageRequest.of(0, 1));
+
+ assertThat(queries).contains("select original_user_alias from User original_user_alias");
+ assertThat(queries).contains("select count(original_user_alias) from User original_user_alias");
}
@Test
@@ -169,7 +174,7 @@ public interface UserRepositoryWithRewriter
List findByNativeQuery(String param);
@Query(value = "select original_user_alias from User original_user_alias", queryRewriter = TestQueryRewriter.class)
- List findByNonNativeQuery(String param);
+ Page findByNonNativeQuery(String param, PageRequest pageRequest);
@Query(value = "select original_user_alias from User original_user_alias", queryRewriter = TestQueryRewriter.class)
List findByNonNativeSortedQuery(String param, Sort sort);
@@ -214,6 +219,7 @@ private static String replaceAlias(String query, Sort sort) {
results.put(ORIGINAL_QUERY, query);
results.put(REWRITTEN_QUERY, rewrittenQuery);
results.put(SORT, sort.toString());
+ queries.add(query);
return rewrittenQuery;
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlComplianceTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlComplianceTests.java
index aadf2c2589..81722f9b90 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlComplianceTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlComplianceTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,8 +17,6 @@
import static org.assertj.core.api.Assertions.*;
-import org.antlr.v4.runtime.CharStreams;
-import org.antlr.v4.runtime.CommonTokenStream;
import org.junit.jupiter.api.Test;
/**
@@ -32,14 +30,9 @@ class JpqlComplianceTests {
private static String parseWithoutChanges(String query) {
- JpqlLexer lexer = new JpqlLexer(CharStreams.fromString(query));
- JpqlParser parser = new JpqlParser(new CommonTokenStream(lexer));
+ JpaQueryEnhancer.JpqlQueryParser parser = JpaQueryEnhancer.JpqlQueryParser.parseQuery(query);
- parser.addErrorListener(new BadJpqlGrammarErrorListener(query));
-
- JpqlParser.StartContext parsedQuery = parser.start();
-
- return QueryRenderer.render(new JpqlQueryRenderer().visit(parsedQuery));
+ return QueryRenderer.render(new JpqlQueryRenderer().visit(parser.getContext()));
}
private void assertQuery(String query) {
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlParserQueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlParserQueryEnhancerUnitTests.java
index b867aba845..8b6385e65d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlParserQueryEnhancerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlParserQueryEnhancerUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java
index c50f07c596..7b46397124 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,14 +19,13 @@
import java.util.stream.Stream;
-import org.antlr.v4.runtime.CharStreams;
-import org.antlr.v4.runtime.CommonTokenStream;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
+
import org.springframework.data.jpa.repository.query.QueryRenderer.TokenRenderer;
/**
@@ -37,6 +36,7 @@
*
* @author Greg Turnquist
* @author Christoph Strobl
+ * @author Mark Paluch
* @since 3.1
*/
class JpqlQueryRendererTests {
@@ -48,14 +48,9 @@ class JpqlQueryRendererTests {
*/
private static String parseWithoutChanges(String query) {
- JpqlLexer lexer = new JpqlLexer(CharStreams.fromString(query));
- JpqlParser parser = new JpqlParser(new CommonTokenStream(lexer));
-
- parser.addErrorListener(new BadJpqlGrammarErrorListener(query));
-
- JpqlParser.StartContext parsedQuery = parser.start();
+ JpaQueryEnhancer.JpqlQueryParser parser = JpaQueryEnhancer.JpqlQueryParser.parseQuery(query);
- return TokenRenderer.render(new JpqlQueryRenderer().visit(parsedQuery));
+ return TokenRenderer.render(new JpqlQueryRenderer().visit(parser.getContext()));
}
static Stream reservedWords() {
@@ -296,7 +291,7 @@ void fromClauseDowncastingExample1() {
assertQuery("""
SELECT b.name, b.ISBN
FROM Order o JOIN TREAT(o.product AS Book) b
- """);
+ """);
}
@Test
@@ -305,7 +300,7 @@ void fromClauseDowncastingExample2() {
assertQuery("""
SELECT e FROM Employee e JOIN TREAT(e.projects AS LargeProject) lp
WHERE lp.budget > 1000
- """);
+ """);
}
/**
@@ -320,7 +315,7 @@ void fromClauseDowncastingExample3_SPEC_BUG() {
WHERE TREAT(p AS LargeProject).budget > 1000
OR TREAT(p AS SmallProject).name LIKE 'Persist%'
OR p.description LIKE "cost overrun"
- """);
+ """);
}
@Test
@@ -331,7 +326,7 @@ void fromClauseDowncastingExample3fixed() {
WHERE TREAT(p AS LargeProject).budget > 1000
OR TREAT(p AS SmallProject).name LIKE 'Persist%'
OR p.description LIKE 'cost overrun'
- """);
+ """);
}
@Test
@@ -341,7 +336,16 @@ void fromClauseDowncastingExample4() {
SELECT e FROM Employee e
WHERE TREAT(e AS Exempt).vacationDays > 10
OR TREAT(e AS Contractor).hours > 100
- """);
+ """);
+ }
+
+ @Test // GH-3024, GH-3863
+ void casting() {
+
+ assertQuery("""
+ select cast(i as string) from Item i where cast(i.date as date) <= cast(:currentDateTime as date)
+ """);
+ assertQuery("SELECT e FROM Employee e WHERE CAST(e.salary NUMERIC(10, 2)) > 0.0");
}
@Test
@@ -405,7 +409,7 @@ void allExample() {
WHERE emp.salary > ALL (SELECT m.salary
FROM Manager m
WHERE m.department = emp.department)
- """);
+ """);
}
@Test
@@ -417,7 +421,7 @@ void existsSubSelectExample2() {
WHERE EXISTS (SELECT spouseEmp
FROM Employee spouseEmp
WHERE spouseEmp = emp.spouse)
- """);
+ """);
}
@Test
@@ -485,7 +489,7 @@ void updateCaseExample1() {
WHEN e.rating = 2 THEN e.salary * 1.05
ELSE e.salary * 1.01
END
- """);
+ """);
}
@Test
@@ -498,7 +502,7 @@ void updateCaseExample2() {
WHEN 2 THEN e.salary * 1.05
ELSE e.salary * 1.01
END
- """);
+ """);
}
@Test
@@ -538,7 +542,7 @@ void inClauseWithTypeLiteralsShouldWork() {
SELECT e
FROM Employee e
WHERE TYPE(e) IN (Exempt, Contractor)
- """);
+ """);
}
@Test
@@ -561,6 +565,18 @@ WHERE TYPE(e) IN :empTypes
""");
}
+ @Test
+ void inClauseWithFunctionAndLiterals() {
+
+ assertQuery("""
+ select f from FooEntity f where upper(f.name) IN ('Y', 'Basic', 'Remit')
+ """);
+ assertQuery(
+ """
+ select count(f) from FooEntity f where f.status IN (com.example.eql_bug_check.entity.FooStatus.FOO, com.example.eql_bug_check.entity.FooStatus.BAR)
+ """);
+ }
+
@Test
void notEqualsForTypeShouldWork() {
@@ -591,6 +607,14 @@ SELECT c.country, COUNT(c)
GROUP BY c.country
HAVING COUNT(c) > 30
""");
+
+ assertQuery("""
+ SELECT COUNT(f)
+ FROM FooEntity f
+ WHERE f.name IN ('Y', 'Basic', 'Remit')
+ AND f.size = 10
+ HAVING COUNT(f) > 0
+ """);
}
@Test
@@ -929,6 +953,14 @@ void findOrdersThatHaveProductNamedByAParameter() {
""");
}
+ @Test // GH-4013
+ void minMaxFunctionsShouldWork() {
+ assertQuery("SELECT MAX(e.age), e.address.city FROM Employee e");
+ assertQuery("SELECT MAX(1), e.address.city FROM Employee e");
+ assertQuery("SELECT MAX(MIN(MOD(e.salary, 10))), e.address.city FROM Employee e");
+ assertQuery("SELECT MIN(MOD(e.salary, 10)), e.address.city FROM Employee e");
+ }
+
@Test // GH-2982
void floorShouldBeValidEntityName() {
@@ -1025,6 +1057,14 @@ void signedExpressionsShouldWork(String query) {
assertQuery(query);
}
+ @Test // GH-3873
+ void escapeClauseShouldWork() {
+ assertQuery("select t.name from SomeDbo t where t.name LIKE :name escape '\\\\'");
+ assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE '\\\\'");
+ assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE ?1");
+ assertQuery("SELECT e FROM SampleEntity e WHERE LOWER(e.label) LIKE LOWER(?1) ESCAPE :param");
+ }
+
@ParameterizedTest // GH-3451
@MethodSource("reservedWords")
void entityNameWithPackageContainingReservedWord(String reservedWord) {
@@ -1033,4 +1073,13 @@ void entityNameWithPackageContainingReservedWord(String reservedWord) {
assertQuery(source);
}
+ @Test // GH-3834
+ void reservedWordsShouldWork() {
+
+ assertQuery("select ie from ItemExample ie left join ie.object io where io.externalId = :externalId");
+ assertQuery("select ie.object from ItemExample ie left join ie.object io where io.externalId = :externalId");
+ assertQuery("select ie from ItemExample ie left join ie.object io where io.object = :externalId");
+ assertQuery("select ie from ItemExample ie where ie.status = com.app.domain.object.Status.UP");
+ }
+
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java
index c2de2ca015..147477fc2f 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlSpecificationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlSpecificationTests.java
index f32a9d1c75..289e522455 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlSpecificationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlSpecificationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,10 +17,9 @@
import static org.assertj.core.api.Assertions.*;
-import org.antlr.v4.runtime.CharStreams;
-import org.antlr.v4.runtime.CommonTokenStream;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+
import org.springframework.data.jpa.repository.query.QueryRenderer.TokenRenderer;
/**
@@ -41,14 +40,9 @@ class JpqlSpecificationTests {
*/
private static String parseWithoutChanges(String query) {
- JpqlLexer lexer = new JpqlLexer(CharStreams.fromString(query));
- JpqlParser parser = new JpqlParser(new CommonTokenStream(lexer));
-
- parser.addErrorListener(new BadJpqlGrammarErrorListener(query));
-
- JpqlParser.StartContext parsedQuery = parser.start();
+ JpaQueryEnhancer.JpqlQueryParser parser = JpaQueryEnhancer.JpqlQueryParser.parseQuery(query);
- return TokenRenderer.render(new JpqlQueryRenderer().visit(parsedQuery));
+ return TokenRenderer.render(new JpqlQueryRenderer().visit(parser.getContext()));
}
private void assertQuery(String query) {
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/KeysetScrollSpecificationUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/KeysetScrollSpecificationUnitTests.java
index 39a43cb1d5..9d8c92a18a 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/KeysetScrollSpecificationUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/KeysetScrollSpecificationUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/LikeBindingUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/LikeBindingUnitTests.java
index c67b1ce836..3000455292 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/LikeBindingUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/LikeBindingUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/MetaAnnotatedQueryMethodIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/MetaAnnotatedQueryMethodIntegrationTests.java
index 8947bda883..ae76cb023a 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/MetaAnnotatedQueryMethodIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/MetaAnnotatedQueryMethodIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/MetaAnnotatedQueryMethodUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/MetaAnnotatedQueryMethodUnitTests.java
index b9e899121f..29e50b85b6 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/MetaAnnotatedQueryMethodUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/MetaAnnotatedQueryMethodUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NamedOrIndexedQueryParameterSetterUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NamedOrIndexedQueryParameterSetterUnitTests.java
index 844ae69e01..6f1692142d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NamedOrIndexedQueryParameterSetterUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NamedOrIndexedQueryParameterSetterUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NamedQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NamedQueryUnitTests.java
index ebdd2a8395..68cae8bc60 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NamedQueryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NamedQueryUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,6 +36,7 @@
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.provider.QueryExtractor;
+import org.springframework.data.jpa.repository.QueryRewriter;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.core.RepositoryMetadata;
@@ -88,7 +89,8 @@ void rejectsPersistenceProviderIfIncapableOfExtractingQueriesAndPagebleBeingUsed
JpaQueryMethod queryMethod = new JpaQueryMethod(method, metadata, projectionFactory, extractor);
when(em.createNamedQuery(queryMethod.getNamedCountQueryName())).thenThrow(new IllegalArgumentException());
- assertThatExceptionOfType(QueryCreationException.class).isThrownBy(() -> NamedQuery.lookupFrom(queryMethod, em));
+ assertThatExceptionOfType(QueryCreationException.class)
+ .isThrownBy(() -> NamedQuery.lookupFrom(queryMethod, em, QueryRewriter.IdentityQueryRewriter.INSTANCE));
}
@Test // DATAJPA-142
@@ -100,7 +102,8 @@ void doesNotRejectPersistenceProviderIfNamedCountQueryIsAvailable() {
TypedQuery countQuery = mock(TypedQuery.class);
when(em.createNamedQuery(eq(queryMethod.getNamedCountQueryName()), eq(Long.class))).thenReturn(countQuery);
- NamedQuery query = (NamedQuery) NamedQuery.lookupFrom(queryMethod, em);
+ NamedQuery query = (NamedQuery) NamedQuery.lookupFrom(queryMethod, em,
+ QueryRewriter.IdentityQueryRewriter.INSTANCE);
query.doCreateCountQuery(new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[1]));
verify(em, times(1)).createNamedQuery(queryMethod.getNamedCountQueryName(), Long.class);
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NativeJpaQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NativeJpaQueryUnitTests.java
index 7a9cf35d1f..40a0279903 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NativeJpaQueryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/NativeJpaQueryUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/OpenJpaJpa21UtilsTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/OpenJpaJpa21UtilsTests.java
index b8299fa9a1..4c5cac42e1 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/OpenJpaJpa21UtilsTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/OpenJpaJpa21UtilsTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/OpenJpaParameterMetadataProviderIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/OpenJpaParameterMetadataProviderIntegrationTests.java
index a2013af402..7517a2a7e1 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/OpenJpaParameterMetadataProviderIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/OpenJpaParameterMetadataProviderIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/OpenJpaQueryUtilsIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/OpenJpaQueryUtilsIntegrationTests.java
index 2363f429d5..fd8f1cb634 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/OpenJpaQueryUtilsIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/OpenJpaQueryUtilsIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterBinderUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterBinderUnitTests.java
index 4f90c40c71..e80d9a8692 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterBinderUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterBinderUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterBindingParserUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterBindingParserUnitTests.java
index b4bd22d9ad..edcaf0e4ea 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterBindingParserUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterBindingParserUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterExpressionProviderTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterExpressionProviderTests.java
index 6d1d5393b9..b706551305 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterExpressionProviderTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterExpressionProviderTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderIntegrationTests.java
index 6dc7b84b1c..c0f86397d3 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderUnitTests.java
index c62b6e8b09..86a4de3ab2 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/PartTreeJpaQueryIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/PartTreeJpaQueryIntegrationTests.java
index ddd71dbfa7..4bd5f9c2dd 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/PartTreeJpaQueryIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/PartTreeJpaQueryIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License
import org.springframework.aop.framework.Advised;
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java
index 30645398b2..99b8a7a730 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerTckTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerTckTests.java
index 3e3465e3d3..077d469177 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerTckTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerTckTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2023-2024 the original author or authors.
+ * Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -68,6 +68,10 @@ static Stream nativeCountQueries() {
"select u from User as u", //
"select count(u) from User as u"),
+ Arguments.of( //
+ "SELECT id FROM Person", //
+ "select count(id) from Person"),
+
Arguments.of( //
"SELECT u FROM User u where u.foo.bar = ?", //
"select count(u) FROM User u where u.foo.bar = ?"),
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java
index d476c445b2..3113627c8e 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactoryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactoryUnitTests.java
index 51fb6d8d37..0b35d49b04 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactoryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryParameterSetterFactoryUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsIntegrationTests.java
index 59eb5f8667..1d4f917a5d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
import jakarta.persistence.criteria.From;
import jakarta.persistence.criteria.Join;
import jakarta.persistence.criteria.JoinType;
+import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.spi.PersistenceProvider;
import jakarta.persistence.spi.PersistenceProviderResolver;
@@ -91,6 +92,44 @@ void reusesExistingJoinForExpression() {
assertThat(from.getJoins()).hasSize(1);
}
+ @Test // GH-2756
+ void reusesExistingFetchJoinForExpression() {
+
+ CriteriaBuilder builder = em.getCriteriaBuilder();
+ CriteriaQuery query = builder.createQuery(User.class);
+ Root from = query.from(User.class);
+ from.fetch("https://github.com/manager");
+
+ PropertyPath managerFirstname = PropertyPath.from("manager.firstname", User.class);
+ PropertyPath managerLastname = PropertyPath.from("manager.lastname", User.class);
+
+ QueryUtils.toExpressionRecursively(from, managerLastname);
+ QueryUtils.toExpressionRecursively(from, managerFirstname);
+
+ assertThat(from.getFetches()).hasSize(1);
+ assertThat(from.getJoins()).isEmpty();
+ }
+
+ @Test // GH-2756
+ void prefersFetchOverJoin() {
+
+ CriteriaBuilder builder = em.getCriteriaBuilder();
+ CriteriaQuery query = builder.createQuery(User.class);
+ Root from = query.from(User.class);
+ from.fetch("https://github.com/manager");
+ from.join("manager");
+
+ PropertyPath managerFirstname = PropertyPath.from("manager.firstname", User.class);
+ PropertyPath managerLastname = PropertyPath.from("manager.lastname", User.class);
+
+ QueryUtils.toExpressionRecursively(from, managerLastname);
+ Path expr = (Path) QueryUtils.toExpressionRecursively(from, managerFirstname);
+
+ assertThat(expr.getParentPath()).hasFieldOrPropertyWithValue("fetched", true);
+ assertThat(from.getFetches()).hasSize(1);
+ assertThat(from.getJoins()).hasSize(1);
+ }
+
@Test // DATAJPA-401, DATAJPA-1238
void createsJoinForNavigationAcrossOptionalAssociation() {
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsUnitTests.java
index b2b2c4acd6..717791afec 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -51,6 +51,7 @@
* @author Erik Pellizzon
* @author Pranav HS
* @author Eduard Dudar
+ * @author Mark Paluch
*/
class QueryUtilsUnitTests {
@@ -130,13 +131,13 @@ void detectsAliasCorrectly() {
.isEqualTo("u");
assertThat(detectAlias(
"from Foo f left join f.bar b with type(b) = BarChild where (f.id = (select max(f.id) from Foo f2 where type(f2) = FooChild) or 1 <> 1) and 1=1"))
- .isEqualTo("f");
+ .isEqualTo("f");
assertThat(detectAlias(
"(from Foo f max(f) ((((select * from Foo f2 (from Foo f3) max(*)) (from Foo f4)) max(f5)) (f6)) (from Foo f7))"))
- .isEqualTo("f");
+ .isEqualTo("f");
assertThat(detectAlias(
"SELECT e FROM DbEvent e WHERE (CAST(:modifiedFrom AS date) IS NULL OR e.modificationDate >= :modifiedFrom)"))
- .isEqualTo("e");
+ .isEqualTo("e");
assertThat(detectAlias("from User u where (cast(:effective as date) is null) OR :effective >= u.createdAt"))
.isEqualTo("u");
assertThat(detectAlias("from User u where (cast(:effectiveDate as date) is null) OR :effectiveDate >= u.createdAt"))
@@ -145,7 +146,7 @@ void detectsAliasCorrectly() {
.isEqualTo("u");
assertThat(
detectAlias("from User u where (cast(:e1f2f3ectiveFrom as date) is null) OR :effectiveFrom >= u.createdAt"))
- .isEqualTo("u");
+ .isEqualTo("u");
}
@Test // GH-2260
@@ -175,13 +176,13 @@ void testRemoveSubqueries() throws Exception {
.isEqualTo("(select u from User u where not exists )");
assertThat(normalizeWhitespace(
removeSubqueries("select u from User u where not exists (from User u2 where not exists (from User u3))")))
- .isEqualTo("select u from User u where not exists");
+ .isEqualTo("select u from User u where not exists");
assertThat(normalizeWhitespace(
removeSubqueries("select u from User u where not exists ((from User u2 where not exists (from User u3)))")))
- .isEqualTo("select u from User u where not exists ( )");
+ .isEqualTo("select u from User u where not exists ( )");
assertThat(normalizeWhitespace(
removeSubqueries("(select u from User u where not exists ((from User u2 where not exists (from User u3))))")))
- .isEqualTo("(select u from User u where not exists ( ))");
+ .isEqualTo("(select u from User u where not exists ( ))");
}
@Test // GH-2581
@@ -543,6 +544,32 @@ void doesNotPrefixAliasedFunctionCallNameWhenQueryStringContainsMultipleWhiteSpa
assertThat(applySorting(query, sort, "m")).endsWith("order by avgPrice asc");
}
+ @Test // GH-3911
+ void discoversFunctionAliasesCorrectly() {
+
+ assertThat(getFunctionAliases("SELECT COUNT(1) a alias1,2 s alias2")).isEmpty();
+ assertThat(getFunctionAliases("SELECT COUNT(1) as alias1,2 as alias2")).containsExactly("alias1");
+ assertThat(getFunctionAliases("SELECT COUNT(1) as alias1,COUNT(2) as alias2")).contains("alias1", "alias2");
+ assertThat(getFunctionAliases("SELECT COUNT(1) as alias1, 2 as alias2")).containsExactly("alias1");
+ assertThat(getFunctionAliases("SELECT COUNT(1) as alias1, COUNT(2) as alias2")).contains("alias1", "alias2");
+ assertThat(getFunctionAliases("COUNT(1) as alias1,COUNT(2) as alias2")).contains("alias1", "alias2");
+ assertThat(getFunctionAliases("COUNT(1) as alias1,COUNT(2) as alias2")).contains("alias1", "alias2");
+ assertThat(getFunctionAliases("1 as alias1, COUNT(2) as alias2")).containsExactly("alias2");
+ assertThat(getFunctionAliases("1 as alias1, COUNT(2) as alias2")).containsExactly("alias2");
+ assertThat(getFunctionAliases("COUNT(1) as alias1,2 as alias2")).containsExactly("alias1");
+ assertThat(getFunctionAliases("COUNT(1) as alias1, 2 as alias2")).containsExactly("alias1");
+ }
+
+ @Test // GH-3911
+ void discoversFieldAliasesCorrectly() {
+
+ assertThat(getFieldAliases("SELECT 1 a alias1,2 s alias2")).isEmpty();
+ assertThat(getFieldAliases("SELECT 1 as alias1,2 as alias2")).contains("alias1", "alias2");
+ assertThat(getFieldAliases("SELECT 1 as alias1,2 as alias2")).contains("alias1", "alias2");
+ assertThat(getFieldAliases("1 as alias1,2 as alias2")).contains("alias1", "alias2");
+ assertThat(getFieldAliases("1 as alias1, 2 as alias2")).contains("alias1", "alias2");
+ }
+
@Test // DATAJPA-1000
void discoversCorrectAliasForJoinFetch() {
@@ -564,7 +591,7 @@ void discoversAliasWithComplexFunction() {
assertThat(
QueryUtils.getFunctionAliases("select new MyDto(sum(case when myEntity.prop3=0 then 1 else 0 end) as myAlias")) //
- .contains("myAlias");
+ .contains("myAlias");
}
@Test // DATAJPA-1506
@@ -784,18 +811,19 @@ void applySortingAccountsForNativeWindowFunction() {
// order by in over clause + at the end
assertThat(
QueryUtils.applySorting("select dense_rank() over (order by lastname) from user u order by u.lastname", sort))
- .isEqualTo("select dense_rank() over (order by lastname) from user u order by u.lastname, u.age desc");
+ .isEqualTo("select dense_rank() over (order by lastname) from user u order by u.lastname, u.age desc");
// partition by + order by in over clause
- assertThat(QueryUtils.applySorting(
- "select dense_rank() over (partition by active, age order by lastname) from user u", sort)).isEqualTo(
+ assertThat(QueryUtils
+ .applySorting("select dense_rank() over (partition by active, age order by lastname) from user u", sort))
+ .isEqualTo(
"select dense_rank() over (partition by active, age order by lastname) from user u order by u.age desc");
// partition by + order by in over clause + order by at the end
assertThat(QueryUtils.applySorting(
"select dense_rank() over (partition by active, age order by lastname) from user u order by active", sort))
- .isEqualTo(
- "select dense_rank() over (partition by active, age order by lastname) from user u order by active, u.age desc");
+ .isEqualTo(
+ "select dense_rank() over (partition by active, age order by lastname) from user u order by active, u.age desc");
// partition by + order by in over clause + frame clause
assertThat(QueryUtils.applySorting(
@@ -812,8 +840,7 @@ void applySortingAccountsForNativeWindowFunction() {
// order by in subselect (select expression)
assertThat(
QueryUtils.applySorting("select lastname, (select i.id from item i order by i.id limit 1) from user u", sort))
- .isEqualTo(
- "select lastname, (select i.id from item i order by i.id limit 1) from user u order by u.age desc");
+ .isEqualTo("select lastname, (select i.id from item i order by i.id limit 1) from user u order by u.age desc");
// order by in subselect (select expression) + at the end
assertThat(QueryUtils.applySorting(
@@ -949,7 +976,7 @@ select q.specialist_id, listagg(q.points, '%s') as points
@Test // GH-3324
void createCountQueryForSimpleQuery() {
- assertCountQuery("select * from User","select count(*) from User");
- assertCountQuery("select * from User u","select count(u) from User u");
+ assertCountQuery("select * from User", "select count(*) from User");
+ assertCountQuery("select * from User u", "select count(u) from User u");
}
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryWithNullLikeIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryWithNullLikeIntegrationTests.java
index 59f418aa61..9f7e2da8ea 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryWithNullLikeIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryWithNullLikeIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java
index e5a6b04334..0cca2af02c 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,7 +38,6 @@
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
-
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
@@ -193,15 +192,16 @@ void doesNotValidateCountQueryIfNotPagingMethod() throws Exception {
createJpaQuery(method);
}
- @Test // DATAJPA-352
- @SuppressWarnings("unchecked")
+ @Test // DATAJPA-352, GH-2736
void validatesAndRejectsCountQueryIfPagingMethod() throws Exception {
Method method = SampleRepository.class.getMethod("pageByAnnotatedQuery", Pageable.class);
when(em.createQuery(Mockito.contains("count"))).thenThrow(IllegalArgumentException.class);
- assertThatIllegalArgumentException().isThrownBy(() -> createJpaQuery(method)).withMessageContaining("Count")
+ assertThatIllegalArgumentException() //
+ .isThrownBy(() -> createJpaQuery(method)) //
+ .withMessageContaining("User u") //
.withMessageContaining(method.getName());
}
@@ -293,19 +293,19 @@ void resolvesExpressionInCountQuery() throws Exception {
}
private AbstractJpaQuery createJpaQuery(Method method) {
- return createJpaQuery(method, null);
+ return createJpaQuery(method, Optional.empty());
}
- private AbstractJpaQuery createJpaQuery(JpaQueryMethod queryMethod, @Nullable String queryString, @Nullable String countQueryString) {
+ private AbstractJpaQuery createJpaQuery(JpaQueryMethod queryMethod, String queryString, @Nullable String countQueryString) {
return JpaQueryFactory.INSTANCE.fromMethodWithQueryString(queryMethod, em, queryString, countQueryString,
QueryRewriter.IdentityQueryRewriter.INSTANCE, ValueExpressionDelegate.create());
}
- private AbstractJpaQuery createJpaQuery(Method method, @Nullable Optional countQueryString) {
+ private AbstractJpaQuery createJpaQuery(Method method, Optional countQueryString) {
JpaQueryMethod queryMethod = new JpaQueryMethod(method, metadata, factory, extractor);
- return createJpaQuery(queryMethod, queryMethod.getAnnotatedQuery(), countQueryString == null ? null : countQueryString.orElse(queryMethod.getCountQuery()));
+ return createJpaQuery(queryMethod, queryMethod.getAnnotatedQuery(), countQueryString.orElse(queryMethod.getCountQuery()));
}
interface SampleRepository {
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributeSourceUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributeSourceUnitTests.java
index bcfc8bf9ad..9e0363671d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributeSourceUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributeSourceUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributesUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributesUnitTests.java
index 919f12d1a9..b9c495778d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributesUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StoredProcedureAttributesUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java
index b7cb49db74..05c8cb3a40 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,6 +42,7 @@
* @author Diego Krupitza
* @author Mark Paluch
* @author Aleksei Elin
+ * @author Gunha Hwang
*/
class StringQueryUnitTests {
@@ -161,6 +162,66 @@ void rewritesNamedLikeToUniqueParametersIfNecessary() {
assertThat(((MethodInvocationArgument) parameterBinding.getOrigin()).identifier().getName()).isEqualTo("firstname");
}
+ @Test // GH-3784
+ void rewritesNamedLikeToUniqueParametersRetainingCountQuery() {
+
+ DeclaredQuery query = new StringQuery(
+ "select u from User u where u.firstname like %:firstname or u.firstname like :firstname% or u.firstname = :firstname",
+ false).deriveCountQuery(null);
+
+ assertThat(query.getQueryString()) //
+ .isEqualTo(
+ "select count(u) from User u where u.firstname like :firstname or u.firstname like :firstname_1 or u.firstname = :firstname_2");
+
+ List bindings = query.getParameterBindings();
+ assertThat(bindings).hasSize(3);
+
+ LikeParameterBinding binding = (LikeParameterBinding) bindings.get(0);
+ assertThat(binding).isNotNull();
+ assertThat(binding.getOrigin()).isEqualTo(ParameterOrigin.ofParameter("firstname"));
+ assertThat(binding.getName()).isEqualTo("firstname");
+ assertThat(binding.getType()).isEqualTo(Type.ENDING_WITH);
+
+ binding = (LikeParameterBinding) bindings.get(1);
+ assertThat(binding).isNotNull();
+ assertThat(binding.getOrigin()).isEqualTo(ParameterOrigin.ofParameter("firstname"));
+ assertThat(binding.getName()).isEqualTo("firstname_1");
+ assertThat(binding.getType()).isEqualTo(Type.STARTING_WITH);
+
+ ParameterBinding parameterBinding = bindings.get(2);
+ assertThat(parameterBinding).isNotNull();
+ assertThat(parameterBinding.getOrigin()).isEqualTo(ParameterOrigin.ofParameter("firstname"));
+ assertThat(parameterBinding.getName()).isEqualTo("firstname_2");
+ assertThat(((MethodInvocationArgument) parameterBinding.getOrigin()).identifier().getName()).isEqualTo("firstname");
+ }
+
+ @Test // GH-3784
+ void rewritesExpressionsLikeToUniqueParametersRetainingCountQuery() {
+
+ DeclaredQuery query = new StringQuery(
+ "select u from User u where u.firstname like %:#{firstname} or u.firstname like :#{firstname}%", false)
+ .deriveCountQuery(null);
+
+ assertThat(query.getQueryString()) //
+ .isEqualTo(
+ "select count(u) from User u where u.firstname like :__$synthetic$__1 or u.firstname like :__$synthetic$__2");
+
+ List bindings = query.getParameterBindings();
+ assertThat(bindings).hasSize(2);
+
+ LikeParameterBinding binding = (LikeParameterBinding) bindings.get(0);
+ assertThat(binding).isNotNull();
+ assertThat(binding.getOrigin().isExpression()).isTrue();
+ assertThat(binding.getName()).isEqualTo("__$synthetic$__1");
+ assertThat(binding.getType()).isEqualTo(Type.ENDING_WITH);
+
+ binding = (LikeParameterBinding) bindings.get(1);
+ assertThat(binding).isNotNull();
+ assertThat(binding.getOrigin().isExpression()).isTrue();
+ assertThat(binding.getName()).isEqualTo("__$synthetic$__2");
+ assertThat(binding.getType()).isEqualTo(Type.STARTING_WITH);
+ }
+
@Test // GH-3041
void rewritesPositionalLikeToUniqueParametersIfNecessary() {
@@ -175,6 +236,21 @@ void rewritesPositionalLikeToUniqueParametersIfNecessary() {
assertThat(bindings).hasSize(3);
}
+ @Test // GH-3907
+ void rewritesPositionalLikeToUniqueParametersIfNecessaryUsingPostgresJsonbOperator() {
+
+ StringQuery query = new StringQuery(
+ "select '[\"x\", \"c\"]'::jsonb ?| '[\"x\", \"c\"]'::jsonb from User u where u.firstname like %?1 or u.firstname like ?1% or u.firstname = ?1",
+ true);
+
+ assertThat(query.hasParameterBindings()).isTrue();
+ assertThat(query.getQueryString()).isEqualTo(
+ "select '[\"x\", \"c\"]'::jsonb ?| '[\"x\", \"c\"]'::jsonb from User u where u.firstname like ?1 or u.firstname like ?2 or u.firstname = ?3");
+
+ List bindings = query.getParameterBindings();
+ assertThat(bindings).hasSize(3);
+ }
+
@Test // GH-3041
void reusesNamedLikeBindingsWherePossible() {
@@ -264,6 +340,48 @@ void detectsMultipleNamedInParameterBindings() {
assertNamedBinding(ParameterBinding.class, "bar", bindings.get(2));
}
+ @Test // GH-3784
+ void deriveCountQueryWithNamedInRetainsOrigin() {
+
+ String queryString = "select u from User u where (:logins) IS NULL OR LOWER(u.login) IN (:logins)";
+ DeclaredQuery query = new StringQuery(queryString, false).deriveCountQuery(null);
+
+ assertThat(query.getQueryString())
+ .isEqualTo("select count(u) from User u where (:logins) IS NULL OR LOWER(u.login) IN (:logins_1)");
+
+ List bindings = query.getParameterBindings();
+ assertThat(bindings).hasSize(2);
+
+ assertNamedBinding(ParameterBinding.class, "logins", bindings.get(0));
+ assertThat((MethodInvocationArgument) bindings.get(0).getOrigin()).extracting(MethodInvocationArgument::identifier)
+ .extracting(BindingIdentifier::getName).isEqualTo("logins");
+
+ assertNamedBinding(InParameterBinding.class, "logins_1", bindings.get(1));
+ assertThat((MethodInvocationArgument) bindings.get(1).getOrigin()).extracting(MethodInvocationArgument::identifier)
+ .extracting(BindingIdentifier::getName).isEqualTo("logins");
+ }
+
+ @Test // GH-3784
+ void deriveCountQueryWithPositionalInRetainsOrigin() {
+
+ String queryString = "select u from User u where (?1) IS NULL OR LOWER(u.login) IN (?1)";
+ DeclaredQuery query = new StringQuery(queryString, false).deriveCountQuery(null);
+
+ assertThat(query.getQueryString())
+ .isEqualTo("select count(u) from User u where (?1) IS NULL OR LOWER(u.login) IN (?2)");
+
+ List bindings = query.getParameterBindings();
+ assertThat(bindings).hasSize(2);
+
+ assertPositionalBinding(ParameterBinding.class, 1, bindings.get(0));
+ assertThat((MethodInvocationArgument) bindings.get(0).getOrigin()).extracting(MethodInvocationArgument::identifier)
+ .extracting(BindingIdentifier::getPosition).isEqualTo(1);
+
+ assertPositionalBinding(InParameterBinding.class, 2, bindings.get(1));
+ assertThat((MethodInvocationArgument) bindings.get(1).getOrigin()).extracting(MethodInvocationArgument::identifier)
+ .extracting(BindingIdentifier::getPosition).isEqualTo(1);
+ }
+
@Test // DATAJPA-461
void detectsPositionalInParameterBindings() {
@@ -310,6 +428,56 @@ void allowsReuseOfParameterWithInAndRegularBinding() {
assertNamedBinding(InParameterBinding.class, "foo_1", bindings.get(1));
}
+ @Test // GH-3126
+ void countQueryDerivationRetainsNamedExpressionParameters() {
+
+ StringQuery query = new StringQuery(
+ "select u from User u where foo = :#{bar} ORDER BY CASE WHEN (u.firstname >= :#{name}) THEN 0 ELSE 1 END",
+ false);
+
+ DeclaredQuery countQuery = query.deriveCountQuery(null);
+
+ assertThat(countQuery.getParameterBindings()).hasSize(1);
+ assertThat(countQuery.getParameterBindings()).extracting(ParameterBinding::getOrigin)
+ .extracting(ParameterOrigin::isExpression).isEqualTo(List.of(true));
+
+ query = new StringQuery(
+ "select u from User u where foo = :#{bar} and bar = :bar ORDER BY CASE WHEN (u.firstname >= :bar) THEN 0 ELSE 1 END",
+ false);
+
+ countQuery = query.deriveCountQuery(null);
+
+ assertThat(countQuery.getParameterBindings()).hasSize(2);
+ assertThat(countQuery.getParameterBindings()) //
+ .extracting(ParameterBinding::getOrigin) //
+ .extracting(ParameterOrigin::isExpression).contains(true, false);
+ }
+
+ @Test // GH-3126
+ void countQueryDerivationRetainsIndexedExpressionParameters() {
+
+ StringQuery query = new StringQuery(
+ "select u from User u where foo = ?#{bar} ORDER BY CASE WHEN (u.firstname >= ?#{name}) THEN 0 ELSE 1 END",
+ false);
+
+ DeclaredQuery countQuery = query.deriveCountQuery(null);
+
+ assertThat(countQuery.getParameterBindings()).hasSize(1);
+ assertThat(countQuery.getParameterBindings()).extracting(ParameterBinding::getOrigin)
+ .extracting(ParameterOrigin::isExpression).isEqualTo(List.of(true));
+
+ query = new StringQuery(
+ "select u from User u where foo = ?#{bar} and bar = ?1 ORDER BY CASE WHEN (u.firstname >= ?1) THEN 0 ELSE 1 END",
+ false);
+
+ countQuery = query.deriveCountQuery(null);
+
+ assertThat(countQuery.getParameterBindings()).hasSize(2);
+ assertThat(countQuery.getParameterBindings()) //
+ .extracting(ParameterBinding::getOrigin) //
+ .extracting(ParameterOrigin::isExpression).contains(true, false);
+ }
+
@Test // DATAJPA-461
void detectsMultiplePositionalInParameterBindings() {
@@ -341,7 +509,6 @@ void treatsGreaterThanBindingAsSimpleBinding() {
assertThat(bindings).hasSize(1);
assertPositionalBinding(ParameterBinding.class, 1, bindings.get(0));
-
}
@Test // DATAJPA-473
@@ -437,6 +604,19 @@ void shouldReplaceExpressionWithLikeParameters() {
.isEqualTo("select a from A a where a.b LIKE :__$synthetic$__1 and a.c LIKE :__$synthetic$__2");
}
+ @Test // GH-3907
+ void considersOnlyDedicatedPositionalBindMarkersAsSuch() {
+
+ StringQuery query = new StringQuery(
+ "select '[\"x\", \"c\"]'::jsonb ?| array[?1]::text[] FROM foo WHERE foo BETWEEN ?1 and ?2", true);
+
+ assertThat(query.getParameterBindings()).hasSize(2);
+
+ query = new StringQuery("select '[\"x\", \"c\"]'::jsonb ?& array[:foo]::text[] FROM foo WHERE foo = :bar", true);
+
+ assertThat(query.getParameterBindings()).hasSize(2);
+ }
+
@Test // DATAJPA-712, GH-3619
void shouldReplaceAllPositionExpressionParametersWithInClause() {
@@ -539,32 +719,32 @@ private void checkAlias(String query, String expected, String description, boole
@Test // DATAJPA-1200
void testHasNamedParameter() {
- checkHasNamedParameter("select something from x where id = :id", true, "named parameter", true);
- checkHasNamedParameter("in the :id middle", true, "middle", false);
- checkHasNamedParameter(":id start", true, "beginning", false);
- checkHasNamedParameter(":id", true, "alone", false);
- checkHasNamedParameter("select something from x where id = :id", true, "named parameter", true);
- checkHasNamedParameter(":UPPERCASE", true, "uppercase", false);
- checkHasNamedParameter(":lowercase", true, "lowercase", false);
- checkHasNamedParameter(":2something", true, "beginning digit", false);
- checkHasNamedParameter(":2", true, "only digit", false);
- checkHasNamedParameter(":.something", true, "dot", false);
- checkHasNamedParameter(":_something", true, "underscore", false);
- checkHasNamedParameter(":$something", true, "dollar", false);
- checkHasNamedParameter(":\uFE0F", true, "non basic latin emoji", false); //
- checkHasNamedParameter(":\u4E01", true, "chinese japanese korean", false);
-
- checkHasNamedParameter("no bind variable", false, "no bind variable", false);
- checkHasNamedParameter(":\u2004whitespace", false, "non basic latin whitespace", false);
- checkHasNamedParameter("select something from x where id = ?1", false, "indexed parameter", true);
- checkHasNamedParameter("::", false, "double colon", false);
- checkHasNamedParameter(":", false, "end of query", false);
- checkHasNamedParameter(":\u0003", false, "non-printable", false);
- checkHasNamedParameter(":*", false, "basic latin emoji", false);
- checkHasNamedParameter("\\:", false, "escaped colon", false);
- checkHasNamedParameter("::id", false, "double colon with identifier", false);
- checkHasNamedParameter("\\:id", false, "escaped colon with identifier", false);
- checkHasNamedParameter("select something from x where id = #something", false, "hash", true);
+ checkHasNamedParameter("select something from x where id = :id", true, "named parameter");
+ checkHasNamedParameter("in the :id middle", true, "middle");
+ checkHasNamedParameter(":id start", true, "beginning");
+ checkHasNamedParameter(":id", true, "alone");
+ checkHasNamedParameter("select something from x where id = :id", true, "named parameter");
+ checkHasNamedParameter(":UPPERCASE", true, "uppercase");
+ checkHasNamedParameter(":lowercase", true, "lowercase");
+ checkHasNamedParameter(":2something", true, "beginning digit");
+ checkHasNamedParameter(":2", true, "only digit");
+ checkHasNamedParameter(":.something", true, "dot");
+ checkHasNamedParameter(":_something", true, "underscore");
+ checkHasNamedParameter(":$something", true, "dollar");
+ checkHasNamedParameter(":\uFE0F", true, "non basic latin emoji"); //
+ checkHasNamedParameter(":\u4E01", true, "chinese japanese korean");
+
+ checkHasNamedParameter("no bind variable", false, "no bind variable");
+ checkHasNamedParameter(":\u2004whitespace", false, "non basic latin whitespace");
+ checkHasNamedParameter("select something from x where id = ?1", false, "indexed parameter");
+ checkHasNamedParameter("::", false, "double colon");
+ checkHasNamedParameter(":", false, "end of query");
+ checkHasNamedParameter(":\u0003", false, "non-printable");
+ checkHasNamedParameter(":*", false, "basic latin emoji");
+ checkHasNamedParameter("\\:", false, "escaped colon");
+ checkHasNamedParameter("::id", false, "double colon with identifier");
+ checkHasNamedParameter("\\:id", false, "escaped colon with identifier");
+ checkHasNamedParameter("select something from x where id = #something", false, "hash");
}
@Test // DATAJPA-1235
@@ -725,7 +905,7 @@ void checkNumberOfNamedParameters(String query, int expectedSize, String label,
.hasSize(expectedSize);
}
- private void checkHasNamedParameter(String query, boolean expected, String label, boolean nativeQuery) {
+ private void checkHasNamedParameter(String query, boolean expected, String label) {
List bindings = new ArrayList<>();
StringQuery.ParameterBindingParser.INSTANCE.parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(query,
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/TupleConverterUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/TupleConverterUnitTests.java
index 13dc550fb0..6d3e3a73b4 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/TupleConverterUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/TupleConverterUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/AnnotatedAuditableUserRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/AnnotatedAuditableUserRepository.java
index 36748415e5..cf549ad521 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/AnnotatedAuditableUserRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/AnnotatedAuditableUserRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/AuditableEntityRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/AuditableEntityRepository.java
index 321fdbf179..216d448d84 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/AuditableEntityRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/AuditableEntityRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/AuditableUserRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/AuditableUserRepository.java
index 127c237fbf..b3d39afc9b 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/AuditableUserRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/AuditableUserRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/BookRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/BookRepository.java
index dd4af2f2d6..c5a89ebf0f 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/BookRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/BookRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/CategoryRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/CategoryRepository.java
index 601c4647ae..676a095567 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/CategoryRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/CategoryRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ClassWithNestedRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ClassWithNestedRepository.java
index 303910c50b..17089b7e60 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ClassWithNestedRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ClassWithNestedRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ConcreteRepository1.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ConcreteRepository1.java
index 52ff1ee123..78ee0efe1d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ConcreteRepository1.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ConcreteRepository1.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ConcreteRepository2.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ConcreteRepository2.java
index 5137c87da7..55fef12d72 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ConcreteRepository2.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ConcreteRepository2.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/CustomAbstractPersistableRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/CustomAbstractPersistableRepository.java
index 12dcbeed5e..d59a163db7 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/CustomAbstractPersistableRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/CustomAbstractPersistableRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/DummyRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/DummyRepository.java
index 07a00c4424..34aef70172 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/DummyRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/DummyRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithEmbeddedId.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithEmbeddedId.java
index c52e42343a..ea1bc60f56 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithEmbeddedId.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithEmbeddedId.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithIdClass.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithIdClass.java
index 703501f0d6..e3413fed97 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithIdClass.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/EmployeeRepositoryWithIdClass.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/EntityWithAssignedIdRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/EntityWithAssignedIdRepository.java
index 505c658d44..fc6f4714bc 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/EntityWithAssignedIdRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/EntityWithAssignedIdRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2024 the original author or authors.
+ * Copyright 2019-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ItemRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ItemRepository.java
index 9335ce52d9..a82370752c 100755
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ItemRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ItemRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ItemSiteRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ItemSiteRepository.java
index 0151618d4b..dd6ba72176 100755
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ItemSiteRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ItemSiteRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/MailMessageRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/MailMessageRepository.java
index 11ecbd0d61..62ad9525e4 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/MailMessageRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/MailMessageRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/MappedTypeRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/MappedTypeRepository.java
index 12c1041ef4..a2ce8ab9b1 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/MappedTypeRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/MappedTypeRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/NameOnlyDto.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/NameOnlyDto.java
index f27d201137..13ee35f497 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/NameOnlyDto.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/NameOnlyDto.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2024 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/NameOnlyRecord.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/NameOnlyRecord.java
new file mode 100644
index 0000000000..b72c448345
--- /dev/null
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/NameOnlyRecord.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.jpa.repository.sample;
+
+public record NameOnlyRecord(String firstname, String lastname) {
+
+}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ParentRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ParentRepository.java
index 4ab5675004..71f665c311 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ParentRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ParentRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ProductRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ProductRepository.java
index 3d34f051ea..2de721721e 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ProductRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/ProductRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RedeclaringRepositoryMethodsRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RedeclaringRepositoryMethodsRepository.java
index dd9343fff3..a5012f6d2b 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RedeclaringRepositoryMethodsRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RedeclaringRepositoryMethodsRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RepositoryMethodsWithEntityGraphConfigRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RepositoryMethodsWithEntityGraphConfigRepository.java
index eee395794b..fe8e0dd4b6 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RepositoryMethodsWithEntityGraphConfigRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RepositoryMethodsWithEntityGraphConfigRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepository.java
index 1895ce863a..083e6f03fb 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepositoryWithMeta.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepositoryWithMeta.java
index 9258d62457..2fc75192e6 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepositoryWithMeta.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepositoryWithMeta.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/SampleConfig.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/SampleConfig.java
index 7f9ac2aab4..a319360651 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/SampleConfig.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/SampleConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/SampleEvaluationContextExtension.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/SampleEvaluationContextExtension.java
index 274ba7e601..a1deba7c24 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/SampleEvaluationContextExtension.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/SampleEvaluationContextExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/SiteRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/SiteRepository.java
index 3bbd36c434..ff5ae98e4c 100755
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/SiteRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/SiteRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java
index 01526cd0bf..d25eefa26c 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -83,9 +83,8 @@ public interface UserRepository extends JpaRepository, JpaSpecifi
java.util.Optional findById(Integer primaryKey);
/**
- * Redeclaration of {@link CrudRepository#deleteById(java.lang.Object)}. to make sure the transaction
- * configuration of the original method is considered if the redeclaration does not carry a {@link Transactional}
- * annotation.
+ * Redeclaration of {@link CrudRepository#deleteById(java.lang.Object)}. to make sure the transaction configuration of
+ * the original method is considered if the redeclaration does not carry a {@link Transactional} annotation.
*/
@Override
void deleteById(Integer id); // DATACMNS-649
@@ -419,7 +418,8 @@ Window findTop3ByFirstnameStartingWithOrderByFirstnameAscEmailAddressAsc(S
@Query("select u from User u where u.firstname = ?#{[0]} and u.firstname = ?1 and u.lastname like %?#{[1]}% and u.lastname like %?2%")
List findByFirstnameAndLastnameWithSpelExpression(String firstname, String lastname);
- @Query(value = "select * from SD_User", countQuery = "select count(1) from SD_User u where u.lastname = :#{#lastname}", nativeQuery = true)
+ @Query(value = "select * from SD_User",
+ countQuery = "select count(1) from SD_User u where u.lastname = :#{#lastname}", nativeQuery = true)
Page findByWithSpelParameterOnlyUsedForCountQuery(String lastname, Pageable page);
// DATAJPA-564
@@ -558,6 +558,9 @@ List findUsersByFirstnameForSpELExpressionWithParameterIndexOnlyWithEntity
@Query(value = "SELECT firstname, lastname FROM SD_User WHERE id = ?1", nativeQuery = true)
NameOnly findByNativeQuery(Integer id);
+ @NativeQuery("SELECT firstname, lastname FROM SD_User WHERE id = ?1")
+ NameOnlyRecord findRecordProjectionByNativeQuery(Integer id);
+
// GH-3155
@NativeQuery(value = "SELECT emailaddress, secondary_email_address FROM SD_User WHERE id = ?1",
sqlResultSetMapping = "emailDto")
@@ -570,26 +573,23 @@ List findUsersByFirstnameForSpELExpressionWithParameterIndexOnlyWithEntity
@Query("SELECT u FROM User u where u.firstname >= ?1 and u.lastname = '000:1'")
List queryWithIndexedParameterAndColonFollowedByIntegerInString(String firstname);
- /**
- * TODO: ORDER BY CASE appears to only with Hibernate. The examples attempting to do this through pure JPQL don't
- * appear to work with Hibernate, so we must set them aside until we can implement HQL.
- */
- // // DATAJPA-1233
- // @Query(value = "SELECT u FROM User u ORDER BY CASE WHEN (u.firstname >= :name) THEN 0 ELSE 1 END, u.firstname")
- // Page findAllOrderedBySpecialNameSingleParam(@Param("name") String name, Pageable page);
- //
- // // DATAJPA-1233
- // @Query(
- // value = "SELECT u FROM User u WHERE :other = 'x' ORDER BY CASE WHEN (u.firstname >= :name) THEN 0 ELSE 1 END,
- // u.firstname")
- // Page findAllOrderedBySpecialNameMultipleParams(@Param("name") String name, @Param("other") String other,
- // Pageable page);
- //
- // // DATAJPA-1233
- // @Query(
- // value = "SELECT u FROM User u WHERE ?2 = 'x' ORDER BY CASE WHEN (u.firstname >= ?1) THEN 0 ELSE 1 END,
- // u.firstname")
- // Page findAllOrderedBySpecialNameMultipleParamsIndexed(String other, String name, Pageable page);
+ @Query(value = "SELECT u FROM User u ORDER BY CASE WHEN (u.firstname >= :name) THEN 0 ELSE 1 END, u.firstname")
+ Page findAllOrderedByNamedParam(@Param("name") String name, Pageable page);
+
+ @Query(value = "SELECT u FROM User u ORDER BY CASE WHEN (u.firstname >= ?1) THEN 0 ELSE 1 END, u.firstname")
+ Page findAllOrderedByIndexedParam(String name, Pageable page);
+
+ @Query(
+ value = "SELECT u FROM User u WHERE :other = 'x' ORDER BY CASE WHEN (u.firstname >= :name) THEN 0 ELSE 1 END, u.firstname")
+ Page findAllOrderedBySpecialNameMultipleParams(@Param("name") String name, @Param("other") String other,
+ Pageable page);
+
+ // Note that parameters used in the order-by statement are just cut off, so we must declare a query that parameter
+ // label order remains valid even after truncating the order by part. (i.e. WHERE ?2 = 'x' ORDER BY CASE WHEN
+ // (u.firstname >= ?1) isn't going to work).
+ @Query(
+ value = "SELECT u FROM User u WHERE ?1 = 'x' ORDER BY CASE WHEN (u.firstname >= ?2) THEN 0 ELSE 1 END, u.firstname")
+ Page findAllOrderedBySpecialNameMultipleParamsIndexed(String other, String name, Pageable page);
// DATAJPA-928
Page findByNativeNamedQueryWithPageable(Pageable pageable);
@@ -607,7 +607,7 @@ List findUsersByFirstnameForSpELExpressionWithParameterIndexOnlyWithEntity
Map findMapWithNullValues();
// DATAJPA-1307
- @Query(value = "select * from SD_User u where u.emailAddress = ?", nativeQuery = true)
+ @Query(value = "select * from SD_#{#entityName} u where u.emailAddress = ?", nativeQuery = true)
User findByEmailNativeAddressJdbcStyleParameter(String emailAddress);
// DATAJPA-1334
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepositoryCustom.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepositoryCustom.java
index 485f71b8d4..86f454c0de 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepositoryCustom.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepositoryCustom.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepositoryImpl.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepositoryImpl.java
index f27d136730..965834876f 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepositoryImpl.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/sample/UserRepositoryImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPopulatingMethodInterceptorUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPopulatingMethodInterceptorUnitTests.java
index c9bcee59a3..723c34a693 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPopulatingMethodInterceptorUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPopulatingMethodInterceptorUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaContextIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaContextIntegrationTests.java
index 6b88b69bf4..6018de0c11 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaContextIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaContextIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaContextUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaContextUnitTests.java
index 1ea6993ce2..899cbd406d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaContextUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaContextUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaEntityMetadataUnitTest.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaEntityMetadataUnitTest.java
index d874935ddb..042ffdd982 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaEntityMetadataUnitTest.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaEntityMetadataUnitTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultQueryHintsTest.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultQueryHintsTest.java
index fea4d697b6..c0b69d22e9 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultQueryHintsTest.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultQueryHintsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2024 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultTransactionDisablingIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultTransactionDisablingIntegrationTests.java
index 1a8e34d1f5..f27993c8e2 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultTransactionDisablingIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/DefaultTransactionDisablingIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkJpaMetamodelEntityInformationIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkJpaMetamodelEntityInformationIntegrationTests.java
index 4922461995..c18afd1320 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkJpaMetamodelEntityInformationIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkJpaMetamodelEntityInformationIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkJpaRepositoryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkJpaRepositoryTests.java
index 34c38daa48..95a9308e02 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkJpaRepositoryTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkJpaRepositoryTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,18 @@
*/
package org.springframework.data.jpa.repository.support;
+import static org.assertj.core.api.Assertions.*;
+
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.PersistenceContext;
+
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import org.springframework.data.jpa.domain.sample.User;
import org.springframework.test.context.ContextConfiguration;
/**
@@ -23,10 +34,49 @@
*
* @author Oliver Gierke
* @author Greg Turnquist
+ * @author Mark Paluch
*/
@ContextConfiguration("classpath:eclipselink.xml")
class EclipseLinkJpaRepositoryTests extends JpaRepositoryTests {
+ @PersistenceContext EntityManager em;
+
+ SimpleJpaRepository repository;
+ User firstUser, secondUser;
+
+ @BeforeEach
+ @Override
+ void setUp() {
+
+ super.setUp();
+
+ repository = new SimpleJpaRepository<>(User.class, em);
+
+ firstUser = new User("Oliver", "Gierke", "gierke@synyx.de");
+ firstUser.setAge(28);
+ secondUser = new User("Joachim", "Arrasz", "arrasz@synyx.de");
+ secondUser.setAge(35);
+
+ repository.deleteAll();
+ repository.saveAllAndFlush(List.of(firstUser, secondUser));
+ }
+
+ @Test // GH-3990
+ void deleteAllBySimpleIdInBatch() {
+
+ repository.deleteAllByIdInBatch(List.of(firstUser.getId(), secondUser.getId()));
+
+ assertThat(repository.count()).isZero();
+ }
+
+ @Test // GH-3990
+ void deleteAllInBatch() {
+
+ repository.deleteAllInBatch(List.of(firstUser, secondUser));
+
+ assertThat(repository.count()).isZero();
+ }
+
@Override
@Disabled("https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477")
void deleteAllByIdInBatch() {
@@ -38,4 +88,5 @@ void deleteAllByIdInBatch() {
void deleteAllByIdInBatchShouldConvertAnIterableToACollection() {
// disabled
}
+
}
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkProxyIdAccessorTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkProxyIdAccessorTests.java
index eb619200c7..c7259a5b17 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkProxyIdAccessorTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EclipseLinkProxyIdAccessorTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityGraphFactoryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityGraphFactoryUnitTests.java
index 647896ffbb..c2039fcd60 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityGraphFactoryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityGraphFactoryUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021-2024 the original author or authors.
+ * Copyright 2021-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistrarPostProcessorIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistrarPostProcessorIntegrationTests.java
index a1d020423d..bf2fa3070e 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistrarPostProcessorIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistrarPostProcessorIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistrarPostProcessorUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistrarPostProcessorUnitTests.java
index 8a6725a615..a34fc121fa 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistrarPostProcessorUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistrarPostProcessorUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerFactoryRefTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerFactoryRefTests.java
index e5848bfef9..50380485a6 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerFactoryRefTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerFactoryRefTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerFactoryRefUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerFactoryRefUnitTests.java
index b25682e9a8..a9ea88ad00 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerFactoryRefUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerFactoryRefUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryByPredicateUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryByPredicateUnitTests.java
index f2c5e9f00c..295ed287c9 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryByPredicateUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/FetchableFluentQueryByPredicateUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2022-2024 the original author or authors.
+ * Copyright 2022-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/HibernateJpaMetamodelEntityInformationIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/HibernateJpaMetamodelEntityInformationIntegrationTests.java
index 82824c084b..deffda2a29 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/HibernateJpaMetamodelEntityInformationIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/HibernateJpaMetamodelEntityInformationIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JavaConfigDefaultTransactionDisablingIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JavaConfigDefaultTransactionDisablingIntegrationTests.java
index 0a5e0d9199..7d985c050d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JavaConfigDefaultTransactionDisablingIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JavaConfigDefaultTransactionDisablingIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaEntityInformationSupportUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaEntityInformationSupportUnitTests.java
index e66e624b12..6b36813294 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaEntityInformationSupportUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaEntityInformationSupportUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationIntegrationTests.java
index 0f5c9ab3a7..a04a0ee1c4 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationUnitTests.java
index 1bed3b7fdf..476957a8d2 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaMetamodelEntityInformationUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2024 the original author or authors.
+ * Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformationUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformationUnitTests.java
index 37050ffe89..03e8b764bb 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformationUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaPersistableEntityInformationUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanEntityPathResolverIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanEntityPathResolverIntegrationTests.java
index 73a3c76ce3..d5f1f891af 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanEntityPathResolverIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanEntityPathResolverIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanUnitTests.java
index bfbbe561cb..dad06c1f9d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryUnitTests.java
index 983c7c2195..4b5ad4cf3e 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryTests.java
index 27daa255a8..563c0c7a67 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/MailMessageRepositoryIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/MailMessageRepositoryIntegrationTests.java
index b813ae8714..3688699d61 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/MailMessageRepositoryIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/MailMessageRepositoryIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/MutableQueryHintsUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/MutableQueryHintsUnitTests.java
index e4c0c3c7c0..c47f5c5c75 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/MutableQueryHintsUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/MutableQueryHintsUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2024 the original author or authors.
+ * Copyright 2020-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaJpaRepositoryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaJpaRepositoryTests.java
index 10440974b2..dd8a85fce2 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaJpaRepositoryTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaJpaRepositoryTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaMetamodelEntityInformationIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaMetamodelEntityInformationIntegrationTests.java
index 70a8e8ed87..5c0a0600dd 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaMetamodelEntityInformationIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaMetamodelEntityInformationIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2024 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaProxyIdAccessorTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaProxyIdAccessorTests.java
index 6162daab39..54372525c8 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaProxyIdAccessorTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/OpenJpaProxyIdAccessorTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QSimpleEntityPathResolverUnitTests_Sample.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QSimpleEntityPathResolverUnitTests_Sample.java
index 2f33aaafd0..773d82abbe 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QSimpleEntityPathResolverUnitTests_Sample.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QSimpleEntityPathResolverUnitTests_Sample.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslIntegrationTests.java
index 2c71c33483..4a59ea90a4 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslJpaPredicateExecutorUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslJpaPredicateExecutorUnitTests.java
index 7962695b6a..87c4690190 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslJpaPredicateExecutorUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslJpaPredicateExecutorUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -282,9 +282,15 @@ void shouldSupportFindAllWithPredicateAndSort() {
assertThat(users).contains(carter, dave, oliver);
}
- @Test // DATAJPA-585
+ @Test // DATAJPA-585, 3761
void worksWithUnpagedPageable() {
+
assertThat(predicateExecutor.findAll(user.dateOfBirth.isNull(), Pageable.unpaged()).getContent()).hasSize(3);
+
+ Page users = predicateExecutor.findAll(user.dateOfBirth.isNull(),
+ Pageable.unpaged(Sort.by(Direction.ASC, "firstname")));
+
+ assertThat(users).containsExactly(carter, dave, oliver);
}
@Test // DATAJPA-912
@@ -393,6 +399,19 @@ void findByFluentPredicatePage() {
assertThat(page1.getContent()).containsExactly(oliver);
}
+ @Test // GH-3762
+ void findByFluentPredicateSortOverridePage() {
+
+ Predicate predicate = user.firstname.contains("v");
+
+ Page page = predicateExecutor.findBy(predicate,
+ q -> q.sortBy(Sort.by("firstname")).page(PageRequest.of(0, 1, Sort.by(Direction.DESC, "firstname"))));
+
+ assertThat(page.getContent()).containsOnly(oliver);
+ assertThat(predicateExecutor.findAll(predicate, page.nextPageable())).containsOnly(dave);
+
+ }
+
@Test // GH-2294
void findByFluentPredicateWithInterfaceBasedProjection() {
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslJpaRepositoryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslJpaRepositoryTests.java
index 7e4778d531..ece657841b 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslJpaRepositoryTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslJpaRepositoryTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslRepositorySupportIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslRepositorySupportIntegrationTests.java
index 6c400a05c4..eb411ddce3 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslRepositorySupportIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslRepositorySupportIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslRepositorySupportTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslRepositorySupportTests.java
index 1eb68aa08b..4e1e1d650a 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslRepositorySupportTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/QuerydslRepositorySupportTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/SimpleJpaRepositoryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/SimpleJpaRepositoryUnitTests.java
index 5b83077bbb..24e43d24cb 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/SimpleJpaRepositoryUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/SimpleJpaRepositoryUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/TransactionalRepositoryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/TransactionalRepositoryTests.java
index 5a29269c82..be195c947c 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/TransactionalRepositoryTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/TransactionalRepositoryTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2024 the original author or authors.
+ * Copyright 2008-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/XmlConfigDefaultTransactionDisablingIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/XmlConfigDefaultTransactionDisablingIntegrationTests.java
index df684286e9..839293c009 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/XmlConfigDefaultTransactionDisablingIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/support/XmlConfigDefaultTransactionDisablingIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessorUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessorUnitTests.java
index 9e60043821..e60565e8c8 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessorUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/ClasspathScanningPersistenceUnitPostProcessorUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/EntityManagerTestUtils.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/EntityManagerTestUtils.java
index 013857d487..479c69c015 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/EntityManagerTestUtils.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/EntityManagerTestUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2014-2024 the original author or authors.
+ * Copyright 2014-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/MergingPersistenceUnitManagerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/MergingPersistenceUnitManagerUnitTests.java
index 495c89d71f..4233d685fb 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/MergingPersistenceUnitManagerUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/MergingPersistenceUnitManagerUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2024 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/ProxyImageNameSubstitutor.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/ProxyImageNameSubstitutor.java
index 24fde9888a..89e64a3024 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/ProxyImageNameSubstitutor.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/support/ProxyImageNameSubstitutor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/BooleanExecutionCondition.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/BooleanExecutionCondition.java
index bd617cb557..590d92d4d0 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/BooleanExecutionCondition.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/BooleanExecutionCondition.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/ClassPathExclusions.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/ClassPathExclusions.java
index aa25c22739..f53d4d6ce4 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/ClassPathExclusions.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/ClassPathExclusions.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/ClassPathExclusionsExtension.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/ClassPathExclusionsExtension.java
index 46dcd05fb5..b8d76f9285 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/ClassPathExclusionsExtension.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/ClassPathExclusionsExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/DisabledOnHibernate.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/DisabledOnHibernate.java
index 0ee4e25989..cdae0ff329 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/DisabledOnHibernate.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/DisabledOnHibernate.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/DisabledOnHibernateCondition.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/DisabledOnHibernateCondition.java
index 804309544f..21e2c87b2d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/DisabledOnHibernateCondition.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/DisabledOnHibernateCondition.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/DisabledOnHibernateConditionTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/DisabledOnHibernateConditionTests.java
index 15a977cb5f..80750aeb5d 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/DisabledOnHibernateConditionTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/DisabledOnHibernateConditionTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/FixedDate.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/FixedDate.java
index 377874e48c..a6e2800784 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/FixedDate.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/FixedDate.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2024 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/HidingClassLoader.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/HidingClassLoader.java
index ce60e381e2..2ed67c83f1 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/HidingClassLoader.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/HidingClassLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2024 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/JpaMetamodelCacheCleanupIntegrationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/JpaMetamodelCacheCleanupIntegrationTests.java
index 19f03a9225..65cb8ea1ad 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/JpaMetamodelCacheCleanupIntegrationTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/JpaMetamodelCacheCleanupIntegrationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2024 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/JpaMetamodelUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/JpaMetamodelUnitTests.java
index a4cd6592bf..73102d6d03 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/JpaMetamodelUnitTests.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/JpaMetamodelUnitTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2024 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/PackageExcludingClassLoader.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/PackageExcludingClassLoader.java
index b768c90fd4..b5c8ed5216 100644
--- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/PackageExcludingClassLoader.java
+++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/util/PackageExcludingClassLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 the original author or authors.
+ * Copyright 2024-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/main/antora/antora-playbook.yml b/src/main/antora/antora-playbook.yml
index 54e23dabe2..04dbefb29a 100644
--- a/src/main/antora/antora-playbook.yml
+++ b/src/main/antora/antora-playbook.yml
@@ -17,7 +17,7 @@ content:
- url: https://github.com/spring-projects/spring-data-commons
# Refname matching:
# https://docs.antora.org/antora/latest/playbook/content-refname-matching/
- branches: [main, 3.2.x]
+ branches: [ main, 3.4.x ]
start_path: src/main/antora
asciidoc:
attributes:
diff --git a/src/main/antora/modules/ROOT/pages/index.adoc b/src/main/antora/modules/ROOT/pages/index.adoc
index 83a6f4ac77..37753da700 100644
--- a/src/main/antora/modules/ROOT/pages/index.adoc
+++ b/src/main/antora/modules/ROOT/pages/index.adoc
@@ -2,7 +2,6 @@
= Spring Data JPA
:revnumber: {version}
:revdate: {localdate}
-:feature-scroll: true
_Spring Data JPA provides repository support for the Jakarta Persistence API (JPA).
It eases development of applications with a consistent programming model that need to access JPA data sources._
@@ -15,7 +14,7 @@ Upgrade Notes, Supported Versions, additional cross-version information.
Oliver Gierke, Thomas Darimont, Christoph Strobl, Mark Paluch, Jay Bryant, Greg Turnquist
-(C) 2008-2024 VMware, Inc.
+(C) 2008-{copyright-year} VMware, Inc.
Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.
diff --git a/src/main/antora/modules/ROOT/pages/jpa/entity-persistence.adoc b/src/main/antora/modules/ROOT/pages/jpa/entity-persistence.adoc
index 0c8392585e..ac8fcd4a75 100644
--- a/src/main/antora/modules/ROOT/pages/jpa/entity-persistence.adoc
+++ b/src/main/antora/modules/ROOT/pages/jpa/entity-persistence.adoc
@@ -18,7 +18,9 @@ Spring Data JPA offers the following strategies to detect whether an entity is n
Without such a Version-property Spring Data JPA inspects the identifier property of the given entity.
If the identifier property is `null`, then the entity is assumed to be new.
Otherwise, it is assumed to be not new.
-2. Implementing `Persistable`: If an entity implements `Persistable`, Spring Data JPA delegates the new detection to the `isNew(…)` method of the entity. See the link:$$https://docs.spring.io/spring-data/data-commons/docs/current/api/index.html?org/springframework/data/domain/Persistable.html$$[JavaDoc] for details.
+In contrast to other Spring Data modules, JPA considers `0` (zero) as the first inserted version of an entity and therefore, a primitive version property cannot be used to determine whether an entity is new or not.
+2. Implementing `Persistable`: If an entity implements `Persistable`, Spring Data JPA delegates the new detection to the `isNew(…)` method of the entity.
+See the link:{spring-data-commons-javadoc-base}/org/springframework/data/domain/Persistable.html[JavaDoc] for details.
3. Implementing `EntityInformation`: You can customize the `EntityInformation` abstraction used in the `SimpleJpaRepository` implementation by creating a subclass of `JpaRepositoryFactory` and overriding the `getEntityInformation(…)` method accordingly. You then have to register the custom implementation of `JpaRepositoryFactory` as a Spring bean. Note that this should be rarely necessary. See the javadoc:org.springframework.data.jpa.repository.support.JpaRepositoryFactory[JavaDoc] for details.
Option 1 is not an option for entities that use manually assigned identifiers and no version attribute as with those the identifier will always be non-`null`.
@@ -39,7 +41,7 @@ public abstract class AbstractEntity implements Persistable {
return isNew; <2>
}
- @PrePersist <3>
+ @PostPersist <3>
@PostLoad
void markNotNew() {
this.isNew = false;
diff --git a/src/main/antora/modules/ROOT/pages/jpa/query-methods.adoc b/src/main/antora/modules/ROOT/pages/jpa/query-methods.adoc
index 8657d42ae4..e88908aba5 100644
--- a/src/main/antora/modules/ROOT/pages/jpa/query-methods.adoc
+++ b/src/main/antora/modules/ROOT/pages/jpa/query-methods.adoc
@@ -74,7 +74,7 @@ NOTE: `In` and `NotIn` also take any subclass of `Collection` as a parameter as
====
`DISTINCT` can be tricky and not always producing the results you expect.
For example, `select distinct u from User u` will produce a complete different result than `select distinct u.lastname from User u`.
-In the first case, since you are including `User.id`, nothing will duplicated, hence you'll get the whole table, and it would be of `User` objects.
+In the first case, since you are including `User.id`, nothing will be duplicated, hence you'll get the whole table, and it would be of `User` objects.
However, that latter query would narrow the focus to just `User.lastname` and find all unique last names for that table.
This would also yield a `List` result set instead of a `List` result set.
@@ -83,7 +83,7 @@ This would also yield a `List` result set instead of a `List` resu
`countDistinctByLastname(String lastname)` can also produce unexpected results.
Spring Data JPA will derive `select count(distinct u.id) from User u where u.lastname = ?1`.
Again, since `u.id` won't hit any duplicates, this query will count up all the users that had the binding last name.
-Which would the same as `countByLastname(String lastname)`!
+Which would be the same as `countByLastname(String lastname)`!
What is the point of this query anyway? To find the number of people with a given last name? To find the number of _distinct_ people with that binding last name?
To find the number of _distinct last names_? (That last one is an entirely different query!)
@@ -176,8 +176,11 @@ public interface UserRepository extends JpaRepository {
Sometimes, no matter how many features you try to apply, it seems impossible to get Spring Data JPA to apply every thing
you'd like to a query before it is sent to the `EntityManager`.
-You have the ability to get your hands on the query, right before it's sent to the `EntityManager` and "rewrite" it. That is,
-you can make any alterations at the last moment.
+You have the ability to get your hands on the query, right before it's sent to the `EntityManager` and "rewrite" it.
+That is, you can make any alterations at the last moment.
+Query rewriting applies to the actual query and, when applicable, to count queries.
+Count queries are optimized and therefore, either not necessary or a count is obtained through other means, such as derived from a Hibernate `SelectionQuery`.
+
.Declare a QueryRewriter using `@Query`
====
@@ -321,7 +324,7 @@ A similar approach also works with named native queries, by adding the `.count`
Next to obtaining mapped results, native queries allow you to read the raw `Tuple` from the database by choosing a `Map` container as the method's return type.
The resulting map contains key/value pairs representing the actual database column name and the value.
-.Native query retuning raw column name/value pairs
+.Native query returning raw column name/value pairs
====
[source, java]
----
@@ -391,7 +394,7 @@ You have multiple options to consume large query results:
You have learned in the previous chapter about `Pageable` and `PageRequest`.
2. <>.
This is a lighter variant than paging because it does not require the total result count.
-3. <>.
+3. <>.
This method avoids https://use-the-index-luke.com/no-offset[the shortcomings of offset-based result retrieval by leveraging database indexes].
Read more on <> for your particular arrangement.
@@ -503,7 +506,7 @@ public interface ConcreteRepository
In the preceding example, the `MappedTypeRepository` interface is the common parent interface for a few domain types extending `AbstractMappedType`.
It also defines the generic `findAllByAttribute(…)` method, which can be used on instances of the specialized repository interfaces.
-If you now invoke `findByAllAttribute(…)` on `ConcreteRepository`, the query becomes `select t from ConcreteType t where t.attribute = ?1`.
+If you now invoke `findAllByAttribute(…)` on `ConcreteRepository`, the query becomes `select t from ConcreteType t where t.attribute = ?1`.
You can also use Expressions to control arguments may also be used to control method arguments.
In these expressions the entity name is not available, but the arguments are.
@@ -629,6 +632,9 @@ To make sure lifecycle queries are actually invoked, an invocation of `deleteByR
In fact, a derived delete query is a shortcut for running the query and then calling `CrudRepository.delete(Iterable