@@ -239,10 +239,19 @@ protected Object invokeMethod(Method method, @Nullable Object[] args, Object tar
239239 Object result = method .invoke (target , args );
240240 if (result instanceof Query query ) {
241241 if (newTarget ) {
242+ InvocationHandler ih = new DeferredQueryInvocationHandler (query , target );
242243 Class <?>[] ifcs = cachedQueryInterfaces .computeIfAbsent (query .getClass (), key ->
243244 ClassUtils .getAllInterfacesForClass (key , this .proxyClassLoader ));
244- result = Proxy .newProxyInstance (this .proxyClassLoader , ifcs ,
245- new DeferredQueryInvocationHandler (query , target ));
245+ try {
246+ result = Proxy .newProxyInstance (this .proxyClassLoader , ifcs , ih );
247+ }
248+ catch (IllegalArgumentException ex ) {
249+ // Hibernate 8.0 NativeMutationOrSelectionQueryImpl multi-interface mismatch?
250+ // Fall back to single declared interface from method signature.
251+ Class <?>[] singleIfc = new Class <?>[] {method .getReturnType ()};
252+ cachedQueryInterfaces .put (query .getClass (), singleIfc );
253+ result = Proxy .newProxyInstance (this .proxyClassLoader , singleIfc , ih );
254+ }
246255 close = false ;
247256 }
248257 else {
@@ -503,7 +512,7 @@ private static class DeferredQueryInvocationHandler implements InvocationHandler
503512
504513 private @ Nullable Map <@ Nullable Object , @ Nullable Object > outputParameters ;
505514
506- public DeferredQueryInvocationHandler (Query target , Object entityHandler ) {
515+ public DeferredQueryInvocationHandler (Query target , @ Nullable Object entityHandler ) {
507516 this .target = target ;
508517 this .entityHandler = entityHandler ;
509518 }
@@ -531,7 +540,11 @@ else if (targetClass.isInstance(proxy)) {
531540 return proxy ;
532541 }
533542 else {
534- return this .target .unwrap (targetClass );
543+ Object retVal = this .target .unwrap (targetClass );
544+ if (retVal instanceof Query query && targetClass .isInterface ()) {
545+ retVal = adaptQueryProxy (proxy , query , targetClass );
546+ }
547+ return retVal ;
535548 }
536549 }
537550 case "getOutputParameterValue" -> {
@@ -552,14 +565,21 @@ else if (targetClass.isInstance(proxy)) {
552565 // Invoke method on actual Query object.
553566 try {
554567 Object retVal = method .invoke (this .target , args );
555- if (method .getName ().equals ("registerStoredProcedureParameter" ) && args .length == 3 &&
568+ Class <?> returnType = method .getReturnType ();
569+ if (retVal == this .target && returnType .isInstance (proxy )) {
570+ retVal = proxy ;
571+ }
572+ else if (retVal instanceof Query query ) {
573+ retVal = adaptQueryProxy (proxy , query , returnType );
574+ }
575+ else if (method .getName ().equals ("registerStoredProcedureParameter" ) && args .length == 3 &&
556576 (args [2 ] == ParameterMode .OUT || args [2 ] == ParameterMode .INOUT )) {
557577 if (this .outputParameters == null ) {
558578 this .outputParameters = new LinkedHashMap <>();
559579 }
560580 this .outputParameters .put (args [0 ], null );
561581 }
562- return ( retVal == this . target ? proxy : retVal ) ;
582+ return retVal ;
563583 }
564584 catch (InvocationTargetException ex ) {
565585 throw ex .getTargetException ();
@@ -589,6 +609,14 @@ else if (targetClass.isInstance(proxy)) {
589609 }
590610 }
591611 }
612+
613+ private Object adaptQueryProxy (Object proxy , Query query , Class <?> expectedType ) {
614+ InvocationHandler ih = this ;
615+ if (query != this .target ) {
616+ ih = new DeferredQueryInvocationHandler (query , this .entityHandler );
617+ }
618+ return Proxy .newProxyInstance (proxy .getClass ().getClassLoader (), new Class <?>[] {expectedType }, ih );
619+ }
592620 }
593621
594622}
0 commit comments