From 52b029d71d440982e6173007010cfe579fbc6191 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 21 Oct 2016 12:23:13 +0200 Subject: [PATCH] DefaultTransactionAttribute stores descriptor (method identification) Issue: SPR-14760 --- .../org/springframework/util/ClassUtils.java | 21 ++++++++-- ...actFallbackTransactionAttributeSource.java | 40 ++++++++++--------- .../DefaultTransactionAttribute.java | 29 ++++++++++++-- .../interceptor/TransactionAspectSupport.java | 21 +++++++++- .../MapTransactionAttributeSource.java | 8 ++-- 5 files changed, 87 insertions(+), 32 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/util/ClassUtils.java b/spring-core/src/main/java/org/springframework/util/ClassUtils.java index 354b1200a1..2c02cd57a0 100644 --- a/spring-core/src/main/java/org/springframework/util/ClassUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ClassUtils.java @@ -511,8 +511,21 @@ public abstract class ClassUtils { * @return the qualified name of the method */ public static String getQualifiedMethodName(Method method) { + return getQualifiedMethodName(method, null); + } + + /** + * Return the qualified name of the given method, consisting of + * fully qualified interface/class name + "." + method name. + * @param method the method + * @param clazz the clazz that the method is being invoked on + * (may be {@code null} to indicate the method's declaring class) + * @return the qualified name of the method + * @since 4.3.4 + */ + public static String getQualifiedMethodName(Method method, Class clazz) { Assert.notNull(method, "Method must not be null"); - return method.getDeclaringClass().getName() + "." + method.getName(); + return (clazz != null ? clazz : method.getDeclaringClass()).getName() + '.' + method.getName(); } /** @@ -640,10 +653,10 @@ public abstract class ClassUtils { return candidates.iterator().next(); } else if (candidates.isEmpty()) { - throw new IllegalStateException("Expected method not found: " + clazz + "." + methodName); + throw new IllegalStateException("Expected method not found: " + clazz.getName() + '.' + methodName); } else { - throw new IllegalStateException("No unique method found: " + clazz + "." + methodName); + throw new IllegalStateException("No unique method found: " + clazz.getName() + '.' + methodName); } } } @@ -980,7 +993,7 @@ public abstract class ClassUtils { public static String addResourcePathToPackagePath(Class clazz, String resourceName) { Assert.notNull(resourceName, "Resource name must not be null"); if (!resourceName.startsWith("/")) { - return classPackageAsResourcePath(clazz) + "/" + resourceName; + return classPackageAsResourcePath(clazz) + '/' + resourceName; } return classPackageAsResourcePath(clazz) + resourceName; } diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java index 070613d569..7c455e2b88 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/AbstractFallbackTransactionAttributeSource.java @@ -97,20 +97,22 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran } else { // We need to work it out. - TransactionAttribute txAtt = computeTransactionAttribute(method, targetClass); + TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass); // Put it in the cache. - if (txAtt == null) { + if (txAttr == null) { this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE); } else { + String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass); + if (txAttr instanceof DefaultTransactionAttribute) { + ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification); + } if (logger.isDebugEnabled()) { - Class classToLog = (targetClass != null ? targetClass : method.getDeclaringClass()); - logger.debug("Adding transactional method '" + classToLog.getSimpleName() + "." + - method.getName() + "' with attribute: " + txAtt); + logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr); } - this.attributeCache.put(cacheKey, txAtt); + this.attributeCache.put(cacheKey, txAttr); } - return txAtt; + return txAttr; } } @@ -148,27 +150,27 @@ public abstract class AbstractFallbackTransactionAttributeSource implements Tran specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); // First try is the method in the target class. - TransactionAttribute txAtt = findTransactionAttribute(specificMethod); - if (txAtt != null) { - return txAtt; + TransactionAttribute txAttr = findTransactionAttribute(specificMethod); + if (txAttr != null) { + return txAttr; } // Second try is the transaction attribute on the target class. - txAtt = findTransactionAttribute(specificMethod.getDeclaringClass()); - if (txAtt != null && ClassUtils.isUserLevelMethod(method)) { - return txAtt; + txAttr = findTransactionAttribute(specificMethod.getDeclaringClass()); + if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { + return txAttr; } if (specificMethod != method) { // Fallback is to look at the original method. - txAtt = findTransactionAttribute(method); - if (txAtt != null) { - return txAtt; + txAttr = findTransactionAttribute(method); + if (txAttr != null) { + return txAttr; } // Last fallback is the class of the original method. - txAtt = findTransactionAttribute(method.getDeclaringClass()); - if (txAtt != null && ClassUtils.isUserLevelMethod(method)) { - return txAtt; + txAttr = findTransactionAttribute(method.getDeclaringClass()); + if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { + return txAttr; } } diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/DefaultTransactionAttribute.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/DefaultTransactionAttribute.java index e253aabd76..83de312a25 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/DefaultTransactionAttribute.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/DefaultTransactionAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 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. @@ -19,10 +19,11 @@ package org.springframework.transaction.interceptor; import org.springframework.transaction.support.DefaultTransactionDefinition; /** - * Transaction attribute that takes the EJB approach to rolling - * back on runtime, but not checked, exceptions. + * Spring's common transaction attribute implementation. + * Rolls back on runtime, but not checked, exceptions by default. * * @author Rod Johnson + * @author Juergen Hoeller * @since 16.03.2003 */ @SuppressWarnings("serial") @@ -30,6 +31,8 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im private String qualifier; + private String descriptor; + /** * Create a new DefaultTransactionAttribute, with default settings. @@ -74,6 +77,7 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im * Associate a qualifier value with this transaction attribute. *

This may be used for choosing a corresponding transaction manager * to process this specific transaction. + * @since 3.0 */ public void setQualifier(String qualifier) { this.qualifier = qualifier; @@ -81,12 +85,31 @@ public class DefaultTransactionAttribute extends DefaultTransactionDefinition im /** * Return a qualifier value associated with this transaction attribute. + * @since 3.0 */ @Override public String getQualifier() { return this.qualifier; } + /** + * Set a descriptor for this transaction attribute, + * e.g. indicating where the attribute is applying. + * @since 4.3.4 + */ + public void setDescriptor(String descriptor) { + this.descriptor = descriptor; + } + + /** + * Return a descriptor for this transaction attribute, + * or {@code null} if none. + * @since 4.3.4 + */ + public String getDescriptor() { + return this.descriptor; + } + /** * The default behavior is as with EJB: rollback on unchecked exception. * Additionally attempt to rollback on Error. diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java index f251649911..035cfaab80 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java @@ -34,6 +34,7 @@ import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionSystemException; import org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager; import org.springframework.transaction.support.TransactionCallback; +import org.springframework.util.ClassUtils; import org.springframework.util.ConcurrentReferenceHashMap; import org.springframework.util.StringUtils; @@ -269,7 +270,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init // If the transaction attribute is null, the method is non-transactional. final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass); final PlatformTransactionManager tm = determineTransactionManager(txAttr); - final String joinpointIdentification = methodIdentification(method, targetClass); + final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. @@ -385,17 +386,33 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init return txManager; } + private String methodIdentification(Method method, Class targetClass, TransactionAttribute txAttr) { + String methodIdentification = methodIdentification(method, targetClass); + if (methodIdentification == null) { + if (txAttr instanceof DefaultTransactionAttribute) { + methodIdentification = ((DefaultTransactionAttribute) txAttr).getDescriptor(); + } + if (methodIdentification == null) { + methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass); + } + } + return methodIdentification; + } + /** * Convenience method to return a String representation of this Method * for use in logging. Can be overridden in subclasses to provide a * different identifier for the given method. + *

The default implementation returns {@code null}, indicating the + * use of {@link DefaultTransactionAttribute#getDescriptor()} instead, + * ending up as {@link ClassUtils#getQualifiedMethodName(Method, Class)}. * @param method the method we're interested in * @param targetClass the class that the method is being invoked on * @return a String representation identifying this method * @see org.springframework.util.ClassUtils#getQualifiedMethodName */ protected String methodIdentification(Method method, Class targetClass) { - return (targetClass != null ? targetClass : method.getDeclaringClass()).getName() + "." + method.getName(); + return null; } /** diff --git a/spring-tx/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java b/spring-tx/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java index e1ab7217ec..4f00f0d3d0 100644 --- a/spring-tx/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java +++ b/spring-tx/src/test/java/org/springframework/transaction/interceptor/MapTransactionAttributeSource.java @@ -31,12 +31,12 @@ public class MapTransactionAttributeSource extends AbstractFallbackTransactionAt private final Map attributeMap = new HashMap<>(); - public void register(Method method, TransactionAttribute txAtt) { - this.attributeMap.put(method, txAtt); + public void register(Method method, TransactionAttribute txAttr) { + this.attributeMap.put(method, txAttr); } - public void register(Class clazz, TransactionAttribute txAtt) { - this.attributeMap.put(clazz, txAtt); + public void register(Class clazz, TransactionAttribute txAttr) { + this.attributeMap.put(clazz, txAttr); }