diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java index 60a45977513..b9b1f463e32 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscoverer.java @@ -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"); * you may not use this file except in compliance with the License. @@ -38,6 +38,14 @@ import org.springframework.util.StringUtils; * for an advice method from the pointcut expression, returning, and throwing clauses. * If an unambiguous interpretation is not available, it returns {@code null}. * + *

Algorithm Summary

+ *

If an unambiguous binding can be deduced, then it is. + * If the advice requirements cannot possibly be satisfied, then {@code null} + * is returned. By setting the {@link #setRaiseExceptions(boolean) raiseExceptions} + * property to {@code true}, descriptive exceptions will be thrown instead of + * returning {@code null} in the case that the parameter names cannot be discovered. + * + *

Algorithm Details

*

This class interprets arguments in the following way: *

    *
  1. If the first parameter of the method is of type {@link JoinPoint} @@ -65,15 +73,15 @@ import org.springframework.util.StringUtils; * zero we proceed to the next stage. If {@code a} > 1 then an * {@code AmbiguousBindingException} is raised. If {@code a} == 1, * and there are no unbound arguments of type {@code Annotation+}, - * then an {@code IllegalArgumentException} is raised. if there is + * then an {@code IllegalArgumentException} is raised. If there is * exactly one such argument, then the corresponding parameter name is * assigned the value from the pointcut expression.
  2. - *
  3. If a returningName has been set, and there are no unbound arguments + *
  4. If a {@code returningName} has been set, and there are no unbound arguments * then an {@code IllegalArgumentException} is raised. If there is * more than one unbound argument then an * {@code AmbiguousBindingException} is raised. If there is exactly * one unbound argument then the corresponding parameter name is assigned - * the value <returningName>.
  5. + * the value of the {@code returningName}. *
  6. If there remain unbound arguments, then the pointcut expression is * examined once more for {@code this}, {@code target}, and * {@code args} pointcut expressions used in the binding form (binding @@ -99,20 +107,12 @@ import org.springframework.util.StringUtils; *

    The behavior on raising an {@code IllegalArgumentException} or * {@code AmbiguousBindingException} is configurable to allow this discoverer * to be used as part of a chain-of-responsibility. By default the condition will - * be logged and the {@code getParameterNames(..)} method will simply return + * be logged and the {@link #getParameterNames(Method)} method will simply return * {@code null}. If the {@link #setRaiseExceptions(boolean) raiseExceptions} * property is set to {@code true}, the conditions will be thrown as * {@code IllegalArgumentException} and {@code AmbiguousBindingException}, * respectively. * - *

    Was that perfectly clear? ;) - * - *

    Short version: If an unambiguous binding can be deduced, then it is. - * If the advice requirements cannot possibly be satisfied, then {@code null} - * is returned. By setting the {@link #setRaiseExceptions(boolean) raiseExceptions} - * property to {@code true}, descriptive exceptions will be thrown instead of - * returning {@code null} in the case that the parameter names cannot be discovered. - * * @author Adrian Colyer * @author Juergen Hoeller * @since 2.0 @@ -158,7 +158,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov /** The pointcut expression associated with the advice, as a simple String. */ @Nullable - private String pointcutExpression; + private final String pointcutExpression; private boolean raiseExceptions; @@ -197,7 +197,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov /** * If {@code afterReturning} advice binds the return value, the - * returning variable name must be specified. + * {@code returning} variable name must be specified. * @param returningName the name of the returning variable */ public void setReturningName(@Nullable String returningName) { @@ -206,18 +206,17 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov /** * If {@code afterThrowing} advice binds the thrown value, the - * throwing variable name must be specified. + * {@code throwing} variable name must be specified. * @param throwingName the name of the throwing variable */ public void setThrowingName(@Nullable String throwingName) { this.throwingName = throwingName; } - /** * Deduce the parameter names for an advice method. - *

    See the {@link AspectJAdviceParameterNameDiscoverer class level javadoc} - * for this class for details of the algorithm used. + *

    See the {@link AspectJAdviceParameterNameDiscoverer class-level javadoc} + * for this class for details on the algorithm used. * @param method the target {@link Method} * @return the parameter names */ @@ -316,13 +315,13 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov } - private void bindParameterName(int index, String name) { + private void bindParameterName(int index, @Nullable String name) { this.parameterNameBindings[index] = name; this.numberOfRemainingUnboundArguments--; } /** - * If the first parameter is of type JoinPoint or ProceedingJoinPoint,bind "thisJoinPoint" as + * If the first parameter is of type JoinPoint or ProceedingJoinPoint, bind "thisJoinPoint" as * parameter name and return true, else return false. */ private boolean maybeBindThisJoinPoint() { @@ -367,8 +366,8 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov } if (throwableIndex == -1) { - throw new IllegalStateException("Binding of throwing parameter '" + this.throwingName - + "' could not be completed as no available arguments are a subtype of Throwable"); + throw new IllegalStateException("Binding of throwing parameter '" + this.throwingName + + "' could not be completed as no available arguments are a subtype of Throwable"); } else { bindParameterName(throwableIndex, this.throwingName); @@ -400,7 +399,6 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov } } - /** * Parse the string pointcut expression looking for: * @this, @target, @args, @within, @withincode, @annotation. @@ -465,7 +463,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov } } - /* + /** * If the token starts meets Java identifier conventions, it's in. */ @Nullable @@ -533,7 +531,6 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov } } - if (varNames.size() > 1) { throw new AmbiguousBindingException("Found " + varNames.size() + " candidate this(), target() or args() variables but only one unbound argument slot"); @@ -609,7 +606,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov // else varNames.size must be 0 and we have nothing to bind. } - /* + /** * We've found the start of a binding pointcut at the given index into the * token array. Now we need to extract the pointcut body and return it. */ @@ -709,7 +706,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov return false; } - /* + /** * Return {@code true} if the given argument type is a subclass * of the given supertype. */ @@ -737,7 +734,7 @@ public class AspectJAdviceParameterNameDiscoverer implements ParameterNameDiscov return count; } - /* + /** * Find the argument index with the given type, and bind the given * {@code varName} in that position. */ diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java index 0a81aef4e9f..98ca29c7a43 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2023 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. @@ -102,7 +102,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements private boolean singletonsCurrentlyInDestruction = false; /** Disposable bean instances: bean name to disposable instance. */ - private final Map disposableBeans = new LinkedHashMap<>(); + private final Map disposableBeans = new LinkedHashMap<>(); /** Map between containing bean names: bean name to Set of bean names that the bean contains. */ private final Map> containedBeanMap = new ConcurrentHashMap<>(16); @@ -340,7 +340,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements * (within the entire factory). * @param beanName the name of the bean */ - public boolean isSingletonCurrentlyInCreation(String beanName) { + public boolean isSingletonCurrentlyInCreation(@Nullable String beanName) { return this.singletonsCurrentlyInCreation.contains(beanName); } @@ -554,7 +554,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements // Destroy the corresponding DisposableBean instance. DisposableBean disposableBean; synchronized (this.disposableBeans) { - disposableBean = (DisposableBean) this.disposableBeans.remove(beanName); + disposableBean = this.disposableBeans.remove(beanName); } destroyBean(beanName, disposableBean); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java index c32414b9678..62a277e0cfc 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java @@ -68,8 +68,8 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { private static final String SHUTDOWN_METHOD_NAME = "shutdown"; - private static final Log logger = LogFactory.getLog(DisposableBeanAdapter.class); + private static final Log logger = LogFactory.getLog(DisposableBeanAdapter.class); private final Object bean; diff --git a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java index 56e202a4a97..d3d916aa160 100644 --- a/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java @@ -447,7 +447,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader @Override public void setApplicationStartup(ApplicationStartup applicationStartup) { - Assert.notNull(applicationStartup, "applicationStartup should not be null"); + Assert.notNull(applicationStartup, "ApplicationStartup must not be null"); this.applicationStartup = applicationStartup; } diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ImportTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ImportTests.java index 0056376f555..04638e1822e 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ImportTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ImportTests.java @@ -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"); * you may not use this file except in compliance with the License. @@ -41,6 +41,7 @@ class ImportTests { private DefaultListableBeanFactory processConfigurationClasses(Class... classes) { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + beanFactory.setAllowBeanDefinitionOverriding(false); for (Class clazz : classes) { beanFactory.registerBeanDefinition(clazz.getSimpleName(), new RootBeanDefinition(clazz)); } @@ -56,9 +57,10 @@ class ImportTests { for (Class clazz : classes) { beanFactory.getBean(clazz); } - } + // ------------------------------------------------------------------------ + @Test void testProcessImportsWithAsm() { int configClasses = 2; @@ -158,6 +160,13 @@ class ImportTests { assertBeanDefinitionCount(configClasses + beansInClasses, FirstLevel.class); } + @Test + void testImportAnnotationWithThreeLevelRecursionAndDoubleImport() { + int configClasses = 5; + int beansInClasses = 5; + assertBeanDefinitionCount(configClasses + beansInClasses, FirstLevel.class, FirstLevelPlus.class); + } + // ------------------------------------------------------------------------ @Test @@ -167,7 +176,6 @@ class ImportTests { assertBeanDefinitionCount((configClasses + beansInClasses), WithMultipleArgumentsToImportAnnotation.class); } - @Test void testImportAnnotationWithMultipleArgumentsResultingInOverriddenBeanDefinition() { DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); @@ -245,6 +253,11 @@ class ImportTests { } } + @Configuration + @Import(ThirdLevel.class) + static class FirstLevelPlus { + } + @Configuration @Import({ThirdLevel.class, InitBean.class}) static class SecondLevel { diff --git a/spring-core/src/main/java/org/springframework/core/MethodParameter.java b/spring-core/src/main/java/org/springframework/core/MethodParameter.java index 42a0dfca93f..18ff60ecde3 100644 --- a/spring-core/src/main/java/org/springframework/core/MethodParameter.java +++ b/spring-core/src/main/java/org/springframework/core/MethodParameter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2023 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. @@ -781,6 +781,7 @@ public class MethodParameter { return new MethodParameter(this); } + /** * Create a new MethodParameter for the given method or constructor. *

    This is a convenience factory method for scenarios where a