Browse Source

Polishing

pull/2011/head
Juergen Hoeller 6 years ago
parent
commit
5e7a8b275d
  1. 20
      spring-web/src/test/java/org/springframework/web/method/ResolvableMethod.java
  2. 54
      src/docs/asciidoc/core/core-aop.adoc
  3. 2
      src/docs/asciidoc/web/webmvc.adoc

20
spring-web/src/test/java/org/springframework/web/method/ResolvableMethod.java

@ -47,6 +47,7 @@ import org.springframework.core.ResolvableType; @@ -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.*; @@ -120,6 +121,7 @@ import static java.util.stream.Collectors.*;
* </pre>
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public class ResolvableMethod {
@ -133,7 +135,7 @@ 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 { @@ -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 { @@ -262,13 +264,11 @@ public class ResolvableMethod {
private final List<Predicate<Method>> 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<Method> filter) {
this.filters.add(new LabeledPredicate<>(message, filter));
}
@ -394,7 +394,6 @@ public class ResolvableMethod { @@ -394,7 +394,6 @@ public class ResolvableMethod {
return new ResolvableMethod(method);
}
// Build & resolve shortcuts...
/**
@ -448,7 +447,6 @@ public class ResolvableMethod { @@ -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 { @@ -462,6 +460,7 @@ public class ResolvableMethod {
}
}
/**
* Predicate with a descriptive label.
*/
@ -471,7 +470,6 @@ public class ResolvableMethod { @@ -471,7 +470,6 @@ public class ResolvableMethod {
private final Predicate<T> delegate;
private LabeledPredicate(String label, Predicate<T> delegate) {
this.label = label;
this.delegate = delegate;
@ -504,6 +502,7 @@ public class ResolvableMethod { @@ -504,6 +502,7 @@ public class ResolvableMethod {
}
}
/**
* Resolver for method arguments.
*/
@ -511,7 +510,6 @@ public class ResolvableMethod { @@ -511,7 +510,6 @@ public class ResolvableMethod {
private final List<Predicate<MethodParameter>> filters = new ArrayList<>(4);
@SafeVarargs
private ArgResolver(Predicate<MethodParameter>... filter) {
this.filters.addAll(Arrays.asList(filter));
@ -603,17 +601,18 @@ public class ResolvableMethod { @@ -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 { @@ -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);
}

54
src/docs/asciidoc/core/core-aop.adoc

@ -3054,41 +3054,41 @@ container and once through the aspect. @@ -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).

2
src/docs/asciidoc/web/webmvc.adoc

@ -3266,7 +3266,7 @@ response body through message conversion (versus view resolution or template ren @@ -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.

Loading…
Cancel
Save