Skip to content

Commit 6d95b99

Browse files
committed
DefaultTransactionAttribute stores descriptor (method identification)
Issue: SPR-14760 (cherry picked from commit 52b029d)
1 parent 6731e52 commit 6d95b99

File tree

5 files changed

+87
-32
lines changed

5 files changed

+87
-32
lines changed

spring-core/src/main/java/org/springframework/util/ClassUtils.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -511,8 +511,21 @@ private static String getQualifiedNameForArray(Class<?> clazz) {
511511
* @return the qualified name of the method
512512
*/
513513
public static String getQualifiedMethodName(Method method) {
514+
return getQualifiedMethodName(method, null);
515+
}
516+
517+
/**
518+
* Return the qualified name of the given method, consisting of
519+
* fully qualified interface/class name + "." + method name.
520+
* @param method the method
521+
* @param clazz the clazz that the method is being invoked on
522+
* (may be {@code null} to indicate the method's declaring class)
523+
* @return the qualified name of the method
524+
* @since 4.3.4
525+
*/
526+
public static String getQualifiedMethodName(Method method, Class<?> clazz) {
514527
Assert.notNull(method, "Method must not be null");
515-
return method.getDeclaringClass().getName() + "." + method.getName();
528+
return (clazz != null ? clazz : method.getDeclaringClass()).getName() + '.' + method.getName();
516529
}
517530

518531
/**
@@ -640,10 +653,10 @@ public static Method getMethod(Class<?> clazz, String methodName, Class<?>... pa
640653
return candidates.iterator().next();
641654
}
642655
else if (candidates.isEmpty()) {
643-
throw new IllegalStateException("Expected method not found: " + clazz + "." + methodName);
656+
throw new IllegalStateException("Expected method not found: " + clazz.getName() + '.' + methodName);
644657
}
645658
else {
646-
throw new IllegalStateException("No unique method found: " + clazz + "." + methodName);
659+
throw new IllegalStateException("No unique method found: " + clazz.getName() + '.' + methodName);
647660
}
648661
}
649662
}
@@ -980,7 +993,7 @@ public static String convertClassNameToResourcePath(String className) {
980993
public static String addResourcePathToPackagePath(Class<?> clazz, String resourceName) {
981994
Assert.notNull(resourceName, "Resource name must not be null");
982995
if (!resourceName.startsWith("/")) {
983-
return classPackageAsResourcePath(clazz) + "/" + resourceName;
996+
return classPackageAsResourcePath(clazz) + '/' + resourceName;
984997
}
985998
return classPackageAsResourcePath(clazz) + resourceName;
986999
}

spring-tx/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -97,20 +97,22 @@ public TransactionAttribute getTransactionAttribute(Method method, Class<?> targ
9797
}
9898
else {
9999
// We need to work it out.
100-
TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass);
100+
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
101101
// Put it in the cache.
102-
if (txAtt == null) {
102+
if (txAttr == null) {
103103
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
104104
}
105105
else {
106+
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
107+
if (txAttr instanceof DefaultTransactionAttribute) {
108+
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
109+
}
106110
if (logger.isDebugEnabled()) {
107-
Class<?> classToLog = (targetClass != null ? targetClass : method.getDeclaringClass());
108-
logger.debug("Adding transactional method '" + classToLog.getSimpleName() + "." +
109-
method.getName() + "' with attribute: " + txAtt);
111+
logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
110112
}
111-
this.attributeCache.put(cacheKey, txAtt);
113+
this.attributeCache.put(cacheKey, txAttr);
112114
}
113-
return txAtt;
115+
return txAttr;
114116
}
115117
}
116118

@@ -148,27 +150,27 @@ protected TransactionAttribute computeTransactionAttribute(Method method, Class<
148150
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
149151

150152
// First try is the method in the target class.
151-
TransactionAttribute txAtt = findTransactionAttribute(specificMethod);
152-
if (txAtt != null) {
153-
return txAtt;
153+
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
154+
if (txAttr != null) {
155+
return txAttr;
154156
}
155157

156158
// Second try is the transaction attribute on the target class.
157-
txAtt = findTransactionAttribute(specificMethod.getDeclaringClass());
158-
if (txAtt != null && ClassUtils.isUserLevelMethod(method)) {
159-
return txAtt;
159+
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
160+
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
161+
return txAttr;
160162
}
161163

162164
if (specificMethod != method) {
163165
// Fallback is to look at the original method.
164-
txAtt = findTransactionAttribute(method);
165-
if (txAtt != null) {
166-
return txAtt;
166+
txAttr = findTransactionAttribute(method);
167+
if (txAttr != null) {
168+
return txAttr;
167169
}
168170
// Last fallback is the class of the original method.
169-
txAtt = findTransactionAttribute(method.getDeclaringClass());
170-
if (txAtt != null && ClassUtils.isUserLevelMethod(method)) {
171-
return txAtt;
171+
txAttr = findTransactionAttribute(method.getDeclaringClass());
172+
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
173+
return txAttr;
172174
}
173175
}
174176

spring-tx/src/main/java/org/springframework/transaction/interceptor/DefaultTransactionAttribute.java

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,17 +19,20 @@
1919
import org.springframework.transaction.support.DefaultTransactionDefinition;
2020

2121
/**
22-
* Transaction attribute that takes the EJB approach to rolling
23-
* back on runtime, but not checked, exceptions.
22+
* Spring's common transaction attribute implementation.
23+
* Rolls back on runtime, but not checked, exceptions by default.
2424
*
2525
* @author Rod Johnson
26+
* @author Juergen Hoeller
2627
* @since 16.03.2003
2728
*/
2829
@SuppressWarnings("serial")
2930
public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute {
3031

3132
private String qualifier;
3233

34+
private String descriptor;
35+
3336

3437
/**
3538
* Create a new DefaultTransactionAttribute, with default settings.
@@ -74,19 +77,39 @@ public DefaultTransactionAttribute(int propagationBehavior) {
7477
* Associate a qualifier value with this transaction attribute.
7578
* <p>This may be used for choosing a corresponding transaction manager
7679
* to process this specific transaction.
80+
* @since 3.0
7781
*/
7882
public void setQualifier(String qualifier) {
7983
this.qualifier = qualifier;
8084
}
8185

8286
/**
8387
* Return a qualifier value associated with this transaction attribute.
88+
* @since 3.0
8489
*/
8590
@Override
8691
public String getQualifier() {
8792
return this.qualifier;
8893
}
8994

95+
/**
96+
* Set a descriptor for this transaction attribute,
97+
* e.g. indicating where the attribute is applying.
98+
* @since 4.3.4
99+
*/
100+
public void setDescriptor(String descriptor) {
101+
this.descriptor = descriptor;
102+
}
103+
104+
/**
105+
* Return a descriptor for this transaction attribute,
106+
* or {@code null} if none.
107+
* @since 4.3.4
108+
*/
109+
public String getDescriptor() {
110+
return this.descriptor;
111+
}
112+
90113
/**
91114
* The default behavior is as with EJB: rollback on unchecked exception.
92115
* Additionally attempt to rollback on Error.

spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.transaction.TransactionSystemException;
3535
import org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager;
3636
import org.springframework.transaction.support.TransactionCallback;
37+
import org.springframework.util.ClassUtils;
3738
import org.springframework.util.ConcurrentReferenceHashMap;
3839
import org.springframework.util.StringUtils;
3940

@@ -269,7 +270,7 @@ protected Object invokeWithinTransaction(Method method, Class<?> targetClass, fi
269270
// If the transaction attribute is null, the method is non-transactional.
270271
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
271272
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
272-
final String joinpointIdentification = methodIdentification(method, targetClass);
273+
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
273274

274275
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
275276
// Standard transaction demarcation with getTransaction and commit/rollback calls.
@@ -385,17 +386,33 @@ private PlatformTransactionManager determineQualifiedTransactionManager(String q
385386
return txManager;
386387
}
387388

389+
private String methodIdentification(Method method, Class<?> targetClass, TransactionAttribute txAttr) {
390+
String methodIdentification = methodIdentification(method, targetClass);
391+
if (methodIdentification == null) {
392+
if (txAttr instanceof DefaultTransactionAttribute) {
393+
methodIdentification = ((DefaultTransactionAttribute) txAttr).getDescriptor();
394+
}
395+
if (methodIdentification == null) {
396+
methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
397+
}
398+
}
399+
return methodIdentification;
400+
}
401+
388402
/**
389403
* Convenience method to return a String representation of this Method
390404
* for use in logging. Can be overridden in subclasses to provide a
391405
* different identifier for the given method.
406+
* <p>The default implementation returns {@code null}, indicating the
407+
* use of {@link DefaultTransactionAttribute#getDescriptor()} instead,
408+
* ending up as {@link ClassUtils#getQualifiedMethodName(Method, Class)}.
392409
* @param method the method we're interested in
393410
* @param targetClass the class that the method is being invoked on
394411
* @return a String representation identifying this method
395412
* @see org.springframework.util.ClassUtils#getQualifiedMethodName
396413
*/
397414
protected String methodIdentification(Method method, Class<?> targetClass) {
398-
return (targetClass != null ? targetClass : method.getDeclaringClass()).getName() + "." + method.getName();
415+
return null;
399416
}
400417

401418
/**

spring-tx/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ public class MapTransactionAttributeSource extends AbstractFallbackTransactionAt
3131
private final Map<Object, TransactionAttribute> attributeMap = new HashMap<Object, TransactionAttribute>();
3232

3333

34-
public void register(Method method, TransactionAttribute txAtt) {
35-
this.attributeMap.put(method, txAtt);
34+
public void register(Method method, TransactionAttribute txAttr) {
35+
this.attributeMap.put(method, txAttr);
3636
}
3737

38-
public void register(Class<?> clazz, TransactionAttribute txAtt) {
39-
this.attributeMap.put(clazz, txAtt);
38+
public void register(Class<?> clazz, TransactionAttribute txAttr) {
39+
this.attributeMap.put(clazz, txAttr);
4040
}
4141

4242

0 commit comments

Comments
 (0)