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
This commit is contained in:
parent
4e33c7d442
commit
544208bc46
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -114,7 +114,7 @@ public class AnnotationTransactionAttributeSource extends AbstractFallbackTransa
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TransactionAttribute findTransactionAttribute(Class clazz) {
|
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
|
||||||
return determineTransactionAttribute(clazz);
|
return determineTransactionAttribute(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran
|
||||||
* @return TransactionAttribute for this method, or <code>null</code> if the method
|
* @return TransactionAttribute for this method, or <code>null</code> if the method
|
||||||
* is not transactional
|
* 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.
|
// First, see if we have a cached value.
|
||||||
Object cacheKey = getCacheKey(method, targetClass);
|
Object cacheKey = getCacheKey(method, targetClass);
|
||||||
Object cached = this.attributeCache.get(cacheKey);
|
Object cached = this.attributeCache.get(cacheKey);
|
||||||
|
|
@ -119,7 +119,7 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran
|
||||||
* @param targetClass the target class (may be <code>null</code>)
|
* @param targetClass the target class (may be <code>null</code>)
|
||||||
* @return the cache key (never <code>null</code>)
|
* @return the cache key (never <code>null</code>)
|
||||||
*/
|
*/
|
||||||
protected Object getCacheKey(Method method, Class targetClass) {
|
protected Object getCacheKey(Method method, Class<?> targetClass) {
|
||||||
return new DefaultCacheKey(method, 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.
|
* {@link #getTransactionAttribute} is effectively a caching decorator for this method.
|
||||||
* @see #getTransactionAttribute
|
* @see #getTransactionAttribute
|
||||||
*/
|
*/
|
||||||
private TransactionAttribute computeTransactionAttribute(Method method, Class targetClass) {
|
private TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
|
||||||
// Don't allow no-public methods as required.
|
// Don't allow no-public methods as required.
|
||||||
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
|
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
|
||||||
return null;
|
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.
|
// 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.
|
// 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.
|
// If we are dealing with method with generic parameters, find the original method.
|
||||||
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
|
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
|
||||||
|
|
||||||
|
|
@ -181,7 +183,7 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran
|
||||||
* @return all transaction attribute associated with this class
|
* @return all transaction attribute associated with this class
|
||||||
* (or <code>null</code> if none)
|
* (or <code>null</code> if none)
|
||||||
*/
|
*/
|
||||||
protected abstract TransactionAttribute findTransactionAttribute(Class clazz);
|
protected abstract TransactionAttribute findTransactionAttribute(Class<?> clazz);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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,
|
* @return TransactionAttribute the matching transaction attribute,
|
||||||
* or <code>null</code> if none found
|
* or <code>null</code> if none found
|
||||||
*/
|
*/
|
||||||
TransactionAttribute getTransactionAttribute(Method method, Class targetClass);
|
TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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());
|
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.
|
* Test case where attribute is on the interface method.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -28,11 +28,11 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
public class MapTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource {
|
public class MapTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource {
|
||||||
|
|
||||||
/** Map from Method or Clazz to TransactionAttribute */
|
private final Map<Object, TransactionAttribute> attributeMap = new HashMap<Object, TransactionAttribute>();
|
||||||
private final Map attributeMap = new HashMap();
|
|
||||||
|
|
||||||
public void register(Method m, TransactionAttribute txAtt) {
|
|
||||||
this.attributeMap.put(m, txAtt);
|
public void register(Method method, TransactionAttribute txAtt) {
|
||||||
|
this.attributeMap.put(method, txAtt);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void register(Class clazz, TransactionAttribute txAtt) {
|
public void register(Class clazz, TransactionAttribute txAtt) {
|
||||||
|
|
@ -41,11 +41,11 @@ public class MapTransactionAttributeSource extends AbstractFallbackTransactionAt
|
||||||
|
|
||||||
|
|
||||||
protected TransactionAttribute findTransactionAttribute(Method method) {
|
protected TransactionAttribute findTransactionAttribute(Method method) {
|
||||||
return (TransactionAttribute) this.attributeMap.get(method);
|
return this.attributeMap.get(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TransactionAttribute findTransactionAttribute(Class clazz) {
|
protected TransactionAttribute findTransactionAttribute(Class clazz) {
|
||||||
return (TransactionAttribute) this.attributeMap.get(clazz);
|
return this.attributeMap.get(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue