@@ -259,10 +259,19 @@ protected Object invokeMethod(Method method, @Nullable Object[] args, Object tar
259259 Object result = method .invoke (target , args );
260260 if (result instanceof Query query ) {
261261 if (newTarget ) {
262+ InvocationHandler ih = new DeferredQueryInvocationHandler (query , target );
262263 Class <?>[] ifcs = cachedQueryInterfaces .computeIfAbsent (query .getClass (), key ->
263264 ClassUtils .getAllInterfacesForClass (key , this .proxyClassLoader ));
264- result = Proxy .newProxyInstance (this .proxyClassLoader , ifcs ,
265- new DeferredQueryInvocationHandler (query , target ));
265+ try {
266+ result = Proxy .newProxyInstance (this .proxyClassLoader , ifcs , ih );
267+ }
268+ catch (IllegalArgumentException ex ) {
269+ // Hibernate 8.0 NativeMutationOrSelectionQueryImpl multi-interface mismatch?
270+ // Fall back to single declared interface from method signature.
271+ Class <?>[] singleIfc = new Class <?>[] {method .getReturnType ()};
272+ cachedQueryInterfaces .put (query .getClass (), singleIfc );
273+ result = Proxy .newProxyInstance (this .proxyClassLoader , singleIfc , ih );
274+ }
266275 close = false ;
267276 }
268277 else {
@@ -523,7 +532,7 @@ private static class DeferredQueryInvocationHandler implements InvocationHandler
523532
524533 private @ Nullable Map <@ Nullable Object , @ Nullable Object > outputParameters ;
525534
526- public DeferredQueryInvocationHandler (Query target , Object entityHandler ) {
535+ public DeferredQueryInvocationHandler (Query target , @ Nullable Object entityHandler ) {
527536 this .target = target ;
528537 this .entityHandler = entityHandler ;
529538 }
@@ -551,7 +560,11 @@ else if (targetClass.isInstance(proxy)) {
551560 return proxy ;
552561 }
553562 else {
554- return this .target .unwrap (targetClass );
563+ Object retVal = this .target .unwrap (targetClass );
564+ if (retVal instanceof Query query && targetClass .isInterface ()) {
565+ retVal = adaptQueryProxy (proxy , query , targetClass );
566+ }
567+ return retVal ;
555568 }
556569 }
557570 case "getOutputParameterValue" -> {
@@ -572,14 +585,21 @@ else if (targetClass.isInstance(proxy)) {
572585 // Invoke method on actual Query object.
573586 try {
574587 Object retVal = method .invoke (this .target , args );
575- if (method .getName ().equals ("registerStoredProcedureParameter" ) && args .length == 3 &&
588+ Class <?> returnType = method .getReturnType ();
589+ if (retVal == this .target && returnType .isInstance (proxy )) {
590+ retVal = proxy ;
591+ }
592+ else if (retVal instanceof Query query ) {
593+ retVal = adaptQueryProxy (proxy , query , returnType );
594+ }
595+ else if (method .getName ().equals ("registerStoredProcedureParameter" ) && args .length == 3 &&
576596 (args [2 ] == ParameterMode .OUT || args [2 ] == ParameterMode .INOUT )) {
577597 if (this .outputParameters == null ) {
578598 this .outputParameters = new LinkedHashMap <>();
579599 }
580600 this .outputParameters .put (args [0 ], null );
581601 }
582- return ( retVal == this . target ? proxy : retVal ) ;
602+ return retVal ;
583603 }
584604 catch (InvocationTargetException ex ) {
585605 throw ex .getTargetException ();
@@ -609,6 +629,14 @@ else if (targetClass.isInstance(proxy)) {
609629 }
610630 }
611631 }
632+
633+ private Object adaptQueryProxy (Object proxy , Query query , Class <?> expectedType ) {
634+ InvocationHandler ih = this ;
635+ if (query != this .target ) {
636+ ih = new DeferredQueryInvocationHandler (query , this .entityHandler );
637+ }
638+ return Proxy .newProxyInstance (proxy .getClass ().getClassLoader (), new Class <?>[] {expectedType }, ih );
639+ }
612640 }
613641
614642}
0 commit comments