From d15df3489e3139d3ae15499c7a5c8c9dbb24b573 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 14 Dec 2016 22:00:41 +0100 Subject: [PATCH] Avoid proxy replacement for generic return type signatures Issue: SPR-15010 (cherry picked from commit 6d1cae2) --- .../aop/framework/CglibAopProxy.java | 3 ++- .../aop/framework/JdkDynamicAopProxy.java | 3 ++- ...nateEntityManagerFactoryIntegrationTests.java | 16 +++++++++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java b/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java index 7e60723e03..9842b4e235 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java @@ -351,7 +351,8 @@ class CglibAopProxy implements AopProxy, Serializable { */ private static Object processReturnType(Object proxy, Object target, Method method, Object retVal) { // Massage return value if necessary - if (retVal != null && retVal == target && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { + if (retVal != null && retVal == target && + !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // Special case: it returned "this". Note that we can't help // if the target sets a reference to itself in another returned object. retVal = proxy; diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java b/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java index 1f90b0b573..c280830a14 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java @@ -215,7 +215,8 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa // Massage return value if necessary. Class returnType = method.getReturnType(); - if (retVal != null && retVal == target && returnType.isInstance(proxy) && + if (retVal != null && retVal == target && + returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // Special case: it returned "this" and the return type of the method // is type-compatible. Note that we can't help if the target sets diff --git a/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java index 0b4fbcbabb..eec903610d 100644 --- a/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java +++ b/spring-orm/src/test/java/org/springframework/orm/jpa/hibernate/HibernateEntityManagerFactoryIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +16,13 @@ package org.springframework.orm.jpa.hibernate; +import javax.persistence.EntityManager; + import org.hibernate.ejb.HibernateEntityManager; import org.hibernate.ejb.HibernateEntityManagerFactory; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.aop.target.SingletonTargetSource; import org.springframework.orm.jpa.AbstractContainerEntityManagerFactoryIntegrationTests; import org.springframework.orm.jpa.EntityManagerFactoryInfo; @@ -48,4 +52,14 @@ public class HibernateEntityManagerFactoryIntegrationTests extends assertNotNull(hibernateEntityManager.getSession()); } + public void testCanUnwrapAopProxy() { + EntityManager em = entityManagerFactory.createEntityManager(); + EntityManager proxy = ProxyFactory.getProxy(EntityManager.class, new SingletonTargetSource(em)); + assertTrue(em instanceof HibernateEntityManager); + assertFalse(proxy instanceof HibernateEntityManager); + assertTrue(proxy.unwrap(HibernateEntityManager.class) instanceof HibernateEntityManager); + assertSame(em, proxy.unwrap(HibernateEntityManager.class)); + assertSame(em.getDelegate(), proxy.getDelegate()); + } + }