Skip to content

Commit 128f7da

Browse files
Polishing.
Move model resolution for path to dedicated methods. Original Pull Request: #3375
1 parent 292c297 commit 128f7da

File tree

1 file changed

+59
-31
lines changed
  • spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query

1 file changed

+59
-31
lines changed

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

Lines changed: 59 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import jakarta.persistence.criteria.From;
3030
import jakarta.persistence.criteria.Join;
3131
import jakarta.persistence.criteria.JoinType;
32+
import jakarta.persistence.criteria.Path;
3233
import jakarta.persistence.metamodel.Attribute;
3334
import jakarta.persistence.metamodel.Attribute.PersistentAttributeType;
3435
import jakarta.persistence.metamodel.Bindable;
@@ -824,45 +825,18 @@ static <T> Expression<T> toExpressionRecursively(From<?, ?> from, PropertyPath p
824825
private static boolean requiresOuterJoin(From<?, ?> from, PropertyPath property, boolean isForSelection,
825826
boolean hasRequiredOuterJoin) {
826827

827-
String segment = property.getSegment();
828-
829828
// already inner joined so outer join is useless
830-
if (isAlreadyInnerJoined(from, segment))
829+
if (isAlreadyInnerJoined(from, property.getSegment())) {
831830
return false;
831+
}
832832

833-
Bindable<?> propertyPathModel;
834833
Bindable<?> model = from.getModel();
835-
836-
// required for EclipseLink: we try to avoid using from.get as EclipseLink produces an inner join
837-
// regardless of which join operation is specified next
838-
// see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=413892
839-
// still occurs as of 2.7
840-
ManagedType<?> managedType = null;
841-
if (model instanceof ManagedType) {
842-
managedType = (ManagedType<?>) model;
843-
} else if (model instanceof SingularAttribute
844-
&& ((SingularAttribute<?, ?>) model).getType() instanceof ManagedType) {
845-
managedType = (ManagedType<?>) ((SingularAttribute<?, ?>) model).getType();
846-
}
847-
if (managedType != null) {
848-
try {
849-
propertyPathModel = (Bindable<?>) managedType.getAttribute(segment);
850-
} catch (IllegalArgumentException ex) {
851-
// ManagedType may be erased type for some vendor if the attribute is declared as generic
852-
// see: https://hibernate.atlassian.net/browse/HHH-16144
853-
// see: https://github.com/hibernate/hibernate-orm/pull/7630
854-
// see: https://github.com/jakartaee/persistence/issues/562
855-
propertyPathModel = from.get(segment).getModel();
856-
}
857-
} else {
858-
propertyPathModel = from.get(segment).getModel();
859-
}
834+
ManagedType<?> managedType = getManagedTypeForModel(model);
835+
Bindable<?> propertyPathModel = getModelForPath(property, managedType, from);
860836

861837
// is the attribute of Collection type?
862838
boolean isPluralAttribute = model instanceof PluralAttribute;
863839

864-
boolean isLeafProperty = !property.hasNext();
865-
866840
if (propertyPathModel == null && isPluralAttribute) {
867841
return true;
868842
}
@@ -883,6 +857,7 @@ private static boolean requiresOuterJoin(From<?, ?> from, PropertyPath property,
883857
boolean isInverseOptionalOneToOne = PersistentAttributeType.ONE_TO_ONE == attribute.getPersistentAttributeType()
884858
&& StringUtils.hasText(getAnnotationProperty(attribute, "mappedBy", ""));
885859

860+
boolean isLeafProperty = !property.hasNext();
886861
if (isLeafProperty && !isForSelection && !isCollection && !isInverseOptionalOneToOne && !hasRequiredOuterJoin) {
887862
return false;
888863
}
@@ -972,4 +947,57 @@ static void checkSortExpression(Order order) {
972947
throw new InvalidDataAccessApiUsageException(String.format(UNSAFE_PROPERTY_REFERENCE, order));
973948
}
974949
}
950+
951+
/**
952+
* Get the {@link Bindable model} that corresponds to the given path utilizing the given {@link ManagedType} if
953+
* present or resolving the model from the {@link Path#getModel() path} by creating it via {@link From#get(String)} in
954+
* case where the type signature may be erased by some vendors if the attribute contains generics.
955+
*
956+
* @param path the current {@link PropertyPath} segment.
957+
* @param managedType primary source for the resulting {@link Bindable}. Can be {@literal null}.
958+
* @param fallback must not be {@literal null}.
959+
* @return the corresponding {@link Bindable} of {@literal null}.
960+
* @see <a href=
961+
* "https://hibernate.atlassian.net/browse/HHH-16144">https://hibernate.atlassian.net/browse/HHH-16144</a>
962+
* @see <a href=
963+
* "https://github.com/jakartaee/persistence/issues/562">https://github.com/jakartaee/persistence/issues/562</a>
964+
*/
965+
@Nullable
966+
private static Bindable<?> getModelForPath(PropertyPath path, @Nullable ManagedType<?> managedType,
967+
Path<?> fallback) {
968+
969+
String segment = path.getSegment();
970+
if (managedType != null) {
971+
try {
972+
return (Bindable<?>) managedType.getAttribute(segment);
973+
} catch (IllegalArgumentException ex) {
974+
// ManagedType may be erased for some vendor if the attribute is declared as generic
975+
}
976+
}
977+
978+
return fallback.get(segment).getModel();
979+
}
980+
981+
/**
982+
* Required for EclipseLink: we try to avoid using from.get as EclipseLink produces an inner join regardless of which
983+
* join operation is specified next
984+
*
985+
* @see <a href=
986+
* "https://bugs.eclipse.org/bugs/show_bug.cgi?id=413892">https://bugs.eclipse.org/bugs/show_bug.cgi?id=413892</a>
987+
* @param model
988+
* @return
989+
*/
990+
@Nullable
991+
private static ManagedType<?> getManagedTypeForModel(Bindable<?> model) {
992+
993+
if (model instanceof ManagedType<?> managedType) {
994+
return managedType;
995+
}
996+
997+
if (!(model instanceof SingularAttribute<?, ?> singularAttribute)) {
998+
return null;
999+
}
1000+
1001+
return singularAttribute.getType() instanceof ManagedType<?> managedType ? managedType : null;
1002+
}
9751003
}

0 commit comments

Comments
 (0)