From 4bcfbc3ba3eced91bd833eb2b4d4620c94c611ba Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 30 Oct 2013 12:38:45 +0100 Subject: [PATCH] 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 --- .../org/springframework/util/ClassUtils.java | 18 +++++++++++++++++- .../MatchAlwaysTransactionAttributeSource.java | 5 +++-- .../NameMatchTransactionAttributeSource.java | 9 +++++++-- 3 files changed, 27 insertions(+), 5 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 0035e1ad86..9ae3c1d4b4 100644 --- a/spring-core/src/main/java/org/springframework/util/ClassUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ClassUtils.java @@ -766,12 +766,28 @@ public abstract class ClassUtils { return method; } + /** + * Determine whether the given method is declared by the user or at least pointing to + * a user-declared method. + *

Checks {@link Method#isSynthetic()} (for implementation methods) as well as the + * {@code GroovyObject} interface (for interface methods; on an implementation class, + * implementations of the {@code GroovyObject} methods will be marked as synthetic anyway). + * Note that, despite being synthetic, bridge methods ({@link Method#isBridge()}) are considered + * as user-level methods since they are eventually pointing to a user-declared generic method. + * @param method the method to check + * @return {@code true} if the method can be considered as user-declared; [@code false} otherwise + */ + public static boolean isUserLevelMethod(Method method) { + return (method.isBridge() || + (!method.isSynthetic() && !method.getDeclaringClass().getName().equals("groovy.lang.GroovyObject"))); + } + /** * Determine whether the given method is overridable in the given target class. * @param method the method to check * @param targetClass the target class to check against */ - private static boolean isOverridable(Method method, Class targetClass) { + private static boolean isOverridable(Method method, Class targetClass) { if (Modifier.isPrivate(method.getModifiers())) { return false; } diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/MatchAlwaysTransactionAttributeSource.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/MatchAlwaysTransactionAttributeSource.java index e27ee94bf5..90c62d3f9f 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/MatchAlwaysTransactionAttributeSource.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/MatchAlwaysTransactionAttributeSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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,6 +19,7 @@ package org.springframework.transaction.interceptor; import java.io.Serializable; import java.lang.reflect.Method; +import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; /** @@ -52,7 +53,7 @@ public class MatchAlwaysTransactionAttributeSource implements TransactionAttribu @Override public TransactionAttribute getTransactionAttribute(Method method, Class targetClass) { - return this.transactionAttribute; + return (ClassUtils.isUserLevelMethod(method) ? this.transactionAttribute : null); } diff --git a/spring-tx/src/main/java/org/springframework/transaction/interceptor/NameMatchTransactionAttributeSource.java b/spring-tx/src/main/java/org/springframework/transaction/interceptor/NameMatchTransactionAttributeSource.java index 9d2b5debc8..83b6cd0f6a 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/interceptor/NameMatchTransactionAttributeSource.java +++ b/spring-tx/src/main/java/org/springframework/transaction/interceptor/NameMatchTransactionAttributeSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -26,6 +26,7 @@ import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.PatternMatchUtils; @@ -100,7 +101,11 @@ public class NameMatchTransactionAttributeSource implements TransactionAttribute @Override public TransactionAttribute getTransactionAttribute(Method method, Class targetClass) { - // look for direct name match + if (!ClassUtils.isUserLevelMethod(method)) { + return null; + } + + // Look for direct name match. String methodName = method.getName(); TransactionAttribute attr = this.nameMap.get(methodName);