Polishing

This commit is contained in:
Sam Brannen 2023-02-24 13:59:26 +01:00
parent 0d10d4beee
commit 7c50464bba
6 changed files with 122 additions and 134 deletions

View File

@ -347,14 +347,14 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
// Second candidate we've found - ambiguous binding // Second candidate we've found - ambiguous binding
throw new AmbiguousBindingException("Binding of throwing parameter '" + throw new AmbiguousBindingException("Binding of throwing parameter '" +
this.throwingName + "' is ambiguous: could be bound to argument " + this.throwingName + "' is ambiguous: could be bound to argument " +
throwableIndex + " or argument " + i); throwableIndex + " or " + i);
} }
} }
} }
if (throwableIndex == -1) { if (throwableIndex == -1) {
throw new IllegalStateException("Binding of throwing parameter '" + this.throwingName throw new IllegalStateException("Binding of throwing parameter '" + this.throwingName +
+ "' could not be completed as no available arguments are a subtype of Throwable"); "' could not be completed as no available arguments are a subtype of Throwable");
} }
else { else {
bindParameterName(throwableIndex, this.throwingName); bindParameterName(throwableIndex, this.throwingName);
@ -373,7 +373,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
if (this.returningName != null) { if (this.returningName != null) {
if (this.numberOfRemainingUnboundArguments > 1) { if (this.numberOfRemainingUnboundArguments > 1) {
throw new AmbiguousBindingException("Binding of returning parameter '" + this.returningName + throw new AmbiguousBindingException("Binding of returning parameter '" + this.returningName +
"' is ambiguous, there are " + this.numberOfRemainingUnboundArguments + " candidates."); "' is ambiguous: there are " + this.numberOfRemainingUnboundArguments + " candidates.");
} }
// We're all set... find the unbound parameter, and bind it. // We're all set... find the unbound parameter, and bind it.
@ -429,7 +429,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
int numAnnotationSlots = countNumberOfUnboundAnnotationArguments(); int numAnnotationSlots = countNumberOfUnboundAnnotationArguments();
if (numAnnotationSlots > 1) { if (numAnnotationSlots > 1) {
throw new AmbiguousBindingException("Found " + varNames.size() + throw new AmbiguousBindingException("Found " + varNames.size() +
" potential annotation variable(s), and " + " potential annotation variable(s) and " +
numAnnotationSlots + " potential argument slots"); numAnnotationSlots + " potential argument slots");
} }
else if (numAnnotationSlots == 1) { else if (numAnnotationSlots == 1) {
@ -486,7 +486,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
private void maybeBindThisOrTargetOrArgsFromPointcutExpression() { private void maybeBindThisOrTargetOrArgsFromPointcutExpression() {
if (this.numberOfRemainingUnboundArguments > 1) { if (this.numberOfRemainingUnboundArguments > 1) {
throw new AmbiguousBindingException("Still " + this.numberOfRemainingUnboundArguments throw new AmbiguousBindingException("Still " + this.numberOfRemainingUnboundArguments
+ " unbound args at this(),target(),args() binding stage, with no way to determine between them"); + " unbound args at this()/target()/args() binding stage, with no way to determine between them");
} }
List<String> varNames = new ArrayList<>(); List<String> varNames = new ArrayList<>();
@ -520,7 +520,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
if (varNames.size() > 1) { if (varNames.size() > 1) {
throw new AmbiguousBindingException("Found " + varNames.size() + throw new AmbiguousBindingException("Found " + varNames.size() +
" candidate this(), target() or args() variables but only one unbound argument slot"); " candidate this(), target(), or args() variables but only one unbound argument slot");
} }
else if (varNames.size() == 1) { else if (varNames.size() == 1) {
for (int j = 0; j < this.parameterNameBindings.length; j++) { for (int j = 0; j < this.parameterNameBindings.length; j++) {
@ -646,8 +646,8 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov
private void maybeBindPrimitiveArgsFromPointcutExpression() { private void maybeBindPrimitiveArgsFromPointcutExpression() {
int numUnboundPrimitives = countNumberOfUnboundPrimitiveArguments(); int numUnboundPrimitives = countNumberOfUnboundPrimitiveArguments();
if (numUnboundPrimitives > 1) { if (numUnboundPrimitives > 1) {
throw new AmbiguousBindingException("Found '" + numUnboundPrimitives + throw new AmbiguousBindingException("Found " + numUnboundPrimitives +
"' unbound primitive arguments with no way to distinguish between them."); " unbound primitive arguments with no way to distinguish between them.");
} }
if (numUnboundPrimitives == 1) { if (numUnboundPrimitives == 1) {
// Look for arg variable and bind it if we find exactly one... // Look for arg variable and bind it if we find exactly one...

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2022 the original author or authors. * Copyright 2002-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,7 +17,6 @@
package org.springframework.aop.aspectj; package org.springframework.aop.aspectj;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
@ -43,17 +42,17 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test @Test
void noArgs() { void noArgs() {
assertParameterNames(getMethod("noArgs"), "execution(* *(..))", new String[0]); assertParameterNames(getMethod("noArgs"), "execution(* *(..))");
} }
@Test @Test
void joinPointOnly() { void joinPointOnly() {
assertParameterNames(getMethod("tjp"), "execution(* *(..))", new String[] {"thisJoinPoint"}); assertParameterNames(getMethod("tjp"), "execution(* *(..))", "thisJoinPoint");
} }
@Test @Test
void joinPointStaticPartOnly() { void joinPointStaticPartOnly() {
assertParameterNames(getMethod("tjpsp"), "execution(* *(..))", new String[] {"thisJoinPointStaticPart"}); assertParameterNames(getMethod("tjpsp"), "execution(* *(..))", "thisJoinPointStaticPart");
} }
@Test @Test
@ -64,18 +63,18 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test @Test
void oneThrowable() { void oneThrowable() {
assertParameterNames(getMethod("oneThrowable"), "foo()", null, "ex", new String[] {"ex"}); assertParameterNamesExtended(getMethod("oneThrowable"), "foo()", null, "ex", "ex");
} }
@Test @Test
void oneJPAndOneThrowable() { void oneJPAndOneThrowable() {
assertParameterNames(getMethod("jpAndOneThrowable"), "foo()", null, "ex", new String[] {"thisJoinPoint", "ex"}); assertParameterNamesExtended(getMethod("jpAndOneThrowable"), "foo()", null, "ex", "thisJoinPoint", "ex");
} }
@Test @Test
void oneJPAndTwoThrowables() { void oneJPAndTwoThrowables() {
assertException(getMethod("jpAndTwoThrowables"), "foo()", null, "ex", AmbiguousBindingException.class, assertException(getMethod("jpAndTwoThrowables"), "foo()", null, "ex", AmbiguousBindingException.class,
"Binding of throwing parameter 'ex' is ambiguous: could be bound to argument 1 or argument 2"); "Binding of throwing parameter 'ex' is ambiguous: could be bound to argument 1 or 2");
} }
@Test @Test
@ -86,13 +85,13 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test @Test
void returning() { void returning() {
assertParameterNames(getMethod("oneObject"), "foo()", "obj", null, new String[] {"obj"}); assertParameterNamesExtended(getMethod("oneObject"), "foo()", "obj", null, "obj");
} }
@Test @Test
void ambiguousReturning() { void ambiguousReturning() {
assertException(getMethod("twoObjects"), "foo()", "obj", null, AmbiguousBindingException.class, assertException(getMethod("twoObjects"), "foo()", "obj", null, AmbiguousBindingException.class,
"Binding of returning parameter 'obj' is ambiguous, there are 2 candidates."); "Binding of returning parameter 'obj' is ambiguous: there are 2 candidates.");
} }
@Test @Test
@ -103,22 +102,22 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test @Test
void thisBindingOneCandidate() { void thisBindingOneCandidate() {
assertParameterNames(getMethod("oneObject"), "this(x)", new String[] {"x"}); assertParameterNames(getMethod("oneObject"), "this(x)", "x");
} }
@Test @Test
void thisBindingWithAlternateTokenizations() { void thisBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("oneObject"), "this( x )", new String[] {"x"}); assertParameterNames(getMethod("oneObject"), "this( x )", "x");
assertParameterNames(getMethod("oneObject"), "this( x)", new String[] {"x"}); assertParameterNames(getMethod("oneObject"), "this( x)", "x");
assertParameterNames(getMethod("oneObject"), "this (x )", new String[] {"x"}); assertParameterNames(getMethod("oneObject"), "this (x )", "x");
assertParameterNames(getMethod("oneObject"), "this(x )", new String[] {"x"}); assertParameterNames(getMethod("oneObject"), "this(x )", "x");
assertParameterNames(getMethod("oneObject"), "foo() && this(x)", new String[] {"x"}); assertParameterNames(getMethod("oneObject"), "foo() && this(x)", "x");
} }
@Test @Test
void thisBindingTwoCandidates() { void thisBindingTwoCandidates() {
assertException(getMethod("oneObject"), "this(x) || this(y)", AmbiguousBindingException.class, assertException(getMethod("oneObject"), "this(x) || this(y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot"); "Found 2 candidate this(), target(), or args() variables but only one unbound argument slot");
} }
@Test @Test
@ -131,22 +130,22 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test @Test
void targetBindingOneCandidate() { void targetBindingOneCandidate() {
assertParameterNames(getMethod("oneObject"), "target(x)", new String[] {"x"}); assertParameterNames(getMethod("oneObject"), "target(x)", "x");
} }
@Test @Test
void targetBindingWithAlternateTokenizations() { void targetBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("oneObject"), "target( x )", new String[] {"x"}); assertParameterNames(getMethod("oneObject"), "target( x )", "x");
assertParameterNames(getMethod("oneObject"), "target( x)", new String[] {"x"}); assertParameterNames(getMethod("oneObject"), "target( x)", "x");
assertParameterNames(getMethod("oneObject"), "target (x )", new String[] {"x"}); assertParameterNames(getMethod("oneObject"), "target (x )", "x");
assertParameterNames(getMethod("oneObject"), "target(x )", new String[] {"x"}); assertParameterNames(getMethod("oneObject"), "target(x )", "x");
assertParameterNames(getMethod("oneObject"), "foo() && target(x)", new String[] {"x"}); assertParameterNames(getMethod("oneObject"), "foo() && target(x)", "x");
} }
@Test @Test
void targetBindingTwoCandidates() { void targetBindingTwoCandidates() {
assertException(getMethod("oneObject"), "target(x) || target(y)", AmbiguousBindingException.class, assertException(getMethod("oneObject"), "target(x) || target(y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot"); "Found 2 candidate this(), target(), or args() variables but only one unbound argument slot");
} }
@Test @Test
@ -159,24 +158,24 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test @Test
void argsBindingOneObject() { void argsBindingOneObject() {
assertParameterNames(getMethod("oneObject"), "args(x)", new String[] {"x"}); assertParameterNames(getMethod("oneObject"), "args(x)", "x");
} }
@Test @Test
void argsBindingOneObjectTwoCandidates() { void argsBindingOneObjectTwoCandidates() {
assertException(getMethod("oneObject"), "args(x,y)", AmbiguousBindingException.class, assertException(getMethod("oneObject"), "args(x,y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot"); "Found 2 candidate this(), target(), or args() variables but only one unbound argument slot");
} }
@Test @Test
void ambiguousArgsBinding() { void ambiguousArgsBinding() {
assertException(getMethod("twoObjects"), "args(x,y)", AmbiguousBindingException.class, 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"); "Still 2 unbound args at this()/target()/args() binding stage, with no way to determine between them");
} }
@Test @Test
void argsOnePrimitive() { void argsOnePrimitive() {
assertParameterNames(getMethod("onePrimitive"), "args(count)", new String[] {"count"}); assertParameterNames(getMethod("onePrimitive"), "args(count)", "count");
} }
@Test @Test
@ -188,37 +187,37 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test @Test
void thisAndPrimitive() { void thisAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && this(obj)", assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && this(obj)",
new String[] {"obj", "count"}); "obj", "count");
} }
@Test @Test
void targetAndPrimitive() { void targetAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && target(obj)", assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && target(obj)",
new String[] {"obj", "count"}); "obj", "count");
} }
@Test @Test
void throwingAndPrimitive() { void throwingAndPrimitive() {
assertParameterNames(getMethod("oneThrowableOnePrimitive"), "args(count)", null, "ex", assertParameterNamesExtended(getMethod("oneThrowableOnePrimitive"), "args(count)", null, "ex",
new String[] {"ex", "count"}); "ex", "count");
} }
@Test @Test
void allTogetherNow() { void allTogetherNow() {
assertParameterNames(getMethod("theBigOne"), "this(foo) && args(x)", null, "ex", assertParameterNamesExtended(getMethod("theBigOne"), "this(foo) && args(x)", null, "ex",
new String[] {"thisJoinPoint", "ex", "x", "foo"}); "thisJoinPoint", "ex", "x", "foo");
} }
@Test @Test
void referenceBinding() { void referenceBinding() {
assertParameterNames(getMethod("onePrimitive"),"somepc(foo)", new String[] {"foo"}); assertParameterNames(getMethod("onePrimitive"),"somepc(foo)", "foo");
} }
@Test @Test
void referenceBindingWithAlternateTokenizations() { void referenceBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("onePrimitive"),"call(bar *) && somepc(foo)", new String[] {"foo"}); assertParameterNames(getMethod("onePrimitive"),"call(bar *) && somepc(foo)", "foo");
assertParameterNames(getMethod("onePrimitive"),"somepc ( foo )", new String[] {"foo"}); assertParameterNames(getMethod("onePrimitive"),"somepc ( foo )", "foo");
assertParameterNames(getMethod("onePrimitive"),"somepc( foo)", new String[] {"foo"}); assertParameterNames(getMethod("onePrimitive"),"somepc( foo)", "foo");
} }
} }
@ -230,38 +229,38 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test @Test
void atThis() { void atThis() {
assertParameterNames(getMethod("oneAnnotation"),"@this(a)", new String[] {"a"}); assertParameterNames(getMethod("oneAnnotation"),"@this(a)", "a");
} }
@Test @Test
void atTarget() { void atTarget() {
assertParameterNames(getMethod("oneAnnotation"),"@target(a)", new String[] {"a"}); assertParameterNames(getMethod("oneAnnotation"),"@target(a)", "a");
} }
@Test @Test
void atArgs() { void atArgs() {
assertParameterNames(getMethod("oneAnnotation"),"@args(a)", new String[] {"a"}); assertParameterNames(getMethod("oneAnnotation"),"@args(a)", "a");
} }
@Test @Test
void atWithin() { void atWithin() {
assertParameterNames(getMethod("oneAnnotation"),"@within(a)", new String[] {"a"}); assertParameterNames(getMethod("oneAnnotation"),"@within(a)", "a");
} }
@Test @Test
void atWithincode() { void atWithincode() {
assertParameterNames(getMethod("oneAnnotation"),"@withincode(a)", new String[] {"a"}); assertParameterNames(getMethod("oneAnnotation"),"@withincode(a)", "a");
} }
@Test @Test
void atAnnotation() { void atAnnotation() {
assertParameterNames(getMethod("oneAnnotation"),"@annotation(a)", new String[] {"a"}); assertParameterNames(getMethod("oneAnnotation"),"@annotation(a)", "a");
} }
@Test @Test
void ambiguousAnnotationTwoVars() { void ambiguousAnnotationTwoVars() {
assertException(getMethod("twoAnnotations"),"@annotation(a) && @this(x)", AmbiguousBindingException.class, assertException(getMethod("twoAnnotations"),"@annotation(a) && @this(x)", AmbiguousBindingException.class,
"Found 2 potential annotation variable(s), and 2 potential argument slots"); "Found 2 potential annotation variable(s) and 2 potential argument slots");
} }
@Test @Test
@ -272,15 +271,14 @@ class AspectJAdviceParameterNameDiscovererTests {
@Test @Test
void annotationMedley() { void annotationMedley() {
assertParameterNames(getMethod("annotationMedley"),"@annotation(a) && args(count) && this(foo)", assertParameterNamesExtended(getMethod("annotationMedley"),"@annotation(a) && args(count) && this(foo)",
null, "ex", new String[] {"ex", "foo", "count", "a"}); null, "ex", "ex", "foo", "count", "a");
} }
@Test @Test
void annotationBinding() { void annotationBinding() {
assertParameterNames(getMethod("pjpAndAnAnnotation"), assertParameterNames(getMethod("pjpAndAnAnnotation"),
"execution(* *(..)) && @annotation(ann)", "execution(* *(..)) && @annotation(ann)", "thisJoinPoint", "ann");
new String[] {"thisJoinPoint","ann"});
} }
} }
@ -296,33 +294,23 @@ class AspectJAdviceParameterNameDiscovererTests {
throw new AssertionError("Bad test specification, no method '" + name + "' found in test class"); throw new AssertionError("Bad test specification, no method '" + name + "' found in test class");
} }
private void assertParameterNames(Method method, String pointcut, String[] parameterNames) { private void assertParameterNames(Method method, String pointcut, String... parameterNames) {
assertParameterNames(method, pointcut, null, null, parameterNames); assertParameterNamesExtended(method, pointcut, null, null, parameterNames);
} }
private void assertParameterNames( private void assertParameterNamesExtended(
Method method, String pointcut, String returning, String throwing, String[] parameterNames) { 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()); assertThat(parameterNames)
.as("bad test specification, must have same number of parameter names as method arguments")
.hasSize(method.getParameterCount());
AspectJAdviceParameterNameDiscoverer discoverer = new AspectJAdviceParameterNameDiscoverer(pointcut); AspectJAdviceParameterNameDiscoverer discoverer = new AspectJAdviceParameterNameDiscoverer(pointcut);
discoverer.setRaiseExceptions(true); discoverer.setRaiseExceptions(true);
discoverer.setReturningName(returning); discoverer.setReturningName(returning);
discoverer.setThrowingName(throwing); discoverer.setThrowingName(throwing);
String[] discoveredNames = discoverer.getParameterNames(method);
String formattedExpectedNames = Arrays.toString(parameterNames); assertThat(discoverer.getParameterNames(method)).isEqualTo(parameterNames);
String formattedActualNames = Arrays.toString(discoveredNames);
assertThat(discoveredNames.length).as("Expecting " + parameterNames.length + " parameter names in return set '" +
formattedExpectedNames + "', but found " + discoveredNames.length +
" '" + formattedActualNames + "'").isEqualTo(parameterNames.length);
for (int i = 0; i < discoveredNames.length; i++) {
assertThat(discoveredNames[i]).as("Parameter names must never be null").isNotNull();
assertThat(discoveredNames[i]).as("Expecting parameter " + i + " to be named '" +
parameterNames[i] + "' but was '" + discoveredNames[i] + "'").isEqualTo(parameterNames[i]);
}
} }
private 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) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -38,56 +38,55 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
* @author Adrian Colyer * @author Adrian Colyer
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Chris Beams * @author Chris Beams
* @author Sam Brannen
*/ */
public class ArgumentBindingTests { class ArgumentBindingTests {
@Test @Test
public void testBindingInPointcutUsedByAdvice() { void bindingInPointcutUsedByAdvice() {
TestBean tb = new TestBean(); AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean());
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
proxyFactory.addAspect(NamedPointcutWithArgs.class); proxyFactory.addAspect(NamedPointcutWithArgs.class);
ITestBean proxiedTestBean = proxyFactory.getProxy(); ITestBean proxiedTestBean = proxyFactory.getProxy();
assertThatIllegalArgumentException().isThrownBy(() -> assertThatIllegalArgumentException()
proxiedTestBean.setName("Supercalifragalisticexpialidocious")); .isThrownBy(() -> proxiedTestBean.setName("enigma"))
.withMessage("enigma");
} }
@Test @Test
public void testAnnotationArgumentNameBinding() { void annotationArgumentNameBinding() {
TransactionalBean tb = new TransactionalBean(); AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TransactionalBean());
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
proxyFactory.addAspect(PointcutWithAnnotationArgument.class); proxyFactory.addAspect(PointcutWithAnnotationArgument.class);
ITransactionalBean proxiedTestBean = proxyFactory.getProxy(); ITransactionalBean proxiedTestBean = proxyFactory.getProxy();
assertThatIllegalStateException().isThrownBy( assertThatIllegalStateException()
proxiedTestBean::doInTransaction); .isThrownBy(proxiedTestBean::doInTransaction)
.withMessage("Invoked with @Transactional");
} }
@Test @Test
public void testParameterNameDiscoverWithReferencePointcut() throws Exception { void parameterNameDiscoverWithReferencePointcut() throws Exception {
AspectJAdviceParameterNameDiscoverer discoverer = AspectJAdviceParameterNameDiscoverer discoverer =
new AspectJAdviceParameterNameDiscoverer("somepc(formal) && set(* *)"); new AspectJAdviceParameterNameDiscoverer("somepc(formal) && set(* *)");
discoverer.setRaiseExceptions(true); discoverer.setRaiseExceptions(true);
Method methodUsedForParameterTypeDiscovery = Method method = getClass().getDeclaredMethod("methodWithOneParam", String.class);
getClass().getMethod("methodWithOneParam", String.class); assertThat(discoverer.getParameterNames(method)).containsExactly("formal");
String[] pnames = discoverer.getParameterNames(methodUsedForParameterTypeDiscovery);
assertThat(pnames.length).as("one parameter name").isEqualTo(1);
assertThat(pnames[0]).isEqualTo("formal");
} }
public void methodWithOneParam(String aParam) { @SuppressWarnings("unused")
private void methodWithOneParam(String aParam) {
} }
public interface ITransactionalBean { interface ITransactionalBean {
@Transactional @Transactional
void doInTransaction(); void doInTransaction();
} }
public static class TransactionalBean implements ITransactionalBean { static class TransactionalBean implements ITransactionalBean {
@Override @Override
@Transactional @Transactional
@ -95,38 +94,35 @@ public class ArgumentBindingTests {
} }
} }
}
/** /**
* Represents Spring's Transactional annotation without actually introducing the dependency * Mimics Spring's @Transactional annotation without actually introducing the dependency.
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@interface Transactional { @interface Transactional {
} }
@Aspect @Aspect
class PointcutWithAnnotationArgument { static class PointcutWithAnnotationArgument {
@Around(value = "execution(* org.springframework..*.*(..)) && @annotation(transaction)") @Around(value = "execution(* org.springframework..*.*(..)) && @annotation(transactional)")
public Object around(ProceedingJoinPoint pjp, Transactional transaction) throws Throwable { public Object around(ProceedingJoinPoint pjp, Transactional transactional) throws Throwable {
System.out.println("Invoked with transaction " + transaction); throw new IllegalStateException("Invoked with @Transactional");
throw new IllegalStateException();
} }
} }
@Aspect @Aspect
class NamedPointcutWithArgs { static class NamedPointcutWithArgs {
@Pointcut("execution(* *(..)) && args(s,..)") @Pointcut("execution(* *(..)) && args(s,..)")
public void pointcutWithArgs(String s) {} public void pointcutWithArgs(String s) {}
@Around("pointcutWithArgs(aString)") @Around("pointcutWithArgs(aString)")
public Object doAround(ProceedingJoinPoint pjp, String aString) throws Throwable { public Object doAround(ProceedingJoinPoint pjp, String aString) throws Throwable {
System.out.println("got '" + aString + "' at '" + pjp + "'");
throw new IllegalArgumentException(aString); throw new IllegalArgumentException(aString);
} }
} }
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -132,7 +132,7 @@ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventM
} }
@Override @Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor(); Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) { for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2022 the original author or authors. * Copyright 2002-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -762,7 +762,7 @@ public class ResolvableType implements Serializable {
/** /**
* Convenience method that will {@link #getGeneric(int...) get} and * Convenience method that will {@link #getGeneric(int...) get} and
* {@link #resolve() resolve} a specific generic parameters. * {@link #resolve() resolve} a specific generic parameter.
* @param indexes the indexes that refer to the generic parameter * @param indexes the indexes that refer to the generic parameter
* (may be omitted to return the first generic) * (may be omitted to return the first generic)
* @return a resolved {@link Class} or {@code null} * @return a resolved {@link Class} or {@code null}

View File

@ -22,10 +22,10 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* A simple log message type for use with Commons Logging, allowing * A simple log message type for use with Commons Logging, allowing for convenient
* for convenient lazy resolution of a given {@link Supplier} instance * lazy resolution of a given {@link Supplier} instance (typically bound to a lambda
* (typically bound to a Java 8 lambda expression) or a printf-style * expression) or a printf-style format string ({@link String#format}) in its
* format string ({@link String#format}) in its {@link #toString()}. * {@link #toString()}.
* *
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Sebastien Deleuze * @author Sebastien Deleuze
@ -78,7 +78,7 @@ public abstract class LogMessage implements CharSequence {
/** /**
* Build a lazily resolving message from the given supplier. * Build a lazily resolving message from the given supplier.
* @param supplier the supplier (typically bound to a Java 8 lambda expression) * @param supplier the supplier (typically bound to a lambda expression)
* @see #toString() * @see #toString()
*/ */
public static LogMessage of(Supplier<? extends CharSequence> supplier) { public static LogMessage of(Supplier<? extends CharSequence> supplier) {
@ -134,8 +134,12 @@ public abstract class LogMessage implements CharSequence {
/** /**
* Build a lazily formatted message from the given format string and varargs. * Build a lazily formatted message from the given format string and varargs.
* <p>This varargs {@code format()} variant may be costly. You should therefore
* use the individual argument variants whenever possible;
* {@link #format(String, Object)}, {@link #format(String, Object, Object)}, etc.
* @param format the format string (following {@link String#format} rules) * @param format the format string (following {@link String#format} rules)
* @param args the varargs array (can be {@code null}, costly, prefer individual arguments) * @param args the varargs array (can be {@code null} and can contain {@code null}
* elements)
* @see String#format(String, Object...) * @see String#format(String, Object...)
*/ */
public static LogMessage format(String format, @Nullable Object... args) { public static LogMessage format(String format, @Nullable Object... args) {