Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: spring-projects/spring-data-jpa
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 3.4.3
Choose a base ref
...
head repository: spring-projects/spring-data-jpa
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 3.4.4
Choose a head ref
  • 12 commits
  • 16 files changed
  • 3 contributors

Commits on Feb 14, 2025

  1. Prepare next development iteration.

    See #3747
    mp911de committed Feb 14, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    e9be8e2 View commit details
  2. After release cleanups.

    See #3747
    mp911de committed Feb 14, 2025
    Copy the full SHA
    187754a View commit details

Commits on Feb 24, 2025

  1. Refine count-query derivation parameter post-processing.

    We've now expanded parameter post-processing for derived count queries to consider binding types (in, like) and to correctly retain invocation parameter redirects instead of assuming an exact mapping of parameter positions in the final query to the actual invocation argument names/indices.
    
    Closes #3784
    mp911de committed Feb 24, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    7f170ea View commit details

Commits on Feb 25, 2025

  1. Reuse existing FETCH JOINs when creating Expressions from PropertyPath.

    We now consider existing fetch joins for attributes when CriteriaQuery has used a fetch join already. This helps Hibernate to e.g. include mandatory fields in the select list when using DISTINCT using fetch joins.
    
    Closes #2756
    mp911de committed Feb 25, 2025

    Partially verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    We cannot verify signatures from co-authors, and some of the co-authors attributed to this commit require their commits to be signed.
    Copy the full SHA
    d34899a View commit details
  2. Upgrade to Hibernate 6.6.9.Final.

    Closes #3788
    mp911de committed Feb 25, 2025
    Copy the full SHA
    4cb6518 View commit details

Commits on Mar 3, 2025

  1. Refine entity state detection wording using primitive versions.

    Closes #3798
    mp911de committed Mar 3, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    668c335 View commit details
  2. Fix regression in HQL parsing when primary alias is missing.

    Original pull request: #3793
    Closes #3792
    christophstrobl authored and mp911de committed Mar 3, 2025
    Copy the full SHA
    7ea9391 View commit details

Commits on Mar 6, 2025

  1. Consider MatchMode when joining associations for QueryByExample.

    This commit makes sure to use different join types depending on the actual match mode.
    
    Closes: #3763
    Original Pull Request: #3794
    
    Signed-off-by: ArnaudLec <lec.arnaud+github@gmail.com>
    ArnaudLec authored and christophstrobl committed Mar 6, 2025
    Copy the full SHA
    99840c9 View commit details
  2. Add integration test for QueryByExample match mode on associations.

    Original Pull Request: #3794
    christophstrobl committed Mar 6, 2025
    Copy the full SHA
    85429ff View commit details

Commits on Mar 11, 2025

  1. Upgrade to Hibernate 6.6.10.Final.

    Closes #3809
    mp911de committed Mar 11, 2025
    Copy the full SHA
    b35a116 View commit details

Commits on Mar 14, 2025

  1. Prepare 3.4.4 (2024.1.4).

    See #3776
    mp911de committed Mar 14, 2025
    Copy the full SHA
    04a3cd9 View commit details
  2. Release version 3.4.4 (2024.1.4).

    See #3776
    mp911de committed Mar 14, 2025
    Copy the full SHA
    3ea732c View commit details
12 changes: 6 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.4.3</version>
<version>3.4.4</version>
<packaging>pom</packaging>

<name>Spring Data JPA Parent</name>
@@ -23,16 +23,16 @@
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>3.4.3</version>
<version>3.4.4</version>
</parent>

<properties>
<antlr>4.13.0</antlr> <!-- align with Hibernate's parser -->
<eclipselink>4.0.5</eclipselink>
<eclipselink-next>4.0.6-SNAPSHOT</eclipselink-next>
<hibernate>6.6.7.Final</hibernate>
<hibernate-62>6.2.32.Final</hibernate-62>
<hibernate-66-snapshots>6.6.8-SNAPSHOT</hibernate-66-snapshots>
<hibernate>6.6.10.Final</hibernate>
<hibernate-62>6.2.33.Final</hibernate-62>
<hibernate-66-snapshots>6.6.11-SNAPSHOT</hibernate-66-snapshots>
<hibernate-70>7.0.0.Beta1</hibernate-70>
<hibernate-70-snapshots>7.0.0-SNAPSHOT</hibernate-70-snapshots>
<hsqldb>2.7.4</hsqldb>
@@ -41,7 +41,7 @@
<jsqlparser>5.0</jsqlparser>
<mysql-connector-java>9.1.0</mysql-connector-java>
<postgresql>42.7.4</postgresql>
<springdata.commons>3.4.3</springdata.commons>
<springdata.commons>3.4.4</springdata.commons>
<vavr>0.10.3</vavr>

<hibernate.groupId>org.hibernate</hibernate.groupId>
4 changes: 2 additions & 2 deletions spring-data-envers/pom.xml
Original file line number Diff line number Diff line change
@@ -5,12 +5,12 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-envers</artifactId>
<version>3.4.3</version>
<version>3.4.4</version>

<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.4.3</version>
<version>3.4.4</version>
<relativePath>../pom.xml</relativePath>
</parent>

2 changes: 1 addition & 1 deletion spring-data-jpa-distribution/pom.xml
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.4.3</version>
<version>3.4.4</version>
<relativePath>../pom.xml</relativePath>
</parent>

4 changes: 2 additions & 2 deletions spring-data-jpa/pom.xml
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>3.4.3</version>
<version>3.4.4</version>

<name>Spring Data JPA</name>
<description>Spring Data module for JPA repositories.</description>
@@ -16,7 +16,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>3.4.3</version>
<version>3.4.4</version>
<relativePath>../pom.xml</relativePath>
</parent>

Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.From;
import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
@@ -35,6 +36,7 @@
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.ExampleMatcher.MatchMode;
import org.springframework.data.domain.ExampleMatcher.PropertyValueTransformer;
import org.springframework.data.jpa.repository.query.EscapeCharacter;
import org.springframework.data.support.ExampleMatcherAccessor;
@@ -57,6 +59,7 @@
* @author Oliver Gierke
* @author Jens Schauder
* @author Greg Turnquist
* @author Arnaud Lecointre
* @since 1.10
*/
public class QueryByExamplePredicateBuilder {
@@ -103,8 +106,8 @@ public static <T> Predicate getPredicate(Root<T> root, CriteriaBuilder cb, Examp
ExampleMatcher matcher = example.getMatcher();

List<Predicate> predicates = getPredicates("", cb, root, root.getModel(), example.getProbe(),
example.getProbeType(), new ExampleMatcherAccessor(matcher), new PathNode("root", null, example.getProbe()),
escapeCharacter);
example.getProbeType(), matcher.getMatchMode(), new ExampleMatcherAccessor(matcher),
new PathNode("root", null, example.getProbe()), escapeCharacter);

if (predicates.isEmpty()) {
return null;
@@ -121,7 +124,7 @@ public static <T> Predicate getPredicate(Root<T> root, CriteriaBuilder cb, Examp

@SuppressWarnings({ "rawtypes", "unchecked" })
static List<Predicate> getPredicates(String path, CriteriaBuilder cb, Path<?> from, ManagedType<?> type, Object value,
Class<?> probeType, ExampleMatcherAccessor exampleAccessor, PathNode currentNode,
Class<?> probeType, MatchMode matchMode, ExampleMatcherAccessor exampleAccessor, PathNode currentNode,
EscapeCharacter escapeCharacter) {

List<Predicate> predicates = new ArrayList<>();
@@ -158,7 +161,7 @@ static List<Predicate> getPredicates(String path, CriteriaBuilder cb, Path<?> fr

predicates
.addAll(getPredicates(currentPath, cb, from.get(attribute.getName()), (ManagedType<?>) attribute.getType(),
attributeValue, probeType, exampleAccessor, currentNode, escapeCharacter));
attributeValue, probeType, matchMode, exampleAccessor, currentNode, escapeCharacter));
continue;
}

@@ -171,8 +174,10 @@ static List<Predicate> getPredicates(String path, CriteriaBuilder cb, Path<?> fr
ClassUtils.getShortName(probeType), node));
}

predicates.addAll(getPredicates(currentPath, cb, ((From<?, ?>) from).join(attribute.getName()),
(ManagedType<?>) attribute.getType(), attributeValue, probeType, exampleAccessor, node, escapeCharacter));
JoinType joinType = matchMode.equals(MatchMode.ALL) ? JoinType.INNER : JoinType.LEFT;
predicates.addAll(getPredicates(currentPath, cb, ((From<?, ?>) from).join(attribute.getName(), joinType),
(ManagedType<?>) attribute.getType(), attributeValue, probeType, matchMode, exampleAccessor, node,
escapeCharacter));

continue;
}
Original file line number Diff line number Diff line change
@@ -100,8 +100,13 @@ public QueryRendererBuilder visitFromQuery(HqlParser.FromQueryContext ctx) {

if (ctx.fromClause() != null) {
builder.appendExpression(visit(ctx.fromClause()));
if(primaryFromAlias == null) {
builder.append(TOKEN_AS);
builder.append(TOKEN_DOUBLE_UNDERSCORE);
}
}


if (ctx.whereClause() != null) {
builder.appendExpression(visit(ctx.whereClause()));
}
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -889,7 +889,7 @@ private static <T> 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 +898,13 @@ private static <T> 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)) {
Original file line number Diff line number Diff line change
@@ -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;

@@ -141,8 +142,12 @@ public DeclaredQuery deriveCountQuery(@Nullable String countQueryProjection) {

for (ParameterBinding binding : bindings) {

if (binding.getOrigin().isExpression() && derivedBindings.removeIf(
it -> !it.getOrigin().isExpression() && it.getIdentifier().equals(binding.getIdentifier()))) {
Predicate<ParameterBinding> identifier = binding::bindsTo;
Predicate<ParameterBinding> notCompatible = Predicate.not(binding::isCompatibleWith);

// replace incompatible bindings
if ( derivedBindings.removeIf(
it -> identifier.test(it) && notCompatible.test(it))) {
derivedBindings.add(binding);
}
}
Original file line number Diff line number Diff line change
@@ -16,13 +16,15 @@
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.*;

import jakarta.persistence.Id;
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<Person> example = of(person, matcher);

QueryByExamplePredicateBuilder.getPredicate(root, cb, example, EscapeCharacter.DEFAULT);

verify(root, times(1)).join("father", expectedJoinType);
}

@SuppressWarnings("unused")
static class Person {

Loading