From 544208bc461a3cfb2ac4ecfab5c2fc6c67ac517b Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 11 Aug 2010 21:47:50 +0000 Subject: [PATCH] introspect superclass when given a CGLIB proxy as target class (SPR-7448); use generic Class in TransactionAttributeSource signature git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@3566 50f2f4bb-b051-0410-bef5-90022cba6387 --- .../AnnotationTransactionAttributeSource.java | 4 ++-- ...actFallbackTransactionAttributeSource.java | 12 +++++----- .../TransactionAttributeSource.java | 4 ++-- ...tationTransactionAttributeSourceTests.java | 22 ++++++++++++++++++- .../MapTransactionAttributeSource.java | 20 ++++++++--------- 5 files changed, 42 insertions(+), 20 deletions(-) diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSource.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSource.java index 607b3047d4c..ffebe02a1bf 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSource.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -114,7 +114,7 @@ public class AnnotationTransactionAttributeSource extends AbstractFallbackTransa } @Override - protected TransactionAttribute findTransactionAttribute(Class clazz) { + protected TransactionAttribute findTransactionAttribute(Class clazz) { return determineTransactionAttribute(clazz); } diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java index 01dbf705e6d..8ef4e5ef1fa 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java @@ -80,7 +80,7 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran * @return TransactionAttribute for this method, or null if the method * is not transactional */ - public TransactionAttribute getTransactionAttribute(Method method, Class targetClass) { + public TransactionAttribute getTransactionAttribute(Method method, Class targetClass) { // First, see if we have a cached value. Object cacheKey = getCacheKey(method, targetClass); Object cached = this.attributeCache.get(cacheKey); @@ -119,7 +119,7 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran * @param targetClass the target class (may be null) * @return the cache key (never null) */ - protected Object getCacheKey(Method method, Class targetClass) { + protected Object getCacheKey(Method method, Class targetClass) { return new DefaultCacheKey(method, targetClass); } @@ -128,15 +128,17 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran * {@link #getTransactionAttribute} is effectively a caching decorator for this method. * @see #getTransactionAttribute */ - private TransactionAttribute computeTransactionAttribute(Method method, Class targetClass) { + private TransactionAttribute computeTransactionAttribute(Method method, Class targetClass) { // Don't allow no-public methods as required. if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } + // Ignore CGLIB subclasses - introspect the actual user class. + Class userClass = ClassUtils.getUserClass(targetClass); // The method may be on an interface, but we need attributes from the target class. // If the target class is null, the method will be unchanged. - Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass); + Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass); // If we are dealing with method with generic parameters, find the original method. specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); @@ -181,7 +183,7 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran * @return all transaction attribute associated with this class * (or null if none) */ - protected abstract TransactionAttribute findTransactionAttribute(Class clazz); + protected abstract TransactionAttribute findTransactionAttribute(Class clazz); /** diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSource.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSource.java index 3dcbf6a6fcb..14df0875b5e 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSource.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionAttributeSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006 the original author or authors. + * Copyright 2002-2010 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. @@ -39,6 +39,6 @@ public interface TransactionAttributeSource { * @return TransactionAttribute the matching transaction attribute, * or null if none found */ - TransactionAttribute getTransactionAttribute(Method method, Class targetClass); + TransactionAttribute getTransactionAttribute(Method method, Class targetClass); } diff --git a/org.springframework.transaction/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSourceTests.java b/org.springframework.transaction/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSourceTests.java index 322a659bb47..9bd446fc87c 100644 --- a/org.springframework.transaction/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSourceTests.java +++ b/org.springframework.transaction/src/test/java/org/springframework/transaction/annotation/AnnotationTransactionAttributeSourceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006 the original author or authors. + * Copyright 2002-2010 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. @@ -95,6 +95,26 @@ public class AnnotationTransactionAttributeSourceTests { assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); } + /** + * Test the important case where the invocation is on a proxied interface method + * but the attribute is defined on the target class. + */ + @Test + public void testTransactionAttributeDeclaredOnCglibClassMethod() throws Exception { + Method classMethod = ITestBean.class.getMethod("getAge", (Class[]) null); + TestBean1 tb = new TestBean1(); + ProxyFactory pf = new ProxyFactory(tb); + pf.setProxyTargetClass(true); + Object proxy = pf.getProxy(); + + AnnotationTransactionAttributeSource atas = new AnnotationTransactionAttributeSource(); + TransactionAttribute actual = atas.getTransactionAttribute(classMethod, proxy.getClass()); + + RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); + rbta.getRollbackRules().add(new RollbackRuleAttribute(Exception.class)); + assertEquals(rbta.getRollbackRules(), ((RuleBasedTransactionAttribute) actual).getRollbackRules()); + } + /** * Test case where attribute is on the interface method. */ diff --git a/org.springframework.transaction/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java b/org.springframework.transaction/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java index 35ef3bf103e..a260d3ef719 100644 --- a/org.springframework.transaction/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java +++ b/org.springframework.transaction/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2010 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. @@ -27,25 +27,25 @@ import java.util.Map; * @author Juergen Hoeller */ public class MapTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource { - - /** Map from Method or Clazz to TransactionAttribute */ - private final Map attributeMap = new HashMap(); - - public void register(Method m, TransactionAttribute txAtt) { - this.attributeMap.put(m, txAtt); + + private final Map attributeMap = new HashMap(); + + + public void register(Method method, TransactionAttribute txAtt) { + this.attributeMap.put(method, txAtt); } - + public void register(Class clazz, TransactionAttribute txAtt) { this.attributeMap.put(clazz, txAtt); } protected TransactionAttribute findTransactionAttribute(Method method) { - return (TransactionAttribute) this.attributeMap.get(method); + return this.attributeMap.get(method); } protected TransactionAttribute findTransactionAttribute(Class clazz) { - return (TransactionAttribute) this.attributeMap.get(clazz); + return this.attributeMap.get(clazz); } }