Skip to content

Commit 4bcfbc3

Browse files
committed
Apply name-matching transaction attributes to user-level methods only
In particular, do not apply them to GroovyObject methods and other kinds of synthetic methods in language runtimes. The only exception are bridge methods since those do eventually point to a user-level generic method. Issue: SPR-10803
1 parent 0fe4962 commit 4bcfbc3

File tree

3 files changed

+27
-5
lines changed

3 files changed

+27
-5
lines changed

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -766,12 +766,28 @@ public static Method getMostSpecificMethod(Method method, Class<?> targetClass)
766766
return method;
767767
}
768768

769+
/**
770+
* Determine whether the given method is declared by the user or at least pointing to
771+
* a user-declared method.
772+
* <p>Checks {@link Method#isSynthetic()} (for implementation methods) as well as the
773+
* {@code GroovyObject} interface (for interface methods; on an implementation class,
774+
* implementations of the {@code GroovyObject} methods will be marked as synthetic anyway).
775+
* Note that, despite being synthetic, bridge methods ({@link Method#isBridge()}) are considered
776+
* as user-level methods since they are eventually pointing to a user-declared generic method.
777+
* @param method the method to check
778+
* @return {@code true} if the method can be considered as user-declared; [@code false} otherwise
779+
*/
780+
public static boolean isUserLevelMethod(Method method) {
781+
return (method.isBridge() ||
782+
(!method.isSynthetic() && !method.getDeclaringClass().getName().equals("groovy.lang.GroovyObject")));
783+
}
784+
769785
/**
770786
* Determine whether the given method is overridable in the given target class.
771787
* @param method the method to check
772788
* @param targetClass the target class to check against
773789
*/
774-
private static boolean isOverridable(Method method, Class targetClass) {
790+
private static boolean isOverridable(Method method, Class<?> targetClass) {
775791
if (Modifier.isPrivate(method.getModifiers())) {
776792
return false;
777793
}

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

Lines changed: 3 additions & 2 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-2013 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,6 +19,7 @@
1919
import java.io.Serializable;
2020
import java.lang.reflect.Method;
2121

22+
import org.springframework.util.ClassUtils;
2223
import org.springframework.util.ObjectUtils;
2324

2425
/**
@@ -52,7 +53,7 @@ public void setTransactionAttribute(TransactionAttribute transactionAttribute) {
5253

5354
@Override
5455
public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) {
55-
return this.transactionAttribute;
56+
return (ClassUtils.isUserLevelMethod(method) ? this.transactionAttribute : null);
5657
}
5758

5859

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

Lines changed: 7 additions & 2 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-2013 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.
@@ -26,6 +26,7 @@
2626
import org.apache.commons.logging.Log;
2727
import org.apache.commons.logging.LogFactory;
2828

29+
import org.springframework.util.ClassUtils;
2930
import org.springframework.util.ObjectUtils;
3031
import org.springframework.util.PatternMatchUtils;
3132

@@ -100,7 +101,11 @@ public void addTransactionalMethod(String methodName, TransactionAttribute attr)
100101

101102
@Override
102103
public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) {
103-
// look for direct name match
104+
if (!ClassUtils.isUserLevelMethod(method)) {
105+
return null;
106+
}
107+
108+
// Look for direct name match.
104109
String methodName = method.getName();
105110
TransactionAttribute attr = this.nameMap.get(methodName);
106111

0 commit comments

Comments
 (0)