Merge branch '5.3.x'

# Conflicts:
#	spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java
#	spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationClassFilter.java
#	spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMatchingPointcut.java
#	spring-aop/src/main/java/org/springframework/aop/support/annotation/AnnotationMethodMatcher.java
#	spring-beans/src/main/java/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessor.java
#	spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java
#	spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedNotification.java
#	spring-context/src/main/java/org/springframework/jmx/export/annotation/ManagedOperationParameter.java
#	spring-core/src/main/java/org/springframework/javapoet/support/package-info.java
#	spring-core/src/main/java/org/springframework/util/TypeUtils.java
#	spring-web/src/main/java/org/springframework/http/HttpMethod.java
This commit is contained in:
Sam Brannen 2022-03-18 16:47:12 +01:00
commit b570f60560
33 changed files with 631 additions and 730 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2022 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.
@ -34,7 +34,7 @@ import org.springframework.util.ClassUtils;
/**
* AspectJ-based proxy factory, allowing for programmatic building
* of proxies which include AspectJ aspects (code style as well
* Java 5 annotation style).
* annotation style).
*
* @author Rob Harrop
* @author Juergen Hoeller

View File

@ -60,8 +60,8 @@ public class AspectMetadata implements Serializable {
private final Class<?> aspectClass;
/**
* AspectJ reflection information (AspectJ 5 / Java 5 specific).
* Re-resolved on deserialization since it isn't serializable itself.
* AspectJ reflection information.
* <p>Re-resolved on deserialization since it isn't serializable itself.
*/
private transient AjType<?> ajType;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
@ -183,8 +183,8 @@ public abstract class AopUtils {
* may be {@code DefaultFoo}. In this case, the method may be
* {@code DefaultFoo.bar()}. This enables attributes on that method to be found.
* <p><b>NOTE:</b> In contrast to {@link org.springframework.util.ClassUtils#getMostSpecificMethod},
* this method resolves Java 5 bridge methods in order to retrieve attributes
* from the <i>original</i> method definition.
* this method resolves bridge methods in order to retrieve attributes from
* the <i>original</i> method definition.
* @param method the method to be invoked, which may come from an interface
* @param targetClass the target class for the current invocation.
* May be {@code null} or may not even implement the method.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
@ -24,8 +24,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Simple ClassFilter that looks for a specific Java 5 annotation
* being present on a class.
* Simple ClassFilter that looks for a specific annotation being present on a class.
*
* @author Juergen Hoeller
* @since 2.0

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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,9 +26,8 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Simple Pointcut that looks for a specific Java 5 annotation
* being present on a {@link #forClassAnnotation class} or
* {@link #forMethodAnnotation method}.
* Simple {@link Pointcut} that looks for a specific annotation being present on a
* {@linkplain #forClassAnnotation class} or {@linkplain #forMethodAnnotation method}.
*
* @author Juergen Hoeller
* @author Sam Brannen

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
@ -27,9 +27,10 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Simple MethodMatcher that looks for a specific Java 5 annotation
* being present on a method (checking both the method on the invoked
* interface, if any, and the corresponding method on the target class).
* Simple {@link org.springframework.aop.MethodMatcher MethodMatcher} that looks
* for a specific annotation being present on a method (checking both the method
* on the invoked interface, if any, and the corresponding method on the target
* class).
*
* @author Juergen Hoeller
* @author Sam Brannen

View File

@ -1,44 +0,0 @@
/*
* Copyright 2002-2018 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj;
import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.jupiter.api.Test;
/**
* Additional parameter name discover tests that need Java 5.
* Yes this will re-run the tests from the superclass, but that
* doesn't matter in the grand scheme of things...
*
* @author Adrian Colyer
* @author Chris Beams
*/
public class AspectJAdviceParameterNameDiscoverAnnotationTests extends AspectJAdviceParameterNameDiscovererTests {
@Test
public void testAnnotationBinding() {
assertParameterNames(getMethod("pjpAndAnAnnotation"),
"execution(* *(..)) && @annotation(ann)",
new String[] {"thisJoinPoint","ann"});
}
public void pjpAndAnAnnotation(ProceedingJoinPoint pjp, MyAnnotation ann) {}
@interface MyAnnotation {}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.
@ -17,8 +17,11 @@
package org.springframework.aop.aspectj;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException;
@ -27,200 +30,265 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Unit tests for the {@link AspectJAdviceParameterNameDiscoverer} class.
*
* <p>See also {@link TigerAspectJAdviceParameterNameDiscovererTests} for tests relating to annotations.
* Unit tests for {@link AspectJAdviceParameterNameDiscoverer}.
*
* @author Adrian Colyer
* @author Chris Beams
* @author Sam Brannen
*/
public class AspectJAdviceParameterNameDiscovererTests {
class AspectJAdviceParameterNameDiscovererTests {
@Test
public void testNoArgs() {
assertParameterNames(getMethod("noArgs"), "execution(* *(..))", new String[0]);
@Nested
class StandardTests {
@Test
void noArgs() {
assertParameterNames(getMethod("noArgs"), "execution(* *(..))", new String[0]);
}
@Test
void joinPointOnly() {
assertParameterNames(getMethod("tjp"), "execution(* *(..))", new String[] {"thisJoinPoint"});
}
@Test
void joinPointStaticPartOnly() {
assertParameterNames(getMethod("tjpsp"), "execution(* *(..))", new String[] {"thisJoinPointStaticPart"});
}
@Test
void twoJoinPoints() {
assertException(getMethod("twoJoinPoints"), "foo()", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
}
@Test
void oneThrowable() {
assertParameterNames(getMethod("oneThrowable"), "foo()", null, "ex", new String[] {"ex"});
}
@Test
void oneJPAndOneThrowable() {
assertParameterNames(getMethod("jpAndOneThrowable"), "foo()", null, "ex", new String[] {"thisJoinPoint", "ex"});
}
@Test
void oneJPAndTwoThrowables() {
assertException(getMethod("jpAndTwoThrowables"), "foo()", null, "ex", AmbiguousBindingException.class,
"Binding of throwing parameter 'ex' is ambiguous: could be bound to argument 1 or argument 2");
}
@Test
void throwableNoCandidates() {
assertException(getMethod("noArgs"), "foo()", null, "ex", IllegalStateException.class,
"Not enough arguments in method to satisfy binding of returning and throwing variables");
}
@Test
void returning() {
assertParameterNames(getMethod("oneObject"), "foo()", "obj", null, new String[] {"obj"});
}
@Test
void ambiguousReturning() {
assertException(getMethod("twoObjects"), "foo()", "obj", null, AmbiguousBindingException.class,
"Binding of returning parameter 'obj' is ambiguous, there are 2 candidates.");
}
@Test
void returningNoCandidates() {
assertException(getMethod("noArgs"), "foo()", "obj", null, IllegalStateException.class,
"Not enough arguments in method to satisfy binding of returning and throwing variables");
}
@Test
void thisBindingOneCandidate() {
assertParameterNames(getMethod("oneObject"), "this(x)", new String[] {"x"});
}
@Test
void thisBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("oneObject"), "this( x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this( x)", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this (x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this(x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "foo() && this(x)", new String[] {"x"});
}
@Test
void thisBindingTwoCandidates() {
assertException(getMethod("oneObject"), "this(x) || this(y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
}
@Test
void thisBindingWithBadPointcutExpressions() {
assertException(getMethod("oneObject"), "this(", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
assertException(getMethod("oneObject"), "this(x && foo()", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
}
@Test
void targetBindingOneCandidate() {
assertParameterNames(getMethod("oneObject"), "target(x)", new String[] {"x"});
}
@Test
void targetBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("oneObject"), "target( x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target( x)", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target (x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target(x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "foo() && target(x)", new String[] {"x"});
}
@Test
void targetBindingTwoCandidates() {
assertException(getMethod("oneObject"), "target(x) || target(y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
}
@Test
void targetBindingWithBadPointcutExpressions() {
assertException(getMethod("oneObject"), "target(", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
assertException(getMethod("oneObject"), "target(x && foo()", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
}
@Test
void argsBindingOneObject() {
assertParameterNames(getMethod("oneObject"), "args(x)", new String[] {"x"});
}
@Test
void argsBindingOneObjectTwoCandidates() {
assertException(getMethod("oneObject"), "args(x,y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
}
@Test
void ambiguousArgsBinding() {
assertException(getMethod("twoObjects"), "args(x,y)", AmbiguousBindingException.class,
"Still 2 unbound args at this(),target(),args() binding stage, with no way to determine between them");
}
@Test
void argsOnePrimitive() {
assertParameterNames(getMethod("onePrimitive"), "args(count)", new String[] {"count"});
}
@Test
void argsOnePrimitiveOneObject() {
assertException(getMethod("oneObjectOnePrimitive"), "args(count,obj)", AmbiguousBindingException.class,
"Found 2 candidate variable names but only one candidate binding slot when matching primitive args");
}
@Test
void thisAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && this(obj)",
new String[] {"obj", "count"});
}
@Test
void targetAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && target(obj)",
new String[] {"obj", "count"});
}
@Test
void throwingAndPrimitive() {
assertParameterNames(getMethod("oneThrowableOnePrimitive"), "args(count)", null, "ex",
new String[] {"ex", "count"});
}
@Test
void allTogetherNow() {
assertParameterNames(getMethod("theBigOne"), "this(foo) && args(x)", null, "ex",
new String[] {"thisJoinPoint", "ex", "x", "foo"});
}
@Test
void referenceBinding() {
assertParameterNames(getMethod("onePrimitive"),"somepc(foo)", new String[] {"foo"});
}
@Test
void referenceBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("onePrimitive"),"call(bar *) && somepc(foo)", new String[] {"foo"});
assertParameterNames(getMethod("onePrimitive"),"somepc ( foo )", new String[] {"foo"});
assertParameterNames(getMethod("onePrimitive"),"somepc( foo)", new String[] {"foo"});
}
}
@Test
public void testJoinPointOnly() {
assertParameterNames(getMethod("tjp"), "execution(* *(..))", new String[] {"thisJoinPoint"});
}
/**
* Tests just the annotation binding part of {@link AspectJAdviceParameterNameDiscoverer}.
*/
@Nested
class AnnotationTests {
@Test
public void testJoinPointStaticPartOnly() {
assertParameterNames(getMethod("tjpsp"), "execution(* *(..))", new String[] {"thisJoinPointStaticPart"});
}
@Test
void atThis() {
assertParameterNames(getMethod("oneAnnotation"),"@this(a)", new String[] {"a"});
}
@Test
public void testTwoJoinPoints() {
assertException(getMethod("twoJoinPoints"), "foo()", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
}
@Test
void atTarget() {
assertParameterNames(getMethod("oneAnnotation"),"@target(a)", new String[] {"a"});
}
@Test
public void testOneThrowable() {
assertParameterNames(getMethod("oneThrowable"), "foo()", null, "ex", new String[] {"ex"});
}
@Test
void atArgs() {
assertParameterNames(getMethod("oneAnnotation"),"@args(a)", new String[] {"a"});
}
@Test
public void testOneJPAndOneThrowable() {
assertParameterNames(getMethod("jpAndOneThrowable"), "foo()", null, "ex", new String[] {"thisJoinPoint", "ex"});
}
@Test
void atWithin() {
assertParameterNames(getMethod("oneAnnotation"),"@within(a)", new String[] {"a"});
}
@Test
public void testOneJPAndTwoThrowables() {
assertException(getMethod("jpAndTwoThrowables"), "foo()", null, "ex", AmbiguousBindingException.class,
"Binding of throwing parameter 'ex' is ambiguous: could be bound to argument 1 or argument 2");
}
@Test
void atWithincode() {
assertParameterNames(getMethod("oneAnnotation"),"@withincode(a)", new String[] {"a"});
}
@Test
public void testThrowableNoCandidates() {
assertException(getMethod("noArgs"), "foo()", null, "ex", IllegalStateException.class,
"Not enough arguments in method to satisfy binding of returning and throwing variables");
}
@Test
void atAnnotation() {
assertParameterNames(getMethod("oneAnnotation"),"@annotation(a)", new String[] {"a"});
}
@Test
public void testReturning() {
assertParameterNames(getMethod("oneObject"), "foo()", "obj", null, new String[] {"obj"});
}
@Test
void ambiguousAnnotationTwoVars() {
assertException(getMethod("twoAnnotations"),"@annotation(a) && @this(x)", AmbiguousBindingException.class,
"Found 2 potential annotation variable(s), and 2 potential argument slots");
}
@Test
public void testAmbiguousReturning() {
assertException(getMethod("twoObjects"), "foo()", "obj", null, AmbiguousBindingException.class,
"Binding of returning parameter 'obj' is ambiguous, there are 2 candidates.");
}
@Test
void ambiguousAnnotationOneVar() {
assertException(getMethod("oneAnnotation"),"@annotation(a) && @this(x)",IllegalArgumentException.class,
"Found 2 candidate annotation binding variables but only one potential argument binding slot");
}
@Test
public void testReturningNoCandidates() {
assertException(getMethod("noArgs"), "foo()", "obj", null, IllegalStateException.class,
"Not enough arguments in method to satisfy binding of returning and throwing variables");
}
@Test
void annotationMedley() {
assertParameterNames(getMethod("annotationMedley"),"@annotation(a) && args(count) && this(foo)",
null, "ex", new String[] {"ex", "foo", "count", "a"});
}
@Test
public void testThisBindingOneCandidate() {
assertParameterNames(getMethod("oneObject"), "this(x)", new String[] {"x"});
}
@Test
void annotationBinding() {
assertParameterNames(getMethod("pjpAndAnAnnotation"),
"execution(* *(..)) && @annotation(ann)",
new String[] {"thisJoinPoint","ann"});
}
@Test
public void testThisBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("oneObject"), "this( x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this( x)", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this (x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "this(x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "foo() && this(x)", new String[] {"x"});
}
@Test
public void testThisBindingTwoCandidates() {
assertException(getMethod("oneObject"), "this(x) || this(y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
}
@Test
public void testThisBindingWithBadPointcutExpressions() {
assertException(getMethod("oneObject"), "this(", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
assertException(getMethod("oneObject"), "this(x && foo()", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
}
@Test
public void testTargetBindingOneCandidate() {
assertParameterNames(getMethod("oneObject"), "target(x)", new String[] {"x"});
}
@Test
public void testTargetBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("oneObject"), "target( x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target( x)", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target (x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "target(x )", new String[] {"x"});
assertParameterNames(getMethod("oneObject"), "foo() && target(x)", new String[] {"x"});
}
@Test
public void testTargetBindingTwoCandidates() {
assertException(getMethod("oneObject"), "target(x) || target(y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
}
@Test
public void testTargetBindingWithBadPointcutExpressions() {
assertException(getMethod("oneObject"), "target(", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
assertException(getMethod("oneObject"), "target(x && foo()", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
}
@Test
public void testArgsBindingOneObject() {
assertParameterNames(getMethod("oneObject"), "args(x)", new String[] {"x"});
}
@Test
public void testArgsBindingOneObjectTwoCandidates() {
assertException(getMethod("oneObject"), "args(x,y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
}
@Test
public void testAmbiguousArgsBinding() {
assertException(getMethod("twoObjects"), "args(x,y)", AmbiguousBindingException.class,
"Still 2 unbound args at this(),target(),args() binding stage, with no way to determine between them");
}
@Test
public void testArgsOnePrimitive() {
assertParameterNames(getMethod("onePrimitive"), "args(count)", new String[] {"count"});
}
@Test
public void testArgsOnePrimitiveOneObject() {
assertException(getMethod("oneObjectOnePrimitive"), "args(count,obj)", AmbiguousBindingException.class,
"Found 2 candidate variable names but only one candidate binding slot when matching primitive args");
}
@Test
public void testThisAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && this(obj)",
new String[] {"obj", "count"});
}
@Test
public void testTargetAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && target(obj)",
new String[] {"obj", "count"});
}
@Test
public void testThrowingAndPrimitive() {
assertParameterNames(getMethod("oneThrowableOnePrimitive"), "args(count)", null, "ex",
new String[] {"ex", "count"});
}
@Test
public void testAllTogetherNow() {
assertParameterNames(getMethod("theBigOne"), "this(foo) && args(x)", null, "ex",
new String[] {"thisJoinPoint", "ex", "x", "foo"});
}
@Test
public void testReferenceBinding() {
assertParameterNames(getMethod("onePrimitive"),"somepc(foo)", new String[] {"foo"});
}
@Test
public void testReferenceBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("onePrimitive"),"call(bar *) && somepc(foo)", new String[] {"foo"});
assertParameterNames(getMethod("onePrimitive"),"somepc ( foo )", new String[] {"foo"});
assertParameterNames(getMethod("onePrimitive"),"somepc( foo)", new String[] {"foo"});
}
protected Method getMethod(String name) {
private Method getMethod(String name) {
// Assumes no overloading of test methods...
Method[] candidates = getClass().getMethods();
for (Method candidate : candidates) {
for (Method candidate : getClass().getMethods()) {
if (candidate.getName().equals(name)) {
return candidate;
}
@ -228,11 +296,11 @@ public class AspectJAdviceParameterNameDiscovererTests {
throw new AssertionError("Bad test specification, no method '" + name + "' found in test class");
}
protected void assertParameterNames(Method method, String pointcut, String[] parameterNames) {
private void assertParameterNames(Method method, String pointcut, String[] parameterNames) {
assertParameterNames(method, pointcut, null, null, parameterNames);
}
protected void assertParameterNames(
private void assertParameterNames(
Method method, String pointcut, String returning, String throwing, String[] parameterNames) {
assertThat(parameterNames.length).as("bad test specification, must have same number of parameter names as method arguments").isEqualTo(method.getParameterCount());
@ -243,8 +311,8 @@ public class AspectJAdviceParameterNameDiscovererTests {
discoverer.setThrowingName(throwing);
String[] discoveredNames = discoverer.getParameterNames(method);
String formattedExpectedNames = format(parameterNames);
String formattedActualNames = format(discoveredNames);
String formattedExpectedNames = Arrays.toString(parameterNames);
String formattedActualNames = Arrays.toString(discoveredNames);
assertThat(discoveredNames.length).as("Expecting " + parameterNames.length + " parameter names in return set '" +
formattedExpectedNames + "', but found " + discoveredNames.length +
@ -257,37 +325,23 @@ public class AspectJAdviceParameterNameDiscovererTests {
}
}
protected void assertException(Method method, String pointcut, Class<? extends Throwable> exceptionType, String message) {
private void assertException(Method method, String pointcut, Class<? extends Throwable> exceptionType, String message) {
assertException(method, pointcut, null, null, exceptionType, message);
}
protected void assertException(Method method, String pointcut, String returning,
private void assertException(Method method, String pointcut, String returning,
String throwing, Class<? extends Throwable> exceptionType, String message) {
AspectJAdviceParameterNameDiscoverer discoverer = new AspectJAdviceParameterNameDiscoverer(pointcut);
discoverer.setRaiseExceptions(true);
discoverer.setReturningName(returning);
discoverer.setThrowingName(throwing);
assertThatExceptionOfType(exceptionType).isThrownBy(() ->
discoverer.getParameterNames(method))
assertThatExceptionOfType(exceptionType)
.isThrownBy(() -> discoverer.getParameterNames(method))
.withMessageContaining(message);
}
private static String format(String[] names) {
StringBuilder sb = new StringBuilder();
sb.append('(');
for (int i = 0; i < names.length; i++) {
sb.append(names[i]);
if ((i + 1) < names.length) {
sb.append(',');
}
}
sb.append(')');
return sb.toString();
}
// Methods to discover parameter names for
public void noArgs() {
@ -329,4 +383,14 @@ public class AspectJAdviceParameterNameDiscovererTests {
public void theBigOne(JoinPoint jp, Throwable x, int y, Object foo) {
}
public void oneAnnotation(MyAnnotation ann) {}
public void twoAnnotations(MyAnnotation ann, MyAnnotation anotherAnn) {}
public void annotationMedley(Throwable t, Object foo, int x, MyAnnotation ma) {}
public void pjpAndAnAnnotation(ProceedingJoinPoint pjp, MyAnnotation ann) {}
@interface MyAnnotation {}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2022 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.
@ -17,6 +17,9 @@
package org.springframework.aop.aspectj;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
@ -25,6 +28,8 @@ import org.aspectj.weaver.tools.PointcutPrimitive;
import org.aspectj.weaver.tools.UnsupportedPointcutPrimitiveException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import test.annotation.EmptySpringAnnotation;
import test.annotation.transaction.Tx;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
@ -56,12 +61,19 @@ public class AspectJExpressionPointcutTests {
private Method setSomeNumber;
private final Map<String, Method> methodsOnHasGeneric = new HashMap<>();
@BeforeEach
public void setUp() throws NoSuchMethodException {
getAge = TestBean.class.getMethod("getAge");
setAge = TestBean.class.getMethod("setAge", int.class);
setSomeNumber = TestBean.class.getMethod("setSomeNumber", Number.class);
// Assumes no overloading
for (Method method : HasGeneric.class.getMethods()) {
methodsOnHasGeneric.put(method.getName(), method);
}
}
@ -299,6 +311,279 @@ public class AspectJExpressionPointcutTests {
}
}
@Test
public void testMatchGenericArgument() {
String expression = "execution(* set*(java.util.List<org.springframework.beans.testfixture.beans.TestBean>) )";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
// TODO this will currently map, would be nice for optimization
//assertTrue(ajexp.matches(HasGeneric.class));
//assertFalse(ajexp.matches(TestBean.class));
Method takesGenericList = methodsOnHasGeneric.get("setFriends");
assertThat(ajexp.matches(takesGenericList, HasGeneric.class)).isTrue();
assertThat(ajexp.matches(methodsOnHasGeneric.get("setEnemies"), HasGeneric.class)).isTrue();
assertThat(ajexp.matches(methodsOnHasGeneric.get("setPartners"), HasGeneric.class)).isFalse();
assertThat(ajexp.matches(methodsOnHasGeneric.get("setPhoneNumbers"), HasGeneric.class)).isFalse();
assertThat(ajexp.matches(getAge, TestBean.class)).isFalse();
}
@Test
public void testMatchVarargs() throws Exception {
@SuppressWarnings("unused")
class MyTemplate {
public int queryForInt(String sql, Object... params) {
return 0;
}
}
String expression = "execution(int *.*(String, Object...))";
AspectJExpressionPointcut jdbcVarArgs = new AspectJExpressionPointcut();
jdbcVarArgs.setExpression(expression);
assertThat(jdbcVarArgs.matches(
MyTemplate.class.getMethod("queryForInt", String.class, Object[].class),
MyTemplate.class)).isTrue();
Method takesGenericList = methodsOnHasGeneric.get("setFriends");
assertThat(jdbcVarArgs.matches(takesGenericList, HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(methodsOnHasGeneric.get("setEnemies"), HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(methodsOnHasGeneric.get("setPartners"), HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(methodsOnHasGeneric.get("setPhoneNumbers"), HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(getAge, TestBean.class)).isFalse();
}
@Test
public void testMatchAnnotationOnClassWithAtWithin() throws Exception {
String expression = "@within(test.annotation.transaction.Tx)";
testMatchAnnotationOnClass(expression);
}
@Test
public void testMatchAnnotationOnClassWithoutBinding() throws Exception {
String expression = "within(@test.annotation.transaction.Tx *)";
testMatchAnnotationOnClass(expression);
}
@Test
public void testMatchAnnotationOnClassWithSubpackageWildcard() throws Exception {
String expression = "within(@(test.annotation..*) *)";
AspectJExpressionPointcut springAnnotatedPc = testMatchAnnotationOnClass(expression);
assertThat(springAnnotatedPc.matches(TestBean.class.getMethod("setName", String.class), TestBean.class)).isFalse();
assertThat(springAnnotatedPc.matches(SpringAnnotated.class.getMethod("foo"), SpringAnnotated.class)).isTrue();
expression = "within(@(test.annotation.transaction..*) *)";
AspectJExpressionPointcut springTxAnnotatedPc = testMatchAnnotationOnClass(expression);
assertThat(springTxAnnotatedPc.matches(SpringAnnotated.class.getMethod("foo"), SpringAnnotated.class)).isFalse();
}
@Test
public void testMatchAnnotationOnClassWithExactPackageWildcard() throws Exception {
String expression = "within(@(test.annotation.transaction.*) *)";
testMatchAnnotationOnClass(expression);
}
private AspectJExpressionPointcut testMatchAnnotationOnClass(String expression) throws Exception {
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
assertThat(ajexp.matches(getAge, TestBean.class)).isFalse();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isTrue();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isTrue();
assertThat(ajexp.matches(BeanB.class.getMethod("setName", String.class), BeanB.class)).isTrue();
assertThat(ajexp.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
return ajexp;
}
@Test
public void testAnnotationOnMethodWithFQN() throws Exception {
String expression = "@annotation(test.annotation.transaction.Tx)";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
assertThat(ajexp.matches(getAge, TestBean.class)).isFalse();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(ajexp.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(ajexp.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isTrue();
assertThat(ajexp.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
}
@Test
public void testAnnotationOnCglibProxyMethod() throws Exception {
String expression = "@annotation(test.annotation.transaction.Tx)";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
ProxyFactory factory = new ProxyFactory(new BeanA());
factory.setProxyTargetClass(true);
BeanA proxy = (BeanA) factory.getProxy();
assertThat(ajexp.matches(BeanA.class.getMethod("getAge"), proxy.getClass())).isTrue();
}
@Test
public void testAnnotationOnDynamicProxyMethod() throws Exception {
String expression = "@annotation(test.annotation.transaction.Tx)";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
ProxyFactory factory = new ProxyFactory(new BeanA());
factory.setProxyTargetClass(false);
IBeanA proxy = (IBeanA) factory.getProxy();
assertThat(ajexp.matches(IBeanA.class.getMethod("getAge"), proxy.getClass())).isTrue();
}
@Test
public void testAnnotationOnMethodWithWildcard() throws Exception {
String expression = "execution(@(test.annotation..*) * *(..))";
AspectJExpressionPointcut anySpringMethodAnnotation = new AspectJExpressionPointcut();
anySpringMethodAnnotation.setExpression(expression);
assertThat(anySpringMethodAnnotation.matches(getAge, TestBean.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(
HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(
HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isTrue();
assertThat(anySpringMethodAnnotation.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
}
@Test
public void testAnnotationOnMethodArgumentsWithFQN() throws Exception {
String expression = "@args(*, test.annotation.EmptySpringAnnotation))";
AspectJExpressionPointcut takesSpringAnnotatedArgument2 = new AspectJExpressionPointcut();
takesSpringAnnotatedArgument2.setExpression(expression);
assertThat(takesSpringAnnotatedArgument2.matches(getAge, TestBean.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesAnnotatedParameters", TestBean.class, SpringAnnotated.class),
ProcessesSpringAnnotatedParameters.class)).isTrue();
// True because it maybeMatches with potential argument subtypes
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, BeanA.class),
ProcessesSpringAnnotatedParameters.class)).isTrue();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, BeanA.class),
ProcessesSpringAnnotatedParameters.class, new TestBean(), new BeanA())).isFalse();
}
@Test
public void testAnnotationOnMethodArgumentsWithWildcards() throws Exception {
String expression = "execution(* *(*, @(test..*) *))";
AspectJExpressionPointcut takesSpringAnnotatedArgument2 = new AspectJExpressionPointcut();
takesSpringAnnotatedArgument2.setExpression(expression);
assertThat(takesSpringAnnotatedArgument2.matches(getAge, TestBean.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesAnnotatedParameters", TestBean.class, SpringAnnotated.class),
ProcessesSpringAnnotatedParameters.class)).isTrue();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, BeanA.class),
ProcessesSpringAnnotatedParameters.class)).isFalse();
}
public static class HasGeneric {
public void setFriends(List<TestBean> friends) {
}
public void setEnemies(List<TestBean> enemies) {
}
public void setPartners(List<?> partners) {
}
public void setPhoneNumbers(List<String> numbers) {
}
}
public static class ProcessesSpringAnnotatedParameters {
public void takesAnnotatedParameters(TestBean tb, SpringAnnotated sa) {
}
public void takesNoAnnotatedParameters(TestBean tb, BeanA tb3) {
}
}
@Tx
public static class HasTransactionalAnnotation {
public void foo() {
}
public Object bar(String foo) {
throw new UnsupportedOperationException();
}
}
@EmptySpringAnnotation
public static class SpringAnnotated {
public void foo() {
}
}
interface IBeanA {
@Tx
int getAge();
}
static class BeanA implements IBeanA {
@SuppressWarnings("unused")
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
@Tx
@Override
public int getAge() {
return age;
}
}
@Tx
static class BeanB {
@SuppressWarnings("unused")
private String name;
public void setName(String name) {
this.name = name;
}
}
}

View File

@ -1,89 +0,0 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj;
import org.junit.jupiter.api.Test;
import org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException;
/**
* Tests just the annotation binding part of {@link AspectJAdviceParameterNameDiscoverer};
* see supertype for remaining tests.
*
* @author Adrian Colyer
* @author Chris Beams
*/
public class TigerAspectJAdviceParameterNameDiscovererTests extends AspectJAdviceParameterNameDiscovererTests {
@Test
public void testAtThis() {
assertParameterNames(getMethod("oneAnnotation"),"@this(a)", new String[] {"a"});
}
@Test
public void testAtTarget() {
assertParameterNames(getMethod("oneAnnotation"),"@target(a)", new String[] {"a"});
}
@Test
public void testAtArgs() {
assertParameterNames(getMethod("oneAnnotation"),"@args(a)", new String[] {"a"});
}
@Test
public void testAtWithin() {
assertParameterNames(getMethod("oneAnnotation"),"@within(a)", new String[] {"a"});
}
@Test
public void testAtWithincode() {
assertParameterNames(getMethod("oneAnnotation"),"@withincode(a)", new String[] {"a"});
}
@Test
public void testAtAnnotation() {
assertParameterNames(getMethod("oneAnnotation"),"@annotation(a)", new String[] {"a"});
}
@Test
public void testAmbiguousAnnotationTwoVars() {
assertException(getMethod("twoAnnotations"),"@annotation(a) && @this(x)", AmbiguousBindingException.class,
"Found 2 potential annotation variable(s), and 2 potential argument slots");
}
@Test
public void testAmbiguousAnnotationOneVar() {
assertException(getMethod("oneAnnotation"),"@annotation(a) && @this(x)",IllegalArgumentException.class,
"Found 2 candidate annotation binding variables but only one potential argument binding slot");
}
@Test
public void testAnnotationMedley() {
assertParameterNames(getMethod("annotationMedley"),"@annotation(a) && args(count) && this(foo)",
null, "ex", new String[] {"ex", "foo", "count", "a"});
}
public void oneAnnotation(MyAnnotation ann) {}
public void twoAnnotations(MyAnnotation ann, MyAnnotation anotherAnn) {}
public void annotationMedley(Throwable t, Object foo, int x, MyAnnotation ma) {}
@interface MyAnnotation {}
}

View File

@ -1,330 +0,0 @@
/*
* Copyright 2002-2019 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import test.annotation.EmptySpringAnnotation;
import test.annotation.transaction.Tx;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.testfixture.beans.TestBean;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Java 5 specific {@link AspectJExpressionPointcutTests}.
*
* @author Rod Johnson
* @author Chris Beams
*/
public class TigerAspectJExpressionPointcutTests {
private Method getAge;
private final Map<String, Method> methodsOnHasGeneric = new HashMap<>();
@BeforeEach
public void setup() throws NoSuchMethodException {
getAge = TestBean.class.getMethod("getAge");
// Assumes no overloading
for (Method method : HasGeneric.class.getMethods()) {
methodsOnHasGeneric.put(method.getName(), method);
}
}
@Test
public void testMatchGenericArgument() {
String expression = "execution(* set*(java.util.List<org.springframework.beans.testfixture.beans.TestBean>) )";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
// TODO this will currently map, would be nice for optimization
//assertTrue(ajexp.matches(HasGeneric.class));
//assertFalse(ajexp.matches(TestBean.class));
Method takesGenericList = methodsOnHasGeneric.get("setFriends");
assertThat(ajexp.matches(takesGenericList, HasGeneric.class)).isTrue();
assertThat(ajexp.matches(methodsOnHasGeneric.get("setEnemies"), HasGeneric.class)).isTrue();
assertThat(ajexp.matches(methodsOnHasGeneric.get("setPartners"), HasGeneric.class)).isFalse();
assertThat(ajexp.matches(methodsOnHasGeneric.get("setPhoneNumbers"), HasGeneric.class)).isFalse();
assertThat(ajexp.matches(getAge, TestBean.class)).isFalse();
}
@Test
public void testMatchVarargs() throws Exception {
@SuppressWarnings("unused")
class MyTemplate {
public int queryForInt(String sql, Object... params) {
return 0;
}
}
String expression = "execution(int *.*(String, Object...))";
AspectJExpressionPointcut jdbcVarArgs = new AspectJExpressionPointcut();
jdbcVarArgs.setExpression(expression);
assertThat(jdbcVarArgs.matches(
MyTemplate.class.getMethod("queryForInt", String.class, Object[].class),
MyTemplate.class)).isTrue();
Method takesGenericList = methodsOnHasGeneric.get("setFriends");
assertThat(jdbcVarArgs.matches(takesGenericList, HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(methodsOnHasGeneric.get("setEnemies"), HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(methodsOnHasGeneric.get("setPartners"), HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(methodsOnHasGeneric.get("setPhoneNumbers"), HasGeneric.class)).isFalse();
assertThat(jdbcVarArgs.matches(getAge, TestBean.class)).isFalse();
}
@Test
public void testMatchAnnotationOnClassWithAtWithin() throws Exception {
String expression = "@within(test.annotation.transaction.Tx)";
testMatchAnnotationOnClass(expression);
}
@Test
public void testMatchAnnotationOnClassWithoutBinding() throws Exception {
String expression = "within(@test.annotation.transaction.Tx *)";
testMatchAnnotationOnClass(expression);
}
@Test
public void testMatchAnnotationOnClassWithSubpackageWildcard() throws Exception {
String expression = "within(@(test.annotation..*) *)";
AspectJExpressionPointcut springAnnotatedPc = testMatchAnnotationOnClass(expression);
assertThat(springAnnotatedPc.matches(TestBean.class.getMethod("setName", String.class), TestBean.class)).isFalse();
assertThat(springAnnotatedPc.matches(SpringAnnotated.class.getMethod("foo"), SpringAnnotated.class)).isTrue();
expression = "within(@(test.annotation.transaction..*) *)";
AspectJExpressionPointcut springTxAnnotatedPc = testMatchAnnotationOnClass(expression);
assertThat(springTxAnnotatedPc.matches(SpringAnnotated.class.getMethod("foo"), SpringAnnotated.class)).isFalse();
}
@Test
public void testMatchAnnotationOnClassWithExactPackageWildcard() throws Exception {
String expression = "within(@(test.annotation.transaction.*) *)";
testMatchAnnotationOnClass(expression);
}
private AspectJExpressionPointcut testMatchAnnotationOnClass(String expression) throws Exception {
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
assertThat(ajexp.matches(getAge, TestBean.class)).isFalse();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isTrue();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isTrue();
assertThat(ajexp.matches(BeanB.class.getMethod("setName", String.class), BeanB.class)).isTrue();
assertThat(ajexp.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
return ajexp;
}
@Test
public void testAnnotationOnMethodWithFQN() throws Exception {
String expression = "@annotation(test.annotation.transaction.Tx)";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
assertThat(ajexp.matches(getAge, TestBean.class)).isFalse();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(ajexp.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(ajexp.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(ajexp.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isTrue();
assertThat(ajexp.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
}
@Test
public void testAnnotationOnCglibProxyMethod() throws Exception {
String expression = "@annotation(test.annotation.transaction.Tx)";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
ProxyFactory factory = new ProxyFactory(new BeanA());
factory.setProxyTargetClass(true);
BeanA proxy = (BeanA) factory.getProxy();
assertThat(ajexp.matches(BeanA.class.getMethod("getAge"), proxy.getClass())).isTrue();
}
@Test
public void testAnnotationOnDynamicProxyMethod() throws Exception {
String expression = "@annotation(test.annotation.transaction.Tx)";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
ProxyFactory factory = new ProxyFactory(new BeanA());
factory.setProxyTargetClass(false);
IBeanA proxy = (IBeanA) factory.getProxy();
assertThat(ajexp.matches(IBeanA.class.getMethod("getAge"), proxy.getClass())).isTrue();
}
@Test
public void testAnnotationOnMethodWithWildcard() throws Exception {
String expression = "execution(@(test.annotation..*) * *(..))";
AspectJExpressionPointcut anySpringMethodAnnotation = new AspectJExpressionPointcut();
anySpringMethodAnnotation.setExpression(expression);
assertThat(anySpringMethodAnnotation.matches(getAge, TestBean.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(
HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(
HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(anySpringMethodAnnotation.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isTrue();
assertThat(anySpringMethodAnnotation.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
}
@Test
public void testAnnotationOnMethodArgumentsWithFQN() throws Exception {
String expression = "@args(*, test.annotation.EmptySpringAnnotation))";
AspectJExpressionPointcut takesSpringAnnotatedArgument2 = new AspectJExpressionPointcut();
takesSpringAnnotatedArgument2.setExpression(expression);
assertThat(takesSpringAnnotatedArgument2.matches(getAge, TestBean.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesAnnotatedParameters", TestBean.class, SpringAnnotated.class),
ProcessesSpringAnnotatedParameters.class)).isTrue();
// True because it maybeMatches with potential argument subtypes
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, BeanA.class),
ProcessesSpringAnnotatedParameters.class)).isTrue();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, BeanA.class),
ProcessesSpringAnnotatedParameters.class, new TestBean(), new BeanA())).isFalse();
}
@Test
public void testAnnotationOnMethodArgumentsWithWildcards() throws Exception {
String expression = "execution(* *(*, @(test..*) *))";
AspectJExpressionPointcut takesSpringAnnotatedArgument2 = new AspectJExpressionPointcut();
takesSpringAnnotatedArgument2.setExpression(expression);
assertThat(takesSpringAnnotatedArgument2.matches(getAge, TestBean.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("foo"), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("getAge"), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class)).isFalse();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesAnnotatedParameters", TestBean.class, SpringAnnotated.class),
ProcessesSpringAnnotatedParameters.class)).isTrue();
assertThat(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, BeanA.class),
ProcessesSpringAnnotatedParameters.class)).isFalse();
}
public static class HasGeneric {
public void setFriends(List<TestBean> friends) {
}
public void setEnemies(List<TestBean> enemies) {
}
public void setPartners(List<?> partners) {
}
public void setPhoneNumbers(List<String> numbers) {
}
}
public static class ProcessesSpringAnnotatedParameters {
public void takesAnnotatedParameters(TestBean tb, SpringAnnotated sa) {
}
public void takesNoAnnotatedParameters(TestBean tb, BeanA tb3) {
}
}
@Tx
public static class HasTransactionalAnnotation {
public void foo() {
}
public Object bar(String foo) {
throw new UnsupportedOperationException();
}
}
@EmptySpringAnnotation
public static class SpringAnnotated {
public void foo() {
}
}
interface IBeanA {
@Tx
int getAge();
}
static class BeanA implements IBeanA {
@SuppressWarnings("unused")
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
@Tx
@Override
public int getAge() {
return age;
}
}
@Tx
static class BeanB {
@SuppressWarnings("unused")
private String name;
public void setName(String name) {
this.name = name;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.
@ -46,7 +46,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.StringValueResolver;
/**
* Implementation of the {@code JmxAttributeSource} interface that
* Implementation of the {@link JmxAttributeSource} interface that
* reads annotations and exposes the corresponding attributes.
*
* @author Rob Harrop

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2022 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.
@ -23,7 +23,7 @@ import org.springframework.jmx.export.naming.MetadataNamingStrategy;
/**
* Convenient subclass of Spring's standard {@link MBeanExporter},
* activating Java 5 annotation usage for JMX exposure of Spring beans:
* activating annotation usage for JMX exposure of Spring beans:
* {@link ManagedResource}, {@link ManagedAttribute}, {@link ManagedOperation}, etc.
*
* <p>Sets a {@link MetadataNamingStrategy} and a {@link MetadataMBeanInfoAssembler}

View File

@ -27,7 +27,8 @@ import org.springframework.jmx.support.MetricType;
/**
* Method-level annotation that indicates to expose a given bean property as a
* JMX attribute, with added descriptor properties to indicate that it is a metric.
* Only valid when used on a JavaBean getter.
*
* <p>Only valid when used on a JavaBean getter.
*
* @author Jennifer Hickey
* @since 3.0

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
@ -27,11 +27,12 @@ import java.lang.annotation.Target;
/**
* Type-level annotation that indicates a JMX notification emitted by a bean.
*
* <p>This annotation can be used as a <em>{@linkplain Repeatable repeatable}</em>
* <p>This annotation is a {@linkplain java.lang.annotation.Repeatable repeatable}
* annotation.
*
* @author Rob Harrop
* @since 2.0
* @see ManagedNotifications
* @see org.springframework.jmx.export.metadata.ManagedNotification
*/
@Target(ElementType.TYPE)

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2022 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.
@ -24,8 +24,12 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Type-level annotation that indicates JMX notifications emitted by a bean,
* containing multiple {@link ManagedNotification ManagedNotifications}.
* Type-level annotation used as a container for one or more
* {@code @ManagedNotification} declarations.
*
* <p>Note, however, that use of the {@code @ManagedNotifications} container
* is completely optional since {@code @ManagedNotification} is a
* {@linkplain java.lang.annotation.Repeatable repeatable} annotation.
*
* @author Rob Harrop
* @since 2.0

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2022 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.
@ -23,9 +23,11 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Method-level annotation that indicates to expose a given method as a
* JMX operation, corresponding to the {@code ManagedOperation} attribute.
* Only valid when used on a method that is not a JavaBean getter or setter.
* Method-level annotation that indicates to expose a given method as a JMX operation,
* corresponding to the {@link org.springframework.jmx.export.metadata.ManagedOperation}
* attribute.
*
* <p>Only valid when used on a method that is not a JavaBean getter or setter.
*
* @author Rob Harrop
* @since 1.2

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
@ -24,15 +24,15 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Method-level annotation used to provide metadata about operation parameters,
* corresponding to a {@code ManagedOperationParameter} attribute.
* Method-level annotation used to provide metadata about operation parameters, corresponding
* to a {@link org.springframework.jmx.export.metadata.ManagedOperationParameter} attribute.
*
* <p>This annotation can be used as a <em>{@linkplain Repeatable repeatable}</em>
* <p>This annotation is a {@linkplain java.lang.annotation.Repeatable repeatable}
* annotation.
*
* @author Rob Harrop
* @since 1.2
* @see ManagedOperationParameters#value
* @see ManagedOperationParameters
* @see org.springframework.jmx.export.metadata.ManagedOperationParameter
*/
@Target(ElementType.METHOD)

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2022 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.
@ -23,8 +23,12 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Method-level annotation used to provide metadata about operation parameters,
* corresponding to an array of {@code ManagedOperationParameter} attributes.
* Method-level annotation used as a container for one or more
* {@code @ManagedOperationParameter} declarations.
*
* <p>Note, however, that use of the {@code @ManagedOperationParameters} container
* is completely optional since {@code @ManagedOperationParameter} is a
* {@linkplain java.lang.annotation.Repeatable repeatable} annotation.
*
* @author Rob Harrop
* @since 1.2

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2022 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,8 +26,8 @@ import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
/**
* Class-level annotation that indicates to register instances of a class
* with a JMX server, corresponding to the {@code ManagedResource} attribute.
* Class-level annotation that indicates to register instances of a class with a JMX server,
* corresponding to the {@link org.springframework.jmx.export.metadata.ManagedResource} attribute.
*
* <p><b>Note:</b> This annotation is marked as inherited, allowing for generic
* management-aware base classes. In such a scenario, it is recommended to

View File

@ -1,7 +1,8 @@
/**
* Java 5 annotations for MBean exposure.
* Hooked into Spring's JMX export infrastructure
* via a special JmxAttributeSource implementation.
* Annotations for MBean exposure.
*
* <p>Hooked into Spring's JMX export infrastructure via a special
* {@link org.springframework.jmx.export.metadata.JmxAttributeSource} implementation.
*/
@NonNullApi
@NonNullFields

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2022 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.
@ -40,7 +40,7 @@ import org.springframework.util.StringUtils;
* <p>Uses the {@link JmxAttributeSource} strategy interface, so that
* metadata can be read using any supported implementation. Out of the box,
* {@link org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource}
* introspects a well-defined set of Java 5 annotations that come with Spring.
* introspects a well-defined set of annotations that come with Spring.
*
* @author Rob Harrop
* @author Juergen Hoeller

View File

@ -1,5 +1,5 @@
/**
* Java 5 annotation for asynchronous method execution.
* Annotation support for asynchronous method execution.
*/
@NonNullApi
@NonNullFields

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2022 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.
@ -23,7 +23,6 @@ import org.springframework.lang.Nullable;
/**
* Subclass of {@link ModelMap} that implements the {@link Model} interface.
* Java 5 specific like the {@code Model} interface itself.
*
* <p>This is an implementation class exposed to handler methods by Spring MVC, typically via
* a declaration of the {@link org.springframework.ui.Model} interface. There is no need to

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.
@ -22,9 +22,11 @@ import java.util.Map;
import org.springframework.lang.Nullable;
/**
* Java-5-specific interface that defines a holder for model attributes.
* Primarily designed for adding attributes to the model.
* Allows for accessing the overall model as a {@code java.util.Map}.
* Interface that defines a holder for model attributes.
*
* <p>Primarily designed for adding attributes to the model.
*
* <p>Allows for accessing the overall model as a {@code java.util.Map}.
*
* @author Juergen Hoeller
* @since 2.5.1

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2022 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.
@ -24,8 +24,9 @@ import org.springframework.lang.Nullable;
* Subclass of {@link IOException} that properly handles a root cause,
* exposing the root cause just like NestedChecked/RuntimeException does.
*
* <p>Proper root cause handling has not been added to standard IOException before
* Java 6, which is why we need to do it ourselves for Java 5 compatibility purposes.
* <p>Proper root cause handling was added to the standard {@code IOException} in
* Java 6, which is why Spring originally introduced {@code NestedIOException}
* for compatibility with versions prior to Java 6.
*
* <p>The similarity between this class and the NestedChecked/RuntimeException
* class is unavoidable, as this class needs to derive from IOException.

View File

@ -1244,7 +1244,7 @@ public abstract class ClassUtils {
* target class may be {@code DefaultFoo}. In this case, the method may be
* {@code DefaultFoo.bar()}. This enables attributes on that method to be found.
* <p><b>NOTE:</b> In contrast to {@link org.springframework.aop.support.AopUtils#getMostSpecificMethod},
* this method does <i>not</i> resolve Java 5 bridge methods automatically.
* this method does <i>not</i> resolve bridge methods automatically.
* Call {@link org.springframework.core.BridgeMethodResolver#findBridgedMethod}
* if bridge method resolution is desirable (e.g. for obtaining metadata from
* the original method definition).

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
@ -24,7 +24,8 @@ import java.lang.reflect.WildcardType;
import org.springframework.lang.Nullable;
/**
* Utility to work with Java 5 generic type parameters.
* Utility to work with generic type parameters.
*
* <p>Mainly for internal use within the framework.
*
* @author Ramnivas Laddad

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2022 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,7 +19,7 @@ package org.springframework.oxm;
import java.lang.reflect.Type;
/**
* Subinterface of {@link Marshaller} that has support for Java 5 generics.
* Subinterface of {@link Marshaller} that has support for generics.
*
* @author Arjen Poutsma
* @since 3.0.1

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2022 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,7 +19,7 @@ package org.springframework.oxm;
import java.lang.reflect.Type;
/**
* Subinterface of {@link Unmarshaller} that has support for Java 5 generics.
* Subinterface of {@link Unmarshaller} that has support for generics.
*
* @author Arjen Poutsma
* @since 3.0.1

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 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.
@ -24,7 +24,7 @@ import org.springframework.lang.Nullable;
* Strategy interface used by {@link TransactionInterceptor} for metadata retrieval.
*
* <p>Implementations know how to source transaction attributes, whether from configuration,
* metadata attributes at source level (such as Java 5 annotations), or anywhere else.
* metadata attributes at source level (such as annotations), or anywhere else.
*
* @author Rod Johnson
* @author Juergen Hoeller

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2022 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.
@ -17,11 +17,11 @@
package org.springframework.web.bind.annotation;
/**
* Java 5 enumeration of HTTP request methods. Intended for use with the
* Enumeration of HTTP request methods. Intended for use with the
* {@link RequestMapping#method()} attribute of the {@link RequestMapping} annotation.
*
* <p>Note that, by default, {@link org.springframework.web.servlet.DispatcherServlet}
* supports GET, HEAD, POST, PUT, PATCH and DELETE only. DispatcherServlet will
* supports GET, HEAD, POST, PUT, PATCH, and DELETE only. DispatcherServlet will
* process TRACE and OPTIONS with the default HttpServlet behavior unless explicitly
* told to dispatch those request types as well: Check out the "dispatchOptionsRequest"
* and "dispatchTraceRequest" properties, switching them to "true" if necessary.

View File

@ -1788,7 +1788,7 @@ a parent collection definition is redundant and does not result in the desired m
[[beans-collection-elements-strongly-typed]]
===== Strongly-typed collection
With the introduction of generic types in Java 5, you can use strongly typed collections.
Thanks to Java's support for generic types, you can use strongly typed collections.
That is, it is possible to declare a `Collection` type such that it can only contain
(for example) `String` elements. If you use Spring to dependency-inject a
strongly-typed `Collection` into a bean, you can take advantage of Spring's