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

Loading…
Cancel
Save