2424import java .util .List ;
2525
2626import org .springframework .data .jpa .provider .PersistenceProvider ;
27- import org .springframework .data .jpa .repository .query .JpaParameters .JpaParameter ;
2827import org .springframework .data .repository .query .parser .Part .Type ;
2928import org .springframework .lang .Nullable ;
3029import org .springframework .util .Assert ;
@@ -151,8 +150,8 @@ public Object prepare(@Nullable Object valueToBind) {
151150 /**
152151 * Check whether the {@code other} binding uses the same bind target.
153152 *
154- * @param other
155- * @return
153+ * @param other must not be {@literal null}.
154+ * @return {@code true} if the other binding uses the same parameter to bind to as this one.
156155 */
157156 public boolean bindsTo (ParameterBinding other ) {
158157
@@ -171,6 +170,17 @@ public boolean bindsTo(ParameterBinding other) {
171170 return false ;
172171 }
173172
173+ /**
174+ * Check whether this binding can be bound as the {@code other} binding by checking its type and origin. Subclasses
175+ * may override this method to include other properties for the compatibility check.
176+ *
177+ * @param other
178+ * @return {@code true} if the other binding is compatible with this one.
179+ */
180+ public boolean isCompatibleWith (ParameterBinding other ) {
181+ return other .getClass () == getClass () && other .getOrigin ().equals (getOrigin ());
182+ }
183+
174184 /**
175185 * Represents a {@link ParameterBinding} in a JPQL query augmented with instructions of how to apply a parameter as an
176186 * {@code IN} parameter.
@@ -294,6 +304,16 @@ public String toString() {
294304 getType ());
295305 }
296306
307+ @ Override
308+ public boolean isCompatibleWith (ParameterBinding binding ) {
309+
310+ if (super .isCompatibleWith (binding ) && binding instanceof LikeParameterBinding other ) {
311+ return getType () == other .getType ();
312+ }
313+
314+ return false ;
315+ }
316+
297317 /**
298318 * Extracts the like {@link Type} from the given JPA like expression.
299319 *
@@ -319,52 +339,12 @@ static Type getLikeTypeFrom(String expression) {
319339 }
320340 }
321341
322- static class ParameterImpl <T > implements jakarta .persistence .Parameter <T > {
323-
324- private final BindingIdentifier identifier ;
325- private final Class <T > parameterType ;
326-
327- /**
328- * Creates a new {@link ParameterImpl} for the given {@link JpaParameter} and {@link ParameterBinding}.
329- *
330- * @param parameter can be {@literal null}.
331- * @param binding must not be {@literal null}.
332- * @return a {@link jakarta.persistence.Parameter} object based on the information from the arguments.
333- */
334- static jakarta .persistence .Parameter <?> of (@ Nullable JpaParameter parameter , ParameterBinding binding ) {
335-
336- Class <?> type = parameter == null ? Object .class : parameter .getType ();
337-
338- return new ParameterImpl <>(binding .getIdentifier (), type );
339- }
340-
341- public ParameterImpl (BindingIdentifier identifier , Class <T > parameterType ) {
342- this .identifier = identifier ;
343- this .parameterType = parameterType ;
344- }
345-
346- @ Nullable
347- @ Override
348- public String getName () {
349- return identifier .hasName () ? identifier .getName () : null ;
350- }
351-
352- @ Nullable
353- @ Override
354- public Integer getPosition () {
355- return identifier .hasPosition () ? identifier .getPosition () : null ;
356- }
357-
358- @ Override
359- public Class <T > getParameterType () {
360- return parameterType ;
361- }
362-
363- }
364-
365342 /**
366343 * Identifies a binding parameter by name, position or both. Used to bind parameters to a query or to describe a
367344 * {@link MethodInvocationArgument} origin.
345+ *
346+ * @author Mark Paluch
347+ * @since 3.1.2
368348 */
369349 sealed interface BindingIdentifier permits Named ,Indexed ,NamedAndIndexed {
370350
@@ -453,6 +433,11 @@ public boolean hasName() {
453433 public String getName () {
454434 return name ();
455435 }
436+
437+ @ Override
438+ public String toString () {
439+ return name ();
440+ }
456441 }
457442
458443 private record Indexed (int position ) implements BindingIdentifier {
@@ -466,6 +451,11 @@ public boolean hasPosition() {
466451 public int getPosition () {
467452 return position ();
468453 }
454+
455+ @ Override
456+ public String toString () {
457+ return "[" + position () + "]" ;
458+ }
469459 }
470460
471461 private record NamedAndIndexed (String name , int position ) implements BindingIdentifier {
@@ -489,10 +479,18 @@ public boolean hasPosition() {
489479 public int getPosition () {
490480 return position ();
491481 }
482+
483+ @ Override
484+ public String toString () {
485+ return "[" + name () + ", " + position () + "]" ;
486+ }
492487 }
493488
494489 /**
495490 * Value type hierarchy to describe where a binding parameter comes from, either method call or an expression.
491+ *
492+ * @author Mark Paluch
493+ * @since 3.1.2
496494 */
497495 sealed interface ParameterOrigin permits Expression ,MethodInvocationArgument {
498496
@@ -508,11 +506,11 @@ static Expression ofExpression(String expression) {
508506
509507 /**
510508 * Creates a {@link MethodInvocationArgument} object for {@code name} and {@code position}. Either the name or the
511- * position must be given,
509+ * position must be given.
512510 *
513511 * @param name the parameter name from the method invocation, can be {@literal null}.
514512 * @param position the parameter position (1-based) from the method invocation, can be {@literal null}.
515- * @return {@link MethodInvocationArgument} object for {@code name} and {@code position}
513+ * @return {@link MethodInvocationArgument} object for {@code name} and {@code position}.
516514 */
517515 static MethodInvocationArgument ofParameter (@ Nullable String name , @ Nullable Integer position ) {
518516
@@ -528,26 +526,43 @@ static MethodInvocationArgument ofParameter(@Nullable String name, @Nullable Int
528526 return ofParameter (identifier );
529527 }
530528
529+ /**
530+ * Creates a {@link MethodInvocationArgument} object for {@code position}.
531+ *
532+ * @param position the parameter position (1-based) from the method invocation.
533+ * @return {@link MethodInvocationArgument} object for {@code position}.
534+ */
535+ static MethodInvocationArgument ofParameter (int position ) {
536+ return ofParameter (BindingIdentifier .of (position ));
537+ }
538+
531539 /**
532540 * Creates a {@link MethodInvocationArgument} using {@link BindingIdentifier}.
533541 *
534542 * @param identifier must not be {@literal null}.
535543 * @return {@link MethodInvocationArgument} for {@link BindingIdentifier}.
536544 */
537545 static MethodInvocationArgument ofParameter (BindingIdentifier identifier ) {
538-
539546 return new MethodInvocationArgument (identifier );
540547 }
541548
549+ /**
550+ * @return {@code true} if the origin is a method argument reference.
551+ */
542552 boolean isMethodArgument ();
543553
554+ /**
555+ * @return {@code true} if the origin is an expression.
556+ */
544557 boolean isExpression ();
545558 }
546559
547560 /**
548561 * Value object capturing the expression of which a binding parameter originates.
549562 *
550563 * @param expression
564+ * @author Mark Paluch
565+ * @since 3.1.2
551566 */
552567 public record Expression (String expression ) implements ParameterOrigin {
553568
@@ -566,6 +581,8 @@ public boolean isExpression() {
566581 * Value object capturing the method invocation parameter reference.
567582 *
568583 * @param identifier
584+ * @author Mark Paluch
585+ * @since 3.1.2
569586 */
570587 public record MethodInvocationArgument (BindingIdentifier identifier ) implements ParameterOrigin {
571588
0 commit comments