Skip to content

Commit 2c8fb8d

Browse files
committed
Polishing.
Formatting. Preferring iterative code of streams. Adding `@author` tags for previous changes. Original pull request: #436
1 parent 79b5d52 commit 2c8fb8d

File tree

3 files changed

+58
-54
lines changed

3 files changed

+58
-54
lines changed

src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java

+52-45
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,7 @@
2121
import java.lang.annotation.Annotation;
2222
import java.lang.reflect.AnnotatedElement;
2323
import java.lang.reflect.Member;
24-
import java.util.ArrayList;
25-
import java.util.Collections;
26-
import java.util.HashMap;
27-
import java.util.HashSet;
28-
import java.util.Iterator;
29-
import java.util.List;
30-
import java.util.Locale;
31-
import java.util.Map;
32-
import java.util.Objects;
33-
import java.util.Set;
24+
import java.util.*;
3425
import java.util.regex.Matcher;
3526
import java.util.regex.Pattern;
3627
import java.util.stream.Collectors;
@@ -42,15 +33,16 @@
4233
import javax.persistence.Query;
4334
import javax.persistence.criteria.CriteriaBuilder;
4435
import javax.persistence.criteria.Expression;
36+
import javax.persistence.criteria.Fetch;
4537
import javax.persistence.criteria.From;
4638
import javax.persistence.criteria.Join;
4739
import javax.persistence.criteria.JoinType;
4840
import javax.persistence.metamodel.Attribute;
49-
import javax.persistence.metamodel.Attribute.PersistentAttributeType;
5041
import javax.persistence.metamodel.Bindable;
5142
import javax.persistence.metamodel.ManagedType;
5243
import javax.persistence.metamodel.PluralAttribute;
5344
import javax.persistence.metamodel.SingularAttribute;
45+
import javax.persistence.metamodel.Attribute.PersistentAttributeType;
5446

5547
import org.springframework.core.annotation.AnnotationUtils;
5648
import org.springframework.dao.InvalidDataAccessApiUsageException;
@@ -104,7 +96,8 @@ public abstract class QueryUtils {
10496

10597
private static final Pattern ALIAS_MATCH;
10698
private static final Pattern COUNT_MATCH;
107-
private static final Pattern PROJECTION_CLAUSE = Pattern.compile("select\\s+(?:distinct\\s+)?(.+)\\s+from", Pattern.CASE_INSENSITIVE);
99+
private static final Pattern PROJECTION_CLAUSE = Pattern.compile("select\\s+(?:distinct\\s+)?(.+)\\s+from",
100+
Pattern.CASE_INSENSITIVE);
108101

109102
private static final Pattern NO_DIGITS = Pattern.compile("\\D+");
110103

@@ -114,8 +107,8 @@ public abstract class QueryUtils {
114107
private static final String EQUALS_CONDITION_STRING = "%s.%s = :%s";
115108
private static final Pattern ORDER_BY = Pattern.compile(".*order\\s+by\\s+.*", CASE_INSENSITIVE);
116109

117-
private static final Pattern NAMED_PARAMETER = Pattern
118-
.compile(COLON_NO_DOUBLE_COLON + IDENTIFIER + "|#" + IDENTIFIER, CASE_INSENSITIVE);
110+
private static final Pattern NAMED_PARAMETER = Pattern.compile(COLON_NO_DOUBLE_COLON + IDENTIFIER + "|#" + IDENTIFIER,
111+
CASE_INSENSITIVE);
119112

120113
private static final Pattern CONSTRUCTOR_EXPRESSION;
121114

@@ -490,9 +483,9 @@ public static String createCountQueryFor(String originalQuery, @Nullable String
490483
&& !variable.startsWith("count(") //
491484
&& !variable.contains(","); //
492485

493-
String complexCountValue = matcher.matches() &&
494-
StringUtils.hasText(matcher.group(COMPLEX_COUNT_FIRST_INDEX)) ?
495-
COMPLEX_COUNT_VALUE : COMPLEX_COUNT_LAST_VALUE;
486+
String complexCountValue = matcher.matches() && StringUtils.hasText(matcher.group(COMPLEX_COUNT_FIRST_INDEX))
487+
? COMPLEX_COUNT_VALUE
488+
: COMPLEX_COUNT_LAST_VALUE;
496489

497490
String replacement = useVariable ? SIMPLE_COUNT_VALUE : complexCountValue;
498491
countQuery = matcher.replaceFirst(String.format(COUNT_REPLACEMENT_TEMPLATE, replacement));
@@ -626,15 +619,16 @@ static <T> Expression<T> toExpressionRecursively(From<?, ?> from, PropertyPath p
626619
/**
627620
* Creates an expression with proper inner and left joins by recursively navigating the path
628621
*
629-
* @param from the {@link From}
630-
* @param property the property path
631-
* @param isForSelection is the property navigated for the selection or ordering part of the query?
622+
* @param from the {@link From}
623+
* @param property the property path
624+
* @param isForSelection is the property navigated for the selection or ordering part of the query?
632625
* @param hasRequiredOuterJoin has a parent already required an outer join?
633-
* @param <T> the type of the expression
626+
* @param <T> the type of the expression
634627
* @return the expression
635628
*/
636-
@SuppressWarnings("unchecked") static <T> Expression<T> toExpressionRecursively(From<?, ?> from,
637-
PropertyPath property, boolean isForSelection, boolean hasRequiredOuterJoin) {
629+
@SuppressWarnings("unchecked")
630+
static <T> Expression<T> toExpressionRecursively(From<?, ?> from, PropertyPath property, boolean isForSelection,
631+
boolean hasRequiredOuterJoin) {
638632

639633
String segment = property.getSegment();
640634

@@ -663,16 +657,15 @@ static <T> Expression<T> toExpressionRecursively(From<?, ?> from, PropertyPath p
663657
}
664658

665659
/**
666-
* Checks if this attribute requires an outer join.
667-
* This is the case eg. if it hadn't already been fetched with an inner join and if it's an a optional association,
668-
* and if previous paths has already required outer joins.
669-
* It also ensures outer joins are used even when Hibernate defaults to inner joins (HHH-12712 and HHH-12999).
660+
* Checks if this attribute requires an outer join. This is the case eg. if it hadn't already been fetched with an
661+
* inner join and if it's an a optional association, and if previous paths has already required outer joins. It also
662+
* ensures outer joins are used even when Hibernate defaults to inner joins (HHH-12712 and HHH-12999).
670663
*
671-
* @param from the {@link From} to check for fetches.
672-
* @param property the property path
673-
* @param isForSelection is the property navigated for the selection or ordering part of the query? if true,
674-
* we need to generate an explicit outer join in order to prevent Hibernate to use an
675-
* inner join instead. see https://hibernate.atlassian.net/browse/HHH-12999
664+
* @param from the {@link From} to check for fetches.
665+
* @param property the property path
666+
* @param isForSelection is the property navigated for the selection or ordering part of the query? if true, we need
667+
* to generate an explicit outer join in order to prevent Hibernate to use an inner join instead. see
668+
* https://hibernate.atlassian.net/browse/HHH-12999
676669
* @param hasRequiredOuterJoin has a parent already required an outer join?
677670
* @return whether an outer join is to be used for integrating this attribute in a query.
678671
*/
@@ -696,7 +689,7 @@ private static boolean requiresOuterJoin(From<?, ?> from, PropertyPath property,
696689
if (model instanceof ManagedType) {
697690
managedType = (ManagedType<?>) model;
698691
} else if (model instanceof SingularAttribute
699-
&& ((SingularAttribute<?, ?>) model).getType() instanceof ManagedType) {
692+
&& ((SingularAttribute<?, ?>) model).getType() instanceof ManagedType) {
700693
managedType = (ManagedType<?>) ((SingularAttribute<?, ?>) model).getType();
701694
}
702695
if (managedType != null) {
@@ -760,34 +753,48 @@ private static <T> T getAnnotationProperty(Attribute<?, ?> attribute, String pro
760753
/**
761754
* Returns an existing join for the given attribute if one already exists or creates a new one if not.
762755
*
763-
* @param from the {@link From} to get the current joins from.
756+
* @param from the {@link From} to get the current joins from.
764757
* @param attribute the {@link Attribute} to look for in the current joins.
765-
* @param joinType the join type to create if none was found
758+
* @param joinType the join type to create if none was found
766759
* @return will never be {@literal null}.
767760
*/
768761
private static Join<?, ?> getOrCreateJoin(From<?, ?> from, String attribute, JoinType joinType) {
769-
return from.getJoins().stream()
770-
.filter(join -> join.getAttribute().getName().equals(attribute))
771-
.findFirst()
772-
.orElseGet(() -> from.join(attribute, joinType));
762+
763+
for (Join<?, ?> join : from.getJoins()) {
764+
765+
if (join.getAttribute().getName().equals(attribute)) {
766+
return join;
767+
}
768+
}
769+
return from.join(attribute, joinType);
773770
}
774771

775772
/**
776773
* Return whether the given {@link From} contains an inner join for the attribute with the given name.
777774
*
778-
* @param from the {@link From} to check for joins.
775+
* @param from the {@link From} to check for joins.
779776
* @param attribute the attribute name to check.
780777
* @return true if the attribute has already been inner joined
781778
*/
782779
private static boolean isAlreadyInnerJoined(From<?, ?> from, String attribute) {
783780

784-
boolean isInnerJoinFetched = from.getFetches().stream().anyMatch(
785-
fetch -> fetch.getAttribute().getName().equals(attribute) && fetch.getJoinType().equals(JoinType.INNER));
781+
for (Fetch<?, ?> fetch : from.getFetches()) {
786782

787-
boolean isSimplyInnerJoined = from.getJoins().stream()
788-
.anyMatch(join -> join.getAttribute().getName().equals(attribute) && join.getJoinType().equals(JoinType.INNER));
783+
if (fetch.getAttribute().getName().equals(attribute) //
784+
&& fetch.getJoinType().equals(JoinType.INNER)) {
785+
return true;
786+
}
787+
}
788+
789+
for (Join<?, ?> join : from.getJoins()) {
790+
791+
if (join.getAttribute().getName().equals(attribute) //
792+
&& join.getJoinType().equals(JoinType.INNER)) {
793+
return true;
794+
}
795+
}
789796

790-
return isInnerJoinFetched || isSimplyInnerJoined;
797+
return false;
791798
}
792799

793800
/**

src/test/java/org/springframework/data/jpa/repository/query/EclipseLinkQueryUtilsIntegrationTests.java

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
/**
2121
* @author Oliver Gierke
22+
* @author Jens Schauder
2223
*/
2324
@ContextConfiguration("classpath:eclipselink.xml")
2425
public class EclipseLinkQueryUtilsIntegrationTests extends QueryUtilsIntegrationTests {

src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsIntegrationTests.java

+5-9
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
*
6464
* @author Oliver Gierke
6565
* @author Sébastien Péralta
66+
* @author Jens Schauder
6667
* @author Patrice Blanchardie
6768
*/
6869
@RunWith(SpringJUnit4ClassRunner.class)
@@ -114,7 +115,7 @@ public void createsJoinForOptionalOneToOneInReverseDirection() {
114115
});
115116
}
116117

117-
@Test // DATAJPA-1822
118+
@Test // gh-2111
118119
void createsLeftJoinForOptionalToOneWithNestedNonOptional() {
119120

120121
CriteriaBuilder builder = em.getCriteriaBuilder();
@@ -130,7 +131,7 @@ void createsLeftJoinForOptionalToOneWithNestedNonOptional() {
130131
assertThat(getInnerJoins(leftJoin)).isEmpty(); // no inner join customer
131132
}
132133

133-
@Test // DATAJPA-1822
134+
@Test // gh-2111
134135
void createsLeftJoinForNonOptionalToOneWithNestedOptional() {
135136

136137
CriteriaBuilder builder = em.getCriteriaBuilder();
@@ -149,7 +150,7 @@ void createsLeftJoinForNonOptionalToOneWithNestedOptional() {
149150
assertThat(getInnerJoins(leftJoin)).isEmpty(); // no inner join customer
150151
}
151152

152-
@Test // DATAJPA-1822
153+
@Test // gh-2111
153154
void reusesLeftJoinForNonOptionalToOneWithNestedOptional() {
154155

155156
CriteriaBuilder builder = em.getCriteriaBuilder();
@@ -173,7 +174,7 @@ void reusesLeftJoinForNonOptionalToOneWithNestedOptional() {
173174
assertThat(getNonInnerJoins(leftJoin)).hasSize(1); // left join customer
174175
}
175176

176-
@Test // DATAJPA-1822
177+
@Test // gh-2111
177178
void reusesInnerJoinForNonOptionalToOneWithNestedOptional() {
178179

179180
CriteriaBuilder builder = em.getCriteriaBuilder();
@@ -331,11 +332,6 @@ int getNumberOfJoinsAfterCreatingAPath() {
331332
return 0;
332333
}
333334

334-
private Set<Join<?, ?>> getNonInnerJoins(Root<?> root) {
335-
336-
return getNonInnerJoins((From<?, ?>) root);
337-
}
338-
339335
private Set<Join<?, ?>> getNonInnerJoins(From<?, ?> root) {
340336

341337
return root.getJoins().stream().filter(j -> j.getJoinType() != JoinType.INNER).collect(Collectors.toSet());

0 commit comments

Comments
 (0)