From 5e7a8b275d94586237a6725a80cedb761194b3d3 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 5 Nov 2018 19:33:24 +0100 Subject: [PATCH] Polishing --- .../web/method/ResolvableMethod.java | 20 +++---- src/docs/asciidoc/core/core-aop.adoc | 54 +++++++++---------- src/docs/asciidoc/web/webmvc.adoc | 2 +- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/spring-web/src/test/java/org/springframework/web/method/ResolvableMethod.java b/spring-web/src/test/java/org/springframework/web/method/ResolvableMethod.java index 4d50d03bb1..6f806d498d 100644 --- a/spring-web/src/test/java/org/springframework/web/method/ResolvableMethod.java +++ b/spring-web/src/test/java/org/springframework/web/method/ResolvableMethod.java @@ -47,6 +47,7 @@ import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.SynthesizingMethodParameter; +import org.springframework.lang.Nullable; import org.springframework.objenesis.ObjenesisException; import org.springframework.objenesis.SpringObjenesis; import org.springframework.util.Assert; @@ -120,6 +121,7 @@ import static java.util.stream.Collectors.*; * * * @author Rossen Stoyanchev + * @since 5.0 */ public class ResolvableMethod { @@ -133,7 +135,7 @@ public class ResolvableMethod { private ResolvableMethod(Method method) { - Assert.notNull(method, "method is required"); + Assert.notNull(method, "Method is required"); this.method = method; } @@ -202,14 +204,14 @@ public class ResolvableMethod { return new ArgResolver().annotNotPresent(annotationTypes); } - @Override public String toString() { return "ResolvableMethod=" + formatMethod(); } + private String formatMethod() { - return (this.method().getName() + + return (method().getName() + Arrays.stream(this.method.getParameters()) .map(this::formatParameter) .collect(joining(",\n\t", "(\n\t", "\n)"))); @@ -262,13 +264,11 @@ public class ResolvableMethod { private final List> filters = new ArrayList<>(4); - private Builder(Class objectClass) { Assert.notNull(objectClass, "Class must not be null"); this.objectClass = objectClass; } - private void addFilter(String message, Predicate filter) { this.filters.add(new LabeledPredicate<>(message, filter)); } @@ -394,7 +394,6 @@ public class ResolvableMethod { return new ResolvableMethod(method); } - // Build & resolve shortcuts... /** @@ -448,7 +447,6 @@ public class ResolvableMethod { return returning(returnType).build().returnType(); } - @Override public String toString() { return "ResolvableMethod.Builder[\n" + @@ -462,6 +460,7 @@ public class ResolvableMethod { } } + /** * Predicate with a descriptive label. */ @@ -471,7 +470,6 @@ public class ResolvableMethod { private final Predicate delegate; - private LabeledPredicate(String label, Predicate delegate) { this.label = label; this.delegate = delegate; @@ -504,6 +502,7 @@ public class ResolvableMethod { } } + /** * Resolver for method arguments. */ @@ -511,7 +510,6 @@ public class ResolvableMethod { private final List> filters = new ArrayList<>(4); - @SafeVarargs private ArgResolver(Predicate... filter) { this.filters.addAll(Arrays.asList(filter)); @@ -603,17 +601,18 @@ public class ResolvableMethod { } } + private static class MethodInvocationInterceptor implements org.springframework.cglib.proxy.MethodInterceptor, MethodInterceptor { private Method invokedMethod; - Method getInvokedMethod() { return this.invokedMethod; } @Override + @Nullable public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) { if (ReflectionUtils.isObjectMethod(method)) { return ReflectionUtils.invokeMethod(method, object, args); @@ -625,6 +624,7 @@ public class ResolvableMethod { } @Override + @Nullable public Object invoke(org.aopalliance.intercept.MethodInvocation inv) throws Throwable { return intercept(inv.getThis(), inv.getMethod(), inv.getArguments(), null); } diff --git a/src/docs/asciidoc/core/core-aop.adoc b/src/docs/asciidoc/core/core-aop.adoc index 25a4a8e732..ded0a3358a 100644 --- a/src/docs/asciidoc/core/core-aop.adoc +++ b/src/docs/asciidoc/core/core-aop.adoc @@ -3054,41 +3054,41 @@ container and once through the aspect. [[aop-configurable-testing]] ==== Unit Testing `@Configurable` Objects -One of the goals of the `@Configurable` support is to enable independent unit testing of -domain objects without the difficulties associated with hard-coded lookups. If -`@Configurable` types have not been woven by AspectJ, the annotation has no affect -during unit testing. You can set mock or stub property references in the -object under test and proceed as normal. If `@Configurable` types have been woven by -AspectJ, you can still unit test outside of the container as normal, but you -see a warning message each time that you construct an `@Configurable` object indicating -that it has not been configured by Spring. +One of the goals of the `@Configurable` support is to enable independent unit testing +of domain objects without the difficulties associated with hard-coded lookups. +If `@Configurable` types have not been woven by AspectJ, the annotation has no affect +during unit testing. You can set mock or stub property references in the object under +test and proceed as normal. If `@Configurable` types have been woven by AspectJ, +you can still unit test outside of the container as normal, but you see a warning +message each time that you construct a `@Configurable` object indicating that it has +not been configured by Spring. [[aop-configurable-container]] ==== Working with Multiple Application Contexts -The `AnnotationBeanConfigurerAspect` that is used to implement the `@Configurable` support is an -AspectJ singleton aspect. The scope of a singleton aspect is the same as the scope of -`static` members: There is one aspect instance per classloader that -defines the type. This means that, if you define multiple application contexts within the -same classloader hierarchy, you need to consider where to define the -`@EnableSpringConfigured` bean and where to place `spring-aspects.jar` on the classpath. - -Consider a typical Spring web application configuration that has a shared parent application context -that defines common business services, everything needed to support those services, and one child -application context for each servlet (which contains definitions particular to that servlet). All -of these contexts co-exist within the same classloader hierarchy, and so the -`AnnotationBeanConfigurerAspect` can hold a reference to only one of them. In this case, -we recommend defining the `@EnableSpringConfigured` bean in the shared (parent) -application context. This defines the services that you are likely to want to inject -into domain objects. A consequence is that you cannot configure domain objects with -references to beans defined in the child (servlet-specific) contexts by using the +The `AnnotationBeanConfigurerAspect` that is used to implement the `@Configurable` support +is an AspectJ singleton aspect. The scope of a singleton aspect is the same as the scope +of `static` members: There is one aspect instance per classloader that defines the type. +This means that, if you define multiple application contexts within the same classloader +hierarchy, you need to consider where to define the `@EnableSpringConfigured` bean and +where to place `spring-aspects.jar` on the classpath. + +Consider a typical Spring web application configuration that has a shared parent application +context that defines common business services, everything needed to support those services, +and one child application context for each servlet (which contains definitions particular +to that servlet). All of these contexts co-exist within the same classloader hierarchy, +and so the `AnnotationBeanConfigurerAspect` can hold a reference to only one of them. +In this case, we recommend defining the `@EnableSpringConfigured` bean in the shared +(parent) application context. This defines the services that you are likely to want to +inject into domain objects. A consequence is that you cannot configure domain objects +with references to beans defined in the child (servlet-specific) contexts by using the @Configurable mechanism (which is probably not something you want to do anyway). When deploying multiple web applications within the same container, ensure that each -web application loads the types in `spring-aspects.jar` by using its own classloader (for -example, by placing `spring-aspects.jar` in `'WEB-INF/lib'`). If `spring-aspects.jar` is -added only to the container-wide classpath (and hence loaded by the shared parent +web application loads the types in `spring-aspects.jar` by using its own classloader +(for example, by placing `spring-aspects.jar` in `'WEB-INF/lib'`). If `spring-aspects.jar` +is added only to the container-wide classpath (and hence loaded by the shared parent classloader), all web applications share the same aspect instance (which is probably not what you want). diff --git a/src/docs/asciidoc/web/webmvc.adoc b/src/docs/asciidoc/web/webmvc.adoc index 3fb45f2567..16ed94af8f 100644 --- a/src/docs/asciidoc/web/webmvc.adoc +++ b/src/docs/asciidoc/web/webmvc.adoc @@ -3266,7 +3266,7 @@ response body through message conversion (versus view resolution or template ren On startup, the infrastructure classes for `@RequestMapping` and `@ExceptionHandler` methods detect Spring beans of type `@ControllerAdvice` and then apply their methods at runtime. -Global `@ExceptionHandler` methods (from an `@ControllerAdvice`) are applied _after_ local +Global `@ExceptionHandler` methods (from a `@ControllerAdvice`) are applied _after_ local ones (from the `@Controller`). By contrast, global `@ModelAttribute` and `@InitBinder` methods are applied _before_ local ones.