29
29
import jakarta .persistence .criteria .From ;
30
30
import jakarta .persistence .criteria .Join ;
31
31
import jakarta .persistence .criteria .JoinType ;
32
+ import jakarta .persistence .criteria .Path ;
32
33
import jakarta .persistence .metamodel .Attribute ;
33
34
import jakarta .persistence .metamodel .Attribute .PersistentAttributeType ;
34
35
import jakarta .persistence .metamodel .Bindable ;
@@ -824,45 +825,18 @@ static <T> Expression<T> toExpressionRecursively(From<?, ?> from, PropertyPath p
824
825
private static boolean requiresOuterJoin (From <?, ?> from , PropertyPath property , boolean isForSelection ,
825
826
boolean hasRequiredOuterJoin ) {
826
827
827
- String segment = property .getSegment ();
828
-
829
828
// already inner joined so outer join is useless
830
- if (isAlreadyInnerJoined (from , segment ))
829
+ if (isAlreadyInnerJoined (from , property . getSegment ())) {
831
830
return false ;
831
+ }
832
832
833
- Bindable <?> propertyPathModel ;
834
833
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 );
860
836
861
837
// is the attribute of Collection type?
862
838
boolean isPluralAttribute = model instanceof PluralAttribute ;
863
839
864
- boolean isLeafProperty = !property .hasNext ();
865
-
866
840
if (propertyPathModel == null && isPluralAttribute ) {
867
841
return true ;
868
842
}
@@ -883,6 +857,7 @@ private static boolean requiresOuterJoin(From<?, ?> from, PropertyPath property,
883
857
boolean isInverseOptionalOneToOne = PersistentAttributeType .ONE_TO_ONE == attribute .getPersistentAttributeType ()
884
858
&& StringUtils .hasText (getAnnotationProperty (attribute , "mappedBy" , "" ));
885
859
860
+ boolean isLeafProperty = !property .hasNext ();
886
861
if (isLeafProperty && !isForSelection && !isCollection && !isInverseOptionalOneToOne && !hasRequiredOuterJoin ) {
887
862
return false ;
888
863
}
@@ -972,4 +947,57 @@ static void checkSortExpression(Order order) {
972
947
throw new InvalidDataAccessApiUsageException (String .format (UNSAFE_PROPERTY_REFERENCE , order ));
973
948
}
974
949
}
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
+ }
975
1003
}
0 commit comments