From 74072237ee5d3f25057f648ba178a42c745004ae Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Fri, 6 Mar 2015 16:57:32 +0100 Subject: [PATCH] Break down Core and Web chapters in reference doc Core and Web chapters are important chapters in the Spring Framework reference documentation, and splitting them in multiple files will help to evolve the documentation while not creating too many files. Issue: SPR-12309 --- build.gradle | 2 +- src/asciidoc/core-aop-api.adoc | 1750 +++++++++ src/asciidoc/core-aop.adoc | 4 +- src/asciidoc/core-beans.adoc | 188 +- src/asciidoc/core-expressions.adoc | 1455 +++++++ src/asciidoc/core-resources.adoc | 666 ++++ src/asciidoc/core-validation.adoc | 1836 +++++++++ src/asciidoc/core.adoc | 5714 +--------------------------- src/asciidoc/testing.adoc | 36 +- src/asciidoc/web-integration.adoc | 249 ++ src/asciidoc/web-mvc.adoc | 44 +- src/asciidoc/web-portlet.adoc | 1468 +++++++ src/asciidoc/web-view.adoc | 16 +- src/asciidoc/web-websocket.adoc | 2158 +++++++++++ src/asciidoc/web.adoc | 3880 +------------------ 15 files changed, 9735 insertions(+), 9731 deletions(-) create mode 100644 src/asciidoc/core-aop-api.adoc create mode 100644 src/asciidoc/core-expressions.adoc create mode 100644 src/asciidoc/core-resources.adoc create mode 100644 src/asciidoc/core-validation.adoc create mode 100644 src/asciidoc/web-integration.adoc create mode 100644 src/asciidoc/web-portlet.adoc create mode 100644 src/asciidoc/web-websocket.adoc diff --git a/build.gradle b/build.gradle index 113272795e3..77267790f70 100644 --- a/build.gradle +++ b/build.gradle @@ -1106,7 +1106,7 @@ configure(rootProject) { asciidoctor { sourceDir project.file('src/asciidoc') separateOutputDirs = false - backends = ['docbook5'] + backends = ['docbook'] options doctype: 'book', eruby: 'erubis' attributes 'spring-version': project.version, revnumber : project.version, diff --git a/src/asciidoc/core-aop-api.adoc b/src/asciidoc/core-aop-api.adoc new file mode 100644 index 00000000000..13402649be6 --- /dev/null +++ b/src/asciidoc/core-aop-api.adoc @@ -0,0 +1,1750 @@ +[[aop-api]] += Spring AOP APIs + + +[[aop-api-introduction]] +== Introduction +The previous chapter described the Spring's support for AOP using +@AspectJ and schema-based aspect definitions. In this chapter we discuss the lower-level +Spring AOP APIs and the AOP support used in Spring 1.2 applications. For new +applications, we recommend the use of the Spring 2.0 and later AOP support described in +the previous chapter, but when working with existing applications, or when reading books +and articles, you may come across Spring 1.2 style examples. Spring 4.0 is backwards +compatible with Spring 1.2 and everything described in this chapter is fully supported +in Spring 4.0. + + + + +[[aop-api-pointcuts]] +== Pointcut API in Spring +Let's look at how Spring handles the crucial pointcut concept. + + + +[[aop-api-concepts]] +=== Concepts +Spring's pointcut model enables pointcut reuse independent of advice types. It's +possible to target different advice using the same pointcut. + +The `org.springframework.aop.Pointcut` interface is the central interface, used to +target advices to particular classes and methods. The complete interface is shown below: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface Pointcut { + + ClassFilter getClassFilter(); + + MethodMatcher getMethodMatcher(); + + } +---- + +Splitting the `Pointcut` interface into two parts allows reuse of class and method +matching parts, and fine-grained composition operations (such as performing a "union" +with another method matcher). + +The `ClassFilter` interface is used to restrict the pointcut to a given set of target +classes. If the `matches()` method always returns true, all target classes will be +matched: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface ClassFilter { + + boolean matches(Class clazz); + } +---- + +The `MethodMatcher` interface is normally more important. The complete interface is +shown below: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface MethodMatcher { + + boolean matches(Method m, Class targetClass); + + boolean isRuntime(); + + boolean matches(Method m, Class targetClass, Object[] args); + } +---- + +The `matches(Method, Class)` method is used to test whether this pointcut will ever +match a given method on a target class. This evaluation can be performed when an AOP +proxy is created, to avoid the need for a test on every method invocation. If the +2-argument matches method returns true for a given method, and the `isRuntime()` method +for the MethodMatcher returns true, the 3-argument matches method will be invoked on +every method invocation. This enables a pointcut to look at the arguments passed to the +method invocation immediately before the target advice is to execute. + +Most MethodMatchers are static, meaning that their `isRuntime()` method returns false. +In this case, the 3-argument matches method will never be invoked. + +[TIP] +=== + +If possible, try to make pointcuts static, allowing the AOP framework to cache the +results of pointcut evaluation when an AOP proxy is created. +=== + + + +[[aop-api-pointcut-ops]] +=== Operations on pointcuts +Spring supports operations on pointcuts: notably, __union__ and __intersection__. + +* Union means the methods that either pointcut matches. +* Intersection means the methods that both pointcuts match. +* Union is usually more useful. +* Pointcuts can be composed using the static methods in the + __org.springframework.aop.support.Pointcuts__ class, or using the + __ComposablePointcut__ class in the same package. However, using AspectJ pointcut + expressions is usually a simpler approach. + + + +[[aop-api-pointcuts-aspectj]] +=== AspectJ expression pointcuts +Since 2.0, the most important type of pointcut used by Spring is +`org.springframework.aop.aspectj.AspectJExpressionPointcut`. This is a pointcut that +uses an AspectJ supplied library to parse an AspectJ pointcut expression string. + +See the previous chapter for a discussion of supported AspectJ pointcut primitives. + + + +[[aop-api-pointcuts-impls]] +=== Convenience pointcut implementations +Spring provides several convenient pointcut implementations. Some can be used out of the +box; others are intended to be subclassed in application-specific pointcuts. + + +[[aop-api-pointcuts-static]] +==== Static pointcuts +Static pointcuts are based on method and target class, and cannot take into account the +method's arguments. Static pointcuts are sufficient - __and best__ - for most usages. +It's possible for Spring to evaluate a static pointcut only once, when a method is first +invoked: after that, there is no need to evaluate the pointcut again with each method +invocation. + +Let's consider some static pointcut implementations included with Spring. + +[[aop-api-pointcuts-regex]] +===== Regular expression pointcuts +One obvious way to specify static pointcuts is regular expressions. Several AOP +frameworks besides Spring make this possible. +`org.springframework.aop.support.JdkRegexpMethodPointcut` is a generic regular +expression pointcut, using the regular expression support in JDK 1.4+. + +Using the `JdkRegexpMethodPointcut` class, you can provide a list of pattern Strings. If +any of these is a match, the pointcut will evaluate to true. (So the result is +effectively the union of these pointcuts.) + +The usage is shown below: + +[source,xml,indent=0] +[subs="verbatim"] +---- + + + + .*set.* + .*absquatulate + + + +---- + +Spring provides a convenience class, `RegexpMethodPointcutAdvisor`, that allows us to +also reference an Advice (remember that an Advice can be an interceptor, before advice, +throws advice etc.). Behind the scenes, Spring will use a `JdkRegexpMethodPointcut`. +Using `RegexpMethodPointcutAdvisor` simplifies wiring, as the one bean encapsulates both +pointcut and advice, as shown below: + +[source,xml,indent=0] +[subs="verbatim"] +---- + + + + + + + .*set.* + .*absquatulate + + + +---- + +__RegexpMethodPointcutAdvisor__ can be used with any Advice type. + +[[aop-api-pointcuts-attribute-driven]] +===== Attribute-driven pointcuts +An important type of static pointcut is a __metadata-driven__ pointcut. This uses the +values of metadata attributes: typically, source-level metadata. + + +[[aop-api-pointcuts-dynamic]] +==== Dynamic pointcuts +Dynamic pointcuts are costlier to evaluate than static pointcuts. They take into account +method __arguments__, as well as static information. This means that they must be +evaluated with every method invocation; the result cannot be cached, as arguments will +vary. + +The main example is the `control flow` pointcut. + +[[aop-api-pointcuts-cflow]] +===== Control flow pointcuts +Spring control flow pointcuts are conceptually similar to AspectJ __cflow__ pointcuts, +although less powerful. (There is currently no way to specify that a pointcut executes +below a join point matched by another pointcut.) A control flow pointcut matches the +current call stack. For example, it might fire if the join point was invoked by a method +in the `com.mycompany.web` package, or by the `SomeCaller` class. Control flow pointcuts +are specified using the `org.springframework.aop.support.ControlFlowPointcut` class. +[NOTE] +=== +Control flow pointcuts are significantly more expensive to evaluate at runtime than even +other dynamic pointcuts. In Java 1.4, the cost is about 5 times that of other dynamic +pointcuts. +=== + + + +[[aop-api-pointcuts-superclasses]] +=== Pointcut superclasses +Spring provides useful pointcut superclasses to help you to implement your own pointcuts. + +Because static pointcuts are most useful, you'll probably subclass +StaticMethodMatcherPointcut, as shown below. This requires implementing just one +abstract method (although it's possible to override other methods to customize behavior): + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + class TestStaticPointcut extends StaticMethodMatcherPointcut { + + public boolean matches(Method m, Class targetClass) { + // return true if custom criteria match + } + } +---- + +There are also superclasses for dynamic pointcuts. + +You can use custom pointcuts with any advice type in Spring 1.0 RC2 and above. + + + +[[aop-api-pointcuts-custom]] +=== Custom pointcuts +Because pointcuts in Spring AOP are Java classes, rather than language features (as in +AspectJ) it's possible to declare custom pointcuts, whether static or dynamic. Custom +pointcuts in Spring can be arbitrarily complex. However, using the AspectJ pointcut +expression language is recommended if possible. + +[NOTE] +=== +Later versions of Spring may offer support for "semantic pointcuts" as offered by JAC: +for example, "all methods that change instance variables in the target object." +=== + + + + +[[aop-api-advice]] +== Advice API in Spring +Let's now look at how Spring AOP handles advice. + + + +[[aop-api-advice-lifecycle]] +=== Advice lifecycles +Each advice is a Spring bean. An advice instance can be shared across all advised +objects, or unique to each advised object. This corresponds to __per-class__ or +__per-instance__ advice. + +Per-class advice is used most often. It is appropriate for generic advice such as +transaction advisors. These do not depend on the state of the proxied object or add new +state; they merely act on the method and arguments. + +Per-instance advice is appropriate for introductions, to support mixins. In this case, +the advice adds state to the proxied object. + +It's possible to use a mix of shared and per-instance advice in the same AOP proxy. + + + +[[aop-api-advice-types]] +=== Advice types in Spring +Spring provides several advice types out of the box, and is extensible to support +arbitrary advice types. Let us look at the basic concepts and standard advice types. + + +[[aop-api-advice-around]] +==== Interception around advice +The most fundamental advice type in Spring is __interception around advice__. + +Spring is compliant with the AOP Alliance interface for around advice using method +interception. MethodInterceptors implementing around advice should implement the +following interface: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface MethodInterceptor extends Interceptor { + + Object invoke(MethodInvocation invocation) throws Throwable; + } +---- + +The `MethodInvocation` argument to the `invoke()` method exposes the method being +invoked; the target join point; the AOP proxy; and the arguments to the method. The +`invoke()` method should return the invocation's result: the return value of the join +point. + +A simple `MethodInterceptor` implementation looks as follows: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class DebugInterceptor implements MethodInterceptor { + + public Object invoke(MethodInvocation invocation) throws Throwable { + System.out.println("Before: invocation=[" + invocation + "]"); + Object rval = invocation.proceed(); + System.out.println("Invocation returned"); + return rval; + } + } +---- + +Note the call to the MethodInvocation's `proceed()` method. This proceeds down the +interceptor chain towards the join point. Most interceptors will invoke this method, and +return its return value. However, a MethodInterceptor, like any around advice, can +return a different value or throw an exception rather than invoke the proceed method. +However, you don't want to do this without good reason! + +[NOTE] +=== +MethodInterceptors offer interoperability with other AOP Alliance-compliant AOP +implementations. The other advice types discussed in the remainder of this section +implement common AOP concepts, but in a Spring-specific way. While there is an advantage +in using the most specific advice type, stick with MethodInterceptor around advice if +you are likely to want to run the aspect in another AOP framework. Note that pointcuts +are not currently interoperable between frameworks, and the AOP Alliance does not +currently define pointcut interfaces. +=== + + +[[aop-api-advice-before]] +==== Before advice +A simpler advice type is a __before advice__. This does not need a `MethodInvocation` +object, since it will only be called before entering the method. + +The main advantage of a before advice is that there is no need to invoke the `proceed()` +method, and therefore no possibility of inadvertently failing to proceed down the +interceptor chain. + +The `MethodBeforeAdvice` interface is shown below. (Spring's API design would allow for +field before advice, although the usual objects apply to field interception and it's +unlikely that Spring will ever implement it). + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface MethodBeforeAdvice extends BeforeAdvice { + + void before(Method m, Object[] args, Object target) throws Throwable; + } +---- + +Note the return type is `void`. Before advice can insert custom behavior before the join +point executes, but cannot change the return value. If a before advice throws an +exception, this will abort further execution of the interceptor chain. The exception +will propagate back up the interceptor chain. If it is unchecked, or on the signature of +the invoked method, it will be passed directly to the client; otherwise it will be +wrapped in an unchecked exception by the AOP proxy. + +An example of a before advice in Spring, which counts all method invocations: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class CountingBeforeAdvice implements MethodBeforeAdvice { + + private int count; + + public void before(Method m, Object[] args, Object target) throws Throwable { + ++count; + } + + public int getCount() { + return count; + } + } +---- + +[TIP] +=== + +Before advice can be used with any pointcut. +=== + + +[[aop-api-advice-throws]] +==== Throws advice +__Throws advice__ is invoked after the return of the join point if the join point threw +an exception. Spring offers typed throws advice. Note that this means that the +`org.springframework.aop.ThrowsAdvice` interface does not contain any methods: It is a +tag interface identifying that the given object implements one or more typed throws +advice methods. These should be in the form of: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + afterThrowing([Method, args, target], subclassOfThrowable) +---- + +Only the last argument is required. The method signatures may have either one or four +arguments, depending on whether the advice method is interested in the method and +arguments. The following classes are examples of throws advice. + +The advice below is invoked if a `RemoteException` is thrown (including subclasses): + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class RemoteThrowsAdvice implements ThrowsAdvice { + + public void afterThrowing(RemoteException ex) throws Throwable { + // Do something with remote exception + } + } +---- + +The following advice is invoked if a `ServletException` is thrown. Unlike the above +advice, it declares 4 arguments, so that it has access to the invoked method, method +arguments and target object: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class ServletThrowsAdviceWithArguments implements ThrowsAdvice { + + public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) { + // Do something with all arguments + } + } +---- + +The final example illustrates how these two methods could be used in a single class, +which handles both `RemoteException` and `ServletException`. Any number of throws advice +methods can be combined in a single class. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public static class CombinedThrowsAdvice implements ThrowsAdvice { + + public void afterThrowing(RemoteException ex) throws Throwable { + // Do something with remote exception + } + + public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) { + // Do something with all arguments + } + } +---- + +[NOTE] +=== +If a throws-advice method throws an exception itself, it will override the +original exception (i.e. change the exception thrown to the user). The overriding +exception will typically be a RuntimeException; this is compatible with any method +signature. However, if a throws-advice method throws a checked exception, it will have +to match the declared exceptions of the target method and is hence to some degree +coupled to specific target method signatures. __Do not throw an undeclared checked +exception that is incompatible with the target method's signature!__ +=== + +[TIP] +=== + +Throws advice can be used with any pointcut. +=== + + +[[aop-api-advice-after-returning]] +==== After Returning advice +An after returning advice in Spring must implement the +__org.springframework.aop.AfterReturningAdvice__ interface, shown below: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface AfterReturningAdvice extends Advice { + + void afterReturning(Object returnValue, Method m, Object[] args, Object target) + throws Throwable; + } +---- + +An after returning advice has access to the return value (which it cannot modify), +invoked method, methods arguments and target. + +The following after returning advice counts all successful method invocations that have +not thrown exceptions: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class CountingAfterReturningAdvice implements AfterReturningAdvice { + + private int count; + + public void afterReturning(Object returnValue, Method m, Object[] args, Object target) + throws Throwable { + ++count; + } + + public int getCount() { + return count; + } + } +---- + +This advice doesn't change the execution path. If it throws an exception, this will be +thrown up the interceptor chain instead of the return value. + +[TIP] +=== + +After returning advice can be used with any pointcut. +=== + + +[[aop-api-advice-introduction]] +==== Introduction advice +Spring treats introduction advice as a special kind of interception advice. + +Introduction requires an `IntroductionAdvisor`, and an `IntroductionInterceptor`, +implementing the following interface: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface IntroductionInterceptor extends MethodInterceptor { + + boolean implementsInterface(Class intf); + } +---- + +The `invoke()` method inherited from the AOP Alliance `MethodInterceptor` interface must +implement the introduction: that is, if the invoked method is on an introduced +interface, the introduction interceptor is responsible for handling the method call - it +cannot invoke `proceed()`. + +Introduction advice cannot be used with any pointcut, as it applies only at class, +rather than method, level. You can only use introduction advice with the +`IntroductionAdvisor`, which has the following methods: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface IntroductionAdvisor extends Advisor, IntroductionInfo { + + ClassFilter getClassFilter(); + + void validateInterfaces() throws IllegalArgumentException; + } + + public interface IntroductionInfo { + + Class[] getInterfaces(); + } +---- + +There is no `MethodMatcher`, and hence no `Pointcut`, associated with introduction +advice. Only class filtering is logical. + +The `getInterfaces()` method returns the interfaces introduced by this advisor. + +The `validateInterfaces()` method is used internally to see whether or not the +introduced interfaces can be implemented by the configured `IntroductionInterceptor`. + +Let's look at a simple example from the Spring test suite. Let's suppose we want to +introduce the following interface to one or more objects: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface Lockable { + void lock(); + void unlock(); + boolean locked(); + } +---- + +This illustrates a __mixin__. We want to be able to cast advised objects to Lockable, +whatever their type, and call lock and unlock methods. If we call the lock() method, we +want all setter methods to throw a `LockedException`. Thus we can add an aspect that +provides the ability to make objects immutable, without them having any knowledge of it: +a good example of AOP. + +Firstly, we'll need an `IntroductionInterceptor` that does the heavy lifting. In this +case, we extend the `org.springframework.aop.support.DelegatingIntroductionInterceptor` +convenience class. We could implement IntroductionInterceptor directly, but using +`DelegatingIntroductionInterceptor` is best for most cases. + +The `DelegatingIntroductionInterceptor` is designed to delegate an introduction to an +actual implementation of the introduced interface(s), concealing the use of interception +to do so. The delegate can be set to any object using a constructor argument; the +default delegate (when the no-arg constructor is used) is this. Thus in the example +below, the delegate is the `LockMixin` subclass of `DelegatingIntroductionInterceptor`. +Given a delegate (by default itself), a `DelegatingIntroductionInterceptor` instance +looks for all interfaces implemented by the delegate (other than +IntroductionInterceptor), and will support introductions against any of them. It's +possible for subclasses such as `LockMixin` to call the `suppressInterface(Class intf)` +method to suppress interfaces that should not be exposed. However, no matter how many +interfaces an `IntroductionInterceptor` is prepared to support, the +`IntroductionAdvisor` used will control which interfaces are actually exposed. An +introduced interface will conceal any implementation of the same interface by the target. + +Thus `LockMixin` extends `DelegatingIntroductionInterceptor` and implements `Lockable` +itself. The superclass automatically picks up that Lockable can be supported for +introduction, so we don't need to specify that. We could introduce any number of +interfaces in this way. + +Note the use of the `locked` instance variable. This effectively adds additional state +to that held in the target object. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable { + + private boolean locked; + + public void lock() { + this.locked = true; + } + + public void unlock() { + this.locked = false; + } + + public boolean locked() { + return this.locked; + } + + public Object invoke(MethodInvocation invocation) throws Throwable { + if (locked() && invocation.getMethod().getName().indexOf("set") == 0) { + throw new LockedException(); + } + return super.invoke(invocation); + } + + } +---- + +Often it isn't necessary to override the `invoke()` method: the +`DelegatingIntroductionInterceptor` implementation - which calls the delegate method if +the method is introduced, otherwise proceeds towards the join point - is usually +sufficient. In the present case, we need to add a check: no setter method can be invoked +if in locked mode. + +The introduction advisor required is simple. All it needs to do is hold a distinct +`LockMixin` instance, and specify the introduced interfaces - in this case, just +`Lockable`. A more complex example might take a reference to the introduction +interceptor (which would be defined as a prototype): in this case, there's no +configuration relevant for a `LockMixin`, so we simply create it using `new`. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class LockMixinAdvisor extends DefaultIntroductionAdvisor { + + public LockMixinAdvisor() { + super(new LockMixin(), Lockable.class); + } + } +---- + +We can apply this advisor very simply: it requires no configuration. (However, it __is__ +necessary: It's impossible to use an `IntroductionInterceptor` without an +__IntroductionAdvisor__.) As usual with introductions, the advisor must be per-instance, +as it is stateful. We need a different instance of `LockMixinAdvisor`, and hence +`LockMixin`, for each advised object. The advisor comprises part of the advised object's +state. + +We can apply this advisor programmatically, using the `Advised.addAdvisor()` method, or +(the recommended way) in XML configuration, like any other advisor. All proxy creation +choices discussed below, including "auto proxy creators," correctly handle introductions +and stateful mixins. + + + + +[[aop-api-advisor]] +== Advisor API in Spring +In Spring, an Advisor is an aspect that contains just a single advice object associated +with a pointcut expression. + +Apart from the special case of introductions, any advisor can be used with any advice. +`org.springframework.aop.support.DefaultPointcutAdvisor` is the most commonly used +advisor class. For example, it can be used with a `MethodInterceptor`, `BeforeAdvice` or +`ThrowsAdvice`. + +It is possible to mix advisor and advice types in Spring in the same AOP proxy. For +example, you could use a interception around advice, throws advice and before advice in +one proxy configuration: Spring will automatically create the necessary interceptor +chain. + + + + +[[aop-pfb]] +== Using the ProxyFactoryBean to create AOP proxies +If you're using the Spring IoC container (an ApplicationContext or BeanFactory) for your +business objects - and you should be! - you will want to use one of Spring's AOP +FactoryBeans. (Remember that a factory bean introduces a layer of indirection, enabling +it to create objects of a different type.) + +[NOTE] +=== +The Spring AOP support also uses factory beans under the covers. +=== + +The basic way to create an AOP proxy in Spring is to use the +__org.springframework.aop.framework.ProxyFactoryBean__. This gives complete control over +the pointcuts and advice that will apply, and their ordering. However, there are simpler +options that are preferable if you don't need such control. + + + +[[aop-pfb-1]] +=== Basics +The `ProxyFactoryBean`, like other Spring `FactoryBean` implementations, introduces a +level of indirection. If you define a `ProxyFactoryBean` with name `foo`, what objects +referencing `foo` see is not the `ProxyFactoryBean` instance itself, but an object +created by the `ProxyFactoryBean`'s implementation of the `getObject()` method. This +method will create an AOP proxy wrapping a target object. + +One of the most important benefits of using a `ProxyFactoryBean` or another IoC-aware +class to create AOP proxies, is that it means that advices and pointcuts can also be +managed by IoC. This is a powerful feature, enabling certain approaches that are hard to +achieve with other AOP frameworks. For example, an advice may itself reference +application objects (besides the target, which should be available in any AOP +framework), benefiting from all the pluggability provided by Dependency Injection. + + + +[[aop-pfb-2]] +=== JavaBean properties +In common with most `FactoryBean` implementations provided with Spring, the +`ProxyFactoryBean` class is itself a JavaBean. Its properties are used to: + +* Specify the target you want to proxy. +* Specify whether to use CGLIB (see below and also <>). + +Some key properties are inherited from `org.springframework.aop.framework.ProxyConfig` +(the superclass for all AOP proxy factories in Spring). These key properties include: + +* `proxyTargetClass`: `true` if the target class is to be proxied, rather than the + target class' interfaces. If this property value is set to `true`, then CGLIB proxies + will be created (but see also <>). +* `optimize`: controls whether or not aggressive optimizations are applied to proxies + __created via CGLIB__. One should not blithely use this setting unless one fully + understands how the relevant AOP proxy handles optimization. This is currently used + only for CGLIB proxies; it has no effect with JDK dynamic proxies. +* `frozen`: if a proxy configuration is `frozen`, then changes to the configuration are + no longer allowed. This is useful both as a slight optimization and for those cases + when you don't want callers to be able to manipulate the proxy (via the `Advised` + interface) after the proxy has been created. The default value of this property is + `false`, so changes such as adding additional advice are allowed. +* `exposeProxy`: determines whether or not the current proxy should be exposed in a + `ThreadLocal` so that it can be accessed by the target. If a target needs to obtain + the proxy and the `exposeProxy` property is set to `true`, the target can use the + `AopContext.currentProxy()` method. + +Other properties specific to `ProxyFactoryBean` include: + +* `proxyInterfaces`: array of String interface names. If this isn't supplied, a CGLIB + proxy for the target class will be used (but see also <>). +* `interceptorNames`: String array of `Advisor`, interceptor or other advice names to + apply. Ordering is significant, on a first come-first served basis. That is to say + that the first interceptor in the list will be the first to be able to intercept the + invocation. + +The names are bean names in the current factory, including bean names from ancestor +factories. You can't mention bean references here since doing so would result in the +`ProxyFactoryBean` ignoring the singleton setting of the advice. + +You can append an interceptor name with an asterisk ( `*`). This will result in the +application of all advisor beans with names starting with the part before the asterisk +to be applied. An example of using this feature can be found in <>. + +* singleton: whether or not the factory should return a single object, no matter how + often the `getObject()` method is called. Several `FactoryBean` implementations offer + such a method. The default value is `true`. If you want to use stateful advice - for + example, for stateful mixins - use prototype advices along with a singleton value of + `false`. + + + +[[aop-pfb-proxy-types]] +=== JDK- and CGLIB-based proxies +This section serves as the definitive documentation on how the `ProxyFactoryBean` +chooses to create one of either a JDK- and CGLIB-based proxy for a particular target +object (that is to be proxied). + +[NOTE] +=== +The behavior of the `ProxyFactoryBean` with regard to creating JDK- or CGLIB-based +proxies changed between versions 1.2.x and 2.0 of Spring. The `ProxyFactoryBean` now +exhibits similar semantics with regard to auto-detecting interfaces as those of the +`TransactionProxyFactoryBean` class. +=== + +If the class of a target object that is to be proxied (hereafter simply referred to as +the target class) doesn't implement any interfaces, then a CGLIB-based proxy will be +created. This is the easiest scenario, because JDK proxies are interface based, and no +interfaces means JDK proxying isn't even possible. One simply plugs in the target bean, +and specifies the list of interceptors via the `interceptorNames` property. Note that a +CGLIB-based proxy will be created even if the `proxyTargetClass` property of the +`ProxyFactoryBean` has been set to `false`. (Obviously this makes no sense, and is best +removed from the bean definition because it is at best redundant, and at worst +confusing.) + +If the target class implements one (or more) interfaces, then the type of proxy that is +created depends on the configuration of the `ProxyFactoryBean`. + +If the `proxyTargetClass` property of the `ProxyFactoryBean` has been set to `true`, +then a CGLIB-based proxy will be created. This makes sense, and is in keeping with the +principle of least surprise. Even if the `proxyInterfaces` property of the +`ProxyFactoryBean` has been set to one or more fully qualified interface names, the fact +that the `proxyTargetClass` property is set to `true` __will__ cause CGLIB-based +proxying to be in effect. + +If the `proxyInterfaces` property of the `ProxyFactoryBean` has been set to one or more +fully qualified interface names, then a JDK-based proxy will be created. The created +proxy will implement all of the interfaces that were specified in the `proxyInterfaces` +property; if the target class happens to implement a whole lot more interfaces than +those specified in the `proxyInterfaces` property, that is all well and good but those +additional interfaces will not be implemented by the returned proxy. + +If the `proxyInterfaces` property of the `ProxyFactoryBean` has __not__ been set, but +the target class __does implement one (or more)__ interfaces, then the +`ProxyFactoryBean` will auto-detect the fact that the target class does actually +implement at least one interface, and a JDK-based proxy will be created. The interfaces +that are actually proxied will be __all__ of the interfaces that the target class +implements; in effect, this is the same as simply supplying a list of each and every +interface that the target class implements to the `proxyInterfaces` property. However, +it is significantly less work, and less prone to typos. + + + +[[aop-api-proxying-intf]] +=== Proxying interfaces +Let's look at a simple example of `ProxyFactoryBean` in action. This example involves: + +* A __target bean__ that will be proxied. This is the "personTarget" bean definition in + the example below. +* An Advisor and an Interceptor used to provide advice. +* An AOP proxy bean definition specifying the target object (the personTarget bean) and + the interfaces to proxy, along with the advices to apply. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + + + + + myAdvisor + debugInterceptor + + + +---- + +Note that the `interceptorNames` property takes a list of String: the bean names of the +interceptor or advisors in the current factory. Advisors, interceptors, before, after +returning and throws advice objects can be used. The ordering of advisors is significant. + +[NOTE] +=== +You might be wondering why the list doesn't hold bean references. The reason for this is +that if the ProxyFactoryBean's singleton property is set to false, it must be able to +return independent proxy instances. If any of the advisors is itself a prototype, an +independent instance would need to be returned, so it's necessary to be able to obtain +an instance of the prototype from the factory; holding a reference isn't sufficient. +=== + +The "person" bean definition above can be used in place of a Person implementation, as +follows: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + Person person = (Person) factory.getBean("person"); +---- + +Other beans in the same IoC context can express a strongly typed dependency on it, as +with an ordinary Java object: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + +---- + +The `PersonUser` class in this example would expose a property of type Person. As far as +it's concerned, the AOP proxy can be used transparently in place of a "real" person +implementation. However, its class would be a dynamic proxy class. It would be possible +to cast it to the `Advised` interface (discussed below). + +It's possible to conceal the distinction between target and proxy using an anonymous +__inner bean__, as follows. Only the `ProxyFactoryBean` definition is different; the +advice is included only for completeness: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + + + + myAdvisor + debugInterceptor + + + +---- + +This has the advantage that there's only one object of type `Person`: useful if we want +to prevent users of the application context from obtaining a reference to the un-advised +object, or need to avoid any ambiguity with Spring IoC __autowiring__. There's also +arguably an advantage in that the ProxyFactoryBean definition is self-contained. +However, there are times when being able to obtain the un-advised target from the +factory might actually be an __advantage__: for example, in certain test scenarios. + + + +[[aop-api-proxying-class]] +=== Proxying classes +What if you need to proxy a class, rather than one or more interfaces? + +Imagine that in our example above, there was no `Person` interface: we needed to advise +a class called `Person` that didn't implement any business interface. In this case, you +can configure Spring to use CGLIB proxying, rather than dynamic proxies. Simply set the +`proxyTargetClass` property on the ProxyFactoryBean above to true. While it's best to +program to interfaces, rather than classes, the ability to advise classes that don't +implement interfaces can be useful when working with legacy code. (In general, Spring +isn't prescriptive. While it makes it easy to apply good practices, it avoids forcing a +particular approach.) + +If you want to, you can force the use of CGLIB in any case, even if you do have +interfaces. + +CGLIB proxying works by generating a subclass of the target class at runtime. Spring +configures this generated subclass to delegate method calls to the original target: the +subclass is used to implement the __Decorator__ pattern, weaving in the advice. + +CGLIB proxying should generally be transparent to users. However, there are some issues +to consider: + +* `Final` methods can't be advised, as they can't be overridden. +* There is no need to add CGLIB to your classpath. As of Spring 3.2, CGLIB is repackaged + and included in the spring-core JAR. In other words, CGLIB-based AOP will work "out of + the box" just as do JDK dynamic proxies. + +There's little performance difference between CGLIB proxying and dynamic proxies. As of +Spring 1.0, dynamic proxies are slightly faster. However, this may change in the future. +Performance should not be a decisive consideration in this case. + + + +[[aop-global-advisors]] +=== Using 'global' advisors +By appending an asterisk to an interceptor name, all advisors with bean names matching +the part before the asterisk, will be added to the advisor chain. This can come in handy +if you need to add a standard set of 'global' advisors: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + global* + + + + + + +---- + + + + +[[aop-concise-proxy]] +== Concise proxy definitions +Especially when defining transactional proxies, you may end up with many similar proxy +definitions. The use of parent and child bean definitions, along with inner bean +definitions, can result in much cleaner and more concise proxy definitions. + +First a parent, __template__, bean definition is created for the proxy: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + PROPAGATION_REQUIRED + + + +---- + +This will never be instantiated itself, so may actually be incomplete. Then each proxy +which needs to be created is just a child bean definition, which wraps the target of the +proxy as an inner bean definition, since the target will never be used on its own anyway. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + +---- + +It is of course possible to override properties from the parent template, such as in +this case, the transaction propagation settings: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + PROPAGATION_REQUIRED,readOnly + PROPAGATION_REQUIRED,readOnly + PROPAGATION_REQUIRED,readOnly + PROPAGATION_REQUIRED + + + +---- + +Note that in the example above, we have explicitly marked the parent bean definition as +__abstract__ by using the __abstract__ attribute, as described +<>, so that it may not actually ever be +instantiated. Application contexts (but not simple bean factories) will by default +pre-instantiate all singletons. It is therefore important (at least for singleton beans) +that if you have a (parent) bean definition which you intend to use only as a template, +and this definition specifies a class, you must make sure to set the __abstract__ +attribute to __true__, otherwise the application context will actually try to +pre-instantiate it. + + + + +[[aop-prog]] +== Creating AOP proxies programmatically with the ProxyFactory +It's easy to create AOP proxies programmatically using Spring. This enables you to use +Spring AOP without dependency on Spring IoC. + +The following listing shows creation of a proxy for a target object, with one +interceptor and one advisor. The interfaces implemented by the target object will +automatically be proxied: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ProxyFactory factory = new ProxyFactory(myBusinessInterfaceImpl); + factory.addAdvice(myMethodInterceptor); + factory.addAdvisor(myAdvisor); + MyBusinessInterface tb = (MyBusinessInterface) factory.getProxy(); +---- + +The first step is to construct an object of type +`org.springframework.aop.framework.ProxyFactory`. You can create this with a target +object, as in the above example, or specify the interfaces to be proxied in an alternate +constructor. + +You can add advices (with interceptors as a specialized kind of advice) and/or advisors, +and manipulate them for the life of the ProxyFactory. If you add an +IntroductionInterceptionAroundAdvisor, you can cause the proxy to implement additional +interfaces. + +There are also convenience methods on ProxyFactory (inherited from `AdvisedSupport`) +which allow you to add other advice types such as before and throws advice. +AdvisedSupport is the superclass of both ProxyFactory and ProxyFactoryBean. + +[TIP] +=== + +Integrating AOP proxy creation with the IoC framework is best practice in most +applications. We recommend that you externalize configuration from Java code with AOP, +as in general. +=== + + + + +[[aop-api-advised]] +== Manipulating advised objects +However you create AOP proxies, you can manipulate them using the +`org.springframework.aop.framework.Advised` interface. Any AOP proxy can be cast to this +interface, whichever other interfaces it implements. This interface includes the +following methods: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + Advisor[] getAdvisors(); + + void addAdvice(Advice advice) throws AopConfigException; + + void addAdvice(int pos, Advice advice) throws AopConfigException; + + void addAdvisor(Advisor advisor) throws AopConfigException; + + void addAdvisor(int pos, Advisor advisor) throws AopConfigException; + + int indexOf(Advisor advisor); + + boolean removeAdvisor(Advisor advisor) throws AopConfigException; + + void removeAdvisor(int index) throws AopConfigException; + + boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException; + + boolean isFrozen(); +---- + +The `getAdvisors()` method will return an Advisor for every advisor, interceptor or +other advice type that has been added to the factory. If you added an Advisor, the +returned advisor at this index will be the object that you added. If you added an +interceptor or other advice type, Spring will have wrapped this in an advisor with a +pointcut that always returns true. Thus if you added a `MethodInterceptor`, the advisor +returned for this index will be an `DefaultPointcutAdvisor` returning your +`MethodInterceptor` and a pointcut that matches all classes and methods. + +The `addAdvisor()` methods can be used to add any Advisor. Usually the advisor holding +pointcut and advice will be the generic `DefaultPointcutAdvisor`, which can be used with +any advice or pointcut (but not for introductions). + +By default, it's possible to add or remove advisors or interceptors even once a proxy +has been created. The only restriction is that it's impossible to add or remove an +introduction advisor, as existing proxies from the factory will not show the interface +change. (You can obtain a new proxy from the factory to avoid this problem.) + +A simple example of casting an AOP proxy to the `Advised` interface and examining and +manipulating its advice: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + Advised advised = (Advised) myObject; + Advisor[] advisors = advised.getAdvisors(); + int oldAdvisorCount = advisors.length; + System.out.println(oldAdvisorCount + " advisors"); + + // Add an advice like an interceptor without a pointcut + // Will match all proxied methods + // Can use for interceptors, before, after returning or throws advice + advised.addAdvice(new DebugInterceptor()); + + // Add selective advice using a pointcut + advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice)); + + assertEquals("Added two advisors", oldAdvisorCount + 2, advised.getAdvisors().length); +---- + +[NOTE] +=== +It's questionable whether it's advisable (no pun intended) to modify advice on a +business object in production, although there are no doubt legitimate usage cases. +However, it can be very useful in development: for example, in tests. I have sometimes +found it very useful to be able to add test code in the form of an interceptor or other +advice, getting inside a method invocation I want to test. (For example, the advice can +get inside a transaction created for that method: for example, to run SQL to check that +a database was correctly updated, before marking the transaction for roll back.) +=== + +Depending on how you created the proxy, you can usually set a `frozen` flag, in which +case the `Advised` `isFrozen()` method will return true, and any attempts to modify +advice through addition or removal will result in an `AopConfigException`. The ability +to freeze the state of an advised object is useful in some cases, for example, to +prevent calling code removing a security interceptor. It may also be used in Spring 1.1 +to allow aggressive optimization if runtime advice modification is known not to be +required. + + + + +[[aop-autoproxy]] +== Using the "auto-proxy" facility +So far we've considered explicit creation of AOP proxies using a `ProxyFactoryBean` or +similar factory bean. + +Spring also allows us to use "auto-proxy" bean definitions, which can automatically +proxy selected bean definitions. This is built on Spring "bean post processor" +infrastructure, which enables modification of any bean definition as the container loads. + +In this model, you set up some special bean definitions in your XML bean definition file +to configure the auto proxy infrastructure. This allows you just to declare the targets +eligible for auto-proxying: you don't need to use `ProxyFactoryBean`. + +There are two ways to do this: + +* Using an auto-proxy creator that refers to specific beans in the current context. +* A special case of auto-proxy creation that deserves to be considered separately; + auto-proxy creation driven by source-level metadata attributes. + + + +[[aop-autoproxy-choices]] +=== Autoproxy bean definitions +The `org.springframework.aop.framework.autoproxy` package provides the following +standard auto-proxy creators. + + +[[aop-api-autoproxy]] +==== BeanNameAutoProxyCreator +The `BeanNameAutoProxyCreator` class is a `BeanPostProcessor` that automatically creates +AOP proxies for beans with names matching literal values or wildcards. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + myInterceptor + + + +---- + +As with `ProxyFactoryBean`, there is an `interceptorNames` property rather than a list +of interceptors, to allow correct behavior for prototype advisors. Named "interceptors" +can be advisors or any advice type. + +As with auto proxying in general, the main point of using `BeanNameAutoProxyCreator` is +to apply the same configuration consistently to multiple objects, with minimal volume of +configuration. It is a popular choice for applying declarative transactions to multiple +objects. + +Bean definitions whose names match, such as "jdkMyBean" and "onlyJdk" in the above +example, are plain old bean definitions with the target class. An AOP proxy will be +created automatically by the `BeanNameAutoProxyCreator`. The same advice will be applied +to all matching beans. Note that if advisors are used (rather than the interceptor in +the above example), the pointcuts may apply differently to different beans. + + +[[aop-api-autoproxy-default]] +==== DefaultAdvisorAutoProxyCreator +A more general and extremely powerful auto proxy creator is +`DefaultAdvisorAutoProxyCreator`. This will automagically apply eligible advisors in the +current context, without the need to include specific bean names in the auto-proxy +advisor's bean definition. It offers the same merit of consistent configuration and +avoidance of duplication as `BeanNameAutoProxyCreator`. + +Using this mechanism involves: + +* Specifying a `DefaultAdvisorAutoProxyCreator` bean definition. +* Specifying any number of Advisors in the same or related contexts. Note that these + __must__ be Advisors, not just interceptors or other advices. This is necessary + because there must be a pointcut to evaluate, to check the eligibility of each advice + to candidate bean definitions. + +The `DefaultAdvisorAutoProxyCreator` will automatically evaluate the pointcut contained +in each advisor, to see what (if any) advice it should apply to each business object +(such as "businessObject1" and "businessObject2" in the example). + +This means that any number of advisors can be applied automatically to each business +object. If no pointcut in any of the advisors matches any method in a business object, +the object will not be proxied. As bean definitions are added for new business objects, +they will automatically be proxied if necessary. + +Autoproxying in general has the advantage of making it impossible for callers or +dependencies to obtain an un-advised object. Calling getBean("businessObject1") on this +ApplicationContext will return an AOP proxy, not the target business object. (The "inner +bean" idiom shown earlier also offers this benefit.) + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + + +---- + +The `DefaultAdvisorAutoProxyCreator` is very useful if you want to apply the same advice +consistently to many business objects. Once the infrastructure definitions are in place, +you can simply add new business objects without including specific proxy configuration. +You can also drop in additional aspects very easily - for example, tracing or +performance monitoring aspects - with minimal change to configuration. + +The DefaultAdvisorAutoProxyCreator offers support for filtering (using a naming +convention so that only certain advisors are evaluated, allowing use of multiple, +differently configured, AdvisorAutoProxyCreators in the same factory) and ordering. +Advisors can implement the `org.springframework.core.Ordered` interface to ensure +correct ordering if this is an issue. The TransactionAttributeSourceAdvisor used in the +above example has a configurable order value; the default setting is unordered. + + +[[aop-api-autoproxy-abstract]] +==== AbstractAdvisorAutoProxyCreator +This is the superclass of DefaultAdvisorAutoProxyCreator. You can create your own +auto-proxy creators by subclassing this class, in the unlikely event that advisor +definitions offer insufficient customization to the behavior of the framework +`DefaultAdvisorAutoProxyCreator`. + + + +[[aop-autoproxy-metadata]] +=== Using metadata-driven auto-proxying +A particularly important type of auto-proxying is driven by metadata. This produces a +similar programming model to .NET `ServicedComponents`. Instead of defining metadata in +XML descriptors, configuration for transaction management and other enterprise services +is held in source-level attributes. + +In this case, you use the `DefaultAdvisorAutoProxyCreator`, in combination with Advisors +that understand metadata attributes. The metadata specifics are held in the pointcut +part of the candidate advisors, rather than in the auto-proxy creation class itself. + +This is really a special case of the `DefaultAdvisorAutoProxyCreator`, but deserves +consideration on its own. (The metadata-aware code is in the pointcuts contained in the +advisors, not the AOP framework itself.) + +The `/attributes` directory of the JPetStore sample application shows the use of +attribute-driven auto-proxying. In this case, there's no need to use the +`TransactionProxyFactoryBean`. Simply defining transactional attributes on business +objects is sufficient, because of the use of metadata-aware pointcuts. The bean +definitions include the following code, in `/WEB-INF/declarativeServices.xml`. Note that +this is generic, and can be used outside the JPetStore: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + + +---- + +The `DefaultAdvisorAutoProxyCreator` bean definition (the name is not significant, hence +it can even be omitted) will pick up all eligible pointcuts in the current application +context. In this case, the "transactionAdvisor" bean definition, of type +`TransactionAttributeSourceAdvisor`, will apply to classes or methods carrying a +transaction attribute. The TransactionAttributeSourceAdvisor depends on a +TransactionInterceptor, via constructor dependency. The example resolves this via +autowiring. The `AttributesTransactionAttributeSource` depends on an implementation of +the `org.springframework.metadata.Attributes` interface. In this fragment, the +"attributes" bean satisfies this, using the Jakarta Commons Attributes API to obtain +attribute information. (The application code must have been compiled using the Commons +Attributes compilation task.) + +The `/annotation` directory of the JPetStore sample application contains an analogous +example for auto-proxying driven by JDK 1.5+ annotations. The following configuration +enables automatic detection of Spring's `Transactional` annotation, leading to implicit +proxies for beans containing that annotation: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + +---- + +The `TransactionInterceptor` defined here depends on a `PlatformTransactionManager` +definition, which is not included in this generic file (although it could be) because it +will be specific to the application's transaction requirements (typically JTA, as in +this example, or Hibernate, JDO or JDBC): + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + +---- + +[TIP] +=== + +If you require only declarative transaction management, using these generic XML +definitions will result in Spring automatically proxying all classes or methods with +transaction attributes. You won't need to work directly with AOP, and the programming +model is similar to that of .NET ServicedComponents. +=== + +This mechanism is extensible. It's possible to do auto-proxying based on custom +attributes. You need to: + +* Define your custom attribute. +* Specify an Advisor with the necessary advice, including a pointcut that is triggered + by the presence of the custom attribute on a class or method. You may be able to use + an existing advice, merely implementing a static pointcut that picks up the custom + attribute. + +It's possible for such advisors to be unique to each advised class (for example, mixins): +they simply need to be defined as prototype, rather than singleton, bean definitions. +For example, the `LockMixin` introduction interceptor from the Spring test suite, +shown above, could be used in conjunction with a generic `DefaultIntroductionAdvisor`: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + +---- + +Note that both `lockMixin` and `lockableAdvisor` are defined as prototypes. + + + + +[[aop-targetsource]] +== Using TargetSources +Spring offers the concept of a __TargetSource__, expressed in the +`org.springframework.aop.TargetSource` interface. This interface is responsible for +returning the "target object" implementing the join point. The `TargetSource` +implementation is asked for a target instance each time the AOP proxy handles a method +invocation. + +Developers using Spring AOP don't normally need to work directly with TargetSources, but +this provides a powerful means of supporting pooling, hot swappable and other +sophisticated targets. For example, a pooling TargetSource can return a different target +instance for each invocation, using a pool to manage instances. + +If you do not specify a TargetSource, a default implementation is used that wraps a +local object. The same target is returned for each invocation (as you would expect). + +Let's look at the standard target sources provided with Spring, and how you can use them. + +[TIP] +=== + +When using a custom target source, your target will usually need to be a prototype +rather than a singleton bean definition. This allows Spring to create a new target +instance when required. +=== + + + +[[aop-ts-swap]] +=== Hot swappable target sources +The `org.springframework.aop.target.HotSwappableTargetSource` exists to allow the target +of an AOP proxy to be switched while allowing callers to keep their references to it. + +Changing the target source's target takes effect immediately. The +`HotSwappableTargetSource` is threadsafe. + +You can change the target via the `swap()` method on HotSwappableTargetSource as follows: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper"); + Object oldTarget = swapper.swap(newTarget); +---- + +The XML definitions required look as follows: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + +---- + +The above `swap()` call changes the target of the swappable bean. Clients who hold a +reference to that bean will be unaware of the change, but will immediately start hitting +the new target. + +Although this example doesn't add any advice - and it's not necessary to add advice to +use a `TargetSource` - of course any `TargetSource` can be used in conjunction with +arbitrary advice. + + + +[[aop-ts-pool]] +=== Pooling target sources +Using a pooling target source provides a similar programming model to stateless session +EJBs, in which a pool of identical instances is maintained, with method invocations +going to free objects in the pool. + +A crucial difference between Spring pooling and SLSB pooling is that Spring pooling can +be applied to any POJO. As with Spring in general, this service can be applied in a +non-invasive way. + +Spring provides out-of-the-box support for Commons Pool 2.2, which provides a +fairly efficient pooling implementation. You'll need the commons-pool Jar on your +application's classpath to use this feature. It's also possible to subclass +`org.springframework.aop.target.AbstractPoolingTargetSource` to support any other +pooling API. + +[NOTE] +=== +Commons Pool 1.5+ is also supported but deprecated as of Spring Framework 4.2. +=== + + +Sample configuration is shown below: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + ... properties omitted + + + + + + + + + + + +---- + +Note that the target object - "businessObjectTarget" in the example - __must__ be a +prototype. This allows the `PoolingTargetSource` implementation to create new instances +of the target to grow the pool as necessary. See the javadocs of +`AbstractPoolingTargetSource` and the concrete subclass you wish to use for information +about its properties: "maxSize" is the most basic, and always guaranteed to be present. + +In this case, "myInterceptor" is the name of an interceptor that would need to be +defined in the same IoC context. However, it isn't necessary to specify interceptors to +use pooling. If you want only pooling, and no other advice, don't set the +interceptorNames property at all. + +It's possible to configure Spring so as to be able to cast any pooled object to the +`org.springframework.aop.target.PoolingConfig` interface, which exposes information +about the configuration and current size of the pool through an introduction. You'll +need to define an advisor like this: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- + +This advisor is obtained by calling a convenience method on the +`AbstractPoolingTargetSource` class, hence the use of MethodInvokingFactoryBean. This +advisor's name ("poolConfigAdvisor" here) must be in the list of interceptors names in +the ProxyFactoryBean exposing the pooled object. + +The cast will look as follows: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + PoolingConfig conf = (PoolingConfig) beanFactory.getBean("businessObject"); + System.out.println("Max pool size is " + conf.getMaxSize()); +---- + +[NOTE] +=== +Pooling stateless service objects is not usually necessary. We don't believe it should +be the default choice, as most stateless objects are naturally thread safe, and instance +pooling is problematic if resources are cached. +=== + +Simpler pooling is available using auto-proxying. It's possible to set the TargetSources +used by any auto-proxy creator. + + + +[[aop-ts-prototype]] +=== Prototype target sources +Setting up a "prototype" target source is similar to a pooling TargetSource. In this +case, a new instance of the target will be created on every method invocation. Although +the cost of creating a new object isn't high in a modern JVM, the cost of wiring up the +new object (satisfying its IoC dependencies) may be more expensive. Thus you shouldn't +use this approach without very good reason. + +To do this, you could modify the `poolTargetSource` definition shown above as follows. +(I've also changed the name, for clarity.) + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + +---- + +There's only one property: the name of the target bean. Inheritance is used in the +TargetSource implementations to ensure consistent naming. As with the pooling target +source, the target bean must be a prototype bean definition. + + + +[[aop-ts-threadlocal]] +=== ThreadLocal target sources + +`ThreadLocal` target sources are useful if you need an object to be created for each +incoming request (per thread that is). The concept of a `ThreadLocal` provide a JDK-wide +facility to transparently store resource alongside a thread. Setting up a +`ThreadLocalTargetSource` is pretty much the same as was explained for the other types +of target source: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + +---- + +[NOTE] +=== +ThreadLocals come with serious issues (potentially resulting in memory leaks) when +incorrectly using them in a multi-threaded and multi-classloader environments. One +should always consider wrapping a threadlocal in some other class and never directly use +the `ThreadLocal` itself (except of course in the wrapper class). Also, one should +always remember to correctly set and unset (where the latter simply involved a call to +`ThreadLocal.set(null)`) the resource local to the thread. Unsetting should be done in +any case since not unsetting it might result in problematic behavior. Spring's +ThreadLocal support does this for you and should always be considered in favor of using +ThreadLocals without other proper handling code. +=== + + + + +[[aop-extensibility]] +== Defining new Advice types + +Spring AOP is designed to be extensible. While the interception implementation strategy +is presently used internally, it is possible to support arbitrary advice types in +addition to the out-of-the-box interception around advice, before, throws advice and +after returning advice. + +The `org.springframework.aop.framework.adapter` package is an SPI package allowing +support for new custom advice types to be added without changing the core framework. +The only constraint on a custom `Advice` type is that it must implement the +`org.aopalliance.aop.Advice` marker interface. + +Please refer to the `org.springframework.aop.framework.adapter` javadocs for further +information. + + + + +[[aop-api-resources]] +== Further resources +Please refer to the Spring sample applications for further examples of Spring AOP: + +* The JPetStore's default configuration illustrates the use of the + `TransactionProxyFactoryBean` for declarative transaction management. +* The `/attributes` directory of the JPetStore illustrates the use of attribute-driven + declarative transaction management. \ No newline at end of file diff --git a/src/asciidoc/core-aop.adoc b/src/asciidoc/core-aop.adoc index 7e2cfa55f2c..f248398dbd0 100644 --- a/src/asciidoc/core-aop.adoc +++ b/src/asciidoc/core-aop.adoc @@ -36,11 +36,11 @@ AOP is used in the Spring Framework to... * ... allow users to implement custom aspects, complementing their use of OOP with AOP. [NOTE] -=== +==== If you are interested only in generic declarative services or other pre-packaged declarative middleware services such as pooling, you do not need to work directly with Spring AOP, and can skip most of this chapter. -=== +==== diff --git a/src/asciidoc/core-beans.adoc b/src/asciidoc/core-beans.adoc index bff4174a53e..4432083b4f3 100644 --- a/src/asciidoc/core-beans.adoc +++ b/src/asciidoc/core-beans.adoc @@ -92,12 +92,12 @@ which is what most of this chapter uses to convey key concepts and features of t Spring IoC container. [NOTE] -=== +==== XML-based metadata is __not__ the only allowed form of configuration metadata. The Spring IoC container itself is __totally__ decoupled from the format in which this configuration metadata is actually written. These days many developers choose <> for their Spring applications. -=== +==== For information about using other forms of metadata with the Spring container, see: @@ -171,13 +171,13 @@ as the local file system, from the Java `CLASSPATH`, and so on. ---- [NOTE] -=== +==== After you learn about Spring's IoC container, you may want to know more about Spring's `Resource` abstraction, as described in <>, which provides a convenient mechanism for reading an InputStream from locations defined in a URI syntax. In particular, `Resource` paths are used to construct applications contexts as described in <>. -=== +==== The following example shows the service layer objects `(services.xml)` configuration file: @@ -271,7 +271,7 @@ contents of the files being imported, including the top level `` element be valid XML bean definitions according to the Spring Schema. [NOTE] -=== +==== It is possible, but not recommended, to reference files in parent directories using a relative "../" path. Doing so creates a dependency on a file that is outside the current application. In particular, this reference is not recommended for "classpath:" URLs (for @@ -285,7 +285,7 @@ aware that you are coupling your application's configuration to specific absolut locations. It is generally preferable to keep an indirection for such absolute locations, for example, through "${...}" placeholders that are resolved against JVM system properties at runtime. -=== +==== @@ -662,14 +662,14 @@ dependency injection (DI). See <>. [NOTE] -=== +==== In Spring documentation,__ factory bean__ refers to a bean that is configured in the Spring container that will create objects through an <> or <> factory method. By contrast, `FactoryBean` (notice the capitalization) refers to a Spring-specific <>. -=== +==== @@ -1276,11 +1276,11 @@ bean is a <> bean, this typo and the resulting e may only be discovered long after the container is deployed. [NOTE] -=== +==== The `local` attribute on the `idref` element is no longer supported in the 4.0 beans xsd since it does not provide value over a regular `bean` reference anymore. Simply change your existing `idref local` references to `idref bean` when upgrading to the 4.0 schema. -=== +==== A common place (at least in versions earlier than Spring 2.0) where the `` element brings value is in the configuration of <> in a @@ -1342,11 +1342,11 @@ container with a proxy that will have the same name as the parent bean. ---- [NOTE] -=== +==== The `local` attribute on the `ref` element is no longer supported in the 4.0 beans xsd since it does not provide value over a regular `bean` reference anymore. Simply change your existing `ref local` references to `ref bean` when upgrading to the 4.0 schema. -=== +==== [[beans-inner-beans]] @@ -1659,13 +1659,13 @@ whereas the `-ref` part indicates that this is not a straight value but rather a reference to another bean. [NOTE] -=== +==== The p-namespace is not as flexible as the standard XML format. For example, the format for declaring property references clashes with properties that end in `Ref`, whereas the standard XML format does not. We recommend that you choose your approach carefully and communicate this to your team members, to avoid producing XML documents that use all three approaches at the same time. -=== +==== [[beans-c-namespace]] @@ -1718,10 +1718,10 @@ argument indexes: ---- [NOTE] -=== +==== Due to the XML grammar, the index notation requires the presence of the leading `_` as XML attribute names cannot start with a number (even though some IDE allow it). -=== +==== In practice, the constructor resolution <> is quite efficient in matching @@ -1785,13 +1785,13 @@ delimiters: ---- [NOTE] -=== +==== The `depends-on` attribute in the bean definition can specify both an initialization time dependency and, in the case of <> beans only, a corresponding destroy time dependency. Dependent beans that define a `depends-on` relationship with a given bean are destroyed first, prior to the given bean itself being destroyed. Thus `depends-on` can also control shutdown order. -=== +==== @@ -2031,7 +2031,7 @@ bytecode generation from the CGLIB library to generate dynamically a subclass th overrides the method. [NOTE] -=== +==== For this dynamic subclassing to work, the class that the Spring container will subclass cannot be `final`, and the method to be overridden cannot be `final` either. Also, testing a class that has an `abstract` method requires you to subclass the class @@ -2041,7 +2041,7 @@ is no longer necessary to add CGLIB to your classpath, because CGLIB classes are repackaged under org.springframework and distributed within the spring-core JAR. This is done both for convenience as well as to avoid potential conflicts with other projects that use differing versions of CGLIB. -=== +==== Looking at the `CommandManager` class in the previous code snippet, you see that the Spring container will dynamically override the implementation of the `createCommand()` @@ -2248,13 +2248,13 @@ The following scopes are supported out of the box. You can also create |=== [NOTE] -=== +==== As of Spring 3.0, a __thread scope__ is available, but is not registered by default. For more information, see the documentation for {javadoc-baseurl}/org/springframework/context/support/SimpleThreadScope.html[`SimpleThreadScope`]. For instructions on how to register this or any other custom scope, see <>. -=== +==== @@ -2513,10 +2513,10 @@ object from the relevant scope (for example, an HTTP request) and delegate metho onto the real object. [NOTE] -=== +==== You __do not__ need to use the `` in conjunction with beans that are scoped as `singletons` or `prototypes`. -=== +==== The configuration in the following example is only one line, but it is important to understand the "why" as well as the "how" behind it. @@ -2608,10 +2608,10 @@ By default, when the Spring container creates a proxy for a bean that is marked the `` element, __a CGLIB-based class proxy is created__. [NOTE] -=== +==== CGLIB proxies only intercept public method calls! Do not call non-public methods on such a proxy; they will not be delegated to the actual scoped target object. -=== +==== Alternatively, you can configure the Spring container to create standard JDK interface-based proxies for such scoped beans, by specifying `false` for the value of @@ -2725,11 +2725,11 @@ of the custom `Scope` implementation that you wish to register and use. Suppose that you write your custom `Scope` implementation, and then register it as below. [NOTE] -=== +==== The example below uses `SimpleThreadScope` which is included with Spring, but not registered by default. The instructions would be the same for your own custom `Scope` implementations. -=== +==== [source,java,indent=0] [subs="verbatim,quotes"] @@ -2785,10 +2785,10 @@ of the scope. You can also do the `Scope` registration declaratively, using the ---- [NOTE] -=== +==== When you place `` in a `FactoryBean` implementation, it is the factory bean itself that is scoped, not the object returned from `getObject()`. -=== +==== @@ -3051,13 +3051,13 @@ As of Spring 2.5, you have three options for controlling bean lifecycle behavior annotations>>. You can combine these mechanisms to control a given bean. [NOTE] -=== +==== If multiple lifecycle mechanisms are configured for a bean, and each mechanism is configured with a different method name, then each configured method is executed in the order listed below. However, if the same method name is configured - for example, `init()` for an initialization method - for more than one of these lifecycle mechanisms, that method is executed once, as explained in the preceding section. -=== +==== Multiple lifecycle mechanisms configured for the same bean, with different initialization methods, are called as follows: @@ -3191,11 +3191,11 @@ above. [[beans-factory-shutdown]] ==== Shutting down the Spring IoC container gracefully in non-web applications [NOTE] -=== +==== This section applies only to non-web applications. Spring's web-based `ApplicationContext` implementations already have code in place to shut down the Spring IoC container gracefully when the relevant web application is shut down. -=== +==== If you are using Spring's IoC container in a non-web application environment; for example, in a rich client desktop environment; you register a shutdown hook with the @@ -3449,13 +3449,13 @@ parent bean id, returns an error. Similarly, the container's internal abstract. [NOTE] -=== +==== `ApplicationContext` pre-instantiates all singletons by default. Therefore, it is important (at least for singleton beans) that if you have a (parent) bean definition which you intend to use only as a template, and this definition specifies a class, you must make sure to set the __abstract__ attribute to __true__, otherwise the application context will actually (attempt to) pre-instantiate the `abstract` bean. -=== +==== @@ -3488,7 +3488,7 @@ interface too. For further details, consult the javadocs of the `BeanPostProcess registration of `BeanPostProcessors`>> [NOTE] -=== +==== ++BeanPostProcessor++s operate on bean (or object) __instances__; that is to say, the Spring IoC container instantiates a bean instance and __then__ ++BeanPostProcessor++s do their work. @@ -3502,7 +3502,7 @@ another container, even if both containers are part of the same hierarchy. To change the actual bean definition (i.e., the __blueprint__ that defines the bean), you instead need to use a `BeanFactoryPostProcessor` as described in <>. -=== +==== The `org.springframework.beans.factory.config.BeanPostProcessor` interface consists of exactly two callback methods. When such a class is registered as a post-processor with @@ -3530,7 +3530,7 @@ Since a ++BeanPostProcessor++ needs to be instantiated early in order to apply t initialization of other beans in the context, this early type detection is critical. [NOTE] -=== +==== *Programmatically registering BeanPostProcessors* @@ -3544,10 +3544,10 @@ respect the `Ordered` interface__. Here it is the __order of registration__ that dictates the order of execution. Note also that `BeanPostProcessors` registered programmatically are always processed before those registered through auto-detection, regardless of any explicit ordering. -=== +==== [NOTE] -=== +==== *BeanPostProcessors and AOP auto-proxying* @@ -3571,7 +3571,7 @@ ineligible for auto-proxying or other kinds of bean post-processing. For example have a dependency annotated with `@Resource` where the field/setter name does not directly correspond to the declared name of a bean and no name attribute is used, then Spring will access other beans for matching them by type. -=== +==== The following examples show how to write, register, and use `BeanPostProcessors` in an `ApplicationContext`. @@ -3704,7 +3704,7 @@ consider implementing the `Ordered` interface too. Consult the javadocs of the `BeanFactoryPostProcessor` and `Ordered` interfaces for more details. [NOTE] -=== +==== If you want to change the actual bean __instances__ (i.e., the objects that are created from the configuration metadata), then you instead need to use a `BeanPostProcessor` (described above in <>). While it is technically possible @@ -3718,7 +3718,7 @@ you are using container hierarchies. If you define a `BeanFactoryPostProcessor` container, it will __only__ be applied to the bean definitions in that container. Bean definitions in one container will not be post-processed by `BeanFactoryPostProcessors` in another container, even if both containers are part of the same hierarchy. -=== +==== A bean factory post-processor is executed automatically when it is declared inside an `ApplicationContext`, in order to apply changes to the configuration metadata that @@ -3735,14 +3735,14 @@ post-processors, at the appropriate time. You can deploy these post-processor be you would any other bean. [NOTE] -=== +==== As with ++BeanPostProcessor++s , you typically do not want to configure ++BeanFactoryPostProcessor++s for lazy initialization. If no other bean references a `Bean(Factory)PostProcessor`, that post-processor will not get instantiated at all. Thus, marking it for lazy initialization will be ignored, and the `Bean(Factory)PostProcessor` will be instantiated eagerly even if you set the `default-lazy-init` attribute to `true` on the declaration of your `` element. -=== +==== [[beans-factory-placeholderconfigurer]] @@ -3894,11 +3894,11 @@ foo.fred.bob.sammy=123 is set to the scalar value `123`. [NOTE] -=== +==== Specified override values are always __literal__ values; they are not translated into bean references. This convention also applies when the original value in the XML bean definition specifies a bean reference. -=== +==== With the `context` namespace introduced in Spring 2.5, it is possible to configure property overriding with a dedicated configuration element: @@ -3986,10 +3986,10 @@ Injection for Java) annotations contained in the javax.inject package such as `@ and `@Named`. Details about those annotations can be found in the <>. [NOTE] -=== +==== Annotation injection is performed __before__ XML injection, thus the latter configuration will override the former for properties wired through both approaches. -=== +==== As always, you can register them as individual bean definitions, but they can also be implicitly registered by including the following tag in an XML-based Spring configuration (notice the inclusion of the `context` namespace): @@ -4019,13 +4019,13 @@ as well as the aforementioned {javadoc-baseurl}/org/springframework/beans/factory/annotation/RequiredAnnotationBeanPostProcessor.html[`RequiredAnnotationBeanPostProcessor`].) [NOTE] -=== +==== `` only looks for annotations on beans in the same application context in which it is defined. This means that, if you put `` in a `WebApplicationContext` for a `DispatcherServlet`, it only checks for `@Autowired` beans in your controllers, and not your services. See <> for more information. -=== +==== @@ -4085,10 +4085,10 @@ As expected, you can apply the `@Autowired` annotation to "traditional" setter m ---- [NOTE] -=== +==== JSR 330's @Inject annotation can be used in place of Spring's `@Autowired` annotation in the examples below. See <> for more details -=== +==== You can also apply the annotation to methods with arbitrary names and/or multiple arguments: @@ -4223,7 +4223,7 @@ indicating __required__ dependencies. This behavior can be changed as demonstrat ---- [NOTE] -=== +==== Only __one annotated constructor per-class__ can be marked as __required__, but multiple non-required constructors can be annotated. In that case, each is considered among the candidates and Spring uses the __greediest__ constructor whose dependencies can be @@ -4234,7 +4234,7 @@ The __required__ attribute indicates that the property is not required for autow purposes, the property is ignored if it cannot be autowired. `@Required`, on the other hand, is stronger in that it enforces the property that was set by any means supported by the container. If no value is injected, a corresponding exception is raised. -=== +==== You can also use `@Autowired` for interfaces that are well-known resolvable dependencies: `BeanFactory`, `ApplicationContext`, `Environment`, `ResourceLoader`, @@ -4259,12 +4259,12 @@ automatically resolved, with no special setup necessary. ---- [NOTE] -=== +==== `@Autowired`, `@Inject`, `@Resource`, and `@Value` annotations are handled by a Spring `BeanPostProcessor` implementations which in turn means that you __cannot__ apply these annotations within your own `BeanPostProcessor` or `BeanFactoryPostProcessor` types (if any). These types must be 'wired up' explicitly via XML or using a Spring `@Bean` method. -=== +==== @@ -4756,14 +4756,14 @@ name "movieFinder" injected into its setter method: ---- [NOTE] -=== +==== The name provided with the annotation is resolved as a bean name by the `ApplicationContext` of which the `CommonAnnotationBeanPostProcessor` is aware. The names can be resolved through JNDI if you configure Spring's {javadoc-baseurl}/org/springframework/jndi/support/SimpleJndiBeanFactory.html[`SimpleJndiBeanFactory`] explicitly. However, it is recommended that you rely on the default behavior and simply use Spring's JNDI lookup capabilities to preserve the level of indirection. -=== +==== In the exclusive case of `@Resource` usage with no explicit name specified, and similar to `@Autowired`, `@Resource` finds a primary type match instead of a specific named bean @@ -4830,10 +4830,10 @@ pre-populated upon initialization and cleared upon destruction. ---- [NOTE] -=== +==== For details about the effects of combining various lifecycle mechanisms, see <>. -=== +==== @@ -4854,12 +4854,12 @@ type expressions, or your own custom filter criteria to select which classes wil bean definitions registered with the container. [NOTE] -=== +==== Starting with Spring 3.0, many features provided by the Spring JavaConfig project are part of the core Spring Framework. This allows you to define beans using Java rather than using the traditional XML files. Take a look at the `@Configuration`, `@Bean`, `@Import`, and `@DependsOn` annotations for examples of how to use these new features. -=== +==== @@ -4983,10 +4983,10 @@ comma/semicolon/space-separated list that includes the parent package of each cl ---- [NOTE] -=== +==== for concision, the above may have used the `value` attribute of the annotation, i.e. `ComponentScan("org.example")` -=== +==== The following is an alternative using XML @@ -5016,14 +5016,14 @@ The use of `` implicitly enables the functionality of === [NOTE] -=== +==== The scanning of classpath packages requires the presence of corresponding directory entries in the classpath. When you build JARs with Ant, make sure that you do __not__ activate the files-only switch of the JAR task. Also, classpath directories may not get exposed based on security policies in some environments, e.g. standalone apps on JDK 1.7.0_45 and higher (which requires 'Trusted-Library' setup in your manifests; see http://stackoverflow.com/questions/19394570/java-jre-7u45-breaks-classloader-getresources). -=== +==== Furthermore, the `AutowiredAnnotationBeanPostProcessor` and `CommonAnnotationBeanPostProcessor` are both included implicitly when you use the @@ -5031,11 +5031,11 @@ component-scan element. That means that the two components are autodetected __an wired together - all without any bean configuration metadata provided in XML. [NOTE] -=== +==== You can disable the registration of `AutowiredAnnotationBeanPostProcessor` and `CommonAnnotationBeanPostProcessor` by including the __annotation-config__ attribute with a value of false. -=== +==== @@ -5248,13 +5248,13 @@ were detected, the names would be myMovieLister and movieFinderImpl: ---- [NOTE] -=== +==== If you do not want to rely on the default bean-naming strategy, you can provide a custom bean-naming strategy. First, implement the {javadoc-baseurl}/org/springframework/beans/factory/support/BeanNameGenerator.html[`BeanNameGenerator`] interface, and be sure to include a default no-arg constructor. Then, provide the fully-qualified class name when configuring the scanner: -=== +==== [source,java,indent=0] [subs="verbatim,quotes"] @@ -5299,13 +5299,13 @@ within the annotation: ---- [NOTE] -=== +==== To provide a custom strategy for scope resolution rather than relying on the annotation-based approach, implement the {javadoc-baseurl}/org/springframework/context/annotation/ScopeMetadataResolver.html[`ScopeMetadataResolver`] interface, and be sure to include a default no-arg constructor. Then, provide the fully-qualified class name when configuring the scanner: -=== +==== [source,java,indent=0] [subs="verbatim,quotes"] @@ -5396,12 +5396,12 @@ technique: ---- [NOTE] -=== +==== As with most annotation-based alternatives, keep in mind that the annotation metadata is bound to the class definition itself, while the use of XML allows for multiple beans __of the same type__ to provide variations in their qualifier metadata, because that metadata is provided per-instance rather than per-class. -=== +==== @@ -5786,14 +5786,14 @@ definitions within the container. `AnnotationConfigApplicationContext` exposes t ---- [NOTE] -=== +==== Remember that `@Configuration` classes are <> with `@Component`, so they are candidates for component-scanning! In the example above, assuming that `AppConfig` is declared within the `com.acme` package (or any package underneath), it will be picked up during the call to `scan()`, and upon `refresh()` all its `@Bean` methods will be processed and registered as bean definitions within the container. -=== +==== [[beans-java-instantiating-container-web]] @@ -6181,11 +6181,11 @@ In the example above, the `foo` bean receives a reference to `bar` via construct injection. [NOTE] -=== +==== This method of declaring inter-bean dependencies only works when the `@Bean` method is declared within a `@Configuration` class. You cannot declare inter-bean dependencies using plain `@Component` classes. -=== +==== [[beans-java-method-injection]] @@ -6285,19 +6285,19 @@ CGLIB classes have been repackaged under org.springframework and included direct within the spring-core JAR. [NOTE] -=== +==== The behavior could be different according to the scope of your bean. We are talking about singletons here. -=== +==== [NOTE] -=== +==== There are a few restrictions due to the fact that CGLIB dynamically adds features at startup-time: * Configuration classes should not be final * They should have a constructor with no arguments -=== +==== @@ -6650,13 +6650,13 @@ jdbc.password= ---- [NOTE] -=== +==== In `system-test-config.xml` above, the `AppConfig` does not declare an `id` element. While it would be acceptable to do so, it is unnecessary given that no other bean will ever refer to it, and it is unlikely that it will be explicitly fetched from the container by name. Likewise with the `DataSource` bean - it is only ever autowired by type, so an explicit bean id is not strictly required. -=== +==== -- .[[beans-java-combining-xml-centric-component-scan]] Using to pick up `@Configuration` classes @@ -7090,7 +7090,7 @@ is configured with two PropertySource objects -- one representing the set of JVM (_a la_ `System.getenv()`). [NOTE] -=== +==== These default property sources are present for `StandardEnvironment`, for use in standalone applications. {javadoc-baseurl}/org/springframework/web/context/support/StandardServletEnvironment.html[`StandardServletEnvironment`] is populated with additional default property sources including servlet config and servlet @@ -7098,7 +7098,7 @@ context parameters. {javadoc-baseurl}/org/springframework/web/portlet/context/St similarly has access to portlet config and portlet context parameters as property sources. Both can optionally enable a {javadoc-baseurl}/org/springframework/jndi/JndiPropertySource.html[`JndiPropertySource`]. See Javadoc for details. -=== +==== Concretely, when using the `StandardEnvironment`, the call to `env.containsProperty("foo")` will return true if a `foo` system property or `foo` environment variable is present at @@ -7471,7 +7471,7 @@ You can also use the `MessageSourceAware` interface to acquire a reference to an the application context's `MessageSource` when the bean is created and configured. [NOTE] -=== +==== __As an alternative to `ResourceBundleMessageSource`, Spring provides a `ReloadableResourceBundleMessageSource` class. This variant supports the same bundle file format but is more flexible than the standard JDK based @@ -7479,7 +7479,7 @@ file format but is more flexible than the standard JDK based files from any Spring resource location (not just from the classpath) and supports hot reloading of bundle property files (while efficiently caching them in between). Check out the `ReloadableResourceBundleMessageSource` javadocs for details. -=== +==== @@ -7655,7 +7655,7 @@ called, if there are any emails that should be blacklisted, a custom event of ty notify appropriate parties. [NOTE] -=== +==== Spring's eventing mechanism is designed for simple communication between Spring beans within the same application context. However, for more sophisticated enterprise integration needs, the separately-maintained @@ -7663,7 +7663,7 @@ http://projects.spring.io/spring-integration/[Spring Integration] project provid complete support for building lightweight, http://www.enterpriseintegrationpatterns.com[pattern-oriented], event-driven architectures that build upon the well-known Spring programming model. -=== +==== @@ -7764,7 +7764,7 @@ JavaDoc) and the corresponding Spring XML bean definition file(s) (typically application server's deployment directory. [NOTE] -=== +==== Such RAR deployment units are usually self-contained; they do not expose components to the outside world, not even to other modules of the same application. Interaction with a RAR-based ApplicationContext usually occurs through JMS destinations that it shares with @@ -7772,7 +7772,7 @@ other modules. A RAR-based ApplicationContext may also, for example, schedule so reacting to new files in the file system (or the like). If it needs to allow synchronous access from the outside, it could for example export RMI endpoints, which of course may be used by other application modules on the same machine. -=== +==== diff --git a/src/asciidoc/core-expressions.adoc b/src/asciidoc/core-expressions.adoc new file mode 100644 index 00000000000..711d58a782d --- /dev/null +++ b/src/asciidoc/core-expressions.adoc @@ -0,0 +1,1455 @@ +[[expressions]] += Spring Expression Language (SpEL) + + + + +[[expressions-intro]] +== Introduction +The Spring Expression Language (SpEL for short) is a powerful expression language that +supports querying and manipulating an object graph at runtime. The language syntax is +similar to Unified EL but offers additional features, most notably method invocation and +basic string templating functionality. + +While there are several other Java expression languages available, OGNL, MVEL, and JBoss +EL, to name a few, the Spring Expression Language was created to provide the Spring +community with a single well supported expression language that can be used across all +the products in the Spring portfolio. Its language features are driven by the +requirements of the projects in the Spring portfolio, including tooling requirements for +code completion support within the eclipse based Spring Tool Suite. That said, +SpEL is based on a technology agnostic API allowing other expression language +implementations to be integrated should the need arise. + +While SpEL serves as the foundation for expression evaluation within the Spring +portfolio, it is not directly tied to Spring and can be used independently. In order to +be self contained, many of the examples in this chapter use SpEL as if it were an +independent expression language. This requires creating a few bootstrapping +infrastructure classes such as the parser. Most Spring users will not need to deal with +this infrastructure and will instead only author expression strings for evaluation. An +example of this typical use is the integration of SpEL into creating XML or annotated +based bean definitions as shown in the section <> + +This chapter covers the features of the expression language, its API, and its language +syntax. In several places an Inventor and Inventor's Society class are used as the +target objects for expression evaluation. These class declarations and the data used to +populate them are listed at the end of the chapter. + + + + +[[expressions-features]] +== Feature Overview +The expression language supports the following functionality + +* Literal expressions +* Boolean and relational operators +* Regular expressions +* Class expressions +* Accessing properties, arrays, lists, maps +* Method invocation +* Relational operators +* Assignment +* Calling constructors +* Bean references +* Array construction +* Inline lists +* Inline maps +* Ternary operator +* Variables +* User defined functions +* Collection projection +* Collection selection +* Templated expressions + + + + +[[expressions-evaluation]] +== Expression Evaluation using Spring's Expression Interface +This section introduces the simple use of SpEL interfaces and its expression language. +The complete language reference can be found in the section +<>. + +The following code introduces the SpEL API to evaluate the literal string expression +'Hello World'. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ExpressionParser parser = new SpelExpressionParser(); + Expression exp = parser.parseExpression("**''Hello World''**"); + String message = (String) exp.getValue(); +---- + +The value of the message variable is simply 'Hello World'. + +The SpEL classes and interfaces you are most likely to use are located in the packages +`org.springframework.expression` and its sub packages and `spel.support`. + +The interface `ExpressionParser` is responsible for parsing an expression string. In +this example the expression string is a string literal denoted by the surrounding single +quotes. The interface `Expression` is responsible for evaluating the previously defined +expression string. There are two exceptions that can be thrown, `ParseException` and +`EvaluationException` when calling '`parser.parseExpression`' and '`exp.getValue`' +respectively. + +SpEL supports a wide range of features, such as calling methods, accessing properties, +and calling constructors. + +As an example of method invocation, we call the 'concat' method on the string literal. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ExpressionParser parser = new SpelExpressionParser(); + Expression exp = parser.parseExpression("**''Hello World''.concat(''!'')**"); + String message = (String) exp.getValue(); +---- + +The value of message is now 'Hello World!'. + +As an example of calling a JavaBean property, the String property 'Bytes' can be called +as shown below. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ExpressionParser parser = new SpelExpressionParser(); + + // invokes 'getBytes()' + Expression exp = parser.parseExpression("**''Hello World''.bytes**"); + byte[] bytes = (byte[]) exp.getValue(); +---- + +SpEL also supports nested properties using standard 'dot' notation, i.e. +prop1.prop2.prop3 and the setting of property values + +Public fields may also be accessed. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ExpressionParser parser = new SpelExpressionParser(); + + // invokes 'getBytes().length' + Expression exp = parser.parseExpression("**''Hello World''.bytes.length**"); + int length = (Integer) exp.getValue(); +---- + +The String's constructor can be called instead of using a string literal. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ExpressionParser parser = new SpelExpressionParser(); + Expression exp = parser.parseExpression("**new String(''hello world'').toUpperCase()**"); + String message = exp.getValue(String.class); +---- + +Note the use of the generic method `public T getValue(Class desiredResultType)`. +Using this method removes the need to cast the value of the expression to the desired +result type. An `EvaluationException` will be thrown if the value cannot be cast to the +type `T` or converted using the registered type converter. + +The more common usage of SpEL is to provide an expression string that is evaluated +against a specific object instance (called the root object). There are two options here +and which to choose depends on whether the object against which the expression is being +evaluated will be changing with each call to evaluate the expression. In the following +example we retrieve the `name` property from an instance of the Inventor class. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // Create and set a calendar + GregorianCalendar c = new GregorianCalendar(); + c.set(1856, 7, 9); + + // The constructor arguments are name, birthday, and nationality. + Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian"); + + ExpressionParser parser = new SpelExpressionParser(); + Expression exp = parser.parseExpression("**name**"); + + EvaluationContext context = new StandardEvaluationContext(tesla); + String name = (String) exp.getValue(context); +---- + +In the last line, the value of the string variable 'name' will be set to "Nikola Tesla". +The class StandardEvaluationContext is where you can specify which object the "name" +property will be evaluated against. This is the mechanism to use if the root object is +unlikely to change, it can simply be set once in the evaluation context. If the root +object is likely to change repeatedly, it can be supplied on each call to `getValue`, as +this next example shows: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + / Create and set a calendar + GregorianCalendar c = new GregorianCalendar(); + c.set(1856, 7, 9); + + // The constructor arguments are name, birthday, and nationality. + Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian"); + + ExpressionParser parser = new SpelExpressionParser(); + Expression exp = parser.parseExpression("**name**"); + String name = (String) exp.getValue(tesla); +---- + +In this case the inventor `tesla` has been supplied directly to `getValue` and the +expression evaluation infrastructure creates and manages a default evaluation context +internally - it did not require one to be supplied. + +The StandardEvaluationContext is relatively expensive to construct and during repeated +usage it builds up cached state that enables subsequent expression evaluations to be +performed more quickly. For this reason it is better to cache and reuse them where +possible, rather than construct a new one for each expression evaluation. + +In some cases it can be desirable to use a configured evaluation context and yet still +supply a different root object on each call to `getValue`. `getValue` allows both to be +specified on the same call. In these situations the root object passed on the call is +considered to override any (which maybe null) specified on the evaluation context. + +[NOTE] +==== +In standalone usage of SpEL there is a need to create the parser, parse expressions and +perhaps provide evaluation contexts and a root context object. However, more common +usage is to provide only the SpEL expression string as part of a configuration file, for +example for Spring bean or Spring Web Flow definitions. In this case, the parser, +evaluation context, root object and any predefined variables are all set up implicitly, +requiring the user to specify nothing other than the expressions. +==== +As a final introductory example, the use of a boolean operator is shown using the +Inventor object in the previous example. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + Expression exp = parser.parseExpression("name == ''Nikola Tesla''"); + boolean result = exp.getValue(context, Boolean.class); // evaluates to true +---- + + + +[[expressions-evaluation-context]] +=== The EvaluationContext interface +The interface `EvaluationContext` is used when evaluating an expression to resolve +properties, methods, fields, and to help perform type conversion. The out-of-the-box +implementation, `StandardEvaluationContext`, uses reflection to manipulate the object, +caching `java.lang.reflect`'s `Method`, `Field`, and `Constructor` instances for +increased performance. + +The `StandardEvaluationContext` is where you may specify the root object to evaluate +against via the method `setRootObject()` or passing the root object into the +constructor. You can also specify variables and functions that will be used in the +expression using the methods `setVariable()` and `registerFunction()`. The use of +variables and functions are described in the language reference sections +<> and <>. The +`StandardEvaluationContext` is also where you can register custom +++ConstructorResolver++s, ++MethodResolver++s, and ++PropertyAccessor++s to extend how SpEL +evaluates expressions. Please refer to the JavaDoc of these classes for more details. + + +[[expressions-type-conversion]] +==== Type Conversion +By default SpEL uses the conversion service available in Spring core ( +`org.springframework.core.convert.ConversionService`). This conversion service comes +with many converters built in for common conversions but is also fully extensible so +custom conversions between types can be added. Additionally it has the key capability +that it is generics aware. This means that when working with generic types in +expressions, SpEL will attempt conversions to maintain type correctness for any objects +it encounters. + +What does this mean in practice? Suppose assignment, using `setValue()`, is being used +to set a `List` property. The type of the property is actually `List`. SpEL +will recognize that the elements of the list need to be converted to `Boolean` before +being placed in it. A simple example: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + class Simple { + public List booleanList = new ArrayList(); + } + + Simple simple = new Simple(); + + simple.booleanList.add(true); + + StandardEvaluationContext simpleContext = new StandardEvaluationContext(simple); + + // false is passed in here as a string. SpEL and the conversion service will + // correctly recognize that it needs to be a Boolean and convert it + parser.parseExpression("booleanList[0]").setValue(simpleContext, "false"); + + // b will be false + Boolean b = simple.booleanList.get(0); +---- + +[[expressions-parser-configuration]] +=== Parser configuration +It is possible to configure the SpEL expression parser using a parser configuration object +(`org.springframework.expression.spel.SpelParserConfiguration`). The configuration +object controls the behaviour of some of the expression components. For example, if +indexing into an array or collection and the element at the specified index is `null` +it is possible to automatically create the element. This is useful when using expressions made up of a +chain of property references. If indexing into an array or list +and specifying an index that is beyond the end of the current size of the array or +list it is possible to automatically grow the array or list to accommodate that index. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + class Demo { + public List list; + } + + // Turn on: + // - auto null reference initialization + // - auto collection growing + SpelParserConfiguration config = new SpelParserConfiguration(true,true); + + ExpressionParser parser = new SpelExpressionParser(config); + + Expression expression = parser.parseExpression("list[3]"); + + Demo demo = new Demo(); + + Object o = expression.getValue(demo); + + // demo.list will now be a real collection of 4 entries + // Each entry is a new empty String +---- + +It is also possible to configure the behaviour of the SpEL expression compiler. + +[[expressions-spel-compilation]] +=== SpEL compilation + +Spring Framework 4.1 includes a basic expression compiler. Expressions are usually +interpreted which provides a lot of dynamic flexibility during evaluation but +does not provide the optimum performance. For occasional expression usage +this is fine, but when used by other components like Spring Integration, +performance can be very important and there is no real need for the dynamism. + +The new SpEL compiler is intended to address this need. The +compiler will generate a real Java class on the fly during evaluation that embodies the +expression behaviour and use that to achieve much faster expression +evaluation. Due to the lack of typing around expressions the compiler +uses information gathered during the interpreted evaluations of an +expression when performing compilation. For example, it does not know the type +of a property reference purely from the expression but during the first +interpreted evaluation it will find out what it is. Of course, basing the +compilation on this information could cause trouble later if the types of +the various expression elements change over time. For this reason compilation +is best suited to expressions whose type information is not going to change +on repeated evaluations. + +For a basic expression like this: + +`someArray[0].someProperty.someOtherProperty < 0.1` + +which involves array access, some property derefencing and numeric operations, the performance +gain can be very noticeable. In an example microbenchmark run of 50000 iterations, it was +taking 75ms to evaluate using only the interpreter and just 3ms using the compiled version +of the expression. + +[[expressions-compiler-configuration]] +==== Compiler configuration + +The compiler is not turned on by default, but there are two ways to turn +it on. It can be turned on using the parser configuration process discussed earlier or +via a system property when SpEL usage is embedded inside another component. This section +discusses both of these options. + +Is is important to understand that there are a few modes the compiler can operate in, captured +in an enum (`org.springframework.expression.spel.SpelCompilerMode`). The modes are as follows: + +- `OFF` - The compiler is switched off; this is the default. +- `IMMEDIATE` - In immediate mode the expressions are compiled as soon as possible. This +is typically after the first interpreted evaluation. If the compiled expression fails +(typically due to a type changing, as described above) then the caller of the expression +evaluation will receive an exception. +- `MIXED` - In mixed mode the expressions silently switch between interpreted and compiled +mode over time. After some number of interpreted runs they will switch to compiled +form and if something goes wrong with the compiled form (like a type changing, as +described above) then the expression will automatically switch back to interpreted form +again. Sometime later it may generate another compiled form and switch to it. Basically +the exception that the user gets in `IMMEDIATE` mode is instead handled internally. + +`IMMEDIATE` mode exists because `MIXED` mode could cause issues for expressions that +have side effects. If a compiled expression blows up after partially succeeding it +may have already done something that has affected the state of the system. If this +has happened the caller may not want it to silently re-run in interpreted mode +since part of the expression may be running twice. + +After selecting a mode, use the `SpelParserConfiguration` to configure the parser: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, + this.getClass().getClassLoader()); + + SpelExpressionParser parser = new SpelExpressionParser(config); + + Expression expr = parser.parseExpression("payload"); + + MyMessage message = new MyMessage(); + + Object payload = expr.getValue(message); +---- + +When specifying the compiler mode it is also possible to specify a classloader (passing null is allowed). +Compiled expressions will be defined in a child classloader created under any that is supplied. +It is important to ensure if a classloader is specified it can see all the types involved in +the expression evaluation process. +If none is specified then a default classloader will be used (typically the context classloader for +the thread that is running during expression evaluation). + +The second way to configure the compiler is for use when SpEL is embedded inside some other +component and it may not be possible to configure via a configuration object. +In these cases it is possible to use a system property. The property +`spring.expression.compiler.mode` can be set to one of the `SpelCompilerMode` +enum values (`off`, `immediate` or `mixed`). + +[[expressions-compiler-limitations]] +==== Compiler limitations + +With Spring Framework 4.1 the basic compilation framework is in place. However, the framework does not +yet support compiling every kind of expression. The initial focus has been on the common expressions that are +likely to be used in performance critical contexts. These kinds of expression cannot be compiled +at the moment: + +- expressions involving assignment +- expressions relying on the conversion service +- expressions using custom resolvers or accessors +- expressions using selection or projection + +More and more types of expression will be compilable in the future. + +[[expressions-beandef]] +== Expression support for defining bean definitions +SpEL expressions can be used with XML or annotation-based configuration metadata for +defining ++BeanDefinition++s. In both cases the syntax to define the expression is of the +form `#{ }`. + + + +[[expressions-beandef-xml-based]] +=== XML based configuration +A property or constructor-arg value can be set using expressions as shown below. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + +---- + +The variable `systemProperties` is predefined, so you can use it in your expressions as +shown below. Note that you do not have to prefix the predefined variable with the `#` +symbol in this context. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + +---- + +You can also refer to other bean properties by name, for example. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + +---- + + + +[[expressions-beandef-annotation-based]] +=== Annotation-based configuration +The `@Value` annotation can be placed on fields, methods and method/constructor +parameters to specify a default value. + +Here is an example to set the default value of a field variable. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public static class FieldValueTestBean + + @Value("#{ systemProperties[''user.region''] }") + private String defaultLocale; + + public void setDefaultLocale(String defaultLocale) { + this.defaultLocale = defaultLocale; + } + + public String getDefaultLocale() { + return this.defaultLocale; + } + + } +---- + +The equivalent but on a property setter method is shown below. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public static class PropertyValueTestBean + + private String defaultLocale; + + @Value("#{ systemProperties[''user.region''] }") + public void setDefaultLocale(String defaultLocale) { + this.defaultLocale = defaultLocale; + } + + public String getDefaultLocale() { + return this.defaultLocale; + } + + } +---- + +Autowired methods and constructors can also use the `@Value` annotation. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class SimpleMovieLister { + + private MovieFinder movieFinder; + private String defaultLocale; + + @Autowired + public void configure(MovieFinder movieFinder, + @Value("#{ systemProperties[''user.region''] }") String defaultLocale) { + this.movieFinder = movieFinder; + this.defaultLocale = defaultLocale; + } + + // ... + } +---- + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class MovieRecommender { + + private String defaultLocale; + + private CustomerPreferenceDao customerPreferenceDao; + + @Autowired + public MovieRecommender(CustomerPreferenceDao customerPreferenceDao, + @Value("#{systemProperties[''user.country'']}") String defaultLocale) { + this.customerPreferenceDao = customerPreferenceDao; + this.defaultLocale = defaultLocale; + } + + // ... + } +---- + + + + +[[expressions-language-ref]] +== Language Reference + + + +[[expressions-ref-literal]] +=== Literal expressions +The types of literal expressions supported are strings, dates, numeric values (int, +real, and hex), boolean and null. Strings are delimited by single quotes. To put a +single quote itself in a string use two single quote characters. The following listing +shows simple usage of literals. Typically they would not be used in isolation like this, +but as part of a more complex expression, for example using a literal on one side of a +logical comparison operator. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ExpressionParser parser = new SpelExpressionParser(); + + // evals to "Hello World" + String helloWorld = (String) parser.parseExpression("''Hello World''").getValue(); + + double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue(); + + // evals to 2147483647 + int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue(); + + boolean trueValue = (Boolean) parser.parseExpression("true").getValue(); + + Object nullValue = parser.parseExpression("null").getValue(); +---- + +Numbers support the use of the negative sign, exponential notation, and decimal points. +By default real numbers are parsed using Double.parseDouble(). + + + +[[expressions-properties-arrays]] +=== Properties, Arrays, Lists, Maps, Indexers +Navigating with property references is easy: just use a period to indicate a nested +property value. The instances of the `Inventor` class, pupin, and tesla, were populated with +data listed in the section <>. +To navigate "down" and get Tesla's year of birth and Pupin's city of birth the following +expressions are used. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // evals to 1856 + int year = (Integer) parser.parseExpression("Birthdate.Year + 1900").getValue(context); + + String city = (String) parser.parseExpression("placeOfBirth.City").getValue(context); +---- + +Case insensitivity is allowed for the first letter of property names. The contents of +arrays and lists are obtained using square bracket notation. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ExpressionParser parser = new SpelExpressionParser(); + + // Inventions Array + StandardEvaluationContext teslaContext = new StandardEvaluationContext(tesla); + + // evaluates to "Induction motor" + String invention = parser.parseExpression("inventions[3]").getValue( + teslaContext, String.class); + + // Members List + StandardEvaluationContext societyContext = new StandardEvaluationContext(ieee); + + // evaluates to "Nikola Tesla" + String name = parser.parseExpression("Members[0].Name").getValue( + societyContext, String.class); + + // List and Array navigation + // evaluates to "Wireless communication" + String invention = parser.parseExpression("Members[0].Inventions[6]").getValue( + societyContext, String.class); +---- + +The contents of maps are obtained by specifying the literal key value within the +brackets. In this case, because keys for the Officers map are strings, we can specify +string literals. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // Officer's Dictionary + + Inventor pupin = parser.parseExpression("Officers[''president'']").getValue( + societyContext, Inventor.class); + + // evaluates to "Idvor" + String city = parser.parseExpression("Officers[''president''].PlaceOfBirth.City").getValue( + societyContext, String.class); + + // setting values + parser.parseExpression("Officers[''advisors''][0].PlaceOfBirth.Country").setValue( + societyContext, "Croatia"); +---- + + + +[[expressions-inline-lists]] +=== Inline lists +Lists can be expressed directly in an expression using `{}` notation. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // evaluates to a Java list containing the four numbers + List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context); + + List listOfLists = (List) parser.parseExpression("{{''a'',''b''},{''x'',''y''}}").getValue(context); +---- + +`{}` by itself means an empty list. For performance reasons, if the list is itself +entirely composed of fixed literals then a constant list is created to represent the +expression, rather than building a new list on each evaluation. + +[[expressions-inline-maps]] +=== Inline Maps +Maps can also be expressed directly in an expression using `{key:value}` notation. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // evaluates to a Java map containing the two entries + Map inventorInfo = (Map) parser.parseExpression("{name:''Nikola'',dob:''10-July-1856''}").getValue(context); + + Map mapOfMaps = (Map) parser.parseExpression("{name:{first:''Nikola'',last:''Tesla''},dob:{day:10,month:''July'',year:1856}}").getValue(context); +---- +`{:}` by itself means an empty map. For performance reasons, if the map is itself composed +of fixed literals or other nested constant structures (lists or maps) then a constant map is created +to represent the expression, rather than building a new map on each evaluation. Quoting of the map keys +is optional, the examples above are not using quoted keys. + +[[expressions-array-construction]] +=== Array construction +Arrays can be built using the familiar Java syntax, optionally supplying an initializer +to have the array populated at construction time. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context); + + // Array with initializer + int[] numbers2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue(context); + + // Multi dimensional array + int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context); +---- + +It is not currently allowed to supply an initializer when constructing a +multi-dimensional array. + + + +[[expressions-methods]] +=== Methods +Methods are invoked using typical Java programming syntax. You may also invoke methods +on literals. Varargs are also supported. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // string literal, evaluates to "bc" + String c = parser.parseExpression("''abc''.substring(2, 3)").getValue(String.class); + + // evaluates to true + boolean isMember = parser.parseExpression("isMember(''Mihajlo Pupin'')").getValue( + societyContext, Boolean.class); +---- + + + +[[expressions-operators]] +=== Operators + + +[[expressions-operators-relational]] +==== Relational operators +The relational operators; equal, not equal, less than, less than or equal, greater than, +and greater than or equal are supported using standard operator notation. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // evaluates to true + boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class); + + // evaluates to false + boolean falseValue = parser.parseExpression("2 < -5.0").getValue(Boolean.class); + + // evaluates to true + boolean trueValue = parser.parseExpression("''black'' < ''block''").getValue(Boolean.class); +---- + +In addition to standard relational operators SpEL supports the `instanceof` and regular +expression based `matches` operator. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // evaluates to false + boolean falseValue = parser.parseExpression( + "''xyz'' instanceof T(int)").getValue(Boolean.class); + + // evaluates to true + boolean trueValue = parser.parseExpression( + "''5.00'' matches ''\^-?\\d+(\\.\\d{2})?$''").getValue(Boolean.class); + + //evaluates to false + boolean falseValue = parser.parseExpression( + "''5.0067'' matches ''\^-?\\d+(\\.\\d{2})?$''").getValue(Boolean.class); +---- + +Each symbolic operator can also be specified as a purely alphabetic equivalent. This +avoids problems where the symbols used have special meaning for the document type in +which the expression is embedded (eg. an XML document). The textual equivalents are +shown here: `lt` (`<`), `gt` (`>`), `le` (`<=`), `ge` (`>=`), `eq` (`==`), +`ne` (`!=`), `div` (`/`), `mod` (`%`), `not` (`!`). These are case insensitive. + + +[[expressions-operators-logical]] +==== Logical operators +The logical operators that are supported are and, or, and not. Their use is demonstrated +below. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // -- AND -- + + // evaluates to false + boolean falseValue = parser.parseExpression("true and false").getValue(Boolean.class); + + // evaluates to true + String expression = "isMember(''Nikola Tesla'') and isMember(''Mihajlo Pupin'')"; + boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class); + + // -- OR -- + + // evaluates to true + boolean trueValue = parser.parseExpression("true or false").getValue(Boolean.class); + + // evaluates to true + String expression = "isMember(''Nikola Tesla'') or isMember(''Albert Einstein'')"; + boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class); + + // -- NOT -- + + // evaluates to false + boolean falseValue = parser.parseExpression("!true").getValue(Boolean.class); + + // -- AND and NOT -- + String expression = "isMember(''Nikola Tesla'') and !isMember(''Mihajlo Pupin'')"; + boolean falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class); +---- + + +[[expressions-operators-mathematical]] +==== Mathematical operators +The addition operator can be used on both numbers and strings. Subtraction, multiplication +and division can be used only on numbers. Other mathematical operators supported are +modulus (%) and exponential power (^). Standard operator precedence is enforced. These +operators are demonstrated below. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // Addition + int two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2 + + String testString = parser.parseExpression( + "''test'' + '' '' + ''string''").getValue(String.class); // 'test string' + + // Subtraction + int four = parser.parseExpression("1 - -3").getValue(Integer.class); // 4 + + double d = parser.parseExpression("1000.00 - 1e4").getValue(Double.class); // -9000 + + // Multiplication + int six = parser.parseExpression("-2 * -3").getValue(Integer.class); // 6 + + double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class); // 24.0 + + // Division + int minusTwo = parser.parseExpression("6 / -3").getValue(Integer.class); // -2 + + double one = parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class); // 1.0 + + // Modulus + int three = parser.parseExpression("7 % 4").getValue(Integer.class); // 3 + + int one = parser.parseExpression("8 / 5 % 2").getValue(Integer.class); // 1 + + // Operator precedence + int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class); // -21 +---- + + + +[[expressions-assignment]] +=== Assignment +Setting of a property is done by using the assignment operator. This would typically be +done within a call to `setValue` but can also be done inside a call to `getValue`. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + Inventor inventor = new Inventor(); + StandardEvaluationContext inventorContext = new StandardEvaluationContext(inventor); + + parser.parseExpression("Name").setValue(inventorContext, "Alexander Seovic2"); + + // alternatively + + String aleks = parser.parseExpression( + "Name = ''Alexandar Seovic''").getValue(inventorContext, String.class); +---- + + + +[[expressions-types]] +=== Types +The special `T` operator can be used to specify an instance of java.lang.Class (the +_type_). Static methods are invoked using this operator as well. The +`StandardEvaluationContext` uses a `TypeLocator` to find types and the +`StandardTypeLocator` (which can be replaced) is built with an understanding of the +java.lang package. This means T() references to types within java.lang do not need to be +fully qualified, but all other type references must be. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class); + + Class stringClass = parser.parseExpression("T(String)").getValue(Class.class); + + boolean trueValue = parser.parseExpression( + "T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR") + .getValue(Boolean.class); +---- + + + +[[expressions-constructors]] +=== Constructors +Constructors can be invoked using the new operator. The fully qualified class name +should be used for all but the primitive type and String (where int, float, etc, can be +used). + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + Inventor einstein = p.parseExpression( + "new org.spring.samples.spel.inventor.Inventor(''Albert Einstein'', ''German'')") + .getValue(Inventor.class); + + //create new inventor instance within add method of List + p.parseExpression( + "Members.add(new org.spring.samples.spel.inventor.Inventor( + ''Albert Einstein'', ''German''))").getValue(societyContext); +---- + + + +[[expressions-ref-variables]] +=== Variables +Variables can be referenced in the expression using the syntax `#variableName`. Variables +are set using the method setVariable on the `StandardEvaluationContext`. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + Inventor tesla = new Inventor("Nikola Tesla", "Serbian"); + StandardEvaluationContext context = new StandardEvaluationContext(tesla); + context.setVariable("newName", "Mike Tesla"); + + parser.parseExpression("Name = #newName").getValue(context); + + System.out.println(tesla.getName()) // "Mike Tesla" +---- + + +[[expressions-this-root]] +==== The #this and #root variables +The variable #this is always defined and refers to the current evaluation object +(against which unqualified references are resolved). The variable #root is always +defined and refers to the root context object. Although #this may vary as components of +an expression are evaluated, #root always refers to the root. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // create an array of integers + List primes = new ArrayList(); + primes.addAll(Arrays.asList(2,3,5,7,11,13,17)); + + // create parser and set variable 'primes' as the array of integers + ExpressionParser parser = new SpelExpressionParser(); + StandardEvaluationContext context = new StandardEvaluationContext(); + context.setVariable("primes",primes); + + // all prime numbers > 10 from the list (using selection ?{...}) + // evaluates to [11, 13, 17] + List primesGreaterThanTen = (List) parser.parseExpression( + "#primes.?[#this>10]").getValue(context); +---- + + + +[[expressions-ref-functions]] +=== Functions +You can extend SpEL by registering user defined functions that can be called within the +expression string. The function is registered with the `StandardEvaluationContext` using +the method. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public void registerFunction(String name, Method m) +---- + +A reference to a Java Method provides the implementation of the function. For example, a +utility method to reverse a string is shown below. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public abstract class StringUtils { + + public static String reverseString(String input) { + StringBuilder backwards = new StringBuilder(); + for (int i = 0; i < input.length(); i++) + backwards.append(input.charAt(input.length() - 1 - i)); + } + return backwards.toString(); + } + } +---- + +This method is then registered with the evaluation context and can be used within an +expression string. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ExpressionParser parser = new SpelExpressionParser(); + StandardEvaluationContext context = new StandardEvaluationContext(); + + context.registerFunction("reverseString", + StringUtils.class.getDeclaredMethod("reverseString", new Class[] { String.class })); + + String helloWorldReversed = parser.parseExpression( + "#reverseString(''hello'')").getValue(context, String.class); +---- + + + +[[expressions-bean-references]] +=== Bean references +If the evaluation context has been configured with a bean resolver it is possible to +lookup beans from an expression using the (@) symbol. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ExpressionParser parser = new SpelExpressionParser(); + StandardEvaluationContext context = new StandardEvaluationContext(); + context.setBeanResolver(new MyBeanResolver()); + + // This will end up calling resolve(context,"foo") on MyBeanResolver during evaluation + Object bean = parser.parseExpression("@foo").getValue(context); +---- + + + +[[expressions-operator-ternary]] +=== Ternary Operator (If-Then-Else) +You can use the ternary operator for performing if-then-else conditional logic inside +the expression. A minimal example is: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + String falseString = parser.parseExpression( + "false ? ''trueExp'' : ''falseExp''").getValue(String.class); +---- + +In this case, the boolean false results in returning the string value 'falseExp'. A more +realistic example is shown below. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + parser.parseExpression("Name").setValue(societyContext, "IEEE"); + societyContext.setVariable("queryName", "Nikola Tesla"); + + expression = "isMember(#queryName)? #queryName + '' is a member of the '' " + + "+ Name + '' Society'' : #queryName + '' is not a member of the '' + Name + '' Society''"; + + String queryResultString = parser.parseExpression(expression) + .getValue(societyContext, String.class); + // queryResultString = "Nikola Tesla is a member of the IEEE Society" +---- + +Also see the next section on the Elvis operator for an even shorter syntax for the +ternary operator. + + + +[[expressions-operator-elvis]] +=== The Elvis Operator +The Elvis operator is a shortening of the ternary operator syntax and is used in the +http://groovy.codehaus.org/Operators#Operators-ElvisOperator(%3F%3A)[Groovy] language. +With the ternary operator syntax you usually have to repeat a variable twice, for +example: + +[source,groovy,indent=0] +[subs="verbatim,quotes"] +---- + String name = "Elvis Presley"; + String displayName = name != null ? name : "Unknown"; +---- + +Instead you can use the Elvis operator, named for the resemblance to Elvis' hair style. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ExpressionParser parser = new SpelExpressionParser(); + + String name = parser.parseExpression("null?:''Unknown''").getValue(String.class); + + System.out.println(name); // 'Unknown' +---- + +Here is a more complex example. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ExpressionParser parser = new SpelExpressionParser(); + + Inventor tesla = new Inventor("Nikola Tesla", "Serbian"); + StandardEvaluationContext context = new StandardEvaluationContext(tesla); + + String name = parser.parseExpression("Name?:''Elvis Presley''").getValue(context, String.class); + + System.out.println(name); // Nikola Tesla + + tesla.setName(null); + + name = parser.parseExpression("Name?:''Elvis Presley''").getValue(context, String.class); + + System.out.println(name); // Elvis Presley +---- + + + +[[expressions-operator-safe-navigation]] +=== Safe Navigation operator +The Safe Navigation operator is used to avoid a `NullPointerException` and comes from +the http://groovy.codehaus.org/Operators#Operators-SafeNavigationOperator(%3F.)[Groovy] +language. Typically when you have a reference to an object you might need to verify that +it is not null before accessing methods or properties of the object. To avoid this, the +safe navigation operator will simply return null instead of throwing an exception. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ExpressionParser parser = new SpelExpressionParser(); + + Inventor tesla = new Inventor("Nikola Tesla", "Serbian"); + tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan")); + + StandardEvaluationContext context = new StandardEvaluationContext(tesla); + + String city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, String.class); + System.out.println(city); // Smiljan + + tesla.setPlaceOfBirth(null); + + city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, String.class); + + System.out.println(city); // null - does not throw NullPointerException!!! +---- + +[NOTE] +=== +The Elvis operator can be used to apply default values in expressions, e.g. in an +`@Value` expression: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Value("#{systemProperties[''pop3.port''] ?: 25}") +---- + +This will inject a system property `pop3.port` if it is defined or 25 if not. +=== + + + +[[expressions-collection-selection]] +=== Collection Selection +Selection is a powerful expression language feature that allows you to transform some +source collection into another by selecting from its entries. + +Selection uses the syntax `?[selectionExpression]`. This will filter the collection and +return a new collection containing a subset of the original elements. For example, +selection would allow us to easily get a list of Serbian inventors: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + List list = (List) parser.parseExpression( + "Members.?[Nationality == ''Serbian'']").getValue(societyContext); +---- + +Selection is possible upon both lists and maps. In the former case the selection +criteria is evaluated against each individual list element whilst against a map the +selection criteria is evaluated against each map entry (objects of the Java type +`Map.Entry`). Map entries have their key and value accessible as properties for use in +the selection. + +This expression will return a new map consisting of those elements of the original map +where the entry value is less than 27. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + Map newMap = parser.parseExpression("map.?[value<27]").getValue(); +---- + +In addition to returning all the selected elements, it is possible to retrieve just the +first or the last value. To obtain the first entry matching the selection the syntax is +`^[...]` whilst to obtain the last matching selection the syntax is `$[...]`. + + + +[[expressions-collection-projection]] +=== Collection Projection +Projection allows a collection to drive the evaluation of a sub-expression and the +result is a new collection. The syntax for projection is `![projectionExpression]`. Most +easily understood by example, suppose we have a list of inventors but want the list of +cities where they were born. Effectively we want to evaluate 'placeOfBirth.city' for +every entry in the inventor list. Using projection: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // returns ['Smiljan', 'Idvor' ] + List placesOfBirth = (List)parser.parseExpression("Members.![placeOfBirth.city]"); +---- + +A map can also be used to drive projection and in this case the projection expression is +evaluated against each entry in the map (represented as a Java `Map.Entry`). The result +of a projection across a map is a list consisting of the evaluation of the projection +expression against each map entry. + + + +[[expressions-templating]] +=== Expression templating +Expression templates allow a mixing of literal text with one or more evaluation blocks. +Each evaluation block is delimited with prefix and suffix characters that you can +define, a common choice is to use `#{ }` as the delimiters. For example, + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + String randomPhrase = parser.parseExpression( + "random number is #{T(java.lang.Math).random()}", + new TemplateParserContext()).getValue(String.class); + + // evaluates to "random number is 0.7038186818312008" +---- + +The string is evaluated by concatenating the literal text 'random number is ' with the +result of evaluating the expression inside the #{ } delimiter, in this case the result +of calling that random() method. The second argument to the method `parseExpression()` +is of the type `ParserContext`. The `ParserContext` interface is used to influence how +the expression is parsed in order to support the expression templating functionality. +The definition of `TemplateParserContext` is shown below. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class TemplateParserContext implements ParserContext { + + public String getExpressionPrefix() { + return "#{"; + } + + public String getExpressionSuffix() { + return "}"; + } + + public boolean isTemplate() { + return true; + } + } +---- + + + + +[[expressions-example-classes]] +== Classes used in the examples +Inventor.java + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.spring.samples.spel.inventor; + + import java.util.Date; + import java.util.GregorianCalendar; + + public class Inventor { + + private String name; + private String nationality; + private String[] inventions; + private Date birthdate; + private PlaceOfBirth placeOfBirth; + + public Inventor(String name, String nationality) { + GregorianCalendar c= new GregorianCalendar(); + this.name = name; + this.nationality = nationality; + this.birthdate = c.getTime(); + } + + public Inventor(String name, Date birthdate, String nationality) { + this.name = name; + this.nationality = nationality; + this.birthdate = birthdate; + } + + public Inventor() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getNationality() { + return nationality; + } + + public void setNationality(String nationality) { + this.nationality = nationality; + } + + public Date getBirthdate() { + return birthdate; + } + + public void setBirthdate(Date birthdate) { + this.birthdate = birthdate; + } + + public PlaceOfBirth getPlaceOfBirth() { + return placeOfBirth; + } + + public void setPlaceOfBirth(PlaceOfBirth placeOfBirth) { + this.placeOfBirth = placeOfBirth; + } + + public void setInventions(String[] inventions) { + this.inventions = inventions; + } + + public String[] getInventions() { + return inventions; + } + } +---- + +PlaceOfBirth.java + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.spring.samples.spel.inventor; + + public class PlaceOfBirth { + + private String city; + private String country; + + public PlaceOfBirth(String city) { + this.city=city; + } + + public PlaceOfBirth(String city, String country) { + this(city); + this.country = country; + } + + public String getCity() { + return city; + } + + public void setCity(String s) { + this.city = s; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + } +---- + +Society.java + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.spring.samples.spel.inventor; + + import java.util.*; + + public class Society { + + private String name; + + public static String Advisors = "advisors"; + public static String President = "president"; + + private List members = new ArrayList(); + private Map officers = new HashMap(); + + public List getMembers() { + return members; + } + + public Map getOfficers() { + return officers; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isMember(String name) { + for (Inventor inventor : members) { + if (inventor.getName().equals(name)) { + return true; + } + } + return false; + } + + } +---- diff --git a/src/asciidoc/core-resources.adoc b/src/asciidoc/core-resources.adoc new file mode 100644 index 00000000000..140be8b681a --- /dev/null +++ b/src/asciidoc/core-resources.adoc @@ -0,0 +1,666 @@ + +[[resources]] += Resources + + +[[resources-introduction]] +== Introduction +Java's standard `java.net.URL` class and standard handlers for various URL prefixes +unfortunately are not quite adequate enough for all access to low-level resources. For +example, there is no standardized `URL` implementation that may be used to access a +resource that needs to be obtained from the classpath, or relative to a +`ServletContext`. While it is possible to register new handlers for specialized `URL` +prefixes (similar to existing handlers for prefixes such as `http:`), this is generally +quite complicated, and the `URL` interface still lacks some desirable functionality, +such as a method to check for the existence of the resource being pointed to. + + +[[resources-resource]] +== The Resource interface + +Spring's `Resource` interface is meant to be a more capable interface for abstracting +access to low-level resources. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface Resource extends InputStreamSource { + + boolean exists(); + + boolean isOpen(); + + URL getURL() throws IOException; + + File getFile() throws IOException; + + Resource createRelative(String relativePath) throws IOException; + + String getFilename(); + + String getDescription(); + + } +---- + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface InputStreamSource { + + InputStream getInputStream() throws IOException; + + } +---- + +Some of the most important methods from the `Resource` interface are: + +* `getInputStream()`: locates and opens the resource, returning an `InputStream` for + reading from the resource. It is expected that each invocation returns a fresh + `InputStream`. It is the responsibility of the caller to close the stream. +* `exists()`: returns a `boolean` indicating whether this resource actually exists in + physical form. +* `isOpen()`: returns a `boolean` indicating whether this resource represents a handle + with an open stream. If `true`, the `InputStream` cannot be read multiple times, and + must be read once only and then closed to avoid resource leaks. Will be `false` for + all usual resource implementations, with the exception of `InputStreamResource`. +* `getDescription()`: returns a description for this resource, to be used for error + output when working with the resource. This is often the fully qualified file name or + the actual URL of the resource. + +Other methods allow you to obtain an actual `URL` or `File` object representing the +resource (if the underlying implementation is compatible, and supports that +functionality). + +The `Resource` abstraction is used extensively in Spring itself, as an argument type in +many method signatures when a resource is needed. Other methods in some Spring APIs +(such as the constructors to various `ApplicationContext` implementations), take a +`String` which in unadorned or simple form is used to create a `Resource` appropriate to +that context implementation, or via special prefixes on the `String` path, allow the +caller to specify that a specific `Resource` implementation must be created and used. + +While the `Resource` interface is used a lot with Spring and by Spring, it's actually +very useful to use as a general utility class by itself in your own code, for access to +resources, even when your code doesn't know or care about any other parts of Spring. +While this couples your code to Spring, it really only couples it to this small set of +utility classes, which are serving as a more capable replacement for `URL`, and can be +considered equivalent to any other library you would use for this purpose. + +It is important to note that the `Resource` abstraction does not replace functionality: +it wraps it where possible. For example, a `UrlResource` wraps a URL, and uses the +wrapped `URL` to do its work. + + + + +[[resources-implementations]] +== Built-in Resource implementations + +There are a number of `Resource` implementations that come supplied straight out of the +box in Spring: + + + +[[resources-implementations-urlresource]] +=== UrlResource + +The `UrlResource` wraps a `java.net.URL`, and may be used to access any object that is +normally accessible via a URL, such as files, an HTTP target, an FTP target, etc. All +URLs have a standardized `String` representation, such that appropriate standardized +prefixes are used to indicate one URL type from another. This includes `file:` for +accessing filesystem paths, `http:` for accessing resources via the HTTP protocol, +`ftp:` for accessing resources via FTP, etc. + +A `UrlResource` is created by Java code explicitly using the `UrlResource` constructor, +but will often be created implicitly when you call an API method which takes a `String` +argument which is meant to represent a path. For the latter case, a JavaBeans +`PropertyEditor` will ultimately decide which type of `Resource` to create. If the path +string contains a few well-known (to it, that is) prefixes such as `classpath:`, it will +create an appropriate specialized `Resource` for that prefix. However, if it doesn't +recognize the prefix, it will assume the this is just a standard URL string, and will +create a `UrlResource`. + + + +[[resources-implementations-classpathresource]] +=== ClassPathResource + +This class represents a resource which should be obtained from the classpath. This uses +either the thread context class loader, a given class loader, or a given class for +loading resources. + +This `Resource` implementation supports resolution as `java.io.File` if the class path +resource resides in the file system, but not for classpath resources which reside in a +jar and have not been expanded (by the servlet engine, or whatever the environment is) +to the filesystem. To address this the various `Resource` implementations always support +resolution as a `java.net.URL`. + +A `ClassPathResource` is created by Java code explicitly using the `ClassPathResource` +constructor, but will often be created implicitly when you call an API method which +takes a `String` argument which is meant to represent a path. For the latter case, a +JavaBeans `PropertyEditor` will recognize the special prefix `classpath:` on the string +path, and create a `ClassPathResource` in that case. + + + +[[resources-implementations-filesystemresource]] +=== FileSystemResource + +This is a `Resource` implementation for `java.io.File` handles. It obviously supports +resolution as a `File`, and as a `URL`. + + + +[[resources-implementations-servletcontextresource]] +=== ServletContextResource + +This is a `Resource` implementation for `ServletContext` resources, interpreting +relative paths within the relevant web application's root directory. + +This always supports stream access and URL access, but only allows `java.io.File` access +when the web application archive is expanded and the resource is physically on the +filesystem. Whether or not it's expanded and on the filesystem like this, or accessed +directly from the JAR or somewhere else like a DB (it's conceivable) is actually +dependent on the Servlet container. + + + +[[resources-implementations-inputstreamresource]] +=== InputStreamResource + +A `Resource` implementation for a given `InputStream`. This should only be used if no +specific `Resource` implementation is applicable. In particular, prefer +`ByteArrayResource` or any of the file-based `Resource` implementations where possible. + +In contrast to other `Resource` implementations, this is a descriptor for an __already__ +opened resource - therefore returning `true` from `isOpen()`. Do not use it if you need +to keep the resource descriptor somewhere, or if you need to read a stream multiple +times. + + + +[[resources-implementations-bytearrayresource]] +=== ByteArrayResource + +This is a `Resource` implementation for a given byte array. It creates a +`ByteArrayInputStream` for the given byte array. + +It's useful for loading content from any given byte array, without having to resort to a +single-use `InputStreamResource`. + + + + +[[resources-resourceloader]] +== The ResourceLoader + +The `ResourceLoader` interface is meant to be implemented by objects that can return +(i.e. load) `Resource` instances. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface ResourceLoader { + + Resource getResource(String location); + + } +---- + +All application contexts implement the `ResourceLoader` interface, and therefore all +application contexts may be used to obtain `Resource` instances. + +When you call `getResource()` on a specific application context, and the location path +specified doesn't have a specific prefix, you will get back a `Resource` type that is +appropriate to that particular application context. For example, assume the following +snippet of code was executed against a `ClassPathXmlApplicationContext` instance: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + Resource template = ctx.getResource("some/resource/path/myTemplate.txt"); +---- + +What would be returned would be a `ClassPathResource`; if the same method was executed +against a `FileSystemXmlApplicationContext` instance, you'd get back a +`FileSystemResource`. For a `WebApplicationContext`, you'd get back a +`ServletContextResource`, and so on. + +As such, you can load resources in a fashion appropriate to the particular application +context. + +On the other hand, you may also force `ClassPathResource` to be used, regardless of the +application context type, by specifying the special `classpath:` prefix: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt"); +---- + +Similarly, one can force a `UrlResource` to be used by specifying any of the standard +`java.net.URL` prefixes: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt"); +---- + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + Resource template = ctx.getResource("http://myhost.com/resource/path/myTemplate.txt"); +---- + +The following table summarizes the strategy for converting ++String++s to ++Resource++s: + +[[resources-resource-strings]] +.Resource strings +|=== +| Prefix| Example| Explanation + +| classpath: +| `classpath:com/myapp/config.xml` +| Loaded from the classpath. + +| file: +| `file:///data/config.xml` +| Loaded as a `URL`, from the filesystem. footnote:[But see also + pass:specialcharacters,macros[<>].] + +| http: +| `http://myserver/logo.png` +| Loaded as a `URL`. + +| (none) +| `/data/config.xml` +| Depends on the underlying `ApplicationContext`. +|=== + + + + +[[resources-resourceloaderaware]] +== The ResourceLoaderAware interface + +The `ResourceLoaderAware` interface is a special marker interface, identifying objects +that expect to be provided with a `ResourceLoader` reference. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface ResourceLoaderAware { + + void setResourceLoader(ResourceLoader resourceLoader); + } +---- + +When a class implements `ResourceLoaderAware` and is deployed into an application +context (as a Spring-managed bean), it is recognized as `ResourceLoaderAware` by the +application context. The application context will then invoke the +`setResourceLoader(ResourceLoader)`, supplying itself as the argument (remember, all +application contexts in Spring implement the `ResourceLoader` interface). + +Of course, since an `ApplicationContext` is a `ResourceLoader`, the bean could also +implement the `ApplicationContextAware` interface and use the supplied application +context directly to load resources, but in general, it's better to use the specialized +`ResourceLoader` interface if that's all that's needed. The code would just be coupled +to the resource loading interface, which can be considered a utility interface, and not +the whole Spring `ApplicationContext` interface. + +As of Spring 2.5, you can rely upon autowiring of the `ResourceLoader` as an alternative +to implementing the `ResourceLoaderAware` interface. The "traditional" `constructor` and +`byType` autowiring modes (as described in <>) are now capable +of providing a dependency of type `ResourceLoader` for either a constructor argument or +setter method parameter respectively. For more flexibility (including the ability to +autowire fields and multiple parameter methods), consider using the new annotation-based +autowiring features. In that case, the `ResourceLoader` will be autowired into a field, +constructor argument, or method parameter that is expecting the `ResourceLoader` type as +long as the field, constructor, or method in question carries the `@Autowired` +annotation. For more information, see <>. + + + + +[[resources-as-dependencies]] +== Resources as dependencies + +If the bean itself is going to determine and supply the resource path through some sort +of dynamic process, it probably makes sense for the bean to use the `ResourceLoader` +interface to load resources. Consider as an example the loading of a template of some +sort, where the specific resource that is needed depends on the role of the user. If the +resources are static, it makes sense to eliminate the use of the `ResourceLoader` +interface completely, and just have the bean expose the `Resource` properties it needs, +and expect that they will be injected into it. + +What makes it trivial to then inject these properties, is that all application contexts +register and use a special JavaBeans `PropertyEditor` which can convert `String` paths +to `Resource` objects. So if `myBean` has a template property of type `Resource`, it can +be configured with a simple string for that resource, as follows: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + +---- + +Note that the resource path has no prefix, so because the application context itself is +going to be used as the `ResourceLoader`, the resource itself will be loaded via a +`ClassPathResource`, `FileSystemResource`, or `ServletContextResource` (as appropriate) +depending on the exact type of the context. + +If there is a need to force a specific `Resource` type to be used, then a prefix may be +used. The following two examples show how to force a `ClassPathResource` and a +`UrlResource` (the latter being used to access a filesystem file). + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + +---- + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + +---- + + + + +[[resources-app-ctx]] +== Application contexts and Resource paths + + + +[[resources-app-ctx-construction]] +=== Constructing application contexts +An application context constructor (for a specific application context type) generally +takes a string or array of strings as the location path(s) of the resource(s) such as +XML files that make up the definition of the context. + +When such a location path doesn't have a prefix, the specific `Resource` type built from +that path and used to load the bean definitions, depends on and is appropriate to the +specific application context. For example, if you create a +`ClassPathXmlApplicationContext` as follows: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml"); +---- + +The bean definitions will be loaded from the classpath, as a `ClassPathResource` will be +used. But if you create a `FileSystemXmlApplicationContext` as follows: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ApplicationContext ctx = + new FileSystemXmlApplicationContext("conf/appContext.xml"); +---- + +The bean definition will be loaded from a filesystem location, in this case relative to +the current working directory. + +Note that the use of the special classpath prefix or a standard URL prefix on the +location path will override the default type of `Resource` created to load the +definition. So this `FileSystemXmlApplicationContext`... + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ApplicationContext ctx = + new FileSystemXmlApplicationContext("classpath:conf/appContext.xml"); +---- + +... will actually load its bean definitions from the classpath. However, it is still a +`FileSystemXmlApplicationContext`. If it is subsequently used as a `ResourceLoader`, any +unprefixed paths will still be treated as filesystem paths. + + +[[resources-app-ctx-classpathxml]] +==== Constructing ClassPathXmlApplicationContext instances - shortcuts + +The `ClassPathXmlApplicationContext` exposes a number of constructors to enable +convenient instantiation. The basic idea is that one supplies merely a string array +containing just the filenames of the XML files themselves (without the leading path +information), and one __also__ supplies a `Class`; the `ClassPathXmlApplicationContext` +will derive the path information from the supplied class. + +An example will hopefully make this clear. Consider a directory layout that looks like +this: + +[literal] +[subs="verbatim,quotes"] +---- +com/ + foo/ + services.xml + daos.xml + MessengerService.class +---- + +A `ClassPathXmlApplicationContext` instance composed of the beans defined in the +`'services.xml'` and `'daos.xml'` could be instantiated like so... + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ApplicationContext ctx = new ClassPathXmlApplicationContext( + new String[] {"services.xml", "daos.xml"}, MessengerService.class); +---- + +Please do consult the `ClassPathXmlApplicationContext` javadocs for details +on the various constructors. + + + +[[resources-app-ctx-wildcards-in-resource-paths]] +=== Wildcards in application context constructor resource paths +The resource paths in application context constructor values may be a simple path (as +shown above) which has a one-to-one mapping to a target Resource, or alternately may +contain the special "classpath*:" prefix and/or internal Ant-style regular expressions +(matched using Spring's `PathMatcher` utility). Both of the latter are effectively +wildcards + +One use for this mechanism is when doing component-style application assembly. All +components can 'publish' context definition fragments to a well-known location path, and +when the final application context is created using the same path prefixed via +`classpath*:`, all component fragments will be picked up automatically. + +Note that this wildcarding is specific to use of resource paths in application context +constructors (or when using the `PathMatcher` utility class hierarchy directly), and is +resolved at construction time. It has nothing to do with the `Resource` type itself. +It's not possible to use the `classpath*:` prefix to construct an actual `Resource`, as +a resource points to just one resource at a time. + + +[[resources-app-ctx-ant-patterns-in-paths]] +==== Ant-style Patterns +When the path location contains an Ant-style pattern, for example: + +[literal] +[subs="verbatim"] +---- +/WEB-INF/*-context.xml + com/mycompany/**/applicationContext.xml + file:C:/some/path/*-context.xml + classpath:com/mycompany/**/applicationContext.xml +---- + +... the resolver follows a more complex but defined procedure to try to resolve the +wildcard. It produces a Resource for the path up to the last non-wildcard segment and +obtains a URL from it. If this URL is not a "jar:" URL or container-specific variant +(e.g. " `zip:`" in WebLogic, " `wsjar`" in WebSphere, etc.), then a `java.io.File` is +obtained from it and used to resolve the wildcard by traversing the filesystem. In the +case of a jar URL, the resolver either gets a `java.net.JarURLConnection` from it or +manually parses the jar URL and then traverses the contents of the jar file to resolve +the wildcards. + +[[resources-app-ctx-portability]] +===== Implications on portability +If the specified path is already a file URL (either explicitly, or implicitly because +the base `ResourceLoader` is a filesystem one, then wildcarding is guaranteed to work in +a completely portable fashion. + +If the specified path is a classpath location, then the resolver must obtain the last +non-wildcard path segment URL via a `Classloader.getResource()` call. Since this is just +a node of the path (not the file at the end) it is actually undefined (in the +`ClassLoader` javadocs) exactly what sort of a URL is returned in this case. In +practice, it is always a `java.io.File` representing the directory, where the classpath +resource resolves to a filesystem location, or a jar URL of some sort, where the +classpath resource resolves to a jar location. Still, there is a portability concern on +this operation. + +If a jar URL is obtained for the last non-wildcard segment, the resolver must be able to +get a `java.net.JarURLConnection` from it, or manually parse the jar URL, to be able to +walk the contents of the jar, and resolve the wildcard. This will work in most +environments, but will fail in others, and it is strongly recommended that the wildcard +resolution of resources coming from jars be thoroughly tested in your specific +environment before you rely on it. + + +[[resources-classpath-wildcards]] +==== The Classpath*: portability classpath*: prefix + +When constructing an XML-based application context, a location string may use the +special `classpath*:` prefix: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ApplicationContext ctx = + new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml"); +---- + +This special prefix specifies that all classpath resources that match the given name +must be obtained (internally, this essentially happens via a +`ClassLoader.getResources(...)` call), and then merged to form the final application +context definition. + +[NOTE] +==== +The wildcard classpath relies on the `getResources()` method of the underlying +classloader. As most application servers nowadays supply their own classloader +implementation, the behavior might differ especially when dealing with jar files. A +simple test to check if `classpath*` works is to use the classloader to load a file from +within a jar on the classpath: +`getClass().getClassLoader().getResources("")`. Try this test with +files that have the same name but are placed inside two different locations. In case an +inappropriate result is returned, check the application server documentation for +settings that might affect the classloader behavior. +==== + +The " `classpath*:`" prefix can also be combined with a `PathMatcher` pattern in the +rest of the location path, for example " `classpath*:META-INF/*-beans.xml`". In this +case, the resolution strategy is fairly simple: a ClassLoader.getResources() call is +used on the last non-wildcard path segment to get all the matching resources in the +class loader hierarchy, and then off each resource the same PathMatcher resolution +strategy described above is used for the wildcard subpath. + + +[[resources-wildcards-in-path-other-stuff]] +==== Other notes relating to wildcards +Please note that `classpath*:` when combined with Ant-style patterns will only work +reliably with at least one root directory before the pattern starts, unless the actual +target files reside in the file system. This means that a pattern like " +`classpath*:*.xml`" will not retrieve files from the root of jar files but rather only +from the root of expanded directories. This originates from a limitation in the JDK's +`ClassLoader.getResources()` method which only returns file system locations for a +passed-in empty string (indicating potential roots to search). + +Ant-style patterns with " `classpath:`" resources are not guaranteed to find matching +resources if the root package to search is available in multiple class path locations. +This is because a resource such as + +[literal] +[subs="verbatim,quotes"] +---- +com/mycompany/package1/service-context.xml +---- + +may be in only one location, but when a path such as + +[literal] +[subs="verbatim,quotes"] +---- +classpath:com/mycompany/**/service-context.xml +---- + +is used to try to resolve it, the resolver will work off the (first) URL returned by +`getResource("com/mycompany")`;. If this base package node exists in multiple +classloader locations, the actual end resource may not be underneath. Therefore, +preferably, use " `classpath*:`" with the same Ant-style pattern in such a case, which +will search all class path locations that contain the root package. + + + +[[resources-filesystemresource-caveats]] +=== FileSystemResource caveats + +A `FileSystemResource` that is not attached to a `FileSystemApplicationContext` (that +is, a `FileSystemApplicationContext` is not the actual `ResourceLoader`) will treat +absolute vs. relative paths as you would expect. Relative paths are relative to the +current working directory, while absolute paths are relative to the root of the +filesystem. + +For backwards compatibility (historical) reasons however, this changes when the +`FileSystemApplicationContext` is the `ResourceLoader`. The +`FileSystemApplicationContext` simply forces all attached `FileSystemResource` instances +to treat all location paths as relative, whether they start with a leading slash or not. +In practice, this means the following are equivalent: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ApplicationContext ctx = + new FileSystemXmlApplicationContext("conf/context.xml"); +---- + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ApplicationContext ctx = + new FileSystemXmlApplicationContext("/conf/context.xml"); +---- + +As are the following: (Even though it would make sense for them to be different, as one +case is relative and the other absolute.) + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + FileSystemXmlApplicationContext ctx = ...; + ctx.getResource("some/resource/path/myTemplate.txt"); +---- + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + FileSystemXmlApplicationContext ctx = ...; + ctx.getResource("/some/resource/path/myTemplate.txt"); +---- + +In practice, if true absolute filesystem paths are needed, it is better to forgo the use +of absolute paths with `FileSystemResource` / `FileSystemXmlApplicationContext`, and +just force the use of a `UrlResource`, by using the `file:` URL prefix. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // actual context type doesn't matter, the Resource will always be UrlResource + ctx.getResource("file:///some/resource/path/myTemplate.txt"); +---- + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // force this FileSystemXmlApplicationContext to load its definition via a UrlResource + ApplicationContext ctx = + new FileSystemXmlApplicationContext("file:///conf/context.xml"); +---- + diff --git a/src/asciidoc/core-validation.adoc b/src/asciidoc/core-validation.adoc new file mode 100644 index 00000000000..f5fe7806d1a --- /dev/null +++ b/src/asciidoc/core-validation.adoc @@ -0,0 +1,1836 @@ + +[[validation]] += Validation, Data Binding, and Type Conversion + + + + +[[validation-introduction]] +== Introduction + +.JSR-303/JSR-349 Bean Validation +**** +Spring Framework 4.0 supports Bean Validation 1.0 (JSR-303) and Bean Validation 1.1 +(JSR-349) in terms of setup support, also adapting it to Spring's `Validator` interface. + +An application can choose to enable Bean Validation once globally, as described in +<>, and use it exclusively for all validation needs. + +An application can also register additional Spring `Validator` instances per +`DataBinder` instance, as described in <>. This may be useful for +plugging in validation logic without the use of annotations. +**** + +There are pros and cons for considering validation as business logic, and Spring offers +a design for validation (and data binding) that does not exclude either one of them. +Specifically validation should not be tied to the web tier, should be easy to localize +and it should be possible to plug in any validator available. Considering the above, +Spring has come up with a `Validator` interface that is both basic ands eminently usable +in every layer of an application. + +Data binding is useful for allowing user input to be dynamically bound to the domain +model of an application (or whatever objects you use to process user input). Spring +provides the so-called `DataBinder` to do exactly that. The `Validator` and the +`DataBinder` make up the `validation` package, which is primarily used in but not +limited to the MVC framework. + +The `BeanWrapper` is a fundamental concept in the Spring Framework and is used in a lot +of places. However, you probably will not have the need to use the `BeanWrapper` +directly. Because this is reference documentation however, we felt that some explanation +might be in order. We will explain the `BeanWrapper` in this chapter since, if you were +going to use it at all, you would most likely do so when trying to bind data to objects. + +Spring's DataBinder and the lower-level BeanWrapper both use PropertyEditors to parse +and format property values. The `PropertyEditor` concept is part of the JavaBeans +specification, and is also explained in this chapter. Spring 3 introduces a +"core.convert" package that provides a general type conversion facility, as well as a +higher-level "format" package for formatting UI field values. These new packages may be +used as simpler alternatives to PropertyEditors, and will also be discussed in this +chapter. + + + + +[[validator]] +== Validation using Spring's Validator interface + +Spring features a `Validator` interface that you can use to validate objects. The +`Validator` interface works using an `Errors` object so that while validating, +validators can report validation failures to the `Errors` object. + +Let's consider a small data object: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class Person { + + private String name; + private int age; + + // the usual getters and setters... + } +---- + +We're going to provide validation behavior for the `Person` class by implementing the +following two methods of the `org.springframework.validation.Validator` interface: + +* `supports(Class)` - Can this `Validator` validate instances of the supplied `Class`? +* `validate(Object, org.springframework.validation.Errors)` - validates the given object + and in case of validation errors, registers those with the given `Errors` object + +Implementing a `Validator` is fairly straightforward, especially when you know of the +`ValidationUtils` helper class that the Spring Framework also provides. + +[source,java,indent=0] +[subs="verbatim"] +---- + public class PersonValidator implements Validator { + + /** + * This Validator validates *just* Person instances + */ + public boolean supports(Class clazz) { + return Person.class.equals(clazz); + } + + public void validate(Object obj, Errors e) { + ValidationUtils.rejectIfEmpty(e, "name", "name.empty"); + Person p = (Person) obj; + if (p.getAge() < 0) { + e.rejectValue("age", "negativevalue"); + } else if (p.getAge() > 110) { + e.rejectValue("age", "too.darn.old"); + } + } + } +---- + +As you can see, the `static` `rejectIfEmpty(..)` method on the `ValidationUtils` class +is used to reject the `'name'` property if it is `null` or the empty string. Have a look +at the `ValidationUtils` javadocs to see what functionality it provides besides the +example shown previously. + +While it is certainly possible to implement a single `Validator` class to validate each +of the nested objects in a rich object, it may be better to encapsulate the validation +logic for each nested class of object in its own `Validator` implementation. A simple +example of a __'rich'__ object would be a `Customer` that is composed of two `String` +properties (a first and second name) and a complex `Address` object. `Address` objects +may be used independently of `Customer` objects, and so a distinct `AddressValidator` +has been implemented. If you want your `CustomerValidator` to reuse the logic contained +within the `AddressValidator` class without resorting to copy-and-paste, you can +dependency-inject or instantiate an `AddressValidator` within your `CustomerValidator`, +and use it like so: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class CustomerValidator implements Validator { + + private final Validator addressValidator; + + public CustomerValidator(Validator addressValidator) { + if (addressValidator == null) { + throw new IllegalArgumentException("The supplied [Validator] is " + + "required and must not be null."); + } + if (!addressValidator.supports(Address.class)) { + throw new IllegalArgumentException("The supplied [Validator] must " + + support the validation of [Address] instances."); + } + this.addressValidator = addressValidator; + } + + /** + * This Validator validates Customer instances, and any subclasses of Customer too + */ + public boolean supports(Class clazz) { + return Customer.class.isAssignableFrom(clazz); + } + + public void validate(Object target, Errors errors) { + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required"); + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required"); + Customer customer = (Customer) target; + try { + errors.pushNestedPath("address"); + ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors); + } finally { + errors.popNestedPath(); + } + } + } +---- + +Validation errors are reported to the `Errors` object passed to the validator. In case +of Spring Web MVC you can use `` tag to inspect the error messages, but of +course you can also inspect the errors object yourself. More information about the +methods it offers can be found in the javadocs. + + + + +[[validation-conversion]] +== Resolving codes to error messages +We've talked about databinding and validation. Outputting messages corresponding to +validation errors is the last thing we need to discuss. In the example we've shown +above, we rejected the `name` and the `age` field. If we're going to output the error +messages by using a `MessageSource`, we will do so using the error code we've given when +rejecting the field ('name' and 'age' in this case). When you call (either directly, or +indirectly, using for example the `ValidationUtils` class) `rejectValue` or one of the +other `reject` methods from the `Errors` interface, the underlying implementation will +not only register the code you've passed in, but also a number of additional error +codes. What error codes it registers is determined by the `MessageCodesResolver` that is +used. By default, the `DefaultMessageCodesResolver` is used, which for example not only +registers a message with the code you gave, but also messages that include the field +name you passed to the reject method. So in case you reject a field using +`rejectValue("age", "too.darn.old")`, apart from the `too.darn.old` code, Spring will +also register `too.darn.old.age` and `too.darn.old.age.int` (so the first will include +the field name and the second will include the type of the field); this is done as a +convenience to aid developers in targeting error messages and suchlike. + +More information on the `MessageCodesResolver` and the default strategy can be found +online in the javadocs of +{javadoc-baseurl}/org/springframework/validation/MessageCodesResolver.html[`MessageCodesResolver`] +and +{javadoc-baseurl}/org/springframework/validation/DefaultMessageCodesResolver.html[`DefaultMessageCodesResolver`], +respectively. + + + + +[[beans-beans]] +== Bean manipulation and the BeanWrapper + +The `org.springframework.beans` package adheres to the JavaBeans standard provided by +Oracle. A JavaBean is simply a class with a default no-argument constructor, which follows +a naming convention where (by way of an example) a property named `bingoMadness` would +have a setter method `setBingoMadness(..)` and a getter method `getBingoMadness()`. For +more information about JavaBeans and the specification, please refer to Oracle's website ( +http://docs.oracle.com/javase/6/docs/api/java/beans/package-summary.html[javabeans]). + +One quite important class in the beans package is the `BeanWrapper` interface and its +corresponding implementation ( `BeanWrapperImpl`). As quoted from the javadocs, the +`BeanWrapper` offers functionality to set and get property values (individually or in +bulk), get property descriptors, and to query properties to determine if they are +readable or writable. Also, the `BeanWrapper` offers support for nested properties, +enabling the setting of properties on sub-properties to an unlimited depth. Then, the +`BeanWrapper` supports the ability to add standard JavaBeans `PropertyChangeListeners` +and `VetoableChangeListeners`, without the need for supporting code in the target class. +Last but not least, the `BeanWrapper` provides support for the setting of indexed +properties. The `BeanWrapper` usually isn't used by application code directly, but by +the `DataBinder` and the `BeanFactory`. + +The way the `BeanWrapper` works is partly indicated by its name: __it wraps a bean__ to +perform actions on that bean, like setting and retrieving properties. + + + +[[beans-beans-conventions]] +=== Setting and getting basic and nested properties +Setting and getting properties is done using the `setPropertyValue(s)` and +`getPropertyValue(s)` methods that both come with a couple of overloaded variants. +They're all described in more detail in the javadocs Spring comes with. What's important +to know is that there are a couple of conventions for indicating properties of an +object. A couple of examples: + +[[beans-beans-conventions-properties-tbl]] +.Examples of properties +|=== +| Expression| Explanation + +| `name` +| Indicates the property `name` corresponding to the methods `getName()` or `isName()` + and `setName(..)` + +| `account.name` +| Indicates the nested property `name` of the property `account` corresponding e.g. to + the methods `getAccount().setName()` or `getAccount().getName()` + +| `account[2]` +| Indicates the __third__ element of the indexed property `account`. Indexed properties + can be of type `array`, `list` or other __naturally ordered__ collection + +| `account[COMPANYNAME]` +| Indicates the value of the map entry indexed by the key __COMPANYNAME__ of the Map + property `account` +|=== + +Below you'll find some examples of working with the `BeanWrapper` to get and set +properties. + +__(This next section is not vitally important to you if you're not planning to work with +the `BeanWrapper` directly. If you're just using the `DataBinder` and the `BeanFactory` +and their out-of-the-box implementation, you should skip ahead to the section about +`PropertyEditors`.)__ + +Consider the following two classes: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class Company { + + private String name; + private Employee managingDirector; + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public Employee getManagingDirector() { + return this.managingDirector; + } + + public void setManagingDirector(Employee managingDirector) { + this.managingDirector = managingDirector; + } + } +---- + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class Employee { + + private String name; + + private float salary; + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public float getSalary() { + return salary; + } + + public void setSalary(float salary) { + this.salary = salary; + } + } +---- + +The following code snippets show some examples of how to retrieve and manipulate some of +the properties of instantiated `Companies` and `Employees`: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + BeanWrapper company = BeanWrapperImpl(new Company()); + // setting the company name.. + company.setPropertyValue("name", "Some Company Inc."); + // ... can also be done like this: + PropertyValue value = new PropertyValue("name", "Some Company Inc."); + company.setPropertyValue(value); + + // ok, let's create the director and tie it to the company: + BeanWrapper jim = BeanWrapperImpl(new Employee()); + jim.setPropertyValue("name", "Jim Stravinsky"); + company.setPropertyValue("managingDirector", jim.getWrappedInstance()); + + // retrieving the salary of the managingDirector through the company + Float salary = (Float) company.getPropertyValue("managingDirector.salary"); +---- + + + +[[beans-beans-conversion]] +=== Built-in PropertyEditor implementations + +Spring uses the concept of `PropertyEditors` to effect the conversion between an +`Object` and a `String`. If you think about it, it sometimes might be handy to be able +to represent properties in a different way than the object itself. For example, a `Date` +can be represented in a human readable way (as the `String` ' `2007-14-09`'), while +we're still able to convert the human readable form back to the original date (or even +better: convert any date entered in a human readable form, back to `Date` objects). This +behavior can be achieved by __registering custom editors__, of type +`java.beans.PropertyEditor`. Registering custom editors on a `BeanWrapper` or +alternately in a specific IoC container as mentioned in the previous chapter, gives it +the knowledge of how to convert properties to the desired type. Read more about +`PropertyEditors` in the javadocs of the `java.beans` package provided by Oracle. + +A couple of examples where property editing is used in Spring: + +* __setting properties on beans__ is done using `PropertyEditors`. When mentioning + `java.lang.String` as the value of a property of some bean you're declaring in XML + file, Spring will (if the setter of the corresponding property has a + `Class`-parameter) use the `ClassEditor` to try to resolve the parameter to a `Class` + object. +* __parsing HTTP request parameters__ in Spring's MVC framework is done using all kinds + of `PropertyEditors` that you can manually bind in all subclasses of the + `CommandController`. + +Spring has a number of built-in `PropertyEditors` to make life easy. Each of those is +listed below and they are all located in the `org.springframework.beans.propertyeditors` +package. Most, but not all (as indicated below), are registered by default by +`BeanWrapperImpl`. Where the property editor is configurable in some fashion, you can of +course still register your own variant to override the default one: + +[[beans-beans-property-editors-tbl]] +.Built-in PropertyEditors +|=== +| Class| Explanation + +| `ByteArrayPropertyEditor` +| Editor for byte arrays. Strings will simply be converted to their corresponding byte + representations. Registered by default by `BeanWrapperImpl`. + +| `ClassEditor` +| Parses Strings representing classes to actual classes and the other way around. When a + class is not found, an `IllegalArgumentException` is thrown. Registered by default by + `BeanWrapperImpl`. + +| `CustomBooleanEditor` +| Customizable property editor for `Boolean` properties. Registered by default by + `BeanWrapperImpl`, but, can be overridden by registering custom instance of it as + custom editor. + +| `CustomCollectionEditor` +| Property editor for Collections, converting any source `Collection` to a given target + `Collection` type. + +| `CustomDateEditor` +| Customizable property editor for java.util.Date, supporting a custom DateFormat. NOT + registered by default. Must be user registered as needed with appropriate format. + +| `CustomNumberEditor` +| Customizable property editor for any Number subclass like `Integer`, `Long`, `Float`, + `Double`. Registered by default by `BeanWrapperImpl`, but can be overridden by + registering custom instance of it as a custom editor. + +| `FileEditor` +| Capable of resolving Strings to `java.io.File` objects. Registered by default by + `BeanWrapperImpl`. + +| `InputStreamEditor` +| One-way property editor, capable of taking a text string and producing (via an + intermediate `ResourceEditor` and `Resource`) an `InputStream`, so `InputStream` + properties may be directly set as Strings. Note that the default usage will not close + the `InputStream` for you! Registered by default by `BeanWrapperImpl`. + +| `LocaleEditor` +| Capable of resolving Strings to `Locale` objects and vice versa (the String format is + [language]_[country]_[variant], which is the same thing the toString() method of + Locale provides). Registered by default by `BeanWrapperImpl`. + +| `PatternEditor` +| Capable of resolving Strings to `java.util.regex.Pattern` objects and vice versa. + +| `PropertiesEditor` +| Capable of converting Strings (formatted using the format as defined in the javadocs + of the `java.util.Properties` class) to `Properties` objects. Registered by default + by `BeanWrapperImpl`. + +| `StringTrimmerEditor` +| Property editor that trims Strings. Optionally allows transforming an empty string + into a `null` value. NOT registered by default; must be user registered as needed. + +| `URLEditor` +| Capable of resolving a String representation of a URL to an actual `URL` object. + Registered by default by `BeanWrapperImpl`. +|=== + +Spring uses the `java.beans.PropertyEditorManager` to set the search path for property +editors that might be needed. The search path also includes `sun.bean.editors`, which +includes `PropertyEditor` implementations for types such as `Font`, `Color`, and most of +the primitive types. Note also that the standard JavaBeans infrastructure will +automatically discover `PropertyEditor` classes (without you having to register them +explicitly) if they are in the same package as the class they handle, and have the same +name as that class, with `'Editor'` appended; for example, one could have the following +class and package structure, which would be sufficient for the `FooEditor` class to be +recognized and used as the `PropertyEditor` for `Foo`-typed properties. + +[literal] +[subs="verbatim,quotes"] +---- +com + chank + pop + Foo + FooEditor // the PropertyEditor for the Foo class +---- + +Note that you can also use the standard `BeanInfo` JavaBeans mechanism here as well +(described +http://docs.oracle.com/javase/tutorial/javabeans/advanced/customization.html[in +not-amazing-detail here]). Find below an example of using the `BeanInfo` mechanism for +explicitly registering one or more `PropertyEditor` instances with the properties of an +associated class. + +[literal] +[subs="verbatim,quotes"] +---- +com + chank + pop + Foo + FooBeanInfo // the BeanInfo for the Foo class +---- + +Here is the Java source code for the referenced `FooBeanInfo` class. This would +associate a `CustomNumberEditor` with the `age` property of the `Foo` class. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class FooBeanInfo extends SimpleBeanInfo { + + public PropertyDescriptor[] getPropertyDescriptors() { + try { + final PropertyEditor numberPE = new CustomNumberEditor(Integer.class, true); + PropertyDescriptor ageDescriptor = new PropertyDescriptor("age", Foo.class) { + public PropertyEditor createPropertyEditor(Object bean) { + return numberPE; + }; + }; + return new PropertyDescriptor[] { ageDescriptor }; + } + catch (IntrospectionException ex) { + throw new Error(ex.toString()); + } + } + } +---- + + +[[beans-beans-conversion-customeditor-registration]] +==== Registering additional custom PropertyEditors + +When setting bean properties as a string value, a Spring IoC container ultimately uses +standard JavaBeans `PropertyEditors` to convert these Strings to the complex type of the +property. Spring pre-registers a number of custom `PropertyEditors` (for example, to +convert a classname expressed as a string into a real `Class` object). Additionally, +Java's standard JavaBeans `PropertyEditor` lookup mechanism allows a `PropertyEditor` +for a class simply to be named appropriately and placed in the same package as the class +it provides support for, to be found automatically. + +If there is a need to register other custom `PropertyEditors`, there are several +mechanisms available. The most manual approach, which is not normally convenient or +recommended, is to simply use the `registerCustomEditor()` method of the +`ConfigurableBeanFactory` interface, assuming you have a `BeanFactory` reference. +Another, slightly more convenient, mechanism is to use a special bean factory +post-processor called `CustomEditorConfigurer`. Although bean factory post-processors +can be used with `BeanFactory` implementations, the `CustomEditorConfigurer` has a +nested property setup, so it is strongly recommended that it is used with the +`ApplicationContext`, where it may be deployed in similar fashion to any other bean, and +automatically detected and applied. + +Note that all bean factories and application contexts automatically use a number of +built-in property editors, through their use of something called a `BeanWrapper` to +handle property conversions. The standard property editors that the `BeanWrapper` +registers are listed in <>. Additionally, +`ApplicationContexts` also override or add an additional number of editors to handle +resource lookups in a manner appropriate to the specific application context type. + +Standard JavaBeans `PropertyEditor` instances are used to convert property values +expressed as strings to the actual complex type of the property. +`CustomEditorConfigurer`, a bean factory post-processor, may be used to conveniently add +support for additional `PropertyEditor` instances to an `ApplicationContext`. + +Consider a user class `ExoticType`, and another class `DependsOnExoticType` which needs +`ExoticType` set as a property: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package example; + + public class ExoticType { + + private String name; + + public ExoticType(String name) { + this.name = name; + } + } + + public class DependsOnExoticType { + + private ExoticType type; + + public void setType(ExoticType type) { + this.type = type; + } + } +---- + +When things are properly set up, we want to be able to assign the type property as a +string, which a `PropertyEditor` will behind the scenes convert into an actual +`ExoticType` instance: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + +---- + +The `PropertyEditor` implementation could look similar to this: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + // converts string representation to ExoticType object + package example; + + public class ExoticTypeEditor extends PropertyEditorSupport { + + public void setAsText(String text) { + setValue(new ExoticType(text.toUpperCase())); + } + } +---- + +Finally, we use `CustomEditorConfigurer` to register the new `PropertyEditor` with the +`ApplicationContext`, which will then be able to use it as needed: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + +---- + +[[beans-beans-conversion-customeditor-registration-per]] +===== Using PropertyEditorRegistrars + +Another mechanism for registering property editors with the Spring container is to +create and use a `PropertyEditorRegistrar`. This interface is particularly useful when +you need to use the same set of property editors in several different situations: write +a corresponding registrar and reuse that in each case. `PropertyEditorRegistrars` work +in conjunction with an interface called `PropertyEditorRegistry`, an interface that is +implemented by the Spring `BeanWrapper` (and `DataBinder`). `PropertyEditorRegistrars` +are particularly convenient when used in conjunction with the `CustomEditorConfigurer` +(introduced <>), which exposes a +property called `setPropertyEditorRegistrars(..)`: `PropertyEditorRegistrars` added to a +`CustomEditorConfigurer` in this fashion can easily be shared with `DataBinder` and +Spring MVC `Controllers`. Furthermore, it avoids the need for synchronization on custom +editors: a `PropertyEditorRegistrar` is expected to create fresh `PropertyEditor` +instances for each bean creation attempt. + +Using a `PropertyEditorRegistrar` is perhaps best illustrated with an example. First +off, you need to create your own `PropertyEditorRegistrar` implementation: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package com.foo.editors.spring; + + public final class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar { + + public void registerCustomEditors(PropertyEditorRegistry registry) { + + // it is expected that new PropertyEditor instances are created + registry.registerCustomEditor(ExoticType.class, new ExoticTypeEditor()); + + // you could register as many custom property editors as are required here... + } + } +---- + +See also the `org.springframework.beans.support.ResourceEditorRegistrar` for an example +`PropertyEditorRegistrar` implementation. Notice how in its implementation of the +`registerCustomEditors(..)` method it creates new instances of each property editor. + +Next we configure a `CustomEditorConfigurer` and inject an instance of our +`CustomPropertyEditorRegistrar` into it: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + +---- + +Finally, and in a bit of a departure from the focus of this chapter, for those of you +using <>, using `PropertyEditorRegistrars` in +conjunction with data-binding `Controllers` (such as `SimpleFormController`) can be very +convenient. Find below an example of using a `PropertyEditorRegistrar` in the +implementation of an `initBinder(..)` method: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public final class RegisterUserController extends SimpleFormController { + + private final PropertyEditorRegistrar customPropertyEditorRegistrar; + + public RegisterUserController(PropertyEditorRegistrar propertyEditorRegistrar) { + this.customPropertyEditorRegistrar = propertyEditorRegistrar; + } + + protected void initBinder(HttpServletRequest request, + ServletRequestDataBinder binder) throws Exception { + **this.customPropertyEditorRegistrar.registerCustomEditors(binder);** + } + + // other methods to do with registering a User + } +---- + +This style of `PropertyEditor` registration can lead to concise code (the implementation +of `initBinder(..)` is just one line long!), and allows common `PropertyEditor` +registration code to be encapsulated in a class and then shared amongst as many +`Controllers` as needed. + + + + +[[core-convert]] +== Spring Type Conversion +Spring 3 introduces a `core.convert` package that provides a general type conversion +system. The system defines an SPI to implement type conversion logic, as well as an API +to execute type conversions at runtime. Within a Spring container, this system can be +used as an alternative to PropertyEditors to convert externalized bean property value +strings to required property types. The public API may also be used anywhere in your +application where type conversion is needed. + + + +[[core-convert-Converter-API]] +=== Converter SPI +The SPI to implement type conversion logic is simple and strongly typed: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.core.convert.converter; + + public interface Converter { + + T convert(S source); + + } +---- + +To create your own converter, simply implement the interface above. Parameterize `S` +as the type you are converting from, and `T` as the type you are converting to. Such a +converter can also be applied transparently if a collection or array of `S` needs to be +converted to an array or collection of `T`, provided that a delegating array/collection +converter has been registered as well (which `DefaultConversionService` does by default). + +For each call to `convert(S)`, the source argument is guaranteed to be NOT null. Your +Converter may throw any unchecked exception if conversion fails; specifically, an +`IllegalArgumentException` should be thrown to report an invalid source value. +Take care to ensure that your `Converter` implementation is thread-safe. + +Several converter implementations are provided in the `core.convert.support` package as +a convenience. These include converters from Strings to Numbers and other common types. +Consider `StringToInteger` as an example for a typical `Converter` implementation: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.core.convert.support; + + final class StringToInteger implements Converter { + + public Integer convert(String source) { + return Integer.valueOf(source); + } + + } +---- + + + +[[core-convert-ConverterFactory-SPI]] +=== ConverterFactory +When you need to centralize the conversion logic for an entire class hierarchy, for +example, when converting from String to java.lang.Enum objects, implement +`ConverterFactory`: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.core.convert.converter; + + public interface ConverterFactory { + + Converter getConverter(Class targetType); + + } +---- + +Parameterize S to be the type you are converting from and R to be the base type defining +the __range__ of classes you can convert to. Then implement getConverter(Class), +where T is a subclass of R. + +Consider the `StringToEnum` ConverterFactory as an example: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.core.convert.support; + + final class StringToEnumConverterFactory implements ConverterFactory { + + public Converter getConverter(Class targetType) { + return new StringToEnumConverter(targetType); + } + + private final class StringToEnumConverter implements Converter { + + private Class enumType; + + public StringToEnumConverter(Class enumType) { + this.enumType = enumType; + } + + public T convert(String source) { + return (T) Enum.valueOf(this.enumType, source.trim()); + } + } + } +---- + + + +[[core-convert-GenericConverter-SPI]] +=== GenericConverter +When you require a sophisticated Converter implementation, consider the GenericConverter +interface. With a more flexible but less strongly typed signature, a GenericConverter +supports converting between multiple source and target types. In addition, a +GenericConverter makes available source and target field context you can use when +implementing your conversion logic. Such context allows a type conversion to be driven +by a field annotation, or generic information declared on a field signature. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.core.convert.converter; + + public interface GenericConverter { + + public Set getConvertibleTypes(); + + Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType); + + } +---- + +To implement a GenericConverter, have getConvertibleTypes() return the supported +source->target type pairs. Then implement convert(Object, TypeDescriptor, +TypeDescriptor) to implement your conversion logic. The source TypeDescriptor provides +access to the source field holding the value being converted. The target TypeDescriptor +provides access to the target field where the converted value will be set. + +A good example of a GenericConverter is a converter that converts between a Java Array +and a Collection. Such an ArrayToCollectionConverter introspects the field that declares +the target Collection type to resolve the Collection's element type. This allows each +element in the source array to be converted to the Collection element type before the +Collection is set on the target field. + +[NOTE] +==== +Because GenericConverter is a more complex SPI interface, only use it when you need it. +Favor Converter or ConverterFactory for basic type conversion needs. +==== + + +[[core-convert-ConditionalGenericConverter-SPI]] +==== ConditionalGenericConverter +Sometimes you only want a Converter to execute if a specific condition holds true. For +example, you might only want to execute a Converter if a specific annotation is present +on the target field. Or you might only want to execute a Converter if a specific method, +such as static valueOf method, is defined on the target class. +ConditionalGenericConverter is an subinterface of GenericConverter that allows you to +define such custom matching criteria: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface ConditionalGenericConverter extends GenericConverter { + + boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType); + + } +---- + +A good example of a ConditionalGenericConverter is an EntityConverter that converts +between an persistent entity identifier and an entity reference. Such a EntityConverter +might only match if the target entity type declares a static finder method e.g. +findAccount(Long). You would perform such a finder method check in the implementation of +matches(TypeDescriptor, TypeDescriptor). + + + +[[core-convert-ConversionService-API]] +=== ConversionService API +The ConversionService defines a unified API for executing type conversion logic at +runtime. Converters are often executed behind this facade interface: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.core.convert; + + public interface ConversionService { + + boolean canConvert(Class sourceType, Class targetType); + + T convert(Object source, Class targetType); + + boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType); + + Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType); + + } +---- + +Most ConversionService implementations also implement `ConverterRegistry`, which +provides an SPI for registering converters. Internally, a ConversionService +implementation delegates to its registered converters to carry out type conversion logic. + +A robust ConversionService implementation is provided in the `core.convert.support` +package. `GenericConversionService` is the general-purpose implementation suitable for +use in most environments. `ConversionServiceFactory` provides a convenient factory for +creating common ConversionService configurations. + + + +[[core-convert-Spring-config]] +=== Configuring a ConversionService +A ConversionService is a stateless object designed to be instantiated at application +startup, then shared between multiple threads. In a Spring application, you typically +configure a ConversionService instance per Spring container (or ApplicationContext). +That ConversionService will be picked up by Spring and then used whenever a type +conversion needs to be performed by the framework. You may also inject this +ConversionService into any of your beans and invoke it directly. + +[NOTE] +==== +If no ConversionService is registered with Spring, the original PropertyEditor-based +system is used. +==== + +To register a default ConversionService with Spring, add the following bean definition +with id `conversionService`: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + +---- + +A default ConversionService can convert between strings, numbers, enums, collections, +maps, and other common types. To supplement or override the default converters with your +own custom converter(s), set the `converters` property. Property values may implement +either of the Converter, ConverterFactory, or GenericConverter interfaces. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + +---- + +It is also common to use a ConversionService within a Spring MVC application. See +<> for details on use with ``. + +In certain situations you may wish to apply formatting during conversion. See +<> for details on using +`FormattingConversionServiceFactoryBean`. + + + +[[core-convert-programmatic-usage]] +=== Using a ConversionService programmatically +To work with a ConversionService instance programmatically, simply inject a reference to +it like you would for any other bean: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Service + public class MyService { + + @Autowired + public MyService(ConversionService conversionService) { + this.conversionService = conversionService; + } + + public void doIt() { + this.conversionService.convert(...) + } + } +---- + +For most use cases, the `convert` method specifying the _targetType_ can be used but it +will not work with more complex types such as a collection of a parameterized element. +If you want to convert a `List` of `Integer` to a `List` of `String` programmatically, +for instance, you need to provide a formal definition of the source and target types. + +Fortunately, `TypeDescriptor` provides various options to make that straightforward: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + DefaultConversionService cs = new DefaultConversionService(); + + List input = .... + cs.convert(input, + TypeDescriptor.forObject(input), // List type descriptor + TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class))); +---- + +Note that `DefaultConversionService` registers converters automatically which are +appropriate for most environments. This includes collection converters, scalar +converters, and also basic `Object` to `String` converters. The same converters can +be registered with any `ConverterRegistry` using the _static_ `addDefaultConverters` +method on the `DefaultConversionService` class. + +Converters for value types will be reused for arrays and collections, so there is +no need to create a specific converter to convert from a `Collection` of `S` to a +`Collection` of `T`, assuming that standard collection handling is appropriate. + + + + +[[format]] +== Spring Field Formatting +As discussed in the previous section, <> is a +general-purpose type conversion system. It provides a unified ConversionService API as +well as a strongly-typed Converter SPI for implementing conversion logic from one type +to another. A Spring Container uses this system to bind bean property values. In +addition, both the Spring Expression Language (SpEL) and DataBinder use this system to +bind field values. For example, when SpEL needs to coerce a `Short` to a `Long` to +complete an `expression.setValue(Object bean, Object value)` attempt, the core.convert +system performs the coercion. + +Now consider the type conversion requirements of a typical client environment such as a +web or desktop application. In such environments, you typically convert __from String__ +to support the client postback process, as well as back __to String__ to support the +view rendering process. In addition, you often need to localize String values. The more +general __core.convert__ Converter SPI does not address such __formatting__ requirements +directly. To directly address them, Spring 3 introduces a convenient Formatter SPI that +provides a simple and robust alternative to PropertyEditors for client environments. + +In general, use the Converter SPI when you need to implement general-purpose type +conversion logic; for example, for converting between a java.util.Date and and +java.lang.Long. Use the Formatter SPI when you're working in a client environment, such +as a web application, and need to parse and print localized field values. The +ConversionService provides a unified type conversion API for both SPIs. + + + +[[format-Formatter-SPI]] +=== Formatter SPI +The Formatter SPI to implement field formatting logic is simple and strongly typed: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.format; + + public interface Formatter extends Printer, Parser { + } +---- + +Where Formatter extends from the Printer and Parser building-block interfaces: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public interface Printer { + String print(T fieldValue, Locale locale); + } +---- + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + import java.text.ParseException; + + public interface Parser { + T parse(String clientValue, Locale locale) throws ParseException; + } +---- + +To create your own Formatter, simply implement the Formatter interface above. +Parameterize T to be the type of object you wish to format, for example, +`java.util.Date`. Implement the `print()` operation to print an instance of T for +display in the client locale. Implement the `parse()` operation to parse an instance of +T from the formatted representation returned from the client locale. Your Formatter +should throw a ParseException or IllegalArgumentException if a parse attempt fails. Take +care to ensure your Formatter implementation is thread-safe. + +Several Formatter implementations are provided in `format` subpackages as a convenience. +The `number` package provides a `NumberFormatter`, `CurrencyFormatter`, and +`PercentFormatter` to format `java.lang.Number` objects using a `java.text.NumberFormat`. +The `datetime` package provides a `DateFormatter` to format `java.util.Date` objects with +a `java.text.DateFormat`. The `datetime.joda` package provides comprehensive datetime +formatting support based on the http://joda-time.sourceforge.net[Joda Time library]. + +Consider `DateFormatter` as an example `Formatter` implementation: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.format.datetime; + + public final class DateFormatter implements Formatter { + + private String pattern; + + public DateFormatter(String pattern) { + this.pattern = pattern; + } + + public String print(Date date, Locale locale) { + if (date == null) { + return ""; + } + return getDateFormat(locale).format(date); + } + + public Date parse(String formatted, Locale locale) throws ParseException { + if (formatted.length() == 0) { + return null; + } + return getDateFormat(locale).parse(formatted); + } + + protected DateFormat getDateFormat(Locale locale) { + DateFormat dateFormat = new SimpleDateFormat(this.pattern, locale); + dateFormat.setLenient(false); + return dateFormat; + } + + } +---- + +The Spring team welcomes community-driven `Formatter` contributions; see +https://jira.spring.io/browse/SPR[jira.spring.io] to contribute. + + + +[[format-CustomFormatAnnotations]] +=== Annotation-driven Formatting +As you will see, field formatting can be configured by field type or annotation. To bind +an Annotation to a formatter, implement AnnotationFormatterFactory: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.format; + + public interface AnnotationFormatterFactory { + + Set> getFieldTypes(); + + Printer getPrinter(A annotation, Class fieldType); + + Parser getParser(A annotation, Class fieldType); + + } +---- + +Parameterize A to be the field annotationType you wish to associate formatting logic +with, for example `org.springframework.format.annotation.DateTimeFormat`. Have +`getFieldTypes()` return the types of fields the annotation may be used on. Have +`getPrinter()` return a Printer to print the value of an annotated field. Have +`getParser()` return a Parser to parse a clientValue for an annotated field. + +The example AnnotationFormatterFactory implementation below binds the @NumberFormat +Annotation to a formatter. This annotation allows either a number style or pattern to be +specified: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public final class NumberFormatAnnotationFormatterFactory + implements AnnotationFormatterFactory { + + public Set> getFieldTypes() { + return new HashSet>(asList(new Class[] { + Short.class, Integer.class, Long.class, Float.class, + Double.class, BigDecimal.class, BigInteger.class })); + } + + public Printer getPrinter(NumberFormat annotation, Class fieldType) { + return configureFormatterFrom(annotation, fieldType); + } + + public Parser getParser(NumberFormat annotation, Class fieldType) { + return configureFormatterFrom(annotation, fieldType); + } + + private Formatter configureFormatterFrom(NumberFormat annotation, + Class fieldType) { + if (!annotation.pattern().isEmpty()) { + return new NumberFormatter(annotation.pattern()); + } else { + Style style = annotation.style(); + if (style == Style.PERCENT) { + return new PercentFormatter(); + } else if (style == Style.CURRENCY) { + return new CurrencyFormatter(); + } else { + return new NumberFormatter(); + } + } + } + } +---- + +To trigger formatting, simply annotate fields with @NumberFormat: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class MyModel { + + @NumberFormat(style=Style.CURRENCY) + private BigDecimal decimal; + + } +---- + + +[[format-annotations-api]] +==== Format Annotation API +A portable format annotation API exists in the `org.springframework.format.annotation` +package. Use @NumberFormat to format java.lang.Number fields. Use @DateTimeFormat to +format java.util.Date, java.util.Calendar, java.util.Long, or Joda Time fields. + +The example below uses @DateTimeFormat to format a java.util.Date as a ISO Date +(yyyy-MM-dd): + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class MyModel { + + @DateTimeFormat(iso=ISO.DATE) + private Date date; + + } +---- + + + +[[format-FormatterRegistry-SPI]] +=== FormatterRegistry SPI +The FormatterRegistry is an SPI for registering formatters and converters. +`FormattingConversionService` is an implementation of FormatterRegistry suitable for +most environments. This implementation may be configured programmatically or +declaratively as a Spring bean using `FormattingConversionServiceFactoryBean`. Because +this implementation also implements `ConversionService`, it can be directly configured +for use with Spring's DataBinder and the Spring Expression Language (SpEL). + +Review the FormatterRegistry SPI below: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.format; + + public interface FormatterRegistry extends ConverterRegistry { + + void addFormatterForFieldType(Class fieldType, Printer printer, Parser parser); + + void addFormatterForFieldType(Class fieldType, Formatter formatter); + + void addFormatterForFieldType(Formatter formatter); + + void addFormatterForAnnotation(AnnotationFormatterFactory factory); + + } +---- + +As shown above, Formatters can be registered by fieldType or annotation. + +The FormatterRegistry SPI allows you to configure Formatting rules centrally, instead of +duplicating such configuration across your Controllers. For example, you might want to +enforce that all Date fields are formatted a certain way, or fields with a specific +annotation are formatted in a certain way. With a shared FormatterRegistry, you define +these rules once and they are applied whenever formatting is needed. + + + +[[format-FormatterRegistrar-SPI]] +=== FormatterRegistrar SPI +The FormatterRegistrar is an SPI for registering formatters and converters through the +FormatterRegistry: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package org.springframework.format; + + public interface FormatterRegistrar { + + void registerFormatters(FormatterRegistry registry); + + } +---- + +A FormatterRegistrar is useful when registering multiple related converters and +formatters for a given formatting category, such as Date formatting. It can also be +useful where declarative registration is insufficient. For example when a formatter +needs to be indexed under a specific field type different from its own or when +registering a Printer/Parser pair. The next section provides more information on +converter and formatter registration. + + + +[[format-configuring-formatting-mvc]] +=== Configuring Formatting in Spring MVC +In a Spring MVC application, you may configure a custom ConversionService instance +explicitly as an attribute of the `annotation-driven` element of the MVC namespace. This +ConversionService will then be used anytime a type conversion is required during +Controller model binding. If not configured explicitly, Spring MVC will automatically +register default formatters and converters for common types such as numbers and dates. + +To rely on default formatting rules, no custom configuration is required in your Spring +MVC config XML: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + +---- + +With this one-line of configuration, default formatters for Numbers and Date types will +be installed, including support for the @NumberFormat and @DateTimeFormat annotations. +Full support for the Joda Time formatting library is also installed if Joda Time is +present on the classpath. + +To inject a ConversionService instance with custom formatters and converters registered, +set the conversion-service attribute and then specify custom converters, formatters, or +FormatterRegistrars as properties of the FormattingConversionServiceFactoryBean: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + + + + + + + + + + + +---- + +[NOTE] +==== +See <> and the `FormattingConversionServiceFactoryBean` +for more information on when to use FormatterRegistrars. +==== + + + + +[[format-configuring-formatting-globaldatetimeformat]] +== Configuring a global date & time format +By default, date and time fields that are not annotated with `@DateTimeFormat` are +converted from strings using the the `DateFormat.SHORT` style. If you prefer, you can +change this by defining your own global format. + +You will need to ensure that Spring does not register default formatters, and instead +you should register all formatters manually. Use the +`org.springframework.format.datetime.joda.JodaTimeFormatterRegistrar` or +`org.springframework.format.datetime.DateFormatterRegistrar` class depending on whether +you use the Joda Time library. + +For example, the following Java configuration will register a global ' `yyyyMMdd`' +format. This example does not depend on the Joda Time library: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Configuration + public class AppConfig { + + @Bean + public FormattingConversionService conversionService() { + + // Use the DefaultFormattingConversionService but do not register defaults + DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(false); + + // Ensure @NumberFormat is still supported + conversionService.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory()); + + // Register date conversion with a specific global format + DateFormatterRegistrar registrar = new DateFormatterRegistrar(); + registrar.setFormatter(new DateFormatter("yyyyMMdd")); + registrar.registerFormatters(conversionService); + + return conversionService; + } + } +---- + +If you prefer XML based configuration you can use a +`FormattingConversionServiceFactoryBean`. Here is the same example, this time using Joda +Time: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + + + + + + + +---- + +[NOTE] +==== +Joda Time provides separate distinct types to represent `date`, `time` and `date-time` +values. The `dateFormatter`, `timeFormatter` and `dateTimeFormatter` properties of the +`JodaTimeFormatterRegistrar` should be used to configure the different formats for each +type. The `DateTimeFormatterFactoryBean` provides a convenient way to create formatters. +==== + +If you are using Spring MVC remember to explicitly configure the conversion service that +is used. For Java based `@Configuration` this means extending the +`WebMvcConfigurationSupport` class and overriding the `mvcConversionService()` method. +For XML you should use the `'conversion-service'` attribute of the +`mvc:annotation-driven` element. See <> for details. + + + + +[[validation-beanvalidation]] +== Spring Validation +Spring 3 introduces several enhancements to its validation support. First, the JSR-303 +Bean Validation API is now fully supported. Second, when used programmatically, Spring's +DataBinder can now validate objects as well as bind to them. Third, Spring MVC now has +support for declaratively validating `@Controller` inputs. + + + +[[validation-beanvalidation-overview]] +=== Overview of the JSR-303 Bean Validation API +JSR-303 standardizes validation constraint declaration and metadata for the Java +platform. Using this API, you annotate domain model properties with declarative +validation constraints and the runtime enforces them. There are a number of built-in +constraints you can take advantage of. You may also define your own custom constraints. + +To illustrate, consider a simple PersonForm model with two properties: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class PersonForm { + private String name; + private int age; + } +---- + +JSR-303 allows you to define declarative validation constraints against such properties: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class PersonForm { + + @NotNull + @Size(max=64) + private String name; + + @Min(0) + private int age; + + } +---- + +When an instance of this class is validated by a JSR-303 Validator, these constraints +will be enforced. + +For general information on JSR-303/JSR-349, see the http://beanvalidation.org/[Bean +Validation website]. For information on the specific capabilities of the default +reference implementation, see the https://www.hibernate.org/412.html[Hibernate +Validator] documentation. To learn how to setup a Bean Validation provider as a Spring +bean, keep reading. + + + +[[validation-beanvalidation-spring]] +=== Configuring a Bean Validation Provider +Spring provides full support for the Bean Validation API. This includes convenient +support for bootstrapping a JSR-303/JSR-349 Bean Validation provider as a Spring bean. +This allows for a `javax.validation.ValidatorFactory` or `javax.validation.Validator` to +be injected wherever validation is needed in your application. + +Use the `LocalValidatorFactoryBean` to configure a default Validator as a Spring bean: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + +---- + +The basic configuration above will trigger Bean Validation to initialize using its +default bootstrap mechanism. A JSR-303/JSR-349 provider, such as Hibernate Validator, +is expected to be present in the classpath and will be detected automatically. + + +[[validation-beanvalidation-spring-inject]] +==== Injecting a Validator +`LocalValidatorFactoryBean` implements both `javax.validation.ValidatorFactory` and +`javax.validation.Validator`, as well as Spring's +`org.springframework.validation.Validator`. You may inject a reference to either of +these interfaces into beans that need to invoke validation logic. + +Inject a reference to `javax.validation.Validator` if you prefer to work with the Bean +Validation API directly: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + import javax.validation.Validator; + + @Service + public class MyService { + + @Autowired + private Validator validator; +---- + +Inject a reference to `org.springframework.validation.Validator` if your bean requires +the Spring Validation API: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + import org.springframework.validation.Validator; + + @Service + public class MyService { + + @Autowired + private Validator validator; + + } +---- + + +[[validation-beanvalidation-spring-constraints]] +==== Configuring Custom Constraints +Each Bean Validation constraint consists of two parts. First, a `@Constraint` annotation +that declares the constraint and its configurable properties. Second, an implementation +of the `javax.validation.ConstraintValidator` interface that implements the constraint's +behavior. To associate a declaration with an implementation, each `@Constraint` annotation +references a corresponding ValidationConstraint implementation class. At runtime, a +`ConstraintValidatorFactory` instantiates the referenced implementation when the +constraint annotation is encountered in your domain model. + +By default, the `LocalValidatorFactoryBean` configures a `SpringConstraintValidatorFactory` +that uses Spring to create ConstraintValidator instances. This allows your custom +ConstraintValidators to benefit from dependency injection like any other Spring bean. + +Shown below is an example of a custom `@Constraint` declaration, followed by an associated +`ConstraintValidator` implementation that uses Spring for dependency injection: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Target({ElementType.METHOD, ElementType.FIELD}) + @Retention(RetentionPolicy.RUNTIME) + @Constraint(validatedBy=MyConstraintValidator.class) + public @interface MyConstraint { + } +---- + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + import javax.validation.ConstraintValidator; + + public class MyConstraintValidator implements ConstraintValidator { + + @Autowired; + private Foo aDependency; + + ... + } +---- + +As you can see, a ConstraintValidator implementation may have its dependencies +@Autowired like any other Spring bean. + + +[[validation-beanvalidation-spring-method]] +==== Spring-driven Method Validation +The method validation feature supported by Bean Validation 1.1, and as a custom +extension also by Hibernate Validator 4.3, can be integrated into a Spring context +through a `MethodValidationPostProcessor` bean definition: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + +---- + +In order to be eligible for Spring-driven method validation, all target classes need +to be annotated with Spring's `@Validated` annotation, optionally declaring the +validation groups to use. Check out the `MethodValidationPostProcessor` javadocs +for setup details with Hibernate Validator and Bean Validation 1.1 providers. + + +[[validation-beanvalidation-spring-other]] +==== Additional Configuration Options +The default `LocalValidatorFactoryBean` configuration should prove sufficient for most +cases. There are a number of configuration options for various Bean Validation +constructs, from message interpolation to traversal resolution. See the +`LocalValidatorFactoryBean` javadocs for more information on these options. + + + +[[validation-binder]] +=== Configuring a DataBinder +Since Spring 3, a DataBinder instance can be configured with a Validator. Once +configured, the Validator may be invoked by calling `binder.validate()`. Any validation +Errors are automatically added to the binder's BindingResult. + +When working with the DataBinder programmatically, this can be used to invoke validation +logic after binding to a target object: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + Foo target = new Foo(); + DataBinder binder = new DataBinder(target); + binder.setValidator(new FooValidator()); + + // bind to the target object + binder.bind(propertyValues); + + // validate the target object + binder.validate(); + + // get BindingResult that includes any validation errors + BindingResult results = binder.getBindingResult(); +---- + +A DataBinder can also be configured with multiple `Validator` instances via +`dataBinder.addValidators` and `dataBinder.replaceValidators`. This is useful when +combining globally configured Bean Validation with a Spring `Validator` configured +locally on a DataBinder instance. See <>. + + + +[[validation-mvc]] +=== Spring MVC 3 Validation +Beginning with Spring 3, Spring MVC has the ability to automatically validate +`@Controller` inputs. In previous versions it was up to the developer to manually invoke +validation logic. + + +[[validation-mvc-triggering]] +==== Triggering @Controller Input Validation +To trigger validation of a `@Controller` input, simply annotate the input argument as +++@Valid++: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + public class MyController { + + @RequestMapping("/foo", method=RequestMethod.POST) + public void processFoo(**@Valid** Foo foo) { /* ... */ } +---- + +Spring MVC will validate a @Valid object after binding so-long as an appropriate +Validator has been configured. + +[NOTE] +==== +The @Valid annotation is part of the standard JSR-303 Bean Validation API, and is not a +Spring-specific construct. +==== + + +[[validation-mvc-configuring]] +==== Configuring a Validator for use by Spring MVC +The `Validator` instance invoked when a `@Valid` method argument is encountered may be +configured in two ways. First, you may call `binder.setValidator(Validator)` within a +++@Controller++'s `@InitBinder` callback. This allows you to configure a `Validator` +instance per `@Controller` class: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + public class MyController { + + @InitBinder + protected void initBinder(WebDataBinder binder) { + binder.setValidator(new FooValidator()); + } + + @RequestMapping("/foo", method=RequestMethod.POST) + public void processFoo(@Valid Foo foo) { ... } + + } +---- + +Second, you may call `setValidator(Validator)` on the global `WebBindingInitializer`. This +allows you to configure a `Validator` instance across all `@Controller` classes. This can be +achieved easily by using the Spring MVC namespace: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + +---- + +To combine a global and a local validator, configure the global validator as shown above +and then add a local validator: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + public class MyController { + + @InitBinder + protected void initBinder(WebDataBinder binder) { + binder.addValidators(new FooValidator()); + } + + } +---- + + +[[validation-mvc-jsr303]] +==== Configuring a JSR-303/JSR-349 Validator for use by Spring MVC +With Bean Validation, a single `javax.validation.Validator` instance typically validates +__all__ model objects that declare validation constraints. To configure such a JSR-303 +backed Validator with Spring MVC, simply add a Bean Validation provider, such as +Hibernate Validator, to your classpath. Spring MVC will detect it and automatically +enable Bean Validation support across all Controllers. + +The Spring MVC configuration required to enable Bean Validation support is shown below: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + +---- + +With this minimal configuration, anytime a `@Valid` `@Controller` input is encountered, it +will be validated by the Bean Validation provider. That provider, in turn, will enforce +any constraints declared against the input. Any ++ConstraintViolation++s will automatically +be exposed as errors in the `BindingResult` renderable by standard Spring MVC form tags. + diff --git a/src/asciidoc/core.adoc b/src/asciidoc/core.adoc index 38dbfa5d8ee..eb3c20a87a7 100644 --- a/src/asciidoc/core.adoc +++ b/src/asciidoc/core.adoc @@ -27,5720 +27,16 @@ also provided. -- + include::core-beans.adoc[leveloffset=+1] +include::core-resources.adoc[leveloffset=+1] -[[resources]] -== Resources - - -[[resources-introduction]] -=== Introduction -Java's standard `java.net.URL` class and standard handlers for various URL prefixes -unfortunately are not quite adequate enough for all access to low-level resources. For -example, there is no standardized `URL` implementation that may be used to access a -resource that needs to be obtained from the classpath, or relative to a -`ServletContext`. While it is possible to register new handlers for specialized `URL` -prefixes (similar to existing handlers for prefixes such as `http:`), this is generally -quite complicated, and the `URL` interface still lacks some desirable functionality, -such as a method to check for the existence of the resource being pointed to. - - -[[resources-resource]] -=== The Resource interface - -Spring's `Resource` interface is meant to be a more capable interface for abstracting -access to low-level resources. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface Resource extends InputStreamSource { - - boolean exists(); - - boolean isOpen(); - - URL getURL() throws IOException; - - File getFile() throws IOException; - - Resource createRelative(String relativePath) throws IOException; - - String getFilename(); - - String getDescription(); - - } ----- - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface InputStreamSource { - - InputStream getInputStream() throws IOException; - - } ----- - -Some of the most important methods from the `Resource` interface are: - -* `getInputStream()`: locates and opens the resource, returning an `InputStream` for - reading from the resource. It is expected that each invocation returns a fresh - `InputStream`. It is the responsibility of the caller to close the stream. -* `exists()`: returns a `boolean` indicating whether this resource actually exists in - physical form. -* `isOpen()`: returns a `boolean` indicating whether this resource represents a handle - with an open stream. If `true`, the `InputStream` cannot be read multiple times, and - must be read once only and then closed to avoid resource leaks. Will be `false` for - all usual resource implementations, with the exception of `InputStreamResource`. -* `getDescription()`: returns a description for this resource, to be used for error - output when working with the resource. This is often the fully qualified file name or - the actual URL of the resource. - -Other methods allow you to obtain an actual `URL` or `File` object representing the -resource (if the underlying implementation is compatible, and supports that -functionality). - -The `Resource` abstraction is used extensively in Spring itself, as an argument type in -many method signatures when a resource is needed. Other methods in some Spring APIs -(such as the constructors to various `ApplicationContext` implementations), take a -`String` which in unadorned or simple form is used to create a `Resource` appropriate to -that context implementation, or via special prefixes on the `String` path, allow the -caller to specify that a specific `Resource` implementation must be created and used. - -While the `Resource` interface is used a lot with Spring and by Spring, it's actually -very useful to use as a general utility class by itself in your own code, for access to -resources, even when your code doesn't know or care about any other parts of Spring. -While this couples your code to Spring, it really only couples it to this small set of -utility classes, which are serving as a more capable replacement for `URL`, and can be -considered equivalent to any other library you would use for this purpose. - -It is important to note that the `Resource` abstraction does not replace functionality: -it wraps it where possible. For example, a `UrlResource` wraps a URL, and uses the -wrapped `URL` to do its work. - - - - -[[resources-implementations]] -=== Built-in Resource implementations - -There are a number of `Resource` implementations that come supplied straight out of the -box in Spring: - - - -[[resources-implementations-urlresource]] -==== UrlResource - -The `UrlResource` wraps a `java.net.URL`, and may be used to access any object that is -normally accessible via a URL, such as files, an HTTP target, an FTP target, etc. All -URLs have a standardized `String` representation, such that appropriate standardized -prefixes are used to indicate one URL type from another. This includes `file:` for -accessing filesystem paths, `http:` for accessing resources via the HTTP protocol, -`ftp:` for accessing resources via FTP, etc. - -A `UrlResource` is created by Java code explicitly using the `UrlResource` constructor, -but will often be created implicitly when you call an API method which takes a `String` -argument which is meant to represent a path. For the latter case, a JavaBeans -`PropertyEditor` will ultimately decide which type of `Resource` to create. If the path -string contains a few well-known (to it, that is) prefixes such as `classpath:`, it will -create an appropriate specialized `Resource` for that prefix. However, if it doesn't -recognize the prefix, it will assume the this is just a standard URL string, and will -create a `UrlResource`. - - - -[[resources-implementations-classpathresource]] -==== ClassPathResource - -This class represents a resource which should be obtained from the classpath. This uses -either the thread context class loader, a given class loader, or a given class for -loading resources. - -This `Resource` implementation supports resolution as `java.io.File` if the class path -resource resides in the file system, but not for classpath resources which reside in a -jar and have not been expanded (by the servlet engine, or whatever the environment is) -to the filesystem. To address this the various `Resource` implementations always support -resolution as a `java.net.URL`. - -A `ClassPathResource` is created by Java code explicitly using the `ClassPathResource` -constructor, but will often be created implicitly when you call an API method which -takes a `String` argument which is meant to represent a path. For the latter case, a -JavaBeans `PropertyEditor` will recognize the special prefix `classpath:` on the string -path, and create a `ClassPathResource` in that case. - - - -[[resources-implementations-filesystemresource]] -==== FileSystemResource - -This is a `Resource` implementation for `java.io.File` handles. It obviously supports -resolution as a `File`, and as a `URL`. - - - -[[resources-implementations-servletcontextresource]] -==== ServletContextResource - -This is a `Resource` implementation for `ServletContext` resources, interpreting -relative paths within the relevant web application's root directory. - -This always supports stream access and URL access, but only allows `java.io.File` access -when the web application archive is expanded and the resource is physically on the -filesystem. Whether or not it's expanded and on the filesystem like this, or accessed -directly from the JAR or somewhere else like a DB (it's conceivable) is actually -dependent on the Servlet container. - - - -[[resources-implementations-inputstreamresource]] -==== InputStreamResource - -A `Resource` implementation for a given `InputStream`. This should only be used if no -specific `Resource` implementation is applicable. In particular, prefer -`ByteArrayResource` or any of the file-based `Resource` implementations where possible. - -In contrast to other `Resource` implementations, this is a descriptor for an __already__ -opened resource - therefore returning `true` from `isOpen()`. Do not use it if you need -to keep the resource descriptor somewhere, or if you need to read a stream multiple -times. - - - -[[resources-implementations-bytearrayresource]] -==== ByteArrayResource - -This is a `Resource` implementation for a given byte array. It creates a -`ByteArrayInputStream` for the given byte array. - -It's useful for loading content from any given byte array, without having to resort to a -single-use `InputStreamResource`. - - - - -[[resources-resourceloader]] -=== The ResourceLoader - -The `ResourceLoader` interface is meant to be implemented by objects that can return -(i.e. load) `Resource` instances. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface ResourceLoader { - - Resource getResource(String location); - - } ----- - -All application contexts implement the `ResourceLoader` interface, and therefore all -application contexts may be used to obtain `Resource` instances. - -When you call `getResource()` on a specific application context, and the location path -specified doesn't have a specific prefix, you will get back a `Resource` type that is -appropriate to that particular application context. For example, assume the following -snippet of code was executed against a `ClassPathXmlApplicationContext` instance: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Resource template = ctx.getResource("some/resource/path/myTemplate.txt"); ----- - -What would be returned would be a `ClassPathResource`; if the same method was executed -against a `FileSystemXmlApplicationContext` instance, you'd get back a -`FileSystemResource`. For a `WebApplicationContext`, you'd get back a -`ServletContextResource`, and so on. - -As such, you can load resources in a fashion appropriate to the particular application -context. - -On the other hand, you may also force `ClassPathResource` to be used, regardless of the -application context type, by specifying the special `classpath:` prefix: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt"); ----- - -Similarly, one can force a `UrlResource` to be used by specifying any of the standard -`java.net.URL` prefixes: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt"); ----- - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Resource template = ctx.getResource("http://myhost.com/resource/path/myTemplate.txt"); ----- - -The following table summarizes the strategy for converting ++String++s to ++Resource++s: - -[[resources-resource-strings]] -.Resource strings -|=== -| Prefix| Example| Explanation - -| classpath: -| `classpath:com/myapp/config.xml` -| Loaded from the classpath. - -| file: -| `file:///data/config.xml` -| Loaded as a `URL`, from the filesystem. footnote:[But see also - pass:specialcharacters,macros[<>].] - -| http: -| `http://myserver/logo.png` -| Loaded as a `URL`. - -| (none) -| `/data/config.xml` -| Depends on the underlying `ApplicationContext`. -|=== - - - - -[[resources-resourceloaderaware]] -=== The ResourceLoaderAware interface - -The `ResourceLoaderAware` interface is a special marker interface, identifying objects -that expect to be provided with a `ResourceLoader` reference. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface ResourceLoaderAware { - - void setResourceLoader(ResourceLoader resourceLoader); - } ----- - -When a class implements `ResourceLoaderAware` and is deployed into an application -context (as a Spring-managed bean), it is recognized as `ResourceLoaderAware` by the -application context. The application context will then invoke the -`setResourceLoader(ResourceLoader)`, supplying itself as the argument (remember, all -application contexts in Spring implement the `ResourceLoader` interface). - -Of course, since an `ApplicationContext` is a `ResourceLoader`, the bean could also -implement the `ApplicationContextAware` interface and use the supplied application -context directly to load resources, but in general, it's better to use the specialized -`ResourceLoader` interface if that's all that's needed. The code would just be coupled -to the resource loading interface, which can be considered a utility interface, and not -the whole Spring `ApplicationContext` interface. - -As of Spring 2.5, you can rely upon autowiring of the `ResourceLoader` as an alternative -to implementing the `ResourceLoaderAware` interface. The "traditional" `constructor` and -`byType` autowiring modes (as described in <>) are now capable -of providing a dependency of type `ResourceLoader` for either a constructor argument or -setter method parameter respectively. For more flexibility (including the ability to -autowire fields and multiple parameter methods), consider using the new annotation-based -autowiring features. In that case, the `ResourceLoader` will be autowired into a field, -constructor argument, or method parameter that is expecting the `ResourceLoader` type as -long as the field, constructor, or method in question carries the `@Autowired` -annotation. For more information, see <>. - - - - -[[resources-as-dependencies]] -=== Resources as dependencies - -If the bean itself is going to determine and supply the resource path through some sort -of dynamic process, it probably makes sense for the bean to use the `ResourceLoader` -interface to load resources. Consider as an example the loading of a template of some -sort, where the specific resource that is needed depends on the role of the user. If the -resources are static, it makes sense to eliminate the use of the `ResourceLoader` -interface completely, and just have the bean expose the `Resource` properties it needs, -and expect that they will be injected into it. - -What makes it trivial to then inject these properties, is that all application contexts -register and use a special JavaBeans `PropertyEditor` which can convert `String` paths -to `Resource` objects. So if `myBean` has a template property of type `Resource`, it can -be configured with a simple string for that resource, as follows: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - ----- - -Note that the resource path has no prefix, so because the application context itself is -going to be used as the `ResourceLoader`, the resource itself will be loaded via a -`ClassPathResource`, `FileSystemResource`, or `ServletContextResource` (as appropriate) -depending on the exact type of the context. - -If there is a need to force a specific `Resource` type to be used, then a prefix may be -used. The following two examples show how to force a `ClassPathResource` and a -`UrlResource` (the latter being used to access a filesystem file). - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - ----- - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - ----- - - - - -[[resources-app-ctx]] -=== Application contexts and Resource paths - - - -[[resources-app-ctx-construction]] -==== Constructing application contexts -An application context constructor (for a specific application context type) generally -takes a string or array of strings as the location path(s) of the resource(s) such as -XML files that make up the definition of the context. - -When such a location path doesn't have a prefix, the specific `Resource` type built from -that path and used to load the bean definitions, depends on and is appropriate to the -specific application context. For example, if you create a -`ClassPathXmlApplicationContext` as follows: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml"); ----- - -The bean definitions will be loaded from the classpath, as a `ClassPathResource` will be -used. But if you create a `FileSystemXmlApplicationContext` as follows: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ApplicationContext ctx = - new FileSystemXmlApplicationContext("conf/appContext.xml"); ----- - -The bean definition will be loaded from a filesystem location, in this case relative to -the current working directory. - -Note that the use of the special classpath prefix or a standard URL prefix on the -location path will override the default type of `Resource` created to load the -definition. So this `FileSystemXmlApplicationContext`... - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ApplicationContext ctx = - new FileSystemXmlApplicationContext("classpath:conf/appContext.xml"); ----- - -... will actually load its bean definitions from the classpath. However, it is still a -`FileSystemXmlApplicationContext`. If it is subsequently used as a `ResourceLoader`, any -unprefixed paths will still be treated as filesystem paths. - - -[[resources-app-ctx-classpathxml]] -===== Constructing ClassPathXmlApplicationContext instances - shortcuts - -The `ClassPathXmlApplicationContext` exposes a number of constructors to enable -convenient instantiation. The basic idea is that one supplies merely a string array -containing just the filenames of the XML files themselves (without the leading path -information), and one __also__ supplies a `Class`; the `ClassPathXmlApplicationContext` -will derive the path information from the supplied class. - -An example will hopefully make this clear. Consider a directory layout that looks like -this: - -[literal] -[subs="verbatim,quotes"] ----- -com/ - foo/ - services.xml - daos.xml - MessengerService.class ----- - -A `ClassPathXmlApplicationContext` instance composed of the beans defined in the -`'services.xml'` and `'daos.xml'` could be instantiated like so... - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ApplicationContext ctx = new ClassPathXmlApplicationContext( - new String[] {"services.xml", "daos.xml"}, MessengerService.class); ----- - -Please do consult the `ClassPathXmlApplicationContext` javadocs for details -on the various constructors. - - - -[[resources-app-ctx-wildcards-in-resource-paths]] -==== Wildcards in application context constructor resource paths -The resource paths in application context constructor values may be a simple path (as -shown above) which has a one-to-one mapping to a target Resource, or alternately may -contain the special "classpath*:" prefix and/or internal Ant-style regular expressions -(matched using Spring's `PathMatcher` utility). Both of the latter are effectively -wildcards - -One use for this mechanism is when doing component-style application assembly. All -components can 'publish' context definition fragments to a well-known location path, and -when the final application context is created using the same path prefixed via -`classpath*:`, all component fragments will be picked up automatically. - -Note that this wildcarding is specific to use of resource paths in application context -constructors (or when using the `PathMatcher` utility class hierarchy directly), and is -resolved at construction time. It has nothing to do with the `Resource` type itself. -It's not possible to use the `classpath*:` prefix to construct an actual `Resource`, as -a resource points to just one resource at a time. - - -[[resources-app-ctx-ant-patterns-in-paths]] -===== Ant-style Patterns -When the path location contains an Ant-style pattern, for example: - -[literal] -[subs="verbatim"] ----- -/WEB-INF/*-context.xml - com/mycompany/**/applicationContext.xml - file:C:/some/path/*-context.xml - classpath:com/mycompany/**/applicationContext.xml ----- - -... the resolver follows a more complex but defined procedure to try to resolve the -wildcard. It produces a Resource for the path up to the last non-wildcard segment and -obtains a URL from it. If this URL is not a "jar:" URL or container-specific variant -(e.g. " `zip:`" in WebLogic, " `wsjar`" in WebSphere, etc.), then a `java.io.File` is -obtained from it and used to resolve the wildcard by traversing the filesystem. In the -case of a jar URL, the resolver either gets a `java.net.JarURLConnection` from it or -manually parses the jar URL and then traverses the contents of the jar file to resolve -the wildcards. - -[[resources-app-ctx-portability]] -====== Implications on portability -If the specified path is already a file URL (either explicitly, or implicitly because -the base `ResourceLoader` is a filesystem one, then wildcarding is guaranteed to work in -a completely portable fashion. - -If the specified path is a classpath location, then the resolver must obtain the last -non-wildcard path segment URL via a `Classloader.getResource()` call. Since this is just -a node of the path (not the file at the end) it is actually undefined (in the -`ClassLoader` javadocs) exactly what sort of a URL is returned in this case. In -practice, it is always a `java.io.File` representing the directory, where the classpath -resource resolves to a filesystem location, or a jar URL of some sort, where the -classpath resource resolves to a jar location. Still, there is a portability concern on -this operation. - -If a jar URL is obtained for the last non-wildcard segment, the resolver must be able to -get a `java.net.JarURLConnection` from it, or manually parse the jar URL, to be able to -walk the contents of the jar, and resolve the wildcard. This will work in most -environments, but will fail in others, and it is strongly recommended that the wildcard -resolution of resources coming from jars be thoroughly tested in your specific -environment before you rely on it. - - -[[resources-classpath-wildcards]] -===== The Classpath*: portability classpath*: prefix - -When constructing an XML-based application context, a location string may use the -special `classpath*:` prefix: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ApplicationContext ctx = - new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml"); ----- - -This special prefix specifies that all classpath resources that match the given name -must be obtained (internally, this essentially happens via a -`ClassLoader.getResources(...)` call), and then merged to form the final application -context definition. - -[NOTE] -==== -The wildcard classpath relies on the `getResources()` method of the underlying -classloader. As most application servers nowadays supply their own classloader -implementation, the behavior might differ especially when dealing with jar files. A -simple test to check if `classpath*` works is to use the classloader to load a file from -within a jar on the classpath: -`getClass().getClassLoader().getResources("")`. Try this test with -files that have the same name but are placed inside two different locations. In case an -inappropriate result is returned, check the application server documentation for -settings that might affect the classloader behavior. -==== - -The " `classpath*:`" prefix can also be combined with a `PathMatcher` pattern in the -rest of the location path, for example " `classpath*:META-INF/*-beans.xml`". In this -case, the resolution strategy is fairly simple: a ClassLoader.getResources() call is -used on the last non-wildcard path segment to get all the matching resources in the -class loader hierarchy, and then off each resource the same PathMatcher resolution -strategy described above is used for the wildcard subpath. - - -[[resources-wildcards-in-path-other-stuff]] -===== Other notes relating to wildcards -Please note that `classpath*:` when combined with Ant-style patterns will only work -reliably with at least one root directory before the pattern starts, unless the actual -target files reside in the file system. This means that a pattern like " -`classpath*:*.xml`" will not retrieve files from the root of jar files but rather only -from the root of expanded directories. This originates from a limitation in the JDK's -`ClassLoader.getResources()` method which only returns file system locations for a -passed-in empty string (indicating potential roots to search). - -Ant-style patterns with " `classpath:`" resources are not guaranteed to find matching -resources if the root package to search is available in multiple class path locations. -This is because a resource such as - -[literal] -[subs="verbatim,quotes"] ----- -com/mycompany/package1/service-context.xml ----- - -may be in only one location, but when a path such as - -[literal] -[subs="verbatim,quotes"] ----- -classpath:com/mycompany/**/service-context.xml ----- - -is used to try to resolve it, the resolver will work off the (first) URL returned by -`getResource("com/mycompany")`;. If this base package node exists in multiple -classloader locations, the actual end resource may not be underneath. Therefore, -preferably, use " `classpath*:`" with the same Ant-style pattern in such a case, which -will search all class path locations that contain the root package. - - - -[[resources-filesystemresource-caveats]] -==== FileSystemResource caveats - -A `FileSystemResource` that is not attached to a `FileSystemApplicationContext` (that -is, a `FileSystemApplicationContext` is not the actual `ResourceLoader`) will treat -absolute vs. relative paths as you would expect. Relative paths are relative to the -current working directory, while absolute paths are relative to the root of the -filesystem. - -For backwards compatibility (historical) reasons however, this changes when the -`FileSystemApplicationContext` is the `ResourceLoader`. The -`FileSystemApplicationContext` simply forces all attached `FileSystemResource` instances -to treat all location paths as relative, whether they start with a leading slash or not. -In practice, this means the following are equivalent: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ApplicationContext ctx = - new FileSystemXmlApplicationContext("conf/context.xml"); ----- - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ApplicationContext ctx = - new FileSystemXmlApplicationContext("/conf/context.xml"); ----- - -As are the following: (Even though it would make sense for them to be different, as one -case is relative and the other absolute.) - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - FileSystemXmlApplicationContext ctx = ...; - ctx.getResource("some/resource/path/myTemplate.txt"); ----- - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - FileSystemXmlApplicationContext ctx = ...; - ctx.getResource("/some/resource/path/myTemplate.txt"); ----- - -In practice, if true absolute filesystem paths are needed, it is better to forgo the use -of absolute paths with `FileSystemResource` / `FileSystemXmlApplicationContext`, and -just force the use of a `UrlResource`, by using the `file:` URL prefix. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // actual context type doesn't matter, the Resource will always be UrlResource - ctx.getResource("file:///some/resource/path/myTemplate.txt"); ----- - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // force this FileSystemXmlApplicationContext to load its definition via a UrlResource - ApplicationContext ctx = - new FileSystemXmlApplicationContext("file:///conf/context.xml"); ----- - - - -[[validation]] -== Validation, Data Binding, and Type Conversion - - - - -[[validation-introduction]] -=== Introduction - -.JSR-303/JSR-349 Bean Validation -**** -Spring Framework 4.0 supports Bean Validation 1.0 (JSR-303) and Bean Validation 1.1 -(JSR-349) in terms of setup support, also adapting it to Spring's `Validator` interface. - -An application can choose to enable Bean Validation once globally, as described in -<>, and use it exclusively for all validation needs. - -An application can also register additional Spring `Validator` instances per -`DataBinder` instance, as described in <>. This may be useful for -plugging in validation logic without the use of annotations. -**** - -There are pros and cons for considering validation as business logic, and Spring offers -a design for validation (and data binding) that does not exclude either one of them. -Specifically validation should not be tied to the web tier, should be easy to localize -and it should be possible to plug in any validator available. Considering the above, -Spring has come up with a `Validator` interface that is both basic ands eminently usable -in every layer of an application. - -Data binding is useful for allowing user input to be dynamically bound to the domain -model of an application (or whatever objects you use to process user input). Spring -provides the so-called `DataBinder` to do exactly that. The `Validator` and the -`DataBinder` make up the `validation` package, which is primarily used in but not -limited to the MVC framework. - -The `BeanWrapper` is a fundamental concept in the Spring Framework and is used in a lot -of places. However, you probably will not have the need to use the `BeanWrapper` -directly. Because this is reference documentation however, we felt that some explanation -might be in order. We will explain the `BeanWrapper` in this chapter since, if you were -going to use it at all, you would most likely do so when trying to bind data to objects. - -Spring's DataBinder and the lower-level BeanWrapper both use PropertyEditors to parse -and format property values. The `PropertyEditor` concept is part of the JavaBeans -specification, and is also explained in this chapter. Spring 3 introduces a -"core.convert" package that provides a general type conversion facility, as well as a -higher-level "format" package for formatting UI field values. These new packages may be -used as simpler alternatives to PropertyEditors, and will also be discussed in this -chapter. - - - - -[[validator]] -=== Validation using Spring's Validator interface - -Spring features a `Validator` interface that you can use to validate objects. The -`Validator` interface works using an `Errors` object so that while validating, -validators can report validation failures to the `Errors` object. - -Let's consider a small data object: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class Person { - - private String name; - private int age; - - // the usual getters and setters... - } ----- - -We're going to provide validation behavior for the `Person` class by implementing the -following two methods of the `org.springframework.validation.Validator` interface: - -* `supports(Class)` - Can this `Validator` validate instances of the supplied `Class`? -* `validate(Object, org.springframework.validation.Errors)` - validates the given object - and in case of validation errors, registers those with the given `Errors` object - -Implementing a `Validator` is fairly straightforward, especially when you know of the -`ValidationUtils` helper class that the Spring Framework also provides. - -[source,java,indent=0] -[subs="verbatim"] ----- - public class PersonValidator implements Validator { - - /** - * This Validator validates *just* Person instances - */ - public boolean supports(Class clazz) { - return Person.class.equals(clazz); - } - - public void validate(Object obj, Errors e) { - ValidationUtils.rejectIfEmpty(e, "name", "name.empty"); - Person p = (Person) obj; - if (p.getAge() < 0) { - e.rejectValue("age", "negativevalue"); - } else if (p.getAge() > 110) { - e.rejectValue("age", "too.darn.old"); - } - } - } ----- - -As you can see, the `static` `rejectIfEmpty(..)` method on the `ValidationUtils` class -is used to reject the `'name'` property if it is `null` or the empty string. Have a look -at the `ValidationUtils` javadocs to see what functionality it provides besides the -example shown previously. - -While it is certainly possible to implement a single `Validator` class to validate each -of the nested objects in a rich object, it may be better to encapsulate the validation -logic for each nested class of object in its own `Validator` implementation. A simple -example of a __'rich'__ object would be a `Customer` that is composed of two `String` -properties (a first and second name) and a complex `Address` object. `Address` objects -may be used independently of `Customer` objects, and so a distinct `AddressValidator` -has been implemented. If you want your `CustomerValidator` to reuse the logic contained -within the `AddressValidator` class without resorting to copy-and-paste, you can -dependency-inject or instantiate an `AddressValidator` within your `CustomerValidator`, -and use it like so: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class CustomerValidator implements Validator { - - private final Validator addressValidator; - - public CustomerValidator(Validator addressValidator) { - if (addressValidator == null) { - throw new IllegalArgumentException("The supplied [Validator] is " + - "required and must not be null."); - } - if (!addressValidator.supports(Address.class)) { - throw new IllegalArgumentException("The supplied [Validator] must " + - support the validation of [Address] instances."); - } - this.addressValidator = addressValidator; - } - - /** - * This Validator validates Customer instances, and any subclasses of Customer too - */ - public boolean supports(Class clazz) { - return Customer.class.isAssignableFrom(clazz); - } - - public void validate(Object target, Errors errors) { - ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "field.required"); - ValidationUtils.rejectIfEmptyOrWhitespace(errors, "surname", "field.required"); - Customer customer = (Customer) target; - try { - errors.pushNestedPath("address"); - ValidationUtils.invokeValidator(this.addressValidator, customer.getAddress(), errors); - } finally { - errors.popNestedPath(); - } - } - } ----- - -Validation errors are reported to the `Errors` object passed to the validator. In case -of Spring Web MVC you can use `` tag to inspect the error messages, but of -course you can also inspect the errors object yourself. More information about the -methods it offers can be found in the javadocs. - - - - -[[validation-conversion]] -=== Resolving codes to error messages -We've talked about databinding and validation. Outputting messages corresponding to -validation errors is the last thing we need to discuss. In the example we've shown -above, we rejected the `name` and the `age` field. If we're going to output the error -messages by using a `MessageSource`, we will do so using the error code we've given when -rejecting the field ('name' and 'age' in this case). When you call (either directly, or -indirectly, using for example the `ValidationUtils` class) `rejectValue` or one of the -other `reject` methods from the `Errors` interface, the underlying implementation will -not only register the code you've passed in, but also a number of additional error -codes. What error codes it registers is determined by the `MessageCodesResolver` that is -used. By default, the `DefaultMessageCodesResolver` is used, which for example not only -registers a message with the code you gave, but also messages that include the field -name you passed to the reject method. So in case you reject a field using -`rejectValue("age", "too.darn.old")`, apart from the `too.darn.old` code, Spring will -also register `too.darn.old.age` and `too.darn.old.age.int` (so the first will include -the field name and the second will include the type of the field); this is done as a -convenience to aid developers in targeting error messages and suchlike. - -More information on the `MessageCodesResolver` and the default strategy can be found -online in the javadocs of -{javadoc-baseurl}/org/springframework/validation/MessageCodesResolver.html[`MessageCodesResolver`] -and -{javadoc-baseurl}/org/springframework/validation/DefaultMessageCodesResolver.html[`DefaultMessageCodesResolver`], -respectively. - - - - -[[beans-beans]] -=== Bean manipulation and the BeanWrapper - -The `org.springframework.beans` package adheres to the JavaBeans standard provided by -Oracle. A JavaBean is simply a class with a default no-argument constructor, which follows -a naming convention where (by way of an example) a property named `bingoMadness` would -have a setter method `setBingoMadness(..)` and a getter method `getBingoMadness()`. For -more information about JavaBeans and the specification, please refer to Oracle's website ( -http://docs.oracle.com/javase/6/docs/api/java/beans/package-summary.html[javabeans]). - -One quite important class in the beans package is the `BeanWrapper` interface and its -corresponding implementation ( `BeanWrapperImpl`). As quoted from the javadocs, the -`BeanWrapper` offers functionality to set and get property values (individually or in -bulk), get property descriptors, and to query properties to determine if they are -readable or writable. Also, the `BeanWrapper` offers support for nested properties, -enabling the setting of properties on sub-properties to an unlimited depth. Then, the -`BeanWrapper` supports the ability to add standard JavaBeans `PropertyChangeListeners` -and `VetoableChangeListeners`, without the need for supporting code in the target class. -Last but not least, the `BeanWrapper` provides support for the setting of indexed -properties. The `BeanWrapper` usually isn't used by application code directly, but by -the `DataBinder` and the `BeanFactory`. - -The way the `BeanWrapper` works is partly indicated by its name: __it wraps a bean__ to -perform actions on that bean, like setting and retrieving properties. - - - -[[beans-beans-conventions]] -==== Setting and getting basic and nested properties -Setting and getting properties is done using the `setPropertyValue(s)` and -`getPropertyValue(s)` methods that both come with a couple of overloaded variants. -They're all described in more detail in the javadocs Spring comes with. What's important -to know is that there are a couple of conventions for indicating properties of an -object. A couple of examples: - -[[beans-beans-conventions-properties-tbl]] -.Examples of properties -|=== -| Expression| Explanation - -| `name` -| Indicates the property `name` corresponding to the methods `getName()` or `isName()` - and `setName(..)` - -| `account.name` -| Indicates the nested property `name` of the property `account` corresponding e.g. to - the methods `getAccount().setName()` or `getAccount().getName()` - -| `account[2]` -| Indicates the __third__ element of the indexed property `account`. Indexed properties - can be of type `array`, `list` or other __naturally ordered__ collection - -| `account[COMPANYNAME]` -| Indicates the value of the map entry indexed by the key __COMPANYNAME__ of the Map - property `account` -|=== - -Below you'll find some examples of working with the `BeanWrapper` to get and set -properties. - -__(This next section is not vitally important to you if you're not planning to work with -the `BeanWrapper` directly. If you're just using the `DataBinder` and the `BeanFactory` -and their out-of-the-box implementation, you should skip ahead to the section about -`PropertyEditors`.)__ - -Consider the following two classes: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class Company { - - private String name; - private Employee managingDirector; - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - public Employee getManagingDirector() { - return this.managingDirector; - } - - public void setManagingDirector(Employee managingDirector) { - this.managingDirector = managingDirector; - } - } ----- - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class Employee { - - private String name; - - private float salary; - - public String getName() { - return this.name; - } - - public void setName(String name) { - this.name = name; - } - - public float getSalary() { - return salary; - } - - public void setSalary(float salary) { - this.salary = salary; - } - } ----- - -The following code snippets show some examples of how to retrieve and manipulate some of -the properties of instantiated `Companies` and `Employees`: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - BeanWrapper company = BeanWrapperImpl(new Company()); - // setting the company name.. - company.setPropertyValue("name", "Some Company Inc."); - // ... can also be done like this: - PropertyValue value = new PropertyValue("name", "Some Company Inc."); - company.setPropertyValue(value); - - // ok, let's create the director and tie it to the company: - BeanWrapper jim = BeanWrapperImpl(new Employee()); - jim.setPropertyValue("name", "Jim Stravinsky"); - company.setPropertyValue("managingDirector", jim.getWrappedInstance()); - - // retrieving the salary of the managingDirector through the company - Float salary = (Float) company.getPropertyValue("managingDirector.salary"); ----- - - - -[[beans-beans-conversion]] -==== Built-in PropertyEditor implementations - -Spring uses the concept of `PropertyEditors` to effect the conversion between an -`Object` and a `String`. If you think about it, it sometimes might be handy to be able -to represent properties in a different way than the object itself. For example, a `Date` -can be represented in a human readable way (as the `String` ' `2007-14-09`'), while -we're still able to convert the human readable form back to the original date (or even -better: convert any date entered in a human readable form, back to `Date` objects). This -behavior can be achieved by __registering custom editors__, of type -`java.beans.PropertyEditor`. Registering custom editors on a `BeanWrapper` or -alternately in a specific IoC container as mentioned in the previous chapter, gives it -the knowledge of how to convert properties to the desired type. Read more about -`PropertyEditors` in the javadocs of the `java.beans` package provided by Oracle. - -A couple of examples where property editing is used in Spring: - -* __setting properties on beans__ is done using `PropertyEditors`. When mentioning - `java.lang.String` as the value of a property of some bean you're declaring in XML - file, Spring will (if the setter of the corresponding property has a - `Class`-parameter) use the `ClassEditor` to try to resolve the parameter to a `Class` - object. -* __parsing HTTP request parameters__ in Spring's MVC framework is done using all kinds - of `PropertyEditors` that you can manually bind in all subclasses of the - `CommandController`. - -Spring has a number of built-in `PropertyEditors` to make life easy. Each of those is -listed below and they are all located in the `org.springframework.beans.propertyeditors` -package. Most, but not all (as indicated below), are registered by default by -`BeanWrapperImpl`. Where the property editor is configurable in some fashion, you can of -course still register your own variant to override the default one: - -[[beans-beans-property-editors-tbl]] -.Built-in PropertyEditors -|=== -| Class| Explanation - -| `ByteArrayPropertyEditor` -| Editor for byte arrays. Strings will simply be converted to their corresponding byte - representations. Registered by default by `BeanWrapperImpl`. - -| `ClassEditor` -| Parses Strings representing classes to actual classes and the other way around. When a - class is not found, an `IllegalArgumentException` is thrown. Registered by default by - `BeanWrapperImpl`. - -| `CustomBooleanEditor` -| Customizable property editor for `Boolean` properties. Registered by default by - `BeanWrapperImpl`, but, can be overridden by registering custom instance of it as - custom editor. - -| `CustomCollectionEditor` -| Property editor for Collections, converting any source `Collection` to a given target - `Collection` type. - -| `CustomDateEditor` -| Customizable property editor for java.util.Date, supporting a custom DateFormat. NOT - registered by default. Must be user registered as needed with appropriate format. - -| `CustomNumberEditor` -| Customizable property editor for any Number subclass like `Integer`, `Long`, `Float`, - `Double`. Registered by default by `BeanWrapperImpl`, but can be overridden by - registering custom instance of it as a custom editor. - -| `FileEditor` -| Capable of resolving Strings to `java.io.File` objects. Registered by default by - `BeanWrapperImpl`. - -| `InputStreamEditor` -| One-way property editor, capable of taking a text string and producing (via an - intermediate `ResourceEditor` and `Resource`) an `InputStream`, so `InputStream` - properties may be directly set as Strings. Note that the default usage will not close - the `InputStream` for you! Registered by default by `BeanWrapperImpl`. - -| `LocaleEditor` -| Capable of resolving Strings to `Locale` objects and vice versa (the String format is - [language]_[country]_[variant], which is the same thing the toString() method of - Locale provides). Registered by default by `BeanWrapperImpl`. - -| `PatternEditor` -| Capable of resolving Strings to `java.util.regex.Pattern` objects and vice versa. - -| `PropertiesEditor` -| Capable of converting Strings (formatted using the format as defined in the javadocs - of the `java.util.Properties` class) to `Properties` objects. Registered by default - by `BeanWrapperImpl`. - -| `StringTrimmerEditor` -| Property editor that trims Strings. Optionally allows transforming an empty string - into a `null` value. NOT registered by default; must be user registered as needed. - -| `URLEditor` -| Capable of resolving a String representation of a URL to an actual `URL` object. - Registered by default by `BeanWrapperImpl`. -|=== - -Spring uses the `java.beans.PropertyEditorManager` to set the search path for property -editors that might be needed. The search path also includes `sun.bean.editors`, which -includes `PropertyEditor` implementations for types such as `Font`, `Color`, and most of -the primitive types. Note also that the standard JavaBeans infrastructure will -automatically discover `PropertyEditor` classes (without you having to register them -explicitly) if they are in the same package as the class they handle, and have the same -name as that class, with `'Editor'` appended; for example, one could have the following -class and package structure, which would be sufficient for the `FooEditor` class to be -recognized and used as the `PropertyEditor` for `Foo`-typed properties. - -[literal] -[subs="verbatim,quotes"] ----- -com - chank - pop - Foo - FooEditor // the PropertyEditor for the Foo class ----- - -Note that you can also use the standard `BeanInfo` JavaBeans mechanism here as well -(described -http://docs.oracle.com/javase/tutorial/javabeans/advanced/customization.html[in -not-amazing-detail here]). Find below an example of using the `BeanInfo` mechanism for -explicitly registering one or more `PropertyEditor` instances with the properties of an -associated class. - -[literal] -[subs="verbatim,quotes"] ----- -com - chank - pop - Foo - FooBeanInfo // the BeanInfo for the Foo class ----- - -Here is the Java source code for the referenced `FooBeanInfo` class. This would -associate a `CustomNumberEditor` with the `age` property of the `Foo` class. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class FooBeanInfo extends SimpleBeanInfo { - - public PropertyDescriptor[] getPropertyDescriptors() { - try { - final PropertyEditor numberPE = new CustomNumberEditor(Integer.class, true); - PropertyDescriptor ageDescriptor = new PropertyDescriptor("age", Foo.class) { - public PropertyEditor createPropertyEditor(Object bean) { - return numberPE; - }; - }; - return new PropertyDescriptor[] { ageDescriptor }; - } - catch (IntrospectionException ex) { - throw new Error(ex.toString()); - } - } - } ----- - - -[[beans-beans-conversion-customeditor-registration]] -===== Registering additional custom PropertyEditors - -When setting bean properties as a string value, a Spring IoC container ultimately uses -standard JavaBeans `PropertyEditors` to convert these Strings to the complex type of the -property. Spring pre-registers a number of custom `PropertyEditors` (for example, to -convert a classname expressed as a string into a real `Class` object). Additionally, -Java's standard JavaBeans `PropertyEditor` lookup mechanism allows a `PropertyEditor` -for a class simply to be named appropriately and placed in the same package as the class -it provides support for, to be found automatically. - -If there is a need to register other custom `PropertyEditors`, there are several -mechanisms available. The most manual approach, which is not normally convenient or -recommended, is to simply use the `registerCustomEditor()` method of the -`ConfigurableBeanFactory` interface, assuming you have a `BeanFactory` reference. -Another, slightly more convenient, mechanism is to use a special bean factory -post-processor called `CustomEditorConfigurer`. Although bean factory post-processors -can be used with `BeanFactory` implementations, the `CustomEditorConfigurer` has a -nested property setup, so it is strongly recommended that it is used with the -`ApplicationContext`, where it may be deployed in similar fashion to any other bean, and -automatically detected and applied. - -Note that all bean factories and application contexts automatically use a number of -built-in property editors, through their use of something called a `BeanWrapper` to -handle property conversions. The standard property editors that the `BeanWrapper` -registers are listed in <>. Additionally, -`ApplicationContexts` also override or add an additional number of editors to handle -resource lookups in a manner appropriate to the specific application context type. - -Standard JavaBeans `PropertyEditor` instances are used to convert property values -expressed as strings to the actual complex type of the property. -`CustomEditorConfigurer`, a bean factory post-processor, may be used to conveniently add -support for additional `PropertyEditor` instances to an `ApplicationContext`. - -Consider a user class `ExoticType`, and another class `DependsOnExoticType` which needs -`ExoticType` set as a property: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package example; - - public class ExoticType { - - private String name; - - public ExoticType(String name) { - this.name = name; - } - } - - public class DependsOnExoticType { - - private ExoticType type; - - public void setType(ExoticType type) { - this.type = type; - } - } ----- - -When things are properly set up, we want to be able to assign the type property as a -string, which a `PropertyEditor` will behind the scenes convert into an actual -`ExoticType` instance: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - ----- - -The `PropertyEditor` implementation could look similar to this: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // converts string representation to ExoticType object - package example; - - public class ExoticTypeEditor extends PropertyEditorSupport { - - public void setAsText(String text) { - setValue(new ExoticType(text.toUpperCase())); - } - } ----- - -Finally, we use `CustomEditorConfigurer` to register the new `PropertyEditor` with the -`ApplicationContext`, which will then be able to use it as needed: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - ----- - -[[beans-beans-conversion-customeditor-registration-per]] -====== Using PropertyEditorRegistrars - -Another mechanism for registering property editors with the Spring container is to -create and use a `PropertyEditorRegistrar`. This interface is particularly useful when -you need to use the same set of property editors in several different situations: write -a corresponding registrar and reuse that in each case. `PropertyEditorRegistrars` work -in conjunction with an interface called `PropertyEditorRegistry`, an interface that is -implemented by the Spring `BeanWrapper` (and `DataBinder`). `PropertyEditorRegistrars` -are particularly convenient when used in conjunction with the `CustomEditorConfigurer` -(introduced <>), which exposes a -property called `setPropertyEditorRegistrars(..)`: `PropertyEditorRegistrars` added to a -`CustomEditorConfigurer` in this fashion can easily be shared with `DataBinder` and -Spring MVC `Controllers`. Furthermore, it avoids the need for synchronization on custom -editors: a `PropertyEditorRegistrar` is expected to create fresh `PropertyEditor` -instances for each bean creation attempt. - -Using a `PropertyEditorRegistrar` is perhaps best illustrated with an example. First -off, you need to create your own `PropertyEditorRegistrar` implementation: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package com.foo.editors.spring; - - public final class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar { - - public void registerCustomEditors(PropertyEditorRegistry registry) { - - // it is expected that new PropertyEditor instances are created - registry.registerCustomEditor(ExoticType.class, new ExoticTypeEditor()); - - // you could register as many custom property editors as are required here... - } - } ----- - -See also the `org.springframework.beans.support.ResourceEditorRegistrar` for an example -`PropertyEditorRegistrar` implementation. Notice how in its implementation of the -`registerCustomEditors(..)` method it creates new instances of each property editor. - -Next we configure a `CustomEditorConfigurer` and inject an instance of our -`CustomPropertyEditorRegistrar` into it: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - ----- - -Finally, and in a bit of a departure from the focus of this chapter, for those of you -using <>, using `PropertyEditorRegistrars` in -conjunction with data-binding `Controllers` (such as `SimpleFormController`) can be very -convenient. Find below an example of using a `PropertyEditorRegistrar` in the -implementation of an `initBinder(..)` method: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public final class RegisterUserController extends SimpleFormController { - - private final PropertyEditorRegistrar customPropertyEditorRegistrar; - - public RegisterUserController(PropertyEditorRegistrar propertyEditorRegistrar) { - this.customPropertyEditorRegistrar = propertyEditorRegistrar; - } - - protected void initBinder(HttpServletRequest request, - ServletRequestDataBinder binder) throws Exception { - **this.customPropertyEditorRegistrar.registerCustomEditors(binder);** - } - - // other methods to do with registering a User - } ----- - -This style of `PropertyEditor` registration can lead to concise code (the implementation -of `initBinder(..)` is just one line long!), and allows common `PropertyEditor` -registration code to be encapsulated in a class and then shared amongst as many -`Controllers` as needed. - - - - -[[core-convert]] -=== Spring Type Conversion -Spring 3 introduces a `core.convert` package that provides a general type conversion -system. The system defines an SPI to implement type conversion logic, as well as an API -to execute type conversions at runtime. Within a Spring container, this system can be -used as an alternative to PropertyEditors to convert externalized bean property value -strings to required property types. The public API may also be used anywhere in your -application where type conversion is needed. - - - -[[core-convert-Converter-API]] -==== Converter SPI -The SPI to implement type conversion logic is simple and strongly typed: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.core.convert.converter; - - public interface Converter { - - T convert(S source); - - } ----- - -To create your own converter, simply implement the interface above. Parameterize `S` -as the type you are converting from, and `T` as the type you are converting to. Such a -converter can also be applied transparently if a collection or array of `S` needs to be -converted to an array or collection of `T`, provided that a delegating array/collection -converter has been registered as well (which `DefaultConversionService` does by default). - -For each call to `convert(S)`, the source argument is guaranteed to be NOT null. Your -Converter may throw any unchecked exception if conversion fails; specifically, an -`IllegalArgumentException` should be thrown to report an invalid source value. -Take care to ensure that your `Converter` implementation is thread-safe. - -Several converter implementations are provided in the `core.convert.support` package as -a convenience. These include converters from Strings to Numbers and other common types. -Consider `StringToInteger` as an example for a typical `Converter` implementation: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.core.convert.support; - - final class StringToInteger implements Converter { - - public Integer convert(String source) { - return Integer.valueOf(source); - } - - } ----- - - - -[[core-convert-ConverterFactory-SPI]] -==== ConverterFactory -When you need to centralize the conversion logic for an entire class hierarchy, for -example, when converting from String to java.lang.Enum objects, implement -`ConverterFactory`: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.core.convert.converter; - - public interface ConverterFactory { - - Converter getConverter(Class targetType); - - } ----- - -Parameterize S to be the type you are converting from and R to be the base type defining -the __range__ of classes you can convert to. Then implement getConverter(Class), -where T is a subclass of R. - -Consider the `StringToEnum` ConverterFactory as an example: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.core.convert.support; - - final class StringToEnumConverterFactory implements ConverterFactory { - - public Converter getConverter(Class targetType) { - return new StringToEnumConverter(targetType); - } - - private final class StringToEnumConverter implements Converter { - - private Class enumType; - - public StringToEnumConverter(Class enumType) { - this.enumType = enumType; - } - - public T convert(String source) { - return (T) Enum.valueOf(this.enumType, source.trim()); - } - } - } ----- - - - -[[core-convert-GenericConverter-SPI]] -==== GenericConverter -When you require a sophisticated Converter implementation, consider the GenericConverter -interface. With a more flexible but less strongly typed signature, a GenericConverter -supports converting between multiple source and target types. In addition, a -GenericConverter makes available source and target field context you can use when -implementing your conversion logic. Such context allows a type conversion to be driven -by a field annotation, or generic information declared on a field signature. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.core.convert.converter; - - public interface GenericConverter { - - public Set getConvertibleTypes(); - - Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType); - - } ----- - -To implement a GenericConverter, have getConvertibleTypes() return the supported -source->target type pairs. Then implement convert(Object, TypeDescriptor, -TypeDescriptor) to implement your conversion logic. The source TypeDescriptor provides -access to the source field holding the value being converted. The target TypeDescriptor -provides access to the target field where the converted value will be set. - -A good example of a GenericConverter is a converter that converts between a Java Array -and a Collection. Such an ArrayToCollectionConverter introspects the field that declares -the target Collection type to resolve the Collection's element type. This allows each -element in the source array to be converted to the Collection element type before the -Collection is set on the target field. - -[NOTE] -==== -Because GenericConverter is a more complex SPI interface, only use it when you need it. -Favor Converter or ConverterFactory for basic type conversion needs. -==== - - -[[core-convert-ConditionalGenericConverter-SPI]] -===== ConditionalGenericConverter -Sometimes you only want a Converter to execute if a specific condition holds true. For -example, you might only want to execute a Converter if a specific annotation is present -on the target field. Or you might only want to execute a Converter if a specific method, -such as static valueOf method, is defined on the target class. -ConditionalGenericConverter is an subinterface of GenericConverter that allows you to -define such custom matching criteria: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface ConditionalGenericConverter extends GenericConverter { - - boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType); - - } ----- - -A good example of a ConditionalGenericConverter is an EntityConverter that converts -between an persistent entity identifier and an entity reference. Such a EntityConverter -might only match if the target entity type declares a static finder method e.g. -findAccount(Long). You would perform such a finder method check in the implementation of -matches(TypeDescriptor, TypeDescriptor). - - - -[[core-convert-ConversionService-API]] -==== ConversionService API -The ConversionService defines a unified API for executing type conversion logic at -runtime. Converters are often executed behind this facade interface: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.core.convert; - - public interface ConversionService { - - boolean canConvert(Class sourceType, Class targetType); - - T convert(Object source, Class targetType); - - boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType); - - Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType); - - } ----- - -Most ConversionService implementations also implement `ConverterRegistry`, which -provides an SPI for registering converters. Internally, a ConversionService -implementation delegates to its registered converters to carry out type conversion logic. - -A robust ConversionService implementation is provided in the `core.convert.support` -package. `GenericConversionService` is the general-purpose implementation suitable for -use in most environments. `ConversionServiceFactory` provides a convenient factory for -creating common ConversionService configurations. - - - -[[core-convert-Spring-config]] -==== Configuring a ConversionService -A ConversionService is a stateless object designed to be instantiated at application -startup, then shared between multiple threads. In a Spring application, you typically -configure a ConversionService instance per Spring container (or ApplicationContext). -That ConversionService will be picked up by Spring and then used whenever a type -conversion needs to be performed by the framework. You may also inject this -ConversionService into any of your beans and invoke it directly. - -[NOTE] -==== -If no ConversionService is registered with Spring, the original PropertyEditor-based -system is used. -==== - -To register a default ConversionService with Spring, add the following bean definition -with id `conversionService`: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - ----- - -A default ConversionService can convert between strings, numbers, enums, collections, -maps, and other common types. To supplement or override the default converters with your -own custom converter(s), set the `converters` property. Property values may implement -either of the Converter, ConverterFactory, or GenericConverter interfaces. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - ----- - -It is also common to use a ConversionService within a Spring MVC application. See -<> for details on use with ``. - -In certain situations you may wish to apply formatting during conversion. See -<> for details on using -`FormattingConversionServiceFactoryBean`. - - - -[[core-convert-programmatic-usage]] -==== Using a ConversionService programmatically -To work with a ConversionService instance programmatically, simply inject a reference to -it like you would for any other bean: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Service - public class MyService { - - @Autowired - public MyService(ConversionService conversionService) { - this.conversionService = conversionService; - } - - public void doIt() { - this.conversionService.convert(...) - } - } ----- - -For most use cases, the `convert` method specifying the _targetType_ can be used but it -will not work with more complex types such as a collection of a parameterized element. -If you want to convert a `List` of `Integer` to a `List` of `String` programmatically, -for instance, you need to provide a formal definition of the source and target types. - -Fortunately, `TypeDescriptor` provides various options to make that straightforward: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - DefaultConversionService cs = new DefaultConversionService(); - - List input = .... - cs.convert(input, - TypeDescriptor.forObject(input), // List type descriptor - TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class))); ----- - -Note that `DefaultConversionService` registers converters automatically which are -appropriate for most environments. This includes collection converters, scalar -converters, and also basic `Object` to `String` converters. The same converters can -be registered with any `ConverterRegistry` using the _static_ `addDefaultConverters` -method on the `DefaultConversionService` class. - -Converters for value types will be reused for arrays and collections, so there is -no need to create a specific converter to convert from a `Collection` of `S` to a -`Collection` of `T`, assuming that standard collection handling is appropriate. - - - - -[[format]] -=== Spring Field Formatting -As discussed in the previous section, <> is a -general-purpose type conversion system. It provides a unified ConversionService API as -well as a strongly-typed Converter SPI for implementing conversion logic from one type -to another. A Spring Container uses this system to bind bean property values. In -addition, both the Spring Expression Language (SpEL) and DataBinder use this system to -bind field values. For example, when SpEL needs to coerce a `Short` to a `Long` to -complete an `expression.setValue(Object bean, Object value)` attempt, the core.convert -system performs the coercion. - -Now consider the type conversion requirements of a typical client environment such as a -web or desktop application. In such environments, you typically convert __from String__ -to support the client postback process, as well as back __to String__ to support the -view rendering process. In addition, you often need to localize String values. The more -general __core.convert__ Converter SPI does not address such __formatting__ requirements -directly. To directly address them, Spring 3 introduces a convenient Formatter SPI that -provides a simple and robust alternative to PropertyEditors for client environments. - -In general, use the Converter SPI when you need to implement general-purpose type -conversion logic; for example, for converting between a java.util.Date and and -java.lang.Long. Use the Formatter SPI when you're working in a client environment, such -as a web application, and need to parse and print localized field values. The -ConversionService provides a unified type conversion API for both SPIs. - - - -[[format-Formatter-SPI]] -==== Formatter SPI -The Formatter SPI to implement field formatting logic is simple and strongly typed: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.format; - - public interface Formatter extends Printer, Parser { - } ----- - -Where Formatter extends from the Printer and Parser building-block interfaces: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface Printer { - String print(T fieldValue, Locale locale); - } ----- - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - import java.text.ParseException; - - public interface Parser { - T parse(String clientValue, Locale locale) throws ParseException; - } ----- - -To create your own Formatter, simply implement the Formatter interface above. -Parameterize T to be the type of object you wish to format, for example, -`java.util.Date`. Implement the `print()` operation to print an instance of T for -display in the client locale. Implement the `parse()` operation to parse an instance of -T from the formatted representation returned from the client locale. Your Formatter -should throw a ParseException or IllegalArgumentException if a parse attempt fails. Take -care to ensure your Formatter implementation is thread-safe. - -Several Formatter implementations are provided in `format` subpackages as a convenience. -The `number` package provides a `NumberFormatter`, `CurrencyFormatter`, and -`PercentFormatter` to format `java.lang.Number` objects using a `java.text.NumberFormat`. -The `datetime` package provides a `DateFormatter` to format `java.util.Date` objects with -a `java.text.DateFormat`. The `datetime.joda` package provides comprehensive datetime -formatting support based on the http://joda-time.sourceforge.net[Joda Time library]. - -Consider `DateFormatter` as an example `Formatter` implementation: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.format.datetime; - - public final class DateFormatter implements Formatter { - - private String pattern; - - public DateFormatter(String pattern) { - this.pattern = pattern; - } - - public String print(Date date, Locale locale) { - if (date == null) { - return ""; - } - return getDateFormat(locale).format(date); - } - - public Date parse(String formatted, Locale locale) throws ParseException { - if (formatted.length() == 0) { - return null; - } - return getDateFormat(locale).parse(formatted); - } - - protected DateFormat getDateFormat(Locale locale) { - DateFormat dateFormat = new SimpleDateFormat(this.pattern, locale); - dateFormat.setLenient(false); - return dateFormat; - } - - } ----- - -The Spring team welcomes community-driven `Formatter` contributions; see -https://jira.spring.io/browse/SPR[jira.spring.io] to contribute. - - - -[[format-CustomFormatAnnotations]] -==== Annotation-driven Formatting -As you will see, field formatting can be configured by field type or annotation. To bind -an Annotation to a formatter, implement AnnotationFormatterFactory: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.format; - - public interface AnnotationFormatterFactory { - - Set> getFieldTypes(); - - Printer getPrinter(A annotation, Class fieldType); - - Parser getParser(A annotation, Class fieldType); - - } ----- - -Parameterize A to be the field annotationType you wish to associate formatting logic -with, for example `org.springframework.format.annotation.DateTimeFormat`. Have -`getFieldTypes()` return the types of fields the annotation may be used on. Have -`getPrinter()` return a Printer to print the value of an annotated field. Have -`getParser()` return a Parser to parse a clientValue for an annotated field. - -The example AnnotationFormatterFactory implementation below binds the @NumberFormat -Annotation to a formatter. This annotation allows either a number style or pattern to be -specified: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public final class NumberFormatAnnotationFormatterFactory - implements AnnotationFormatterFactory { - - public Set> getFieldTypes() { - return new HashSet>(asList(new Class[] { - Short.class, Integer.class, Long.class, Float.class, - Double.class, BigDecimal.class, BigInteger.class })); - } - - public Printer getPrinter(NumberFormat annotation, Class fieldType) { - return configureFormatterFrom(annotation, fieldType); - } - - public Parser getParser(NumberFormat annotation, Class fieldType) { - return configureFormatterFrom(annotation, fieldType); - } - - private Formatter configureFormatterFrom(NumberFormat annotation, - Class fieldType) { - if (!annotation.pattern().isEmpty()) { - return new NumberFormatter(annotation.pattern()); - } else { - Style style = annotation.style(); - if (style == Style.PERCENT) { - return new PercentFormatter(); - } else if (style == Style.CURRENCY) { - return new CurrencyFormatter(); - } else { - return new NumberFormatter(); - } - } - } - } ----- - -To trigger formatting, simply annotate fields with @NumberFormat: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class MyModel { - - @NumberFormat(style=Style.CURRENCY) - private BigDecimal decimal; - - } ----- - - -[[format-annotations-api]] -===== Format Annotation API -A portable format annotation API exists in the `org.springframework.format.annotation` -package. Use @NumberFormat to format java.lang.Number fields. Use @DateTimeFormat to -format java.util.Date, java.util.Calendar, java.util.Long, or Joda Time fields. - -The example below uses @DateTimeFormat to format a java.util.Date as a ISO Date -(yyyy-MM-dd): - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class MyModel { - - @DateTimeFormat(iso=ISO.DATE) - private Date date; - - } ----- - - - -[[format-FormatterRegistry-SPI]] -==== FormatterRegistry SPI -The FormatterRegistry is an SPI for registering formatters and converters. -`FormattingConversionService` is an implementation of FormatterRegistry suitable for -most environments. This implementation may be configured programmatically or -declaratively as a Spring bean using `FormattingConversionServiceFactoryBean`. Because -this implementation also implements `ConversionService`, it can be directly configured -for use with Spring's DataBinder and the Spring Expression Language (SpEL). - -Review the FormatterRegistry SPI below: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.format; - - public interface FormatterRegistry extends ConverterRegistry { - - void addFormatterForFieldType(Class fieldType, Printer printer, Parser parser); - - void addFormatterForFieldType(Class fieldType, Formatter formatter); - - void addFormatterForFieldType(Formatter formatter); - - void addFormatterForAnnotation(AnnotationFormatterFactory factory); - - } ----- - -As shown above, Formatters can be registered by fieldType or annotation. - -The FormatterRegistry SPI allows you to configure Formatting rules centrally, instead of -duplicating such configuration across your Controllers. For example, you might want to -enforce that all Date fields are formatted a certain way, or fields with a specific -annotation are formatted in a certain way. With a shared FormatterRegistry, you define -these rules once and they are applied whenever formatting is needed. - - - -[[format-FormatterRegistrar-SPI]] -==== FormatterRegistrar SPI -The FormatterRegistrar is an SPI for registering formatters and converters through the -FormatterRegistry: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.springframework.format; - - public interface FormatterRegistrar { - - void registerFormatters(FormatterRegistry registry); - - } ----- - -A FormatterRegistrar is useful when registering multiple related converters and -formatters for a given formatting category, such as Date formatting. It can also be -useful where declarative registration is insufficient. For example when a formatter -needs to be indexed under a specific field type different from its own or when -registering a Printer/Parser pair. The next section provides more information on -converter and formatter registration. - - - -[[format-configuring-formatting-mvc]] -==== Configuring Formatting in Spring MVC -In a Spring MVC application, you may configure a custom ConversionService instance -explicitly as an attribute of the `annotation-driven` element of the MVC namespace. This -ConversionService will then be used anytime a type conversion is required during -Controller model binding. If not configured explicitly, Spring MVC will automatically -register default formatters and converters for common types such as numbers and dates. - -To rely on default formatting rules, no custom configuration is required in your Spring -MVC config XML: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - ----- - -With this one-line of configuration, default formatters for Numbers and Date types will -be installed, including support for the @NumberFormat and @DateTimeFormat annotations. -Full support for the Joda Time formatting library is also installed if Joda Time is -present on the classpath. - -To inject a ConversionService instance with custom formatters and converters registered, -set the conversion-service attribute and then specify custom converters, formatters, or -FormatterRegistrars as properties of the FormattingConversionServiceFactoryBean: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - - - - - - - - - - ----- - -[NOTE] -==== -See <> and the `FormattingConversionServiceFactoryBean` -for more information on when to use FormatterRegistrars. -==== - - - - -[[format-configuring-formatting-globaldatetimeformat]] -=== Configuring a global date & time format -By default, date and time fields that are not annotated with `@DateTimeFormat` are -converted from strings using the the `DateFormat.SHORT` style. If you prefer, you can -change this by defining your own global format. - -You will need to ensure that Spring does not register default formatters, and instead -you should register all formatters manually. Use the -`org.springframework.format.datetime.joda.JodaTimeFormatterRegistrar` or -`org.springframework.format.datetime.DateFormatterRegistrar` class depending on whether -you use the Joda Time library. - -For example, the following Java configuration will register a global ' `yyyyMMdd`' -format. This example does not depend on the Joda Time library: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Configuration - public class AppConfig { - - @Bean - public FormattingConversionService conversionService() { - - // Use the DefaultFormattingConversionService but do not register defaults - DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(false); - - // Ensure @NumberFormat is still supported - conversionService.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory()); - - // Register date conversion with a specific global format - DateFormatterRegistrar registrar = new DateFormatterRegistrar(); - registrar.setFormatter(new DateFormatter("yyyyMMdd")); - registrar.registerFormatters(conversionService); - - return conversionService; - } - } ----- - -If you prefer XML based configuration you can use a -`FormattingConversionServiceFactoryBean`. Here is the same example, this time using Joda -Time: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - - - - - - ----- - -[NOTE] -==== -Joda Time provides separate distinct types to represent `date`, `time` and `date-time` -values. The `dateFormatter`, `timeFormatter` and `dateTimeFormatter` properties of the -`JodaTimeFormatterRegistrar` should be used to configure the different formats for each -type. The `DateTimeFormatterFactoryBean` provides a convenient way to create formatters. -==== - -If you are using Spring MVC remember to explicitly configure the conversion service that -is used. For Java based `@Configuration` this means extending the -`WebMvcConfigurationSupport` class and overriding the `mvcConversionService()` method. -For XML you should use the `'conversion-service'` attribute of the -`mvc:annotation-driven` element. See <> for details. - - - - -[[validation-beanvalidation]] -=== Spring Validation -Spring 3 introduces several enhancements to its validation support. First, the JSR-303 -Bean Validation API is now fully supported. Second, when used programmatically, Spring's -DataBinder can now validate objects as well as bind to them. Third, Spring MVC now has -support for declaratively validating `@Controller` inputs. - - - -[[validation-beanvalidation-overview]] -==== Overview of the JSR-303 Bean Validation API -JSR-303 standardizes validation constraint declaration and metadata for the Java -platform. Using this API, you annotate domain model properties with declarative -validation constraints and the runtime enforces them. There are a number of built-in -constraints you can take advantage of. You may also define your own custom constraints. - -To illustrate, consider a simple PersonForm model with two properties: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class PersonForm { - private String name; - private int age; - } ----- - -JSR-303 allows you to define declarative validation constraints against such properties: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class PersonForm { - - @NotNull - @Size(max=64) - private String name; - - @Min(0) - private int age; - - } ----- - -When an instance of this class is validated by a JSR-303 Validator, these constraints -will be enforced. - -For general information on JSR-303/JSR-349, see the http://beanvalidation.org/[Bean -Validation website]. For information on the specific capabilities of the default -reference implementation, see the https://www.hibernate.org/412.html[Hibernate -Validator] documentation. To learn how to setup a Bean Validation provider as a Spring -bean, keep reading. - - - -[[validation-beanvalidation-spring]] -==== Configuring a Bean Validation Provider -Spring provides full support for the Bean Validation API. This includes convenient -support for bootstrapping a JSR-303/JSR-349 Bean Validation provider as a Spring bean. -This allows for a `javax.validation.ValidatorFactory` or `javax.validation.Validator` to -be injected wherever validation is needed in your application. - -Use the `LocalValidatorFactoryBean` to configure a default Validator as a Spring bean: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - ----- - -The basic configuration above will trigger Bean Validation to initialize using its -default bootstrap mechanism. A JSR-303/JSR-349 provider, such as Hibernate Validator, -is expected to be present in the classpath and will be detected automatically. - - -[[validation-beanvalidation-spring-inject]] -===== Injecting a Validator -`LocalValidatorFactoryBean` implements both `javax.validation.ValidatorFactory` and -`javax.validation.Validator`, as well as Spring's -`org.springframework.validation.Validator`. You may inject a reference to either of -these interfaces into beans that need to invoke validation logic. - -Inject a reference to `javax.validation.Validator` if you prefer to work with the Bean -Validation API directly: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - import javax.validation.Validator; - - @Service - public class MyService { - - @Autowired - private Validator validator; ----- - -Inject a reference to `org.springframework.validation.Validator` if your bean requires -the Spring Validation API: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - import org.springframework.validation.Validator; - - @Service - public class MyService { - - @Autowired - private Validator validator; - - } ----- - - -[[validation-beanvalidation-spring-constraints]] -===== Configuring Custom Constraints -Each Bean Validation constraint consists of two parts. First, a `@Constraint` annotation -that declares the constraint and its configurable properties. Second, an implementation -of the `javax.validation.ConstraintValidator` interface that implements the constraint's -behavior. To associate a declaration with an implementation, each `@Constraint` annotation -references a corresponding ValidationConstraint implementation class. At runtime, a -`ConstraintValidatorFactory` instantiates the referenced implementation when the -constraint annotation is encountered in your domain model. - -By default, the `LocalValidatorFactoryBean` configures a `SpringConstraintValidatorFactory` -that uses Spring to create ConstraintValidator instances. This allows your custom -ConstraintValidators to benefit from dependency injection like any other Spring bean. - -Shown below is an example of a custom `@Constraint` declaration, followed by an associated -`ConstraintValidator` implementation that uses Spring for dependency injection: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Target({ElementType.METHOD, ElementType.FIELD}) - @Retention(RetentionPolicy.RUNTIME) - @Constraint(validatedBy=MyConstraintValidator.class) - public @interface MyConstraint { - } ----- - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - import javax.validation.ConstraintValidator; - - public class MyConstraintValidator implements ConstraintValidator { - - @Autowired; - private Foo aDependency; - - ... - } ----- - -As you can see, a ConstraintValidator implementation may have its dependencies -@Autowired like any other Spring bean. - - -[[validation-beanvalidation-spring-method]] -===== Spring-driven Method Validation -The method validation feature supported by Bean Validation 1.1, and as a custom -extension also by Hibernate Validator 4.3, can be integrated into a Spring context -through a `MethodValidationPostProcessor` bean definition: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - ----- - -In order to be eligible for Spring-driven method validation, all target classes need -to be annotated with Spring's `@Validated` annotation, optionally declaring the -validation groups to use. Check out the `MethodValidationPostProcessor` javadocs -for setup details with Hibernate Validator and Bean Validation 1.1 providers. - - -[[validation-beanvalidation-spring-other]] -===== Additional Configuration Options -The default `LocalValidatorFactoryBean` configuration should prove sufficient for most -cases. There are a number of configuration options for various Bean Validation -constructs, from message interpolation to traversal resolution. See the -`LocalValidatorFactoryBean` javadocs for more information on these options. - - - -[[validation-binder]] -==== Configuring a DataBinder -Since Spring 3, a DataBinder instance can be configured with a Validator. Once -configured, the Validator may be invoked by calling `binder.validate()`. Any validation -Errors are automatically added to the binder's BindingResult. - -When working with the DataBinder programmatically, this can be used to invoke validation -logic after binding to a target object: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Foo target = new Foo(); - DataBinder binder = new DataBinder(target); - binder.setValidator(new FooValidator()); - - // bind to the target object - binder.bind(propertyValues); - - // validate the target object - binder.validate(); - - // get BindingResult that includes any validation errors - BindingResult results = binder.getBindingResult(); ----- - -A DataBinder can also be configured with multiple `Validator` instances via -`dataBinder.addValidators` and `dataBinder.replaceValidators`. This is useful when -combining globally configured Bean Validation with a Spring `Validator` configured -locally on a DataBinder instance. See <>. - - - -[[validation-mvc]] -==== Spring MVC 3 Validation -Beginning with Spring 3, Spring MVC has the ability to automatically validate -`@Controller` inputs. In previous versions it was up to the developer to manually invoke -validation logic. - - -[[validation-mvc-triggering]] -===== Triggering @Controller Input Validation -To trigger validation of a `@Controller` input, simply annotate the input argument as -++@Valid++: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Controller - public class MyController { - - @RequestMapping("/foo", method=RequestMethod.POST) - public void processFoo(**@Valid** Foo foo) { /* ... */ } ----- - -Spring MVC will validate a @Valid object after binding so-long as an appropriate -Validator has been configured. - -[NOTE] -==== -The @Valid annotation is part of the standard JSR-303 Bean Validation API, and is not a -Spring-specific construct. -==== - - -[[validation-mvc-configuring]] -===== Configuring a Validator for use by Spring MVC -The `Validator` instance invoked when a `@Valid` method argument is encountered may be -configured in two ways. First, you may call `binder.setValidator(Validator)` within a -++@Controller++'s `@InitBinder` callback. This allows you to configure a `Validator` -instance per `@Controller` class: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Controller - public class MyController { - - @InitBinder - protected void initBinder(WebDataBinder binder) { - binder.setValidator(new FooValidator()); - } - - @RequestMapping("/foo", method=RequestMethod.POST) - public void processFoo(@Valid Foo foo) { ... } - - } ----- - -Second, you may call `setValidator(Validator)` on the global `WebBindingInitializer`. This -allows you to configure a `Validator` instance across all `@Controller` classes. This can be -achieved easily by using the Spring MVC namespace: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - ----- - -To combine a global and a local validator, configure the global validator as shown above -and then add a local validator: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Controller - public class MyController { - - @InitBinder - protected void initBinder(WebDataBinder binder) { - binder.addValidators(new FooValidator()); - } - - } ----- - - -[[validation-mvc-jsr303]] -===== Configuring a JSR-303/JSR-349 Validator for use by Spring MVC -With Bean Validation, a single `javax.validation.Validator` instance typically validates -__all__ model objects that declare validation constraints. To configure such a JSR-303 -backed Validator with Spring MVC, simply add a Bean Validation provider, such as -Hibernate Validator, to your classpath. Spring MVC will detect it and automatically -enable Bean Validation support across all Controllers. - -The Spring MVC configuration required to enable Bean Validation support is shown below: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - ----- - -With this minimal configuration, anytime a `@Valid` `@Controller` input is encountered, it -will be validated by the Bean Validation provider. That provider, in turn, will enforce -any constraints declared against the input. Any ++ConstraintViolation++s will automatically -be exposed as errors in the `BindingResult` renderable by standard Spring MVC form tags. - - - -[[expressions]] -== Spring Expression Language (SpEL) - - - - -[[expressions-intro]] -=== Introduction -The Spring Expression Language (SpEL for short) is a powerful expression language that -supports querying and manipulating an object graph at runtime. The language syntax is -similar to Unified EL but offers additional features, most notably method invocation and -basic string templating functionality. - -While there are several other Java expression languages available, OGNL, MVEL, and JBoss -EL, to name a few, the Spring Expression Language was created to provide the Spring -community with a single well supported expression language that can be used across all -the products in the Spring portfolio. Its language features are driven by the -requirements of the projects in the Spring portfolio, including tooling requirements for -code completion support within the eclipse based Spring Tool Suite. That said, -SpEL is based on a technology agnostic API allowing other expression language -implementations to be integrated should the need arise. - -While SpEL serves as the foundation for expression evaluation within the Spring -portfolio, it is not directly tied to Spring and can be used independently. In order to -be self contained, many of the examples in this chapter use SpEL as if it were an -independent expression language. This requires creating a few bootstrapping -infrastructure classes such as the parser. Most Spring users will not need to deal with -this infrastructure and will instead only author expression strings for evaluation. An -example of this typical use is the integration of SpEL into creating XML or annotated -based bean definitions as shown in the section <> - -This chapter covers the features of the expression language, its API, and its language -syntax. In several places an Inventor and Inventor's Society class are used as the -target objects for expression evaluation. These class declarations and the data used to -populate them are listed at the end of the chapter. - - - - -[[expressions-features]] -=== Feature Overview -The expression language supports the following functionality - -* Literal expressions -* Boolean and relational operators -* Regular expressions -* Class expressions -* Accessing properties, arrays, lists, maps -* Method invocation -* Relational operators -* Assignment -* Calling constructors -* Bean references -* Array construction -* Inline lists -* Inline maps -* Ternary operator -* Variables -* User defined functions -* Collection projection -* Collection selection -* Templated expressions - - - - -[[expressions-evaluation]] -=== Expression Evaluation using Spring's Expression Interface -This section introduces the simple use of SpEL interfaces and its expression language. -The complete language reference can be found in the section -<>. - -The following code introduces the SpEL API to evaluate the literal string expression -'Hello World'. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ExpressionParser parser = new SpelExpressionParser(); - Expression exp = parser.parseExpression("**''Hello World''**"); - String message = (String) exp.getValue(); ----- - -The value of the message variable is simply 'Hello World'. - -The SpEL classes and interfaces you are most likely to use are located in the packages -`org.springframework.expression` and its sub packages and `spel.support`. - -The interface `ExpressionParser` is responsible for parsing an expression string. In -this example the expression string is a string literal denoted by the surrounding single -quotes. The interface `Expression` is responsible for evaluating the previously defined -expression string. There are two exceptions that can be thrown, `ParseException` and -`EvaluationException` when calling '`parser.parseExpression`' and '`exp.getValue`' -respectively. - -SpEL supports a wide range of features, such as calling methods, accessing properties, -and calling constructors. - -As an example of method invocation, we call the 'concat' method on the string literal. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ExpressionParser parser = new SpelExpressionParser(); - Expression exp = parser.parseExpression("**''Hello World''.concat(''!'')**"); - String message = (String) exp.getValue(); ----- - -The value of message is now 'Hello World!'. - -As an example of calling a JavaBean property, the String property 'Bytes' can be called -as shown below. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ExpressionParser parser = new SpelExpressionParser(); - - // invokes 'getBytes()' - Expression exp = parser.parseExpression("**''Hello World''.bytes**"); - byte[] bytes = (byte[]) exp.getValue(); ----- - -SpEL also supports nested properties using standard 'dot' notation, i.e. -prop1.prop2.prop3 and the setting of property values - -Public fields may also be accessed. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ExpressionParser parser = new SpelExpressionParser(); - - // invokes 'getBytes().length' - Expression exp = parser.parseExpression("**''Hello World''.bytes.length**"); - int length = (Integer) exp.getValue(); ----- - -The String's constructor can be called instead of using a string literal. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ExpressionParser parser = new SpelExpressionParser(); - Expression exp = parser.parseExpression("**new String(''hello world'').toUpperCase()**"); - String message = exp.getValue(String.class); ----- - -Note the use of the generic method `public T getValue(Class desiredResultType)`. -Using this method removes the need to cast the value of the expression to the desired -result type. An `EvaluationException` will be thrown if the value cannot be cast to the -type `T` or converted using the registered type converter. - -The more common usage of SpEL is to provide an expression string that is evaluated -against a specific object instance (called the root object). There are two options here -and which to choose depends on whether the object against which the expression is being -evaluated will be changing with each call to evaluate the expression. In the following -example we retrieve the `name` property from an instance of the Inventor class. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // Create and set a calendar - GregorianCalendar c = new GregorianCalendar(); - c.set(1856, 7, 9); - - // The constructor arguments are name, birthday, and nationality. - Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian"); - - ExpressionParser parser = new SpelExpressionParser(); - Expression exp = parser.parseExpression("**name**"); - - EvaluationContext context = new StandardEvaluationContext(tesla); - String name = (String) exp.getValue(context); ----- - -In the last line, the value of the string variable 'name' will be set to "Nikola Tesla". -The class StandardEvaluationContext is where you can specify which object the "name" -property will be evaluated against. This is the mechanism to use if the root object is -unlikely to change, it can simply be set once in the evaluation context. If the root -object is likely to change repeatedly, it can be supplied on each call to `getValue`, as -this next example shows: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - / Create and set a calendar - GregorianCalendar c = new GregorianCalendar(); - c.set(1856, 7, 9); - - // The constructor arguments are name, birthday, and nationality. - Inventor tesla = new Inventor("Nikola Tesla", c.getTime(), "Serbian"); - - ExpressionParser parser = new SpelExpressionParser(); - Expression exp = parser.parseExpression("**name**"); - String name = (String) exp.getValue(tesla); ----- - -In this case the inventor `tesla` has been supplied directly to `getValue` and the -expression evaluation infrastructure creates and manages a default evaluation context -internally - it did not require one to be supplied. - -The StandardEvaluationContext is relatively expensive to construct and during repeated -usage it builds up cached state that enables subsequent expression evaluations to be -performed more quickly. For this reason it is better to cache and reuse them where -possible, rather than construct a new one for each expression evaluation. - -In some cases it can be desirable to use a configured evaluation context and yet still -supply a different root object on each call to `getValue`. `getValue` allows both to be -specified on the same call. In these situations the root object passed on the call is -considered to override any (which maybe null) specified on the evaluation context. - -[NOTE] -==== -In standalone usage of SpEL there is a need to create the parser, parse expressions and -perhaps provide evaluation contexts and a root context object. However, more common -usage is to provide only the SpEL expression string as part of a configuration file, for -example for Spring bean or Spring Web Flow definitions. In this case, the parser, -evaluation context, root object and any predefined variables are all set up implicitly, -requiring the user to specify nothing other than the expressions. -==== -As a final introductory example, the use of a boolean operator is shown using the -Inventor object in the previous example. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Expression exp = parser.parseExpression("name == ''Nikola Tesla''"); - boolean result = exp.getValue(context, Boolean.class); // evaluates to true ----- - - - -[[expressions-evaluation-context]] -==== The EvaluationContext interface -The interface `EvaluationContext` is used when evaluating an expression to resolve -properties, methods, fields, and to help perform type conversion. The out-of-the-box -implementation, `StandardEvaluationContext`, uses reflection to manipulate the object, -caching `java.lang.reflect`'s `Method`, `Field`, and `Constructor` instances for -increased performance. - -The `StandardEvaluationContext` is where you may specify the root object to evaluate -against via the method `setRootObject()` or passing the root object into the -constructor. You can also specify variables and functions that will be used in the -expression using the methods `setVariable()` and `registerFunction()`. The use of -variables and functions are described in the language reference sections -<> and <>. The -`StandardEvaluationContext` is also where you can register custom -++ConstructorResolver++s, ++MethodResolver++s, and ++PropertyAccessor++s to extend how SpEL -evaluates expressions. Please refer to the JavaDoc of these classes for more details. - - -[[expressions-type-conversion]] -===== Type Conversion -By default SpEL uses the conversion service available in Spring core ( -`org.springframework.core.convert.ConversionService`). This conversion service comes -with many converters built in for common conversions but is also fully extensible so -custom conversions between types can be added. Additionally it has the key capability -that it is generics aware. This means that when working with generic types in -expressions, SpEL will attempt conversions to maintain type correctness for any objects -it encounters. - -What does this mean in practice? Suppose assignment, using `setValue()`, is being used -to set a `List` property. The type of the property is actually `List`. SpEL -will recognize that the elements of the list need to be converted to `Boolean` before -being placed in it. A simple example: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - class Simple { - public List booleanList = new ArrayList(); - } - - Simple simple = new Simple(); - - simple.booleanList.add(true); - - StandardEvaluationContext simpleContext = new StandardEvaluationContext(simple); - - // false is passed in here as a string. SpEL and the conversion service will - // correctly recognize that it needs to be a Boolean and convert it - parser.parseExpression("booleanList[0]").setValue(simpleContext, "false"); - - // b will be false - Boolean b = simple.booleanList.get(0); ----- - -[[expressions-parser-configuration]] -==== Parser configuration -It is possible to configure the SpEL expression parser using a parser configuration object -(`org.springframework.expression.spel.SpelParserConfiguration`). The configuration -object controls the behaviour of some of the expression components. For example, if -indexing into an array or collection and the element at the specified index is `null` -it is possible to automatically create the element. This is useful when using expressions made up of a -chain of property references. If indexing into an array or list -and specifying an index that is beyond the end of the current size of the array or -list it is possible to automatically grow the array or list to accommodate that index. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - class Demo { - public List list; - } - - // Turn on: - // - auto null reference initialization - // - auto collection growing - SpelParserConfiguration config = new SpelParserConfiguration(true,true); - - ExpressionParser parser = new SpelExpressionParser(config); - - Expression expression = parser.parseExpression("list[3]"); - - Demo demo = new Demo(); - - Object o = expression.getValue(demo); - - // demo.list will now be a real collection of 4 entries - // Each entry is a new empty String ----- - -It is also possible to configure the behaviour of the SpEL expression compiler. - -[[expressions-spel-compilation]] -==== SpEL compilation - -Spring Framework 4.1 includes a basic expression compiler. Expressions are usually -interpreted which provides a lot of dynamic flexibility during evaluation but -does not provide the optimum performance. For occasional expression usage -this is fine, but when used by other components like Spring Integration, -performance can be very important and there is no real need for the dynamism. - -The new SpEL compiler is intended to address this need. The -compiler will generate a real Java class on the fly during evaluation that embodies the -expression behaviour and use that to achieve much faster expression -evaluation. Due to the lack of typing around expressions the compiler -uses information gathered during the interpreted evaluations of an -expression when performing compilation. For example, it does not know the type -of a property reference purely from the expression but during the first -interpreted evaluation it will find out what it is. Of course, basing the -compilation on this information could cause trouble later if the types of -the various expression elements change over time. For this reason compilation -is best suited to expressions whose type information is not going to change -on repeated evaluations. - -For a basic expression like this: - -`someArray[0].someProperty.someOtherProperty < 0.1` - -which involves array access, some property derefencing and numeric operations, the performance -gain can be very noticeable. In an example microbenchmark run of 50000 iterations, it was -taking 75ms to evaluate using only the interpreter and just 3ms using the compiled version -of the expression. - -[[expressions-compiler-configuration]] -===== Compiler configuration - -The compiler is not turned on by default, but there are two ways to turn -it on. It can be turned on using the parser configuration process discussed earlier or -via a system property when SpEL usage is embedded inside another component. This section -discusses both of these options. - -Is is important to understand that there are a few modes the compiler can operate in, captured -in an enum (`org.springframework.expression.spel.SpelCompilerMode`). The modes are as follows: - -- `OFF` - The compiler is switched off; this is the default. -- `IMMEDIATE` - In immediate mode the expressions are compiled as soon as possible. This -is typically after the first interpreted evaluation. If the compiled expression fails -(typically due to a type changing, as described above) then the caller of the expression -evaluation will receive an exception. -- `MIXED` - In mixed mode the expressions silently switch between interpreted and compiled -mode over time. After some number of interpreted runs they will switch to compiled -form and if something goes wrong with the compiled form (like a type changing, as -described above) then the expression will automatically switch back to interpreted form -again. Sometime later it may generate another compiled form and switch to it. Basically -the exception that the user gets in `IMMEDIATE` mode is instead handled internally. - -`IMMEDIATE` mode exists because `MIXED` mode could cause issues for expressions that -have side effects. If a compiled expression blows up after partially succeeding it -may have already done something that has affected the state of the system. If this -has happened the caller may not want it to silently re-run in interpreted mode -since part of the expression may be running twice. - -After selecting a mode, use the `SpelParserConfiguration` to configure the parser: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, - this.getClass().getClassLoader()); - - SpelExpressionParser parser = new SpelExpressionParser(config); - - Expression expr = parser.parseExpression("payload"); - - MyMessage message = new MyMessage(); - - Object payload = expr.getValue(message); ----- - -When specifying the compiler mode it is also possible to specify a classloader (passing null is allowed). -Compiled expressions will be defined in a child classloader created under any that is supplied. -It is important to ensure if a classloader is specified it can see all the types involved in -the expression evaluation process. -If none is specified then a default classloader will be used (typically the context classloader for -the thread that is running during expression evaluation). - -The second way to configure the compiler is for use when SpEL is embedded inside some other -component and it may not be possible to configure via a configuration object. -In these cases it is possible to use a system property. The property -`spring.expression.compiler.mode` can be set to one of the `SpelCompilerMode` -enum values (`off`, `immediate` or `mixed`). - -[[expressions-compiler-limitations]] -===== Compiler limitations - -With Spring Framework 4.1 the basic compilation framework is in place. However, the framework does not -yet support compiling every kind of expression. The initial focus has been on the common expressions that are -likely to be used in performance critical contexts. These kinds of expression cannot be compiled -at the moment: - -- expressions involving assignment -- expressions relying on the conversion service -- expressions using custom resolvers or accessors -- expressions using selection or projection - -More and more types of expression will be compilable in the future. - -[[expressions-beandef]] -=== Expression support for defining bean definitions -SpEL expressions can be used with XML or annotation-based configuration metadata for -defining ++BeanDefinition++s. In both cases the syntax to define the expression is of the -form `#{ }`. - - - -[[expressions-beandef-xml-based]] -==== XML based configuration -A property or constructor-arg value can be set using expressions as shown below. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - ----- - -The variable `systemProperties` is predefined, so you can use it in your expressions as -shown below. Note that you do not have to prefix the predefined variable with the `#` -symbol in this context. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - ----- - -You can also refer to other bean properties by name, for example. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - ----- - - - -[[expressions-beandef-annotation-based]] -==== Annotation-based configuration -The `@Value` annotation can be placed on fields, methods and method/constructor -parameters to specify a default value. - -Here is an example to set the default value of a field variable. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public static class FieldValueTestBean - - @Value("#{ systemProperties[''user.region''] }") - private String defaultLocale; - - public void setDefaultLocale(String defaultLocale) { - this.defaultLocale = defaultLocale; - } - - public String getDefaultLocale() { - return this.defaultLocale; - } - - } ----- - -The equivalent but on a property setter method is shown below. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public static class PropertyValueTestBean - - private String defaultLocale; - - @Value("#{ systemProperties[''user.region''] }") - public void setDefaultLocale(String defaultLocale) { - this.defaultLocale = defaultLocale; - } - - public String getDefaultLocale() { - return this.defaultLocale; - } - - } ----- - -Autowired methods and constructors can also use the `@Value` annotation. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class SimpleMovieLister { - - private MovieFinder movieFinder; - private String defaultLocale; - - @Autowired - public void configure(MovieFinder movieFinder, - @Value("#{ systemProperties[''user.region''] }") String defaultLocale) { - this.movieFinder = movieFinder; - this.defaultLocale = defaultLocale; - } - - // ... - } ----- - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class MovieRecommender { - - private String defaultLocale; - - private CustomerPreferenceDao customerPreferenceDao; - - @Autowired - public MovieRecommender(CustomerPreferenceDao customerPreferenceDao, - @Value("#{systemProperties[''user.country'']}") String defaultLocale) { - this.customerPreferenceDao = customerPreferenceDao; - this.defaultLocale = defaultLocale; - } - - // ... - } ----- - - - - -[[expressions-language-ref]] -=== Language Reference - - - -[[expressions-ref-literal]] -==== Literal expressions -The types of literal expressions supported are strings, dates, numeric values (int, -real, and hex), boolean and null. Strings are delimited by single quotes. To put a -single quote itself in a string use two single quote characters. The following listing -shows simple usage of literals. Typically they would not be used in isolation like this, -but as part of a more complex expression, for example using a literal on one side of a -logical comparison operator. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ExpressionParser parser = new SpelExpressionParser(); - - // evals to "Hello World" - String helloWorld = (String) parser.parseExpression("''Hello World''").getValue(); - - double avogadrosNumber = (Double) parser.parseExpression("6.0221415E+23").getValue(); - - // evals to 2147483647 - int maxValue = (Integer) parser.parseExpression("0x7FFFFFFF").getValue(); - - boolean trueValue = (Boolean) parser.parseExpression("true").getValue(); - - Object nullValue = parser.parseExpression("null").getValue(); ----- - -Numbers support the use of the negative sign, exponential notation, and decimal points. -By default real numbers are parsed using Double.parseDouble(). - - - -[[expressions-properties-arrays]] -==== Properties, Arrays, Lists, Maps, Indexers -Navigating with property references is easy: just use a period to indicate a nested -property value. The instances of the `Inventor` class, pupin, and tesla, were populated with -data listed in the section <>. -To navigate "down" and get Tesla's year of birth and Pupin's city of birth the following -expressions are used. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // evals to 1856 - int year = (Integer) parser.parseExpression("Birthdate.Year + 1900").getValue(context); - - String city = (String) parser.parseExpression("placeOfBirth.City").getValue(context); ----- - -Case insensitivity is allowed for the first letter of property names. The contents of -arrays and lists are obtained using square bracket notation. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ExpressionParser parser = new SpelExpressionParser(); - - // Inventions Array - StandardEvaluationContext teslaContext = new StandardEvaluationContext(tesla); - - // evaluates to "Induction motor" - String invention = parser.parseExpression("inventions[3]").getValue( - teslaContext, String.class); - - // Members List - StandardEvaluationContext societyContext = new StandardEvaluationContext(ieee); - - // evaluates to "Nikola Tesla" - String name = parser.parseExpression("Members[0].Name").getValue( - societyContext, String.class); - - // List and Array navigation - // evaluates to "Wireless communication" - String invention = parser.parseExpression("Members[0].Inventions[6]").getValue( - societyContext, String.class); ----- - -The contents of maps are obtained by specifying the literal key value within the -brackets. In this case, because keys for the Officers map are strings, we can specify -string literals. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // Officer's Dictionary - - Inventor pupin = parser.parseExpression("Officers[''president'']").getValue( - societyContext, Inventor.class); - - // evaluates to "Idvor" - String city = parser.parseExpression("Officers[''president''].PlaceOfBirth.City").getValue( - societyContext, String.class); - - // setting values - parser.parseExpression("Officers[''advisors''][0].PlaceOfBirth.Country").setValue( - societyContext, "Croatia"); ----- - - - -[[expressions-inline-lists]] -==== Inline lists -Lists can be expressed directly in an expression using `{}` notation. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // evaluates to a Java list containing the four numbers - List numbers = (List) parser.parseExpression("{1,2,3,4}").getValue(context); - - List listOfLists = (List) parser.parseExpression("{{''a'',''b''},{''x'',''y''}}").getValue(context); ----- - -`{}` by itself means an empty list. For performance reasons, if the list is itself -entirely composed of fixed literals then a constant list is created to represent the -expression, rather than building a new list on each evaluation. - -[[expressions-inline-maps]] -==== Inline Maps -Maps can also be expressed directly in an expression using `{key:value}` notation. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // evaluates to a Java map containing the two entries - Map inventorInfo = (Map) parser.parseExpression("{name:''Nikola'',dob:''10-July-1856''}").getValue(context); - - Map mapOfMaps = (Map) parser.parseExpression("{name:{first:''Nikola'',last:''Tesla''},dob:{day:10,month:''July'',year:1856}}").getValue(context); ----- -`{:}` by itself means an empty map. For performance reasons, if the map is itself composed -of fixed literals or other nested constant structures (lists or maps) then a constant map is created -to represent the expression, rather than building a new map on each evaluation. Quoting of the map keys -is optional, the examples above are not using quoted keys. - -[[expressions-array-construction]] -==== Array construction -Arrays can be built using the familiar Java syntax, optionally supplying an initializer -to have the array populated at construction time. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - int[] numbers1 = (int[]) parser.parseExpression("new int[4]").getValue(context); - - // Array with initializer - int[] numbers2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue(context); - - // Multi dimensional array - int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context); ----- - -It is not currently allowed to supply an initializer when constructing a -multi-dimensional array. - - - -[[expressions-methods]] -==== Methods -Methods are invoked using typical Java programming syntax. You may also invoke methods -on literals. Varargs are also supported. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // string literal, evaluates to "bc" - String c = parser.parseExpression("''abc''.substring(2, 3)").getValue(String.class); - - // evaluates to true - boolean isMember = parser.parseExpression("isMember(''Mihajlo Pupin'')").getValue( - societyContext, Boolean.class); ----- - - - -[[expressions-operators]] -==== Operators - - -[[expressions-operators-relational]] -===== Relational operators -The relational operators; equal, not equal, less than, less than or equal, greater than, -and greater than or equal are supported using standard operator notation. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // evaluates to true - boolean trueValue = parser.parseExpression("2 == 2").getValue(Boolean.class); - - // evaluates to false - boolean falseValue = parser.parseExpression("2 < -5.0").getValue(Boolean.class); - - // evaluates to true - boolean trueValue = parser.parseExpression("''black'' < ''block''").getValue(Boolean.class); ----- - -In addition to standard relational operators SpEL supports the `instanceof` and regular -expression based `matches` operator. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // evaluates to false - boolean falseValue = parser.parseExpression( - "''xyz'' instanceof T(int)").getValue(Boolean.class); - - // evaluates to true - boolean trueValue = parser.parseExpression( - "''5.00'' matches ''\^-?\\d+(\\.\\d{2})?$''").getValue(Boolean.class); - - //evaluates to false - boolean falseValue = parser.parseExpression( - "''5.0067'' matches ''\^-?\\d+(\\.\\d{2})?$''").getValue(Boolean.class); ----- - -Each symbolic operator can also be specified as a purely alphabetic equivalent. This -avoids problems where the symbols used have special meaning for the document type in -which the expression is embedded (eg. an XML document). The textual equivalents are -shown here: `lt` (`<`), `gt` (`>`), `le` (`<=`), `ge` (`>=`), `eq` (`==`), -`ne` (`!=`), `div` (`/`), `mod` (`%`), `not` (`!`). These are case insensitive. - - -[[expressions-operators-logical]] -===== Logical operators -The logical operators that are supported are and, or, and not. Their use is demonstrated -below. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // -- AND -- - - // evaluates to false - boolean falseValue = parser.parseExpression("true and false").getValue(Boolean.class); - - // evaluates to true - String expression = "isMember(''Nikola Tesla'') and isMember(''Mihajlo Pupin'')"; - boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class); - - // -- OR -- - - // evaluates to true - boolean trueValue = parser.parseExpression("true or false").getValue(Boolean.class); - - // evaluates to true - String expression = "isMember(''Nikola Tesla'') or isMember(''Albert Einstein'')"; - boolean trueValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class); - - // -- NOT -- - - // evaluates to false - boolean falseValue = parser.parseExpression("!true").getValue(Boolean.class); - - // -- AND and NOT -- - String expression = "isMember(''Nikola Tesla'') and !isMember(''Mihajlo Pupin'')"; - boolean falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class); ----- - - -[[expressions-operators-mathematical]] -===== Mathematical operators -The addition operator can be used on both numbers and strings. Subtraction, multiplication -and division can be used only on numbers. Other mathematical operators supported are -modulus (%) and exponential power (^). Standard operator precedence is enforced. These -operators are demonstrated below. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // Addition - int two = parser.parseExpression("1 + 1").getValue(Integer.class); // 2 - - String testString = parser.parseExpression( - "''test'' + '' '' + ''string''").getValue(String.class); // 'test string' - - // Subtraction - int four = parser.parseExpression("1 - -3").getValue(Integer.class); // 4 - - double d = parser.parseExpression("1000.00 - 1e4").getValue(Double.class); // -9000 - - // Multiplication - int six = parser.parseExpression("-2 * -3").getValue(Integer.class); // 6 - - double twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Double.class); // 24.0 - - // Division - int minusTwo = parser.parseExpression("6 / -3").getValue(Integer.class); // -2 - - double one = parser.parseExpression("8.0 / 4e0 / 2").getValue(Double.class); // 1.0 - - // Modulus - int three = parser.parseExpression("7 % 4").getValue(Integer.class); // 3 - - int one = parser.parseExpression("8 / 5 % 2").getValue(Integer.class); // 1 - - // Operator precedence - int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class); // -21 ----- - - - -[[expressions-assignment]] -==== Assignment -Setting of a property is done by using the assignment operator. This would typically be -done within a call to `setValue` but can also be done inside a call to `getValue`. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Inventor inventor = new Inventor(); - StandardEvaluationContext inventorContext = new StandardEvaluationContext(inventor); - - parser.parseExpression("Name").setValue(inventorContext, "Alexander Seovic2"); - - // alternatively - - String aleks = parser.parseExpression( - "Name = ''Alexandar Seovic''").getValue(inventorContext, String.class); ----- - - - -[[expressions-types]] -==== Types -The special `T` operator can be used to specify an instance of java.lang.Class (the -_type_). Static methods are invoked using this operator as well. The -`StandardEvaluationContext` uses a `TypeLocator` to find types and the -`StandardTypeLocator` (which can be replaced) is built with an understanding of the -java.lang package. This means T() references to types within java.lang do not need to be -fully qualified, but all other type references must be. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Class dateClass = parser.parseExpression("T(java.util.Date)").getValue(Class.class); - - Class stringClass = parser.parseExpression("T(String)").getValue(Class.class); - - boolean trueValue = parser.parseExpression( - "T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR") - .getValue(Boolean.class); ----- - - - -[[expressions-constructors]] -==== Constructors -Constructors can be invoked using the new operator. The fully qualified class name -should be used for all but the primitive type and String (where int, float, etc, can be -used). - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Inventor einstein = p.parseExpression( - "new org.spring.samples.spel.inventor.Inventor(''Albert Einstein'', ''German'')") - .getValue(Inventor.class); - - //create new inventor instance within add method of List - p.parseExpression( - "Members.add(new org.spring.samples.spel.inventor.Inventor( - ''Albert Einstein'', ''German''))").getValue(societyContext); ----- - - - -[[expressions-ref-variables]] -==== Variables -Variables can be referenced in the expression using the syntax `#variableName`. Variables -are set using the method setVariable on the `StandardEvaluationContext`. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Inventor tesla = new Inventor("Nikola Tesla", "Serbian"); - StandardEvaluationContext context = new StandardEvaluationContext(tesla); - context.setVariable("newName", "Mike Tesla"); - - parser.parseExpression("Name = #newName").getValue(context); - - System.out.println(tesla.getName()) // "Mike Tesla" ----- - - -[[expressions-this-root]] -===== The #this and #root variables -The variable #this is always defined and refers to the current evaluation object -(against which unqualified references are resolved). The variable #root is always -defined and refers to the root context object. Although #this may vary as components of -an expression are evaluated, #root always refers to the root. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // create an array of integers - List primes = new ArrayList(); - primes.addAll(Arrays.asList(2,3,5,7,11,13,17)); - - // create parser and set variable 'primes' as the array of integers - ExpressionParser parser = new SpelExpressionParser(); - StandardEvaluationContext context = new StandardEvaluationContext(); - context.setVariable("primes",primes); - - // all prime numbers > 10 from the list (using selection ?{...}) - // evaluates to [11, 13, 17] - List primesGreaterThanTen = (List) parser.parseExpression( - "#primes.?[#this>10]").getValue(context); ----- - - - -[[expressions-ref-functions]] -==== Functions -You can extend SpEL by registering user defined functions that can be called within the -expression string. The function is registered with the `StandardEvaluationContext` using -the method. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public void registerFunction(String name, Method m) ----- - -A reference to a Java Method provides the implementation of the function. For example, a -utility method to reverse a string is shown below. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public abstract class StringUtils { - - public static String reverseString(String input) { - StringBuilder backwards = new StringBuilder(); - for (int i = 0; i < input.length(); i++) - backwards.append(input.charAt(input.length() - 1 - i)); - } - return backwards.toString(); - } - } ----- - -This method is then registered with the evaluation context and can be used within an -expression string. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ExpressionParser parser = new SpelExpressionParser(); - StandardEvaluationContext context = new StandardEvaluationContext(); - - context.registerFunction("reverseString", - StringUtils.class.getDeclaredMethod("reverseString", new Class[] { String.class })); - - String helloWorldReversed = parser.parseExpression( - "#reverseString(''hello'')").getValue(context, String.class); ----- - - - -[[expressions-bean-references]] -==== Bean references -If the evaluation context has been configured with a bean resolver it is possible to -lookup beans from an expression using the (@) symbol. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ExpressionParser parser = new SpelExpressionParser(); - StandardEvaluationContext context = new StandardEvaluationContext(); - context.setBeanResolver(new MyBeanResolver()); - - // This will end up calling resolve(context,"foo") on MyBeanResolver during evaluation - Object bean = parser.parseExpression("@foo").getValue(context); ----- - - - -[[expressions-operator-ternary]] -==== Ternary Operator (If-Then-Else) -You can use the ternary operator for performing if-then-else conditional logic inside -the expression. A minimal example is: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - String falseString = parser.parseExpression( - "false ? ''trueExp'' : ''falseExp''").getValue(String.class); ----- - -In this case, the boolean false results in returning the string value 'falseExp'. A more -realistic example is shown below. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - parser.parseExpression("Name").setValue(societyContext, "IEEE"); - societyContext.setVariable("queryName", "Nikola Tesla"); - - expression = "isMember(#queryName)? #queryName + '' is a member of the '' " + - "+ Name + '' Society'' : #queryName + '' is not a member of the '' + Name + '' Society''"; - - String queryResultString = parser.parseExpression(expression) - .getValue(societyContext, String.class); - // queryResultString = "Nikola Tesla is a member of the IEEE Society" ----- - -Also see the next section on the Elvis operator for an even shorter syntax for the -ternary operator. - - - -[[expressions-operator-elvis]] -==== The Elvis Operator -The Elvis operator is a shortening of the ternary operator syntax and is used in the -http://groovy.codehaus.org/Operators#Operators-ElvisOperator(%3F%3A)[Groovy] language. -With the ternary operator syntax you usually have to repeat a variable twice, for -example: - -[source,groovy,indent=0] -[subs="verbatim,quotes"] ----- - String name = "Elvis Presley"; - String displayName = name != null ? name : "Unknown"; ----- - -Instead you can use the Elvis operator, named for the resemblance to Elvis' hair style. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ExpressionParser parser = new SpelExpressionParser(); - - String name = parser.parseExpression("null?:''Unknown''").getValue(String.class); - - System.out.println(name); // 'Unknown' ----- - -Here is a more complex example. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ExpressionParser parser = new SpelExpressionParser(); - - Inventor tesla = new Inventor("Nikola Tesla", "Serbian"); - StandardEvaluationContext context = new StandardEvaluationContext(tesla); - - String name = parser.parseExpression("Name?:''Elvis Presley''").getValue(context, String.class); - - System.out.println(name); // Nikola Tesla - - tesla.setName(null); - - name = parser.parseExpression("Name?:''Elvis Presley''").getValue(context, String.class); - - System.out.println(name); // Elvis Presley ----- - - - -[[expressions-operator-safe-navigation]] -==== Safe Navigation operator -The Safe Navigation operator is used to avoid a `NullPointerException` and comes from -the http://groovy.codehaus.org/Operators#Operators-SafeNavigationOperator(%3F.)[Groovy] -language. Typically when you have a reference to an object you might need to verify that -it is not null before accessing methods or properties of the object. To avoid this, the -safe navigation operator will simply return null instead of throwing an exception. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ExpressionParser parser = new SpelExpressionParser(); - - Inventor tesla = new Inventor("Nikola Tesla", "Serbian"); - tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan")); - - StandardEvaluationContext context = new StandardEvaluationContext(tesla); - - String city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, String.class); - System.out.println(city); // Smiljan - - tesla.setPlaceOfBirth(null); - - city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, String.class); - - System.out.println(city); // null - does not throw NullPointerException!!! ----- - -[NOTE] -==== -The Elvis operator can be used to apply default values in expressions, e.g. in an -`@Value` expression: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Value("#{systemProperties[''pop3.port''] ?: 25}") ----- - -This will inject a system property `pop3.port` if it is defined or 25 if not. -==== - - - -[[expressions-collection-selection]] -==== Collection Selection -Selection is a powerful expression language feature that allows you to transform some -source collection into another by selecting from its entries. - -Selection uses the syntax `?[selectionExpression]`. This will filter the collection and -return a new collection containing a subset of the original elements. For example, -selection would allow us to easily get a list of Serbian inventors: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - List list = (List) parser.parseExpression( - "Members.?[Nationality == ''Serbian'']").getValue(societyContext); ----- - -Selection is possible upon both lists and maps. In the former case the selection -criteria is evaluated against each individual list element whilst against a map the -selection criteria is evaluated against each map entry (objects of the Java type -`Map.Entry`). Map entries have their key and value accessible as properties for use in -the selection. - -This expression will return a new map consisting of those elements of the original map -where the entry value is less than 27. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Map newMap = parser.parseExpression("map.?[value<27]").getValue(); ----- - -In addition to returning all the selected elements, it is possible to retrieve just the -first or the last value. To obtain the first entry matching the selection the syntax is -`^[...]` whilst to obtain the last matching selection the syntax is `$[...]`. - - - -[[expressions-collection-projection]] -==== Collection Projection -Projection allows a collection to drive the evaluation of a sub-expression and the -result is a new collection. The syntax for projection is `![projectionExpression]`. Most -easily understood by example, suppose we have a list of inventors but want the list of -cities where they were born. Effectively we want to evaluate 'placeOfBirth.city' for -every entry in the inventor list. Using projection: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - // returns ['Smiljan', 'Idvor' ] - List placesOfBirth = (List)parser.parseExpression("Members.![placeOfBirth.city]"); ----- - -A map can also be used to drive projection and in this case the projection expression is -evaluated against each entry in the map (represented as a Java `Map.Entry`). The result -of a projection across a map is a list consisting of the evaluation of the projection -expression against each map entry. - - - -[[expressions-templating]] -==== Expression templating -Expression templates allow a mixing of literal text with one or more evaluation blocks. -Each evaluation block is delimited with prefix and suffix characters that you can -define, a common choice is to use `#{ }` as the delimiters. For example, - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - String randomPhrase = parser.parseExpression( - "random number is #{T(java.lang.Math).random()}", - new TemplateParserContext()).getValue(String.class); - - // evaluates to "random number is 0.7038186818312008" ----- - -The string is evaluated by concatenating the literal text 'random number is ' with the -result of evaluating the expression inside the #{ } delimiter, in this case the result -of calling that random() method. The second argument to the method `parseExpression()` -is of the type `ParserContext`. The `ParserContext` interface is used to influence how -the expression is parsed in order to support the expression templating functionality. -The definition of `TemplateParserContext` is shown below. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class TemplateParserContext implements ParserContext { - - public String getExpressionPrefix() { - return "#{"; - } - - public String getExpressionSuffix() { - return "}"; - } - - public boolean isTemplate() { - return true; - } - } ----- - - - - -[[expressions-example-classes]] -=== Classes used in the examples -Inventor.java - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.spring.samples.spel.inventor; - - import java.util.Date; - import java.util.GregorianCalendar; - - public class Inventor { - - private String name; - private String nationality; - private String[] inventions; - private Date birthdate; - private PlaceOfBirth placeOfBirth; - - public Inventor(String name, String nationality) { - GregorianCalendar c= new GregorianCalendar(); - this.name = name; - this.nationality = nationality; - this.birthdate = c.getTime(); - } - - public Inventor(String name, Date birthdate, String nationality) { - this.name = name; - this.nationality = nationality; - this.birthdate = birthdate; - } - - public Inventor() { - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getNationality() { - return nationality; - } - - public void setNationality(String nationality) { - this.nationality = nationality; - } - - public Date getBirthdate() { - return birthdate; - } - - public void setBirthdate(Date birthdate) { - this.birthdate = birthdate; - } - - public PlaceOfBirth getPlaceOfBirth() { - return placeOfBirth; - } - - public void setPlaceOfBirth(PlaceOfBirth placeOfBirth) { - this.placeOfBirth = placeOfBirth; - } - - public void setInventions(String[] inventions) { - this.inventions = inventions; - } - - public String[] getInventions() { - return inventions; - } - } ----- - -PlaceOfBirth.java - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.spring.samples.spel.inventor; - - public class PlaceOfBirth { - - private String city; - private String country; - - public PlaceOfBirth(String city) { - this.city=city; - } - - public PlaceOfBirth(String city, String country) { - this(city); - this.country = country; - } - - public String getCity() { - return city; - } - - public void setCity(String s) { - this.city = s; - } - - public String getCountry() { - return country; - } - - public void setCountry(String country) { - this.country = country; - } - - } ----- - -Society.java - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package org.spring.samples.spel.inventor; - - import java.util.*; - - public class Society { - - private String name; - - public static String Advisors = "advisors"; - public static String President = "president"; - - private List members = new ArrayList(); - private Map officers = new HashMap(); - - public List getMembers() { - return members; - } - - public Map getOfficers() { - return officers; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public boolean isMember(String name) { - for (Inventor inventor : members) { - if (inventor.getName().equals(name)) { - return true; - } - } - return false; - } - - } ----- +include::core-validation.adoc[leveloffset=+1] +include::core-expressions.adoc[leveloffset=+1] include::core-aop.adoc[leveloffset=+1] -[[aop-api]] -== Spring AOP APIs - - -[[aop-api-introduction]] -=== Introduction -The previous chapter described the Spring's support for AOP using -@AspectJ and schema-based aspect definitions. In this chapter we discuss the lower-level -Spring AOP APIs and the AOP support used in Spring 1.2 applications. For new -applications, we recommend the use of the Spring 2.0 and later AOP support described in -the previous chapter, but when working with existing applications, or when reading books -and articles, you may come across Spring 1.2 style examples. Spring 4.0 is backwards -compatible with Spring 1.2 and everything described in this chapter is fully supported -in Spring 4.0. - - - - -[[aop-api-pointcuts]] -=== Pointcut API in Spring -Let's look at how Spring handles the crucial pointcut concept. - - - -[[aop-api-concepts]] -==== Concepts -Spring's pointcut model enables pointcut reuse independent of advice types. It's -possible to target different advice using the same pointcut. - -The `org.springframework.aop.Pointcut` interface is the central interface, used to -target advices to particular classes and methods. The complete interface is shown below: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface Pointcut { - - ClassFilter getClassFilter(); - - MethodMatcher getMethodMatcher(); - - } ----- - -Splitting the `Pointcut` interface into two parts allows reuse of class and method -matching parts, and fine-grained composition operations (such as performing a "union" -with another method matcher). - -The `ClassFilter` interface is used to restrict the pointcut to a given set of target -classes. If the `matches()` method always returns true, all target classes will be -matched: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface ClassFilter { - - boolean matches(Class clazz); - } ----- - -The `MethodMatcher` interface is normally more important. The complete interface is -shown below: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface MethodMatcher { - - boolean matches(Method m, Class targetClass); - - boolean isRuntime(); - - boolean matches(Method m, Class targetClass, Object[] args); - } ----- - -The `matches(Method, Class)` method is used to test whether this pointcut will ever -match a given method on a target class. This evaluation can be performed when an AOP -proxy is created, to avoid the need for a test on every method invocation. If the -2-argument matches method returns true for a given method, and the `isRuntime()` method -for the MethodMatcher returns true, the 3-argument matches method will be invoked on -every method invocation. This enables a pointcut to look at the arguments passed to the -method invocation immediately before the target advice is to execute. - -Most MethodMatchers are static, meaning that their `isRuntime()` method returns false. -In this case, the 3-argument matches method will never be invoked. - -[TIP] -==== - -If possible, try to make pointcuts static, allowing the AOP framework to cache the -results of pointcut evaluation when an AOP proxy is created. -==== - - - -[[aop-api-pointcut-ops]] -==== Operations on pointcuts -Spring supports operations on pointcuts: notably, __union__ and __intersection__. - -* Union means the methods that either pointcut matches. -* Intersection means the methods that both pointcuts match. -* Union is usually more useful. -* Pointcuts can be composed using the static methods in the - __org.springframework.aop.support.Pointcuts__ class, or using the - __ComposablePointcut__ class in the same package. However, using AspectJ pointcut - expressions is usually a simpler approach. - - - -[[aop-api-pointcuts-aspectj]] -==== AspectJ expression pointcuts -Since 2.0, the most important type of pointcut used by Spring is -`org.springframework.aop.aspectj.AspectJExpressionPointcut`. This is a pointcut that -uses an AspectJ supplied library to parse an AspectJ pointcut expression string. - -See the previous chapter for a discussion of supported AspectJ pointcut primitives. - - - -[[aop-api-pointcuts-impls]] -==== Convenience pointcut implementations -Spring provides several convenient pointcut implementations. Some can be used out of the -box; others are intended to be subclassed in application-specific pointcuts. - - -[[aop-api-pointcuts-static]] -===== Static pointcuts -Static pointcuts are based on method and target class, and cannot take into account the -method's arguments. Static pointcuts are sufficient - __and best__ - for most usages. -It's possible for Spring to evaluate a static pointcut only once, when a method is first -invoked: after that, there is no need to evaluate the pointcut again with each method -invocation. - -Let's consider some static pointcut implementations included with Spring. - -[[aop-api-pointcuts-regex]] -====== Regular expression pointcuts -One obvious way to specify static pointcuts is regular expressions. Several AOP -frameworks besides Spring make this possible. -`org.springframework.aop.support.JdkRegexpMethodPointcut` is a generic regular -expression pointcut, using the regular expression support in JDK 1.4+. - -Using the `JdkRegexpMethodPointcut` class, you can provide a list of pattern Strings. If -any of these is a match, the pointcut will evaluate to true. (So the result is -effectively the union of these pointcuts.) - -The usage is shown below: - -[source,xml,indent=0] -[subs="verbatim"] ----- - - - - .*set.* - .*absquatulate - - - ----- - -Spring provides a convenience class, `RegexpMethodPointcutAdvisor`, that allows us to -also reference an Advice (remember that an Advice can be an interceptor, before advice, -throws advice etc.). Behind the scenes, Spring will use a `JdkRegexpMethodPointcut`. -Using `RegexpMethodPointcutAdvisor` simplifies wiring, as the one bean encapsulates both -pointcut and advice, as shown below: - -[source,xml,indent=0] -[subs="verbatim"] ----- - - - - - - - .*set.* - .*absquatulate - - - ----- - -__RegexpMethodPointcutAdvisor__ can be used with any Advice type. - -[[aop-api-pointcuts-attribute-driven]] -====== Attribute-driven pointcuts -An important type of static pointcut is a __metadata-driven__ pointcut. This uses the -values of metadata attributes: typically, source-level metadata. - - -[[aop-api-pointcuts-dynamic]] -===== Dynamic pointcuts -Dynamic pointcuts are costlier to evaluate than static pointcuts. They take into account -method __arguments__, as well as static information. This means that they must be -evaluated with every method invocation; the result cannot be cached, as arguments will -vary. - -The main example is the `control flow` pointcut. - -[[aop-api-pointcuts-cflow]] -====== Control flow pointcuts -Spring control flow pointcuts are conceptually similar to AspectJ __cflow__ pointcuts, -although less powerful. (There is currently no way to specify that a pointcut executes -below a join point matched by another pointcut.) A control flow pointcut matches the -current call stack. For example, it might fire if the join point was invoked by a method -in the `com.mycompany.web` package, or by the `SomeCaller` class. Control flow pointcuts -are specified using the `org.springframework.aop.support.ControlFlowPointcut` class. -[NOTE] -==== -Control flow pointcuts are significantly more expensive to evaluate at runtime than even -other dynamic pointcuts. In Java 1.4, the cost is about 5 times that of other dynamic -pointcuts. -==== - - - -[[aop-api-pointcuts-superclasses]] -==== Pointcut superclasses -Spring provides useful pointcut superclasses to help you to implement your own pointcuts. - -Because static pointcuts are most useful, you'll probably subclass -StaticMethodMatcherPointcut, as shown below. This requires implementing just one -abstract method (although it's possible to override other methods to customize behavior): - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - class TestStaticPointcut extends StaticMethodMatcherPointcut { - - public boolean matches(Method m, Class targetClass) { - // return true if custom criteria match - } - } ----- - -There are also superclasses for dynamic pointcuts. - -You can use custom pointcuts with any advice type in Spring 1.0 RC2 and above. - - - -[[aop-api-pointcuts-custom]] -==== Custom pointcuts -Because pointcuts in Spring AOP are Java classes, rather than language features (as in -AspectJ) it's possible to declare custom pointcuts, whether static or dynamic. Custom -pointcuts in Spring can be arbitrarily complex. However, using the AspectJ pointcut -expression language is recommended if possible. - -[NOTE] -==== -Later versions of Spring may offer support for "semantic pointcuts" as offered by JAC: -for example, "all methods that change instance variables in the target object." -==== - - - - -[[aop-api-advice]] -=== Advice API in Spring -Let's now look at how Spring AOP handles advice. - - - -[[aop-api-advice-lifecycle]] -==== Advice lifecycles -Each advice is a Spring bean. An advice instance can be shared across all advised -objects, or unique to each advised object. This corresponds to __per-class__ or -__per-instance__ advice. - -Per-class advice is used most often. It is appropriate for generic advice such as -transaction advisors. These do not depend on the state of the proxied object or add new -state; they merely act on the method and arguments. - -Per-instance advice is appropriate for introductions, to support mixins. In this case, -the advice adds state to the proxied object. - -It's possible to use a mix of shared and per-instance advice in the same AOP proxy. - - - -[[aop-api-advice-types]] -==== Advice types in Spring -Spring provides several advice types out of the box, and is extensible to support -arbitrary advice types. Let us look at the basic concepts and standard advice types. - - -[[aop-api-advice-around]] -===== Interception around advice -The most fundamental advice type in Spring is __interception around advice__. - -Spring is compliant with the AOP Alliance interface for around advice using method -interception. MethodInterceptors implementing around advice should implement the -following interface: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface MethodInterceptor extends Interceptor { - - Object invoke(MethodInvocation invocation) throws Throwable; - } ----- - -The `MethodInvocation` argument to the `invoke()` method exposes the method being -invoked; the target join point; the AOP proxy; and the arguments to the method. The -`invoke()` method should return the invocation's result: the return value of the join -point. - -A simple `MethodInterceptor` implementation looks as follows: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class DebugInterceptor implements MethodInterceptor { - - public Object invoke(MethodInvocation invocation) throws Throwable { - System.out.println("Before: invocation=[" + invocation + "]"); - Object rval = invocation.proceed(); - System.out.println("Invocation returned"); - return rval; - } - } ----- - -Note the call to the MethodInvocation's `proceed()` method. This proceeds down the -interceptor chain towards the join point. Most interceptors will invoke this method, and -return its return value. However, a MethodInterceptor, like any around advice, can -return a different value or throw an exception rather than invoke the proceed method. -However, you don't want to do this without good reason! - -[NOTE] -==== -MethodInterceptors offer interoperability with other AOP Alliance-compliant AOP -implementations. The other advice types discussed in the remainder of this section -implement common AOP concepts, but in a Spring-specific way. While there is an advantage -in using the most specific advice type, stick with MethodInterceptor around advice if -you are likely to want to run the aspect in another AOP framework. Note that pointcuts -are not currently interoperable between frameworks, and the AOP Alliance does not -currently define pointcut interfaces. -==== - - -[[aop-api-advice-before]] -===== Before advice -A simpler advice type is a __before advice__. This does not need a `MethodInvocation` -object, since it will only be called before entering the method. - -The main advantage of a before advice is that there is no need to invoke the `proceed()` -method, and therefore no possibility of inadvertently failing to proceed down the -interceptor chain. - -The `MethodBeforeAdvice` interface is shown below. (Spring's API design would allow for -field before advice, although the usual objects apply to field interception and it's -unlikely that Spring will ever implement it). - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface MethodBeforeAdvice extends BeforeAdvice { - - void before(Method m, Object[] args, Object target) throws Throwable; - } ----- - -Note the return type is `void`. Before advice can insert custom behavior before the join -point executes, but cannot change the return value. If a before advice throws an -exception, this will abort further execution of the interceptor chain. The exception -will propagate back up the interceptor chain. If it is unchecked, or on the signature of -the invoked method, it will be passed directly to the client; otherwise it will be -wrapped in an unchecked exception by the AOP proxy. - -An example of a before advice in Spring, which counts all method invocations: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class CountingBeforeAdvice implements MethodBeforeAdvice { - - private int count; - - public void before(Method m, Object[] args, Object target) throws Throwable { - ++count; - } - - public int getCount() { - return count; - } - } ----- - -[TIP] -==== - -Before advice can be used with any pointcut. -==== - - -[[aop-api-advice-throws]] -===== Throws advice -__Throws advice__ is invoked after the return of the join point if the join point threw -an exception. Spring offers typed throws advice. Note that this means that the -`org.springframework.aop.ThrowsAdvice` interface does not contain any methods: It is a -tag interface identifying that the given object implements one or more typed throws -advice methods. These should be in the form of: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - afterThrowing([Method, args, target], subclassOfThrowable) ----- - -Only the last argument is required. The method signatures may have either one or four -arguments, depending on whether the advice method is interested in the method and -arguments. The following classes are examples of throws advice. - -The advice below is invoked if a `RemoteException` is thrown (including subclasses): - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class RemoteThrowsAdvice implements ThrowsAdvice { - - public void afterThrowing(RemoteException ex) throws Throwable { - // Do something with remote exception - } - } ----- - -The following advice is invoked if a `ServletException` is thrown. Unlike the above -advice, it declares 4 arguments, so that it has access to the invoked method, method -arguments and target object: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class ServletThrowsAdviceWithArguments implements ThrowsAdvice { - - public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) { - // Do something with all arguments - } - } ----- - -The final example illustrates how these two methods could be used in a single class, -which handles both `RemoteException` and `ServletException`. Any number of throws advice -methods can be combined in a single class. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public static class CombinedThrowsAdvice implements ThrowsAdvice { - - public void afterThrowing(RemoteException ex) throws Throwable { - // Do something with remote exception - } - - public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) { - // Do something with all arguments - } - } ----- - -[NOTE] -==== -If a throws-advice method throws an exception itself, it will override the -original exception (i.e. change the exception thrown to the user). The overriding -exception will typically be a RuntimeException; this is compatible with any method -signature. However, if a throws-advice method throws a checked exception, it will have -to match the declared exceptions of the target method and is hence to some degree -coupled to specific target method signatures. __Do not throw an undeclared checked -exception that is incompatible with the target method's signature!__ -==== - -[TIP] -==== - -Throws advice can be used with any pointcut. -==== - - -[[aop-api-advice-after-returning]] -===== After Returning advice -An after returning advice in Spring must implement the -__org.springframework.aop.AfterReturningAdvice__ interface, shown below: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface AfterReturningAdvice extends Advice { - - void afterReturning(Object returnValue, Method m, Object[] args, Object target) - throws Throwable; - } ----- - -An after returning advice has access to the return value (which it cannot modify), -invoked method, methods arguments and target. - -The following after returning advice counts all successful method invocations that have -not thrown exceptions: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class CountingAfterReturningAdvice implements AfterReturningAdvice { - - private int count; - - public void afterReturning(Object returnValue, Method m, Object[] args, Object target) - throws Throwable { - ++count; - } - - public int getCount() { - return count; - } - } ----- - -This advice doesn't change the execution path. If it throws an exception, this will be -thrown up the interceptor chain instead of the return value. - -[TIP] -==== - -After returning advice can be used with any pointcut. -==== - - -[[aop-api-advice-introduction]] -===== Introduction advice -Spring treats introduction advice as a special kind of interception advice. - -Introduction requires an `IntroductionAdvisor`, and an `IntroductionInterceptor`, -implementing the following interface: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface IntroductionInterceptor extends MethodInterceptor { - - boolean implementsInterface(Class intf); - } ----- - -The `invoke()` method inherited from the AOP Alliance `MethodInterceptor` interface must -implement the introduction: that is, if the invoked method is on an introduced -interface, the introduction interceptor is responsible for handling the method call - it -cannot invoke `proceed()`. - -Introduction advice cannot be used with any pointcut, as it applies only at class, -rather than method, level. You can only use introduction advice with the -`IntroductionAdvisor`, which has the following methods: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface IntroductionAdvisor extends Advisor, IntroductionInfo { - - ClassFilter getClassFilter(); - - void validateInterfaces() throws IllegalArgumentException; - } - - public interface IntroductionInfo { - - Class[] getInterfaces(); - } ----- - -There is no `MethodMatcher`, and hence no `Pointcut`, associated with introduction -advice. Only class filtering is logical. - -The `getInterfaces()` method returns the interfaces introduced by this advisor. - -The `validateInterfaces()` method is used internally to see whether or not the -introduced interfaces can be implemented by the configured `IntroductionInterceptor`. - -Let's look at a simple example from the Spring test suite. Let's suppose we want to -introduce the following interface to one or more objects: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public interface Lockable { - void lock(); - void unlock(); - boolean locked(); - } ----- - -This illustrates a __mixin__. We want to be able to cast advised objects to Lockable, -whatever their type, and call lock and unlock methods. If we call the lock() method, we -want all setter methods to throw a `LockedException`. Thus we can add an aspect that -provides the ability to make objects immutable, without them having any knowledge of it: -a good example of AOP. - -Firstly, we'll need an `IntroductionInterceptor` that does the heavy lifting. In this -case, we extend the `org.springframework.aop.support.DelegatingIntroductionInterceptor` -convenience class. We could implement IntroductionInterceptor directly, but using -`DelegatingIntroductionInterceptor` is best for most cases. - -The `DelegatingIntroductionInterceptor` is designed to delegate an introduction to an -actual implementation of the introduced interface(s), concealing the use of interception -to do so. The delegate can be set to any object using a constructor argument; the -default delegate (when the no-arg constructor is used) is this. Thus in the example -below, the delegate is the `LockMixin` subclass of `DelegatingIntroductionInterceptor`. -Given a delegate (by default itself), a `DelegatingIntroductionInterceptor` instance -looks for all interfaces implemented by the delegate (other than -IntroductionInterceptor), and will support introductions against any of them. It's -possible for subclasses such as `LockMixin` to call the `suppressInterface(Class intf)` -method to suppress interfaces that should not be exposed. However, no matter how many -interfaces an `IntroductionInterceptor` is prepared to support, the -`IntroductionAdvisor` used will control which interfaces are actually exposed. An -introduced interface will conceal any implementation of the same interface by the target. - -Thus `LockMixin` extends `DelegatingIntroductionInterceptor` and implements `Lockable` -itself. The superclass automatically picks up that Lockable can be supported for -introduction, so we don't need to specify that. We could introduce any number of -interfaces in this way. - -Note the use of the `locked` instance variable. This effectively adds additional state -to that held in the target object. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable { - - private boolean locked; - - public void lock() { - this.locked = true; - } - - public void unlock() { - this.locked = false; - } - - public boolean locked() { - return this.locked; - } - - public Object invoke(MethodInvocation invocation) throws Throwable { - if (locked() && invocation.getMethod().getName().indexOf("set") == 0) { - throw new LockedException(); - } - return super.invoke(invocation); - } - - } ----- - -Often it isn't necessary to override the `invoke()` method: the -`DelegatingIntroductionInterceptor` implementation - which calls the delegate method if -the method is introduced, otherwise proceeds towards the join point - is usually -sufficient. In the present case, we need to add a check: no setter method can be invoked -if in locked mode. - -The introduction advisor required is simple. All it needs to do is hold a distinct -`LockMixin` instance, and specify the introduced interfaces - in this case, just -`Lockable`. A more complex example might take a reference to the introduction -interceptor (which would be defined as a prototype): in this case, there's no -configuration relevant for a `LockMixin`, so we simply create it using `new`. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class LockMixinAdvisor extends DefaultIntroductionAdvisor { - - public LockMixinAdvisor() { - super(new LockMixin(), Lockable.class); - } - } ----- - -We can apply this advisor very simply: it requires no configuration. (However, it __is__ -necessary: It's impossible to use an `IntroductionInterceptor` without an -__IntroductionAdvisor__.) As usual with introductions, the advisor must be per-instance, -as it is stateful. We need a different instance of `LockMixinAdvisor`, and hence -`LockMixin`, for each advised object. The advisor comprises part of the advised object's -state. - -We can apply this advisor programmatically, using the `Advised.addAdvisor()` method, or -(the recommended way) in XML configuration, like any other advisor. All proxy creation -choices discussed below, including "auto proxy creators," correctly handle introductions -and stateful mixins. - - - - -[[aop-api-advisor]] -=== Advisor API in Spring -In Spring, an Advisor is an aspect that contains just a single advice object associated -with a pointcut expression. - -Apart from the special case of introductions, any advisor can be used with any advice. -`org.springframework.aop.support.DefaultPointcutAdvisor` is the most commonly used -advisor class. For example, it can be used with a `MethodInterceptor`, `BeforeAdvice` or -`ThrowsAdvice`. - -It is possible to mix advisor and advice types in Spring in the same AOP proxy. For -example, you could use a interception around advice, throws advice and before advice in -one proxy configuration: Spring will automatically create the necessary interceptor -chain. - - - - -[[aop-pfb]] -=== Using the ProxyFactoryBean to create AOP proxies -If you're using the Spring IoC container (an ApplicationContext or BeanFactory) for your -business objects - and you should be! - you will want to use one of Spring's AOP -FactoryBeans. (Remember that a factory bean introduces a layer of indirection, enabling -it to create objects of a different type.) - -[NOTE] -==== -The Spring AOP support also uses factory beans under the covers. -==== - -The basic way to create an AOP proxy in Spring is to use the -__org.springframework.aop.framework.ProxyFactoryBean__. This gives complete control over -the pointcuts and advice that will apply, and their ordering. However, there are simpler -options that are preferable if you don't need such control. - - - -[[aop-pfb-1]] -==== Basics -The `ProxyFactoryBean`, like other Spring `FactoryBean` implementations, introduces a -level of indirection. If you define a `ProxyFactoryBean` with name `foo`, what objects -referencing `foo` see is not the `ProxyFactoryBean` instance itself, but an object -created by the `ProxyFactoryBean`'s implementation of the `getObject()` method. This -method will create an AOP proxy wrapping a target object. - -One of the most important benefits of using a `ProxyFactoryBean` or another IoC-aware -class to create AOP proxies, is that it means that advices and pointcuts can also be -managed by IoC. This is a powerful feature, enabling certain approaches that are hard to -achieve with other AOP frameworks. For example, an advice may itself reference -application objects (besides the target, which should be available in any AOP -framework), benefiting from all the pluggability provided by Dependency Injection. - - - -[[aop-pfb-2]] -==== JavaBean properties -In common with most `FactoryBean` implementations provided with Spring, the -`ProxyFactoryBean` class is itself a JavaBean. Its properties are used to: - -* Specify the target you want to proxy. -* Specify whether to use CGLIB (see below and also <>). - -Some key properties are inherited from `org.springframework.aop.framework.ProxyConfig` -(the superclass for all AOP proxy factories in Spring). These key properties include: - -* `proxyTargetClass`: `true` if the target class is to be proxied, rather than the - target class' interfaces. If this property value is set to `true`, then CGLIB proxies - will be created (but see also <>). -* `optimize`: controls whether or not aggressive optimizations are applied to proxies - __created via CGLIB__. One should not blithely use this setting unless one fully - understands how the relevant AOP proxy handles optimization. This is currently used - only for CGLIB proxies; it has no effect with JDK dynamic proxies. -* `frozen`: if a proxy configuration is `frozen`, then changes to the configuration are - no longer allowed. This is useful both as a slight optimization and for those cases - when you don't want callers to be able to manipulate the proxy (via the `Advised` - interface) after the proxy has been created. The default value of this property is - `false`, so changes such as adding additional advice are allowed. -* `exposeProxy`: determines whether or not the current proxy should be exposed in a - `ThreadLocal` so that it can be accessed by the target. If a target needs to obtain - the proxy and the `exposeProxy` property is set to `true`, the target can use the - `AopContext.currentProxy()` method. - -Other properties specific to `ProxyFactoryBean` include: - -* `proxyInterfaces`: array of String interface names. If this isn't supplied, a CGLIB - proxy for the target class will be used (but see also <>). -* `interceptorNames`: String array of `Advisor`, interceptor or other advice names to - apply. Ordering is significant, on a first come-first served basis. That is to say - that the first interceptor in the list will be the first to be able to intercept the - invocation. - -The names are bean names in the current factory, including bean names from ancestor -factories. You can't mention bean references here since doing so would result in the -`ProxyFactoryBean` ignoring the singleton setting of the advice. - -You can append an interceptor name with an asterisk ( `*`). This will result in the -application of all advisor beans with names starting with the part before the asterisk -to be applied. An example of using this feature can be found in <>. - -* singleton: whether or not the factory should return a single object, no matter how - often the `getObject()` method is called. Several `FactoryBean` implementations offer - such a method. The default value is `true`. If you want to use stateful advice - for - example, for stateful mixins - use prototype advices along with a singleton value of - `false`. - - - -[[aop-pfb-proxy-types]] -==== JDK- and CGLIB-based proxies -This section serves as the definitive documentation on how the `ProxyFactoryBean` -chooses to create one of either a JDK- and CGLIB-based proxy for a particular target -object (that is to be proxied). - -[NOTE] -==== -The behavior of the `ProxyFactoryBean` with regard to creating JDK- or CGLIB-based -proxies changed between versions 1.2.x and 2.0 of Spring. The `ProxyFactoryBean` now -exhibits similar semantics with regard to auto-detecting interfaces as those of the -`TransactionProxyFactoryBean` class. -==== - -If the class of a target object that is to be proxied (hereafter simply referred to as -the target class) doesn't implement any interfaces, then a CGLIB-based proxy will be -created. This is the easiest scenario, because JDK proxies are interface based, and no -interfaces means JDK proxying isn't even possible. One simply plugs in the target bean, -and specifies the list of interceptors via the `interceptorNames` property. Note that a -CGLIB-based proxy will be created even if the `proxyTargetClass` property of the -`ProxyFactoryBean` has been set to `false`. (Obviously this makes no sense, and is best -removed from the bean definition because it is at best redundant, and at worst -confusing.) - -If the target class implements one (or more) interfaces, then the type of proxy that is -created depends on the configuration of the `ProxyFactoryBean`. - -If the `proxyTargetClass` property of the `ProxyFactoryBean` has been set to `true`, -then a CGLIB-based proxy will be created. This makes sense, and is in keeping with the -principle of least surprise. Even if the `proxyInterfaces` property of the -`ProxyFactoryBean` has been set to one or more fully qualified interface names, the fact -that the `proxyTargetClass` property is set to `true` __will__ cause CGLIB-based -proxying to be in effect. - -If the `proxyInterfaces` property of the `ProxyFactoryBean` has been set to one or more -fully qualified interface names, then a JDK-based proxy will be created. The created -proxy will implement all of the interfaces that were specified in the `proxyInterfaces` -property; if the target class happens to implement a whole lot more interfaces than -those specified in the `proxyInterfaces` property, that is all well and good but those -additional interfaces will not be implemented by the returned proxy. - -If the `proxyInterfaces` property of the `ProxyFactoryBean` has __not__ been set, but -the target class __does implement one (or more)__ interfaces, then the -`ProxyFactoryBean` will auto-detect the fact that the target class does actually -implement at least one interface, and a JDK-based proxy will be created. The interfaces -that are actually proxied will be __all__ of the interfaces that the target class -implements; in effect, this is the same as simply supplying a list of each and every -interface that the target class implements to the `proxyInterfaces` property. However, -it is significantly less work, and less prone to typos. - - - -[[aop-api-proxying-intf]] -==== Proxying interfaces -Let's look at a simple example of `ProxyFactoryBean` in action. This example involves: - -* A __target bean__ that will be proxied. This is the "personTarget" bean definition in - the example below. -* An Advisor and an Interceptor used to provide advice. -* An AOP proxy bean definition specifying the target object (the personTarget bean) and - the interfaces to proxy, along with the advices to apply. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - - - - myAdvisor - debugInterceptor - - - ----- - -Note that the `interceptorNames` property takes a list of String: the bean names of the -interceptor or advisors in the current factory. Advisors, interceptors, before, after -returning and throws advice objects can be used. The ordering of advisors is significant. - -[NOTE] -==== -You might be wondering why the list doesn't hold bean references. The reason for this is -that if the ProxyFactoryBean's singleton property is set to false, it must be able to -return independent proxy instances. If any of the advisors is itself a prototype, an -independent instance would need to be returned, so it's necessary to be able to obtain -an instance of the prototype from the factory; holding a reference isn't sufficient. -==== - -The "person" bean definition above can be used in place of a Person implementation, as -follows: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Person person = (Person) factory.getBean("person"); ----- - -Other beans in the same IoC context can express a strongly typed dependency on it, as -with an ordinary Java object: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - ----- - -The `PersonUser` class in this example would expose a property of type Person. As far as -it's concerned, the AOP proxy can be used transparently in place of a "real" person -implementation. However, its class would be a dynamic proxy class. It would be possible -to cast it to the `Advised` interface (discussed below). - -It's possible to conceal the distinction between target and proxy using an anonymous -__inner bean__, as follows. Only the `ProxyFactoryBean` definition is different; the -advice is included only for completeness: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - - - myAdvisor - debugInterceptor - - - ----- - -This has the advantage that there's only one object of type `Person`: useful if we want -to prevent users of the application context from obtaining a reference to the un-advised -object, or need to avoid any ambiguity with Spring IoC __autowiring__. There's also -arguably an advantage in that the ProxyFactoryBean definition is self-contained. -However, there are times when being able to obtain the un-advised target from the -factory might actually be an __advantage__: for example, in certain test scenarios. - - - -[[aop-api-proxying-class]] -==== Proxying classes -What if you need to proxy a class, rather than one or more interfaces? - -Imagine that in our example above, there was no `Person` interface: we needed to advise -a class called `Person` that didn't implement any business interface. In this case, you -can configure Spring to use CGLIB proxying, rather than dynamic proxies. Simply set the -`proxyTargetClass` property on the ProxyFactoryBean above to true. While it's best to -program to interfaces, rather than classes, the ability to advise classes that don't -implement interfaces can be useful when working with legacy code. (In general, Spring -isn't prescriptive. While it makes it easy to apply good practices, it avoids forcing a -particular approach.) - -If you want to, you can force the use of CGLIB in any case, even if you do have -interfaces. - -CGLIB proxying works by generating a subclass of the target class at runtime. Spring -configures this generated subclass to delegate method calls to the original target: the -subclass is used to implement the __Decorator__ pattern, weaving in the advice. - -CGLIB proxying should generally be transparent to users. However, there are some issues -to consider: - -* `Final` methods can't be advised, as they can't be overridden. -* There is no need to add CGLIB to your classpath. As of Spring 3.2, CGLIB is repackaged - and included in the spring-core JAR. In other words, CGLIB-based AOP will work "out of - the box" just as do JDK dynamic proxies. - -There's little performance difference between CGLIB proxying and dynamic proxies. As of -Spring 1.0, dynamic proxies are slightly faster. However, this may change in the future. -Performance should not be a decisive consideration in this case. - - - -[[aop-global-advisors]] -==== Using 'global' advisors -By appending an asterisk to an interceptor name, all advisors with bean names matching -the part before the asterisk, will be added to the advisor chain. This can come in handy -if you need to add a standard set of 'global' advisors: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - global* - - - - - - ----- - - - - -[[aop-concise-proxy]] -=== Concise proxy definitions -Especially when defining transactional proxies, you may end up with many similar proxy -definitions. The use of parent and child bean definitions, along with inner bean -definitions, can result in much cleaner and more concise proxy definitions. - -First a parent, __template__, bean definition is created for the proxy: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - PROPAGATION_REQUIRED - - - ----- - -This will never be instantiated itself, so may actually be incomplete. Then each proxy -which needs to be created is just a child bean definition, which wraps the target of the -proxy as an inner bean definition, since the target will never be used on its own anyway. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - ----- - -It is of course possible to override properties from the parent template, such as in -this case, the transaction propagation settings: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - PROPAGATION_REQUIRED,readOnly - PROPAGATION_REQUIRED,readOnly - PROPAGATION_REQUIRED,readOnly - PROPAGATION_REQUIRED - - - ----- - -Note that in the example above, we have explicitly marked the parent bean definition as -__abstract__ by using the __abstract__ attribute, as described -<>, so that it may not actually ever be -instantiated. Application contexts (but not simple bean factories) will by default -pre-instantiate all singletons. It is therefore important (at least for singleton beans) -that if you have a (parent) bean definition which you intend to use only as a template, -and this definition specifies a class, you must make sure to set the __abstract__ -attribute to __true__, otherwise the application context will actually try to -pre-instantiate it. - - - - -[[aop-prog]] -=== Creating AOP proxies programmatically with the ProxyFactory -It's easy to create AOP proxies programmatically using Spring. This enables you to use -Spring AOP without dependency on Spring IoC. - -The following listing shows creation of a proxy for a target object, with one -interceptor and one advisor. The interfaces implemented by the target object will -automatically be proxied: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ProxyFactory factory = new ProxyFactory(myBusinessInterfaceImpl); - factory.addAdvice(myMethodInterceptor); - factory.addAdvisor(myAdvisor); - MyBusinessInterface tb = (MyBusinessInterface) factory.getProxy(); ----- - -The first step is to construct an object of type -`org.springframework.aop.framework.ProxyFactory`. You can create this with a target -object, as in the above example, or specify the interfaces to be proxied in an alternate -constructor. - -You can add advices (with interceptors as a specialized kind of advice) and/or advisors, -and manipulate them for the life of the ProxyFactory. If you add an -IntroductionInterceptionAroundAdvisor, you can cause the proxy to implement additional -interfaces. - -There are also convenience methods on ProxyFactory (inherited from `AdvisedSupport`) -which allow you to add other advice types such as before and throws advice. -AdvisedSupport is the superclass of both ProxyFactory and ProxyFactoryBean. - -[TIP] -==== - -Integrating AOP proxy creation with the IoC framework is best practice in most -applications. We recommend that you externalize configuration from Java code with AOP, -as in general. -==== - - - - -[[aop-api-advised]] -=== Manipulating advised objects -However you create AOP proxies, you can manipulate them using the -`org.springframework.aop.framework.Advised` interface. Any AOP proxy can be cast to this -interface, whichever other interfaces it implements. This interface includes the -following methods: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Advisor[] getAdvisors(); - - void addAdvice(Advice advice) throws AopConfigException; - - void addAdvice(int pos, Advice advice) throws AopConfigException; - - void addAdvisor(Advisor advisor) throws AopConfigException; - - void addAdvisor(int pos, Advisor advisor) throws AopConfigException; - - int indexOf(Advisor advisor); - - boolean removeAdvisor(Advisor advisor) throws AopConfigException; - - void removeAdvisor(int index) throws AopConfigException; - - boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException; - - boolean isFrozen(); ----- - -The `getAdvisors()` method will return an Advisor for every advisor, interceptor or -other advice type that has been added to the factory. If you added an Advisor, the -returned advisor at this index will be the object that you added. If you added an -interceptor or other advice type, Spring will have wrapped this in an advisor with a -pointcut that always returns true. Thus if you added a `MethodInterceptor`, the advisor -returned for this index will be an `DefaultPointcutAdvisor` returning your -`MethodInterceptor` and a pointcut that matches all classes and methods. - -The `addAdvisor()` methods can be used to add any Advisor. Usually the advisor holding -pointcut and advice will be the generic `DefaultPointcutAdvisor`, which can be used with -any advice or pointcut (but not for introductions). - -By default, it's possible to add or remove advisors or interceptors even once a proxy -has been created. The only restriction is that it's impossible to add or remove an -introduction advisor, as existing proxies from the factory will not show the interface -change. (You can obtain a new proxy from the factory to avoid this problem.) - -A simple example of casting an AOP proxy to the `Advised` interface and examining and -manipulating its advice: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - Advised advised = (Advised) myObject; - Advisor[] advisors = advised.getAdvisors(); - int oldAdvisorCount = advisors.length; - System.out.println(oldAdvisorCount + " advisors"); - - // Add an advice like an interceptor without a pointcut - // Will match all proxied methods - // Can use for interceptors, before, after returning or throws advice - advised.addAdvice(new DebugInterceptor()); - - // Add selective advice using a pointcut - advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice)); - - assertEquals("Added two advisors", oldAdvisorCount + 2, advised.getAdvisors().length); ----- - -[NOTE] -==== -It's questionable whether it's advisable (no pun intended) to modify advice on a -business object in production, although there are no doubt legitimate usage cases. -However, it can be very useful in development: for example, in tests. I have sometimes -found it very useful to be able to add test code in the form of an interceptor or other -advice, getting inside a method invocation I want to test. (For example, the advice can -get inside a transaction created for that method: for example, to run SQL to check that -a database was correctly updated, before marking the transaction for roll back.) -==== - -Depending on how you created the proxy, you can usually set a `frozen` flag, in which -case the `Advised` `isFrozen()` method will return true, and any attempts to modify -advice through addition or removal will result in an `AopConfigException`. The ability -to freeze the state of an advised object is useful in some cases, for example, to -prevent calling code removing a security interceptor. It may also be used in Spring 1.1 -to allow aggressive optimization if runtime advice modification is known not to be -required. - - - - -[[aop-autoproxy]] -=== Using the "auto-proxy" facility -So far we've considered explicit creation of AOP proxies using a `ProxyFactoryBean` or -similar factory bean. - -Spring also allows us to use "auto-proxy" bean definitions, which can automatically -proxy selected bean definitions. This is built on Spring "bean post processor" -infrastructure, which enables modification of any bean definition as the container loads. - -In this model, you set up some special bean definitions in your XML bean definition file -to configure the auto proxy infrastructure. This allows you just to declare the targets -eligible for auto-proxying: you don't need to use `ProxyFactoryBean`. - -There are two ways to do this: - -* Using an auto-proxy creator that refers to specific beans in the current context. -* A special case of auto-proxy creation that deserves to be considered separately; - auto-proxy creation driven by source-level metadata attributes. - - - -[[aop-autoproxy-choices]] -==== Autoproxy bean definitions -The `org.springframework.aop.framework.autoproxy` package provides the following -standard auto-proxy creators. - - -[[aop-api-autoproxy]] -===== BeanNameAutoProxyCreator -The `BeanNameAutoProxyCreator` class is a `BeanPostProcessor` that automatically creates -AOP proxies for beans with names matching literal values or wildcards. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - myInterceptor - - - ----- - -As with `ProxyFactoryBean`, there is an `interceptorNames` property rather than a list -of interceptors, to allow correct behavior for prototype advisors. Named "interceptors" -can be advisors or any advice type. - -As with auto proxying in general, the main point of using `BeanNameAutoProxyCreator` is -to apply the same configuration consistently to multiple objects, with minimal volume of -configuration. It is a popular choice for applying declarative transactions to multiple -objects. - -Bean definitions whose names match, such as "jdkMyBean" and "onlyJdk" in the above -example, are plain old bean definitions with the target class. An AOP proxy will be -created automatically by the `BeanNameAutoProxyCreator`. The same advice will be applied -to all matching beans. Note that if advisors are used (rather than the interceptor in -the above example), the pointcuts may apply differently to different beans. - - -[[aop-api-autoproxy-default]] -===== DefaultAdvisorAutoProxyCreator -A more general and extremely powerful auto proxy creator is -`DefaultAdvisorAutoProxyCreator`. This will automagically apply eligible advisors in the -current context, without the need to include specific bean names in the auto-proxy -advisor's bean definition. It offers the same merit of consistent configuration and -avoidance of duplication as `BeanNameAutoProxyCreator`. - -Using this mechanism involves: - -* Specifying a `DefaultAdvisorAutoProxyCreator` bean definition. -* Specifying any number of Advisors in the same or related contexts. Note that these - __must__ be Advisors, not just interceptors or other advices. This is necessary - because there must be a pointcut to evaluate, to check the eligibility of each advice - to candidate bean definitions. - -The `DefaultAdvisorAutoProxyCreator` will automatically evaluate the pointcut contained -in each advisor, to see what (if any) advice it should apply to each business object -(such as "businessObject1" and "businessObject2" in the example). - -This means that any number of advisors can be applied automatically to each business -object. If no pointcut in any of the advisors matches any method in a business object, -the object will not be proxied. As bean definitions are added for new business objects, -they will automatically be proxied if necessary. - -Autoproxying in general has the advantage of making it impossible for callers or -dependencies to obtain an un-advised object. Calling getBean("businessObject1") on this -ApplicationContext will return an AOP proxy, not the target business object. (The "inner -bean" idiom shown earlier also offers this benefit.) - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - ----- - -The `DefaultAdvisorAutoProxyCreator` is very useful if you want to apply the same advice -consistently to many business objects. Once the infrastructure definitions are in place, -you can simply add new business objects without including specific proxy configuration. -You can also drop in additional aspects very easily - for example, tracing or -performance monitoring aspects - with minimal change to configuration. - -The DefaultAdvisorAutoProxyCreator offers support for filtering (using a naming -convention so that only certain advisors are evaluated, allowing use of multiple, -differently configured, AdvisorAutoProxyCreators in the same factory) and ordering. -Advisors can implement the `org.springframework.core.Ordered` interface to ensure -correct ordering if this is an issue. The TransactionAttributeSourceAdvisor used in the -above example has a configurable order value; the default setting is unordered. - - -[[aop-api-autoproxy-abstract]] -===== AbstractAdvisorAutoProxyCreator -This is the superclass of DefaultAdvisorAutoProxyCreator. You can create your own -auto-proxy creators by subclassing this class, in the unlikely event that advisor -definitions offer insufficient customization to the behavior of the framework -`DefaultAdvisorAutoProxyCreator`. - - - -[[aop-autoproxy-metadata]] -==== Using metadata-driven auto-proxying -A particularly important type of auto-proxying is driven by metadata. This produces a -similar programming model to .NET `ServicedComponents`. Instead of defining metadata in -XML descriptors, configuration for transaction management and other enterprise services -is held in source-level attributes. - -In this case, you use the `DefaultAdvisorAutoProxyCreator`, in combination with Advisors -that understand metadata attributes. The metadata specifics are held in the pointcut -part of the candidate advisors, rather than in the auto-proxy creation class itself. - -This is really a special case of the `DefaultAdvisorAutoProxyCreator`, but deserves -consideration on its own. (The metadata-aware code is in the pointcuts contained in the -advisors, not the AOP framework itself.) - -The `/attributes` directory of the JPetStore sample application shows the use of -attribute-driven auto-proxying. In this case, there's no need to use the -`TransactionProxyFactoryBean`. Simply defining transactional attributes on business -objects is sufficient, because of the use of metadata-aware pointcuts. The bean -definitions include the following code, in `/WEB-INF/declarativeServices.xml`. Note that -this is generic, and can be used outside the JPetStore: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - ----- - -The `DefaultAdvisorAutoProxyCreator` bean definition (the name is not significant, hence -it can even be omitted) will pick up all eligible pointcuts in the current application -context. In this case, the "transactionAdvisor" bean definition, of type -`TransactionAttributeSourceAdvisor`, will apply to classes or methods carrying a -transaction attribute. The TransactionAttributeSourceAdvisor depends on a -TransactionInterceptor, via constructor dependency. The example resolves this via -autowiring. The `AttributesTransactionAttributeSource` depends on an implementation of -the `org.springframework.metadata.Attributes` interface. In this fragment, the -"attributes" bean satisfies this, using the Jakarta Commons Attributes API to obtain -attribute information. (The application code must have been compiled using the Commons -Attributes compilation task.) - -The `/annotation` directory of the JPetStore sample application contains an analogous -example for auto-proxying driven by JDK 1.5+ annotations. The following configuration -enables automatic detection of Spring's `Transactional` annotation, leading to implicit -proxies for beans containing that annotation: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - ----- - -The `TransactionInterceptor` defined here depends on a `PlatformTransactionManager` -definition, which is not included in this generic file (although it could be) because it -will be specific to the application's transaction requirements (typically JTA, as in -this example, or Hibernate, JDO or JDBC): - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - ----- - -[TIP] -==== - -If you require only declarative transaction management, using these generic XML -definitions will result in Spring automatically proxying all classes or methods with -transaction attributes. You won't need to work directly with AOP, and the programming -model is similar to that of .NET ServicedComponents. -==== - -This mechanism is extensible. It's possible to do auto-proxying based on custom -attributes. You need to: - -* Define your custom attribute. -* Specify an Advisor with the necessary advice, including a pointcut that is triggered - by the presence of the custom attribute on a class or method. You may be able to use - an existing advice, merely implementing a static pointcut that picks up the custom - attribute. - -It's possible for such advisors to be unique to each advised class (for example, mixins): -they simply need to be defined as prototype, rather than singleton, bean definitions. -For example, the `LockMixin` introduction interceptor from the Spring test suite, -shown above, could be used in conjunction with a generic `DefaultIntroductionAdvisor`: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - ----- - -Note that both `lockMixin` and `lockableAdvisor` are defined as prototypes. - - - - -[[aop-targetsource]] -=== Using TargetSources -Spring offers the concept of a __TargetSource__, expressed in the -`org.springframework.aop.TargetSource` interface. This interface is responsible for -returning the "target object" implementing the join point. The `TargetSource` -implementation is asked for a target instance each time the AOP proxy handles a method -invocation. - -Developers using Spring AOP don't normally need to work directly with TargetSources, but -this provides a powerful means of supporting pooling, hot swappable and other -sophisticated targets. For example, a pooling TargetSource can return a different target -instance for each invocation, using a pool to manage instances. - -If you do not specify a TargetSource, a default implementation is used that wraps a -local object. The same target is returned for each invocation (as you would expect). - -Let's look at the standard target sources provided with Spring, and how you can use them. - -[TIP] -==== - -When using a custom target source, your target will usually need to be a prototype -rather than a singleton bean definition. This allows Spring to create a new target -instance when required. -==== - - - -[[aop-ts-swap]] -==== Hot swappable target sources -The `org.springframework.aop.target.HotSwappableTargetSource` exists to allow the target -of an AOP proxy to be switched while allowing callers to keep their references to it. - -Changing the target source's target takes effect immediately. The -`HotSwappableTargetSource` is threadsafe. - -You can change the target via the `swap()` method on HotSwappableTargetSource as follows: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper"); - Object oldTarget = swapper.swap(newTarget); ----- - -The XML definitions required look as follows: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - ----- - -The above `swap()` call changes the target of the swappable bean. Clients who hold a -reference to that bean will be unaware of the change, but will immediately start hitting -the new target. - -Although this example doesn't add any advice - and it's not necessary to add advice to -use a `TargetSource` - of course any `TargetSource` can be used in conjunction with -arbitrary advice. - - - -[[aop-ts-pool]] -==== Pooling target sources -Using a pooling target source provides a similar programming model to stateless session -EJBs, in which a pool of identical instances is maintained, with method invocations -going to free objects in the pool. - -A crucial difference between Spring pooling and SLSB pooling is that Spring pooling can -be applied to any POJO. As with Spring in general, this service can be applied in a -non-invasive way. - -Spring provides out-of-the-box support for Commons Pool 2.2, which provides a -fairly efficient pooling implementation. You'll need the commons-pool Jar on your -application's classpath to use this feature. It's also possible to subclass -`org.springframework.aop.target.AbstractPoolingTargetSource` to support any other -pooling API. - -[NOTE] -==== -Commons Pool 1.5+ is also supported but deprecated as of Spring Framework 4.2. -==== - - -Sample configuration is shown below: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - ... properties omitted - - - - - - - - - - - ----- - -Note that the target object - "businessObjectTarget" in the example - __must__ be a -prototype. This allows the `PoolingTargetSource` implementation to create new instances -of the target to grow the pool as necessary. See the javadocs of -`AbstractPoolingTargetSource` and the concrete subclass you wish to use for information -about its properties: "maxSize" is the most basic, and always guaranteed to be present. - -In this case, "myInterceptor" is the name of an interceptor that would need to be -defined in the same IoC context. However, it isn't necessary to specify interceptors to -use pooling. If you want only pooling, and no other advice, don't set the -interceptorNames property at all. - -It's possible to configure Spring so as to be able to cast any pooled object to the -`org.springframework.aop.target.PoolingConfig` interface, which exposes information -about the configuration and current size of the pool through an introduction. You'll -need to define an advisor like this: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - -This advisor is obtained by calling a convenience method on the -`AbstractPoolingTargetSource` class, hence the use of MethodInvokingFactoryBean. This -advisor's name ("poolConfigAdvisor" here) must be in the list of interceptors names in -the ProxyFactoryBean exposing the pooled object. - -The cast will look as follows: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - PoolingConfig conf = (PoolingConfig) beanFactory.getBean("businessObject"); - System.out.println("Max pool size is " + conf.getMaxSize()); ----- - -[NOTE] -==== -Pooling stateless service objects is not usually necessary. We don't believe it should -be the default choice, as most stateless objects are naturally thread safe, and instance -pooling is problematic if resources are cached. -==== - -Simpler pooling is available using auto-proxying. It's possible to set the TargetSources -used by any auto-proxy creator. - - - -[[aop-ts-prototype]] -==== Prototype target sources -Setting up a "prototype" target source is similar to a pooling TargetSource. In this -case, a new instance of the target will be created on every method invocation. Although -the cost of creating a new object isn't high in a modern JVM, the cost of wiring up the -new object (satisfying its IoC dependencies) may be more expensive. Thus you shouldn't -use this approach without very good reason. - -To do this, you could modify the `poolTargetSource` definition shown above as follows. -(I've also changed the name, for clarity.) - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - ----- - -There's only one property: the name of the target bean. Inheritance is used in the -TargetSource implementations to ensure consistent naming. As with the pooling target -source, the target bean must be a prototype bean definition. - - - -[[aop-ts-threadlocal]] -==== ThreadLocal target sources - -`ThreadLocal` target sources are useful if you need an object to be created for each -incoming request (per thread that is). The concept of a `ThreadLocal` provide a JDK-wide -facility to transparently store resource alongside a thread. Setting up a -`ThreadLocalTargetSource` is pretty much the same as was explained for the other types -of target source: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - ----- - -[NOTE] -==== -ThreadLocals come with serious issues (potentially resulting in memory leaks) when -incorrectly using them in a multi-threaded and multi-classloader environments. One -should always consider wrapping a threadlocal in some other class and never directly use -the `ThreadLocal` itself (except of course in the wrapper class). Also, one should -always remember to correctly set and unset (where the latter simply involved a call to -`ThreadLocal.set(null)`) the resource local to the thread. Unsetting should be done in -any case since not unsetting it might result in problematic behavior. Spring's -ThreadLocal support does this for you and should always be considered in favor of using -ThreadLocals without other proper handling code. -==== - - - - -[[aop-extensibility]] -=== Defining new Advice types - -Spring AOP is designed to be extensible. While the interception implementation strategy -is presently used internally, it is possible to support arbitrary advice types in -addition to the out-of-the-box interception around advice, before, throws advice and -after returning advice. - -The `org.springframework.aop.framework.adapter` package is an SPI package allowing -support for new custom advice types to be added without changing the core framework. -The only constraint on a custom `Advice` type is that it must implement the -`org.aopalliance.aop.Advice` marker interface. - -Please refer to the `org.springframework.aop.framework.adapter` javadocs for further -information. - - - - -[[aop-api-resources]] -=== Further resources -Please refer to the Spring sample applications for further examples of Spring AOP: - -* The JPetStore's default configuration illustrates the use of the - `TransactionProxyFactoryBean` for declarative transaction management. -* The `/attributes` directory of the JPetStore illustrates the use of attribute-driven - declarative transaction management. +include::core-aop-api.adoc[leveloffset=+1] diff --git a/src/asciidoc/testing.adoc b/src/asciidoc/testing.adoc index 2082f1064f1..19629154d37 100644 --- a/src/asciidoc/testing.adoc +++ b/src/asciidoc/testing.adoc @@ -386,11 +386,11 @@ loader since the default loader supports either resource `locations` or annotate + [NOTE] -=== +==== `@ContextConfiguration` provides support for __inheriting__ resource locations or configuration classes as well as context initializers declared by superclasses by default. -=== +==== + @@ -530,13 +530,13 @@ should be active when loading an `ApplicationContext` for test classes. + [NOTE] -=== +==== `@ActiveProfiles` provides support for __inheriting__ active bean definition profiles declared by superclasses by default. It is also possible to resolve active bean definition profiles programmatically by implementing a custom <> and registering it via the `resolver` attribute of `@ActiveProfiles`. -=== +==== + @@ -757,7 +757,7 @@ conjunction with `@ContextConfiguration`. + [NOTE] -=== +==== If the default conventions are sufficient for your test configuration, you can avoid using `@TransactionConfiguration` altogether. In other words, if you have only one transaction manager -- or if you have multiple transaction managers but the transaction @@ -765,7 +765,7 @@ manager for tests is named "transactionManager" or specified via a `TransactionManagementConfigurer` -- and if you want transactions to roll back automatically, then there is no need to annotate your test class with `@TransactionConfiguration`. -=== +==== + @@ -916,7 +916,7 @@ tests and can be used anywhere in the Spring Framework. .JSR-250 Lifecycle Annotations [NOTE] -=== +==== In the Spring TestContext Framework `@PostConstruct` and `@PreDestroy` may be used with standard semantics on any application components configured in the `ApplicationContext`; however, these lifecycle annotations have limited usage within an actual test class. @@ -928,7 +928,7 @@ class. On the other hand, if a method within a test class is annotated with `@PreDestroy`, that method will __never__ be executed. Within a test class it is therefore recommended to use test lifecycle callbacks from the underlying test framework instead of `@PostConstruct` and `@PreDestroy`. -=== +==== [[integration-testing-annotations-junit]] @@ -1819,11 +1819,11 @@ annotation and supplying a list of profiles that should be activated when loadin `ApplicationContext` for the test. [NOTE] -=== +==== `@ActiveProfiles` may be used with any implementation of the new `SmartContextLoader` SPI, but `@ActiveProfiles` is not supported with implementations of the older `ContextLoader` SPI. -=== +==== Let's take a look at some examples with XML configuration and `@Configuration` classes. @@ -2149,7 +2149,7 @@ the `Environment`'s set of `PropertySources` for the `ApplicationContext` loaded annotated integration test. [NOTE] -=== +==== `@TestPropertySource` may be used with any implementation of the `SmartContextLoader` SPI, but `@TestPropertySource` is not supported with implementations of the older `ContextLoader` SPI. @@ -2157,7 +2157,7 @@ SPI, but `@TestPropertySource` is not supported with implementations of the olde Implementations of `SmartContextLoader` gain access to merged test property source values via the `getPropertySourceLocations()` and `getPropertySourceProperties()` methods in `MergedContextConfiguration`. -=== +==== *Declaring test property sources* @@ -2494,7 +2494,7 @@ is much faster. .Test suites and forked processes [NOTE] -=== +==== The Spring TestContext framework stores application contexts in a __static__ cache. This means that the context is literally stored in a `static` variable. In other words, if tests execute in separate processes the static cache will be cleared between each test @@ -2509,7 +2509,7 @@ http://maven.apache.org/plugins/maven-surefire-plugin/test-mojo.html#forkMode[fo for the Maven Surefire plug-in is set to `always` or `pertest`, the TestContext framework will not be able to cache application contexts between test classes and the build process will run significantly slower as a result. -=== +==== Since having a large number of application contexts loaded within a given test suite can cause the suite to take an unnecessarily long time to execute, it is often beneficial to @@ -2678,13 +2678,13 @@ application context for `ExtendedTests` will be loaded only from .Dirtying a context within a context hierarchy [NOTE] -=== +==== If `@DirtiesContext` is used in a test whose context is configured as part of a context hierarchy, the `hierarchyMode` flag can be used to control how the context cache is cleared. For further details consult the discussion of `@DirtiesContext` in <> and the `@DirtiesContext` javadocs. -=== +==== -- @@ -2726,7 +2726,7 @@ use of `@Autowired` on fields and setter methods. The application context config is presented after all sample code listings. [NOTE] -=== +==== The dependency injection behavior in the following code listings is not specific to JUnit. The same DI techniques can be used in conjunction with any testing framework. @@ -2734,7 +2734,7 @@ The following examples make calls to static assertion methods such as `assertNot but without prepending the call with `Assert`. In such cases, assume that the method was properly imported through an `import static` declaration that is not shown in the example. -=== +==== The first code listing shows a JUnit-based implementation of the test class that uses `@Autowired` for field injection. diff --git a/src/asciidoc/web-integration.adoc b/src/asciidoc/web-integration.adoc new file mode 100644 index 00000000000..e08b90cf181 --- /dev/null +++ b/src/asciidoc/web-integration.adoc @@ -0,0 +1,249 @@ + +[[web-integration]] += Integrating with other web frameworks + + +[[intro]] +== Introduction + +.Spring Web Flow +**** +Spring Web Flow (SWF) aims to be the best solution for the management of web application +page flow. + +SWF integrates with existing frameworks like Spring MVC and JSF, in both Servlet and +Portlet environments. If you have a business process (or processes) that would benefit +from a conversational model as opposed to a purely request model, then SWF may be the +solution. + +SWF allows you to capture logical page flows as self-contained modules that are reusable +in different situations, and as such is ideal for building web application modules that +guide the user through controlled navigations that drive business processes. + +For more information about SWF, consult the +http://projects.spring.io/spring-webflow/[Spring Web Flow website]. +**** + +This chapter details Spring's integration with third party web frameworks, such as +http://www.oracle.com/technetwork/java/javaee/javaserverfaces-139869.html[JSF]. + +One of the core value propositions of the Spring Framework is that of enabling +__choice__. In a general sense, Spring does not force one to use or buy into any +particular architecture, technology, or methodology (although it certainly recommends +some over others). This freedom to pick and choose the architecture, technology, or +methodology that is most relevant to a developer and their development team is +arguably most evident in the web area, where Spring provides its own web framework +(<>), while at the same time providing integration with a number of +popular third party web frameworks. This allows one to continue to leverage any and all +of the skills one may have acquired in a particular web framework such as JSF, while +at the same time being able to enjoy the benefits afforded by Spring in other areas such +as data access, declarative transaction management, and flexible configuration and +application assembly. + +Having dispensed with the woolly sales patter (c.f. the previous paragraph), the +remainder of this chapter will concentrate upon the meaty details of integrating your +favorite web framework with Spring. One thing that is often commented upon by developers +coming to Java from other languages is the seeming super-abundance of web frameworks +available in Java. There are indeed a great number of web frameworks in the Java space; +in fact there are far too many to cover with any semblance of detail in a single +chapter. This chapter thus picks four of the more popular web frameworks in Java, +starting with the Spring configuration that is common to all of the supported web +frameworks, and then detailing the specific integration options for each supported web +framework. + +[NOTE] +==== +Please note that this chapter does not attempt to explain how to use any of the +supported web frameworks. For example, if you want to use JSF for the presentation +layer of your web application, the assumption is that you are already familiar with +JSF itself. If you need further details about any of the supported web frameworks +themselves, please do consult <> at the end of this chapter. +==== + + + + +[[web-integration-common]] +== Common configuration +Before diving into the integration specifics of each supported web framework, let us +first take a look at the Spring configuration that is __not__ specific to any one web +framework. (This section is equally applicable to Spring's own web framework, Spring +MVC.) + +One of the concepts (for want of a better word) espoused by (Spring's) lightweight +application model is that of a layered architecture. Remember that in a 'classic' +layered architecture, the web layer is but one of many layers; it serves as one of the +entry points into a server side application and it delegates to service objects +(facades) defined in a service layer to satisfy business specific (and +presentation-technology agnostic) use cases. In Spring, these service objects, any other +business-specific objects, data access objects, etc. exist in a distinct 'business +context', which contains __no__ web or presentation layer objects (presentation objects +such as Spring MVC controllers are typically configured in a distinct 'presentation +context'). This section details how one configures a Spring container (a +`WebApplicationContext`) that contains all of the 'business beans' in one's application. + +On to specifics: all that one need do is to declare a +{javadoc-baseurl}/org/springframework/web/context/ContextLoaderListener.html[`ContextLoaderListener`] +in the standard Java EE servlet `web.xml` file of one's web application, and add a +`contextConfigLocation` section (in the same file) that defines which +set of Spring XML configuration files to load. + +Find below the configuration: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + org.springframework.web.context.ContextLoaderListener + +---- + +Find below the configuration: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + contextConfigLocation + /WEB-INF/applicationContext*.xml + +---- + +If you don't specify the `contextConfigLocation` context parameter, the +`ContextLoaderListener` will look for a file called `/WEB-INF/applicationContext.xml` to +load. Once the context files are loaded, Spring creates a +{javadoc-baseurl}/org/springframework/web/context/WebApplicationContext.html[`WebApplicationContext`] +object based on the bean definitions and stores it in the `ServletContext` of the web +application. + +All Java web frameworks are built on top of the Servlet API, and so one can use the +following code snippet to get access to this 'business context' `ApplicationContext` +created by the `ContextLoaderListener`. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext); +---- + +The +{javadoc-baseurl}/org/springframework/web/context/support/WebApplicationContextUtils.html[`WebApplicationContextUtils`] +class is for convenience, so you don't have to remember the name of the `ServletContext` +attribute. Its __getWebApplicationContext()__ method will return `null` if an object +doesn't exist under the `WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE` +key. Rather than risk getting `NullPointerExceptions` in your application, it's better +to use the `getRequiredWebApplicationContext()` method. This method throws an exception +when the `ApplicationContext` is missing. + +Once you have a reference to the `WebApplicationContext`, you can retrieve beans by +their name or type. Most developers retrieve beans by name and then cast them to one of +their implemented interfaces. + +Fortunately, most of the frameworks in this section have simpler ways of looking up +beans. Not only do they make it easy to get beans from a Spring container, but they also +allow you to use dependency injection on their controllers. Each web framework section +has more detail on its specific integration strategies. + + + + +[[jsf]] +== JavaServer Faces 1.2 +JavaServer Faces (JSF) is the JCP's standard component-based, event-driven web user +interface framework. As of Java EE 5, it is an official part of the Java EE umbrella. + +For a popular JSF runtime as well as for popular JSF component libraries, check out the +http://myfaces.apache.org/[Apache MyFaces project]. The MyFaces project also provides +common JSF extensions such as http://myfaces.apache.org/orchestra/[MyFaces Orchestra]: +a Spring-based JSF extension that provides rich conversation scope support. + +[NOTE] +==== +Spring Web Flow 2.0 provides rich JSF support through its newly established Spring Faces +module, both for JSF-centric usage (as described in this section) and for Spring-centric +usage (using JSF views within a Spring MVC dispatcher). Check out the +http://projects.spring.io/spring-webflow[Spring Web Flow website] for details! +==== + +The key element in Spring's JSF integration is the JSF `ELResolver` mechanism. + +[[jsf-springbeanfaceselresolver]] +=== SpringBeanFacesELResolver (JSF 1.2+) +`SpringBeanFacesELResolver` is a JSF 1.2 compliant `ELResolver` implementation, +integrating with the standard Unified EL as used by JSF 1.2 and JSP 2.1. Like +`SpringBeanVariableResolver`, it delegates to the Spring's 'business context' +`WebApplicationContext` __first__, then to the default resolver of the underlying JSF +implementation. + +Configuration-wise, simply define `SpringBeanFacesELResolver` in your JSF 1.2 +__faces-context.xml__ file: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + org.springframework.web.jsf.el.SpringBeanFacesELResolver + ... + + +---- + + +[[jsf-facescontextutils]] +=== FacesContextUtils +A custom `VariableResolver` works well when mapping one's properties to beans +in __faces-config.xml__, but at times one may need to grab a bean explicitly. The +{javadoc-baseurl}/org/springframework/web/jsf/FacesContextUtils.html[`FacesContextUtils`] +class makes this easy. It is similar to `WebApplicationContextUtils`, except that it +takes a `FacesContext` parameter rather than a `ServletContext` parameter. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + ApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance()); +---- + + + +[[struts]] +== Apache Struts 2.x +Invented by Craig McClanahan, http://struts.apache.org[Struts] is an open source project +hosted by the Apache Software Foundation. At the time, it greatly simplified the +JSP/Servlet programming paradigm and won over many developers who were using proprietary +frameworks. It simplified the programming model, it was open source (and thus free as in +beer), and it had a large community, which allowed the project to grow and become popular +among Java web developers. + +Check out the Struts +https://struts.apache.org/release/2.3.x/docs/spring-plugin.html[Spring Plugin] for the +built-in Spring integration shipped with Struts. + + + +[[tapestry]] +== Tapestry 5.x +From the http://tapestry.apache.org/[Tapestry homepage]: + +Tapestry is a "__Component oriented framework for creating dynamic, robust, +highly scalable web applications in Java.__" + +While Spring has its own <>, there are a number of unique +advantages to building an enterprise Java application using a combination of Tapestry +for the web user interface and the Spring container for the lower layers. + +For more information, check out Tapestry's dedicated +https://tapestry.apache.org/integrating-with-spring-framework.html[integration module for +Spring]. + + + +[[web-integration-resources]] +== Further Resources +Find below links to further resources about the various web frameworks described in this +chapter. + +* The http://www.oracle.com/technetwork/java/javaee/javaserverfaces-139869.html[JSF] homepage +* The http://struts.apache.org/[Struts] homepage +* The http://tapestry.apache.org/[Tapestry] homepage + diff --git a/src/asciidoc/web-mvc.adoc b/src/asciidoc/web-mvc.adoc index ef9ff06b077..47a4fd78a43 100644 --- a/src/asciidoc/web-mvc.adoc +++ b/src/asciidoc/web-mvc.adoc @@ -1103,14 +1103,14 @@ arguments can be used in arbitrary order with the only exception of `BindingResu arguments. This is described in the next section. [NOTE] -=== +==== Spring 3.1 introduced a new set of support classes for `@RequestMapping` methods called `RequestMappingHandlerMapping` and `RequestMappingHandlerAdapter` respectively. They are recommended for use and even required to take advantage of new features in Spring MVC 3.1 and going forward. The new support classes are enabled by default from the MVC namespace and with use of the MVC Java config but must be configured explicitly if using neither. -=== +==== [[mvc-ann-arguments]] @@ -1124,11 +1124,11 @@ The following are the supported method arguments: `null`. [NOTE] -=== +==== Session access may not be thread-safe, in particular in a Servlet environment. Consider setting the ++RequestMappingHandlerAdapter++'s "synchronizeOnSession" flag to "true" if multiple requests are allowed to access a session concurrently. -=== +==== * `org.springframework.web.context.request.WebRequest` or `org.springframework.web.context.request.NativeWebRequest`. Allows for generic @@ -1380,11 +1380,11 @@ will be raised. The exception is handled in the `DefaultHandlerExceptionResolver sends a `400` error back to the client. [NOTE] -=== +==== Also see <> for information on configuring message converters and a validator through the MVC namespace or the MVC Java config. -=== +==== [[mvc-ann-responsebody]] @@ -1740,12 +1740,12 @@ and wraps the `ServletRequest` in order to make the form data available through `ServletRequest.getParameter{asterisk}()` family of methods. [NOTE] -=== +==== As `HttpPutFormContentFilter` consumes the body of the request, it should not be configured for PUT or PATCH URLs that rely on other converters for `application/x-www-form-urlencoded`. This includes `@RequestBody MultiValueMap` and `HttpEntity>`. -=== +==== [[mvc-ann-cookievalue]] @@ -2031,12 +2031,12 @@ the view class or interface to be used: ---- [NOTE] -=== +==== Note that despite `@JsonView` allowing for more than one class to be specified, the use on a controller method is only supported with exactly one class argument. Consider the use of a composite interface if you need to enable multiple views. -=== +==== For controllers relying on view resolution, simply add the serialization view class to the model: @@ -2180,12 +2180,12 @@ an exception. It is handled by a matching `@ExceptionHandler` method in the same controller or by one of the configured `HandlerExceptionResolver` instances. [NOTE] -=== +==== Under the covers, when a `Callable` raises an Exception, Spring MVC still dispatches to the Servlet container to resume processing. The only difference is that the result of executing the `Callable` is an `Exception` that must be processed with the configured `HandlerExceptionResolver` instances. -=== +==== When using a `DeferredResult`, you have a choice of calling its `setErrorResult(Object)` method and provide an `Exception` or any other Object you'd like to use as the result. @@ -2447,10 +2447,10 @@ If the current time is outside office hours, the user is redirected to a static file that says, for example, you can only access the website during office hours. [NOTE] -=== +==== When using the `RequestMappingHandlerMapping` the actual handler is an instance of `HandlerMethod` which identifies the specific controller method that will be invoked. -=== +==== As you can see, the Spring adapter class `HandlerInterceptorAdapter` makes it easier to extend the `HandlerInterceptor` interface. @@ -2582,13 +2582,13 @@ As you can see, you can identify a parent view, from which all views in the prop file "extend". This way you can specify a default view class, for example. [NOTE] -=== +==== Subclasses of `AbstractCachingViewResolver` cache view instances that they resolve. Caching improves performance of certain view technologies. It's possible to turn off the cache by setting the `cache` property to `false`. Furthermore, if you must refresh a certain view at runtime (for example when a Velocity template is modified), you can use the `removeFromCache(String viewName, Locale loc)` method. -=== +==== @@ -2865,10 +2865,10 @@ extension but with the `Accept` header set to the preferred media-type, and the resolution of request to views would occur. [NOTE] -=== +==== If `ContentNegotiatingViewResolver`'s list of ViewResolvers is not configured explicitly, it automatically uses any ViewResolvers defined in the application context. -=== +==== The corresponding controller code that returns an Atom RSS feed for a URI of the form `http://localhost/content.atom` or `http://localhost/content` with an `Accept` header of @@ -3081,9 +3081,9 @@ by implementing `HandlerMethodMappingNamingStrategy` and configuring it on your a name attribute that can be used to override the default strategy. [NOTE] -=== +==== The assigned request mapping names are logged at TRACE level on startup. -=== +==== The Spring JSP tag library provides a function called `mvcUrl` that can be used to prepare links to controller methods based on this mechanism. @@ -4930,7 +4930,7 @@ Here is an example: ---- [NOTE] -=== +==== An application should have only one configuration extending `DelegatingWebMvcConfiguration` or a single `@EnableWebMvc` annotated class, since they both register the same underlying beans. @@ -4938,7 +4938,7 @@ beans. Modifying beans in this way does not prevent you from using any of the higher-level constructs shown earlier in this section. `WebMvcConfigurerAdapter` subclasses and `WebMvcConfigurer` implementations are still being used. -=== +==== diff --git a/src/asciidoc/web-portlet.adoc b/src/asciidoc/web-portlet.adoc new file mode 100644 index 00000000000..bad4875251f --- /dev/null +++ b/src/asciidoc/web-portlet.adoc @@ -0,0 +1,1468 @@ +[[portlet]] += Portlet MVC Framework + + +[[portlet-introduction]] +== Introduction + +.JSR-168 The Java Portlet Specification +**** +For more general information about portlet development, please review a whitepaper from +Oracle entitled +http://www.oracle.com/technetwork/java/index-raji-test-141933.html["Introduction +to JSR 168"], and of course the +http://jcp.org/aboutJava/communityprocess/final/jsr168/[JSR-168 Specification] itself. +**** + +In addition to supporting conventional (servlet-based) Web development, Spring also +supports JSR-168 Portlet development. As much as possible, the Portlet MVC framework is +a mirror image of the Web MVC framework, and also uses the same underlying view +abstractions and integration technology. So, be sure to review the chapters entitled +<> and <> before continuing with this chapter. + +[NOTE] +==== +Bear in mind that while the concepts of Spring MVC are the same in Spring Portlet MVC, +there are some notable differences created by the unique workflow of JSR-168 portlets. +==== + +The main way in which portlet workflow differs from servlet workflow is that the request +to the portlet can have two distinct phases: the action phase and the render phase. The +action phase is executed only once and is where any 'backend' changes or actions occur, +such as making changes in a database. The render phase then produces what is displayed +to the user each time the display is refreshed. The critical point here is that for a +single overall request, the action phase is executed only once, but the render phase may +be executed multiple times. This provides (and requires) a clean separation between the +activities that modify the persistent state of your system and the activities that +generate what is displayed to the user. + +.Spring Web Flow +**** +Spring Web Flow (SWF) aims to be the best solution for the management of web application +page flow. + +SWF integrates with existing frameworks like Spring MVC and JSF, in both Servlet and +Portlet environments. If you have a business process (or processes) that would benefit +from a conversational model as opposed to a purely request model, then SWF may be the +solution. + +SWF allows you to capture logical page flows as self-contained modules that are reusable +in different situations, and as such is ideal for building web application modules that +guide the user through controlled navigations that drive business processes. + +For more information about SWF, consult the Spring Web Flow website. +**** + +The dual phases of portlet requests are one of the real strengths of the JSR-168 +specification. For example, dynamic search results can be updated routinely on the +display without the user explicitly rerunning the search. Most other portlet MVC +frameworks attempt to completely hide the two phases from the developer and make it look +as much like traditional servlet development as possible - we think this approach +removes one of the main benefits of using portlets. So, the separation of the two phases +is preserved throughout the Spring Portlet MVC framework. The primary manifestation of +this approach is that where the servlet version of the MVC classes will have one method +that deals with the request, the portlet version of the MVC classes will have two +methods that deal with the request: one for the action phase and one for the render +phase. For example, where the servlet version of `AbstractController` has the +`handleRequestInternal(..)` method, the portlet version of `AbstractController` has +`handleActionRequestInternal(..)` and `handleRenderRequestInternal(..)` methods. + +The framework is designed around a `DispatcherPortlet` that dispatches requests to +handlers, with configurable handler mappings and view resolution, just as the +`DispatcherServlet` in the web framework does. File upload is also supported in the same +way. + +Locale resolution and theme resolution are not supported in Portlet MVC - these areas +are in the purview of the portal/portlet container and are not appropriate at the Spring +level. However, all mechanisms in Spring that depend on the locale (such as +internationalization of messages) will still function properly because +`DispatcherPortlet` exposes the current locale in the same way as `DispatcherServlet`. + + + +[[portlet-introduction-controller]] +=== Controllers - The C in MVC +The default handler is still a very simple `Controller` interface, offering just two +methods: + +* `void handleActionRequest(request,response)` +* `ModelAndView handleRenderRequest(request,response)` + +The framework also includes most of the same controller implementation hierarchy, such +as `AbstractController`, `SimpleFormController`, and so on. Data binding, command object +usage, model handling, and view resolution are all the same as in the servlet framework. + + + +[[portlet-introduction-view]] +=== Views - The V in MVC +All the view rendering capabilities of the servlet framework are used directly via a +special bridge servlet named `ViewRendererServlet`. By using this servlet, the portlet +request is converted into a servlet request and the view can be rendered using the +entire normal servlet infrastructure. This means all the existing renderers, such as +JSP, Velocity, etc., can still be used within the portlet. + + + +[[portlet-introduction-scope]] +=== Web-scoped beans +Spring Portlet MVC supports beans whose lifecycle is scoped to the current HTTP request +or HTTP `Session` (both normal and global). This is not a specific feature of Spring +Portlet MVC itself, but rather of the `WebApplicationContext` container(s) that Spring +Portlet MVC uses. These bean scopes are described in detail in +<> + + + + +[[portlet-dispatcher]] +== The DispatcherPortlet + +Portlet MVC is a request-driven web MVC framework, designed around a portlet that +dispatches requests to controllers and offers other functionality facilitating the +development of portlet applications. Spring's `DispatcherPortlet` however, does more +than just that. It is completely integrated with the Spring `ApplicationContext` and +allows you to use every other feature Spring has. + +Like ordinary portlets, the `DispatcherPortlet` is declared in the `portlet.xml` file of +your web application: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + sample + org.springframework.web.portlet.DispatcherPortlet + + text/html + view + + + Sample Portlet + + +---- + +The `DispatcherPortlet` now needs to be configured. + +In the Portlet MVC framework, each `DispatcherPortlet` has its own +`WebApplicationContext`, which inherits all the beans already defined in the Root +`WebApplicationContext`. These inherited beans can be overridden in the portlet-specific +scope, and new scope-specific beans can be defined local to a given portlet instance. + +The framework will, on initialization of a `DispatcherPortlet`, look for a file named +`[portlet-name]-portlet.xml` in the `WEB-INF` directory of your web application and +create the beans defined there (overriding the definitions of any beans defined with the +same name in the global scope). + +The config location used by the `DispatcherPortlet` can be modified through a portlet +initialization parameter (see below for details). + +The Spring `DispatcherPortlet` has a few special beans it uses, in order to be able to +process requests and render the appropriate views. These beans are included in the +Spring framework and can be configured in the `WebApplicationContext`, just as any other +bean would be configured. Each of those beans is described in more detail below. Right +now, we'll just mention them, just to let you know they exist and to enable us to go on +talking about the `DispatcherPortlet`. For most of the beans, defaults are provided so +you don't have to worry about configuring them. + +[[portlet-webappctx-special-beans-tbl]] +.Special beans in the WebApplicationContext +[cols="1,4"] +|=== +| Expression| Explanation + +| handler mapping(s) +| (<>) a list of pre- and post-processors and controllers that + will be executed if they match certain criteria (for instance a matching portlet mode + specified with the controller) + +| controller(s) +| (<>) the beans providing the actual functionality (or at least, + access to the functionality) as part of the MVC triad + +| view resolver +| (<>) capable of resolving view names to view definitions + +| multipart resolver +| (<>) offers functionality to process file uploads from HTML forms + +| handler exception resolver +| (<>) offers functionality to map exceptions to views or + implement other more complex exception handling code +|=== + +When a `DispatcherPortlet` is setup for use and a request comes in for that specific +`DispatcherPortlet`, it starts processing the request. The list below describes the +complete process a request goes through if handled by a `DispatcherPortlet`: + +. The locale returned by `PortletRequest.getLocale()` is bound to the request to let +elements in the process resolve the locale to use when processing the request (rendering +the view, preparing data, etc.). +. If a multipart resolver is specified and this is an `ActionRequest`, the request is +inspected for multiparts and if they are found, it is wrapped in a +`MultipartActionRequest` for further processing by other elements in the process. (See +<> for further information about multipart handling). +. An appropriate handler is searched for. If a handler is found, the execution chain +associated with the handler (pre-processors, post-processors, controllers) will be +executed in order to prepare a model. +. If a model is returned, the view is rendered, using the view resolver that has been +configured with the `WebApplicationContext`. If no model is returned (which could be due +to a pre- or post-processor intercepting the request, for example, for security +reasons), no view is rendered, since the request could already have been fulfilled. + +Exceptions that are thrown during processing of the request get picked up by any of the +handler exception resolvers that are declared in the `WebApplicationContext`. Using +these exception resolvers you can define custom behavior in case such exceptions get +thrown. + +You can customize Spring's `DispatcherPortlet` by adding context parameters in the +`portlet.xml` file or portlet init-parameters. The possibilities are listed below. + +[[portlet-dpp-init-params]] +.DispatcherPortlet initialization parameters +[cols="1,4"] +|=== +| Parameter| Explanation + +| `contextClass` +| Class that implements `WebApplicationContext`, which will be used to instantiate the + context used by this portlet. If this parameter isn't specified, the + `XmlPortletApplicationContext` will be used. + +| `contextConfigLocation` +| String which is passed to the context instance (specified by `contextClass`) to + indicate where context(s) can be found. The String is potentially split up into + multiple Strings (using a comma as a delimiter) to support multiple contexts (in case + of multiple context locations, for beans that are defined twice, the latest takes + precedence). + +| `namespace` +| The namespace of the `WebApplicationContext`. Defaults to `[portlet-name]-portlet`. + +| `viewRendererUrl` +| The URL at which `DispatcherPortlet` can access an instance of `ViewRendererServlet` + (see <>). +|=== + + + + +[[portlet-viewservlet]] +== The ViewRendererServlet + +The rendering process in Portlet MVC is a bit more complex than in Web MVC. In order to +reuse all the <> from Spring Web MVC, we must convert the +`PortletRequest` / `PortletResponse` to `HttpServletRequest` / `HttpServletResponse` and +then call the `render` method of the `View`. To do this, `DispatcherPortlet` uses a +special servlet that exists for just this purpose: the `ViewRendererServlet`. + +In order for `DispatcherPortlet` rendering to work, you must declare an instance of the +`ViewRendererServlet` in the `web.xml` file for your web application as follows: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + ViewRendererServlet + org.springframework.web.servlet.ViewRendererServlet + + + + ViewRendererServlet + /WEB-INF/servlet/view + +---- + +To perform the actual rendering, `DispatcherPortlet` does the following: + +. Binds the `WebApplicationContext` to the request as an attribute under the same +`WEB_APPLICATION_CONTEXT_ATTRIBUTE` key that `DispatcherServlet` uses. +. Binds the `Model` and `View` objects to the request to make them available to the +`ViewRendererServlet`. +. Constructs a `PortletRequestDispatcher` and performs an `include` using the `/WEB- +INF/servlet/view` URL that is mapped to the `ViewRendererServlet`. + +The `ViewRendererServlet` is then able to call the `render` method on the `View` with +the appropriate arguments. + +The actual URL for the `ViewRendererServlet` can be changed using `DispatcherPortlet`'s +`viewRendererUrl` configuration parameter. + + + + +[[portlet-controller]] +== Controllers +The controllers in Portlet MVC are very similar to the Web MVC Controllers, and porting +code from one to the other should be simple. + +The basis for the Portlet MVC controller architecture is the +`org.springframework.web.portlet.mvc.Controller` interface, which is listed below. + +[source,java,indent=0] +---- + public interface Controller { + + /** + * Process the render request and return a ModelAndView object which the + * DispatcherPortlet will render. + */ + ModelAndView handleRenderRequest(RenderRequest request, + RenderResponse response) throws Exception; + + /** + * Process the action request. There is nothing to return. + */ + void handleActionRequest(ActionRequest request, + ActionResponse response) throws Exception; + + } +---- + +As you can see, the Portlet `Controller` interface requires two methods that handle the +two phases of a portlet request: the action request and the render request. The action +phase should be capable of handling an action request, and the render phase should be +capable of handling a render request and returning an appropriate model and view. While +the `Controller` interface is quite abstract, Spring Portlet MVC offers several +controllers that already contain a lot of the functionality you might need; most of +these are very similar to controllers from Spring Web MVC. The `Controller` interface +just defines the most common functionality required of every controller: handling an +action request, handling a render request, and returning a model and a view. + + + +[[portlet-controller-abstractcontroller]] +=== AbstractController and PortletContentGenerator + +Of course, just a `Controller` interface isn't enough. To provide a basic +infrastructure, all of Spring Portlet MVC's ++Controller++s inherit from +`AbstractController`, a class offering access to Spring's `ApplicationContext` and +control over caching. + +[[portlet-ac-features]] +.Features offered by the AbstractController +[cols="1,4"] +|=== +| Parameter| Explanation + +| `requireSession` +| Indicates whether or not this `Controller` requires a session to do its work. This + feature is offered to all controllers. If a session is not present when such a + controller receives a request, the user is informed using a `SessionRequiredException`. + +| `synchronizeSession` +| Use this if you want handling by this controller to be synchronized on the user's + session. To be more specific, the extending controller will override the + `handleRenderRequestInternal(..)` and `handleActionRequestInternal(..)` methods, which + will be synchronized on the user's session if you specify this variable. + +| `renderWhenMinimized` +| If you want your controller to actually render the view when the portlet is in a + minimized state, set this to true. By default, this is set to false so that portlets + that are in a minimized state don't display any content. + +| `cacheSeconds` +| When you want a controller to override the default cache expiration defined for the + portlet, specify a positive integer here. By default it is set to `-1`, which does not + change the default caching. Setting it to `0` will ensure the result is never cached. +|=== + +The `requireSession` and `cacheSeconds` properties are declared on the +`PortletContentGenerator` class, which is the superclass of `AbstractController`) but +are included here for completeness. + +When using the `AbstractController` as a base class for your controllers (which is not +recommended since there are a lot of other controllers that might already do the job for +you) you only have to override either the `handleActionRequestInternal(ActionRequest, +ActionResponse)` method or the `handleRenderRequestInternal(RenderRequest, +RenderResponse)` method (or both), implement your logic, and return a `ModelAndView` +object (in the case of `handleRenderRequestInternal`). + +The default implementations of both `handleActionRequestInternal(..)` and +`handleRenderRequestInternal(..)` throw a `PortletException`. This is consistent with +the behavior of `GenericPortlet` from the JSR- 168 Specification API. So you only need +to override the method that your controller is intended to handle. + +Here is short example consisting of a class and a declaration in the web application +context. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + package samples; + + import javax.portlet.RenderRequest; + import javax.portlet.RenderResponse; + + import org.springframework.web.portlet.mvc.AbstractController; + import org.springframework.web.portlet.ModelAndView; + + public class SampleController extends AbstractController { + + public ModelAndView handleRenderRequestInternal(RenderRequest request, RenderResponse response) { + ModelAndView mav = new ModelAndView("foo"); + mav.addObject("message", "Hello World!"); + return mav; + } + + } +---- + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + +---- + +The class above and the declaration in the web application context is all you need +besides setting up a handler mapping (see <>) to get this very +simple controller working. + + + +[[portlet-controller-simple]] +=== Other simple controllers +Although you can extend `AbstractController`, Spring Portlet MVC provides a number of +concrete implementations which offer functionality that is commonly used in simple MVC +applications. + +The `ParameterizableViewController` is basically the same as the example above, except +for the fact that you can specify the view name that it will return in the web +application context (no need to hard-code the view name). + +The `PortletModeNameViewController` uses the current mode of the portlet as the view +name. So, if your portlet is in View mode (i.e. `PortletMode.VIEW`) then it uses "view" +as the view name. + + + +[[portlet-controller-command]] +=== Command Controllers +Spring Portlet MVC has the exact same hierarchy of __command controllers__ as Spring Web +MVC. They provide a way to interact with data objects and dynamically bind parameters +from the `PortletRequest` to the data object specified. Your data objects don't have to +implement a framework-specific interface, so you can directly manipulate your persistent +objects if you desire. Let's examine what command controllers are available, to get an +overview of what you can do with them: + +* `AbstractCommandController` - a command controller you can use to create your own + command controller, capable of binding request parameters to a data object you + specify. This class does not offer form functionality, it does however offer + validation features and lets you specify in the controller itself what to do with the + command object that has been filled with the parameters from the request. +* `AbstractFormController` - an abstract controller offering form submission support. + Using this controller you can model forms and populate them using a command object you + retrieve in the controller. After a user has filled the form, `AbstractFormController` + binds the fields, validates, and hands the object back to the controller to take + appropriate action. Supported features are: invalid form submission (resubmission), + validation, and normal form workflow. You implement methods to determine which views + are used for form presentation and success. Use this controller if you need forms, but + don't want to specify what views you're going to show the user in the application + context. +* `SimpleFormController` - a concrete `AbstractFormController` that provides even more + support when creating a form with a corresponding command object. The + `SimpleFormController` lets you specify a command object, a viewname for the form, a + viewname for the page you want to show the user when form submission has succeeded, + and more. +* `AbstractWizardFormController` -- a concrete `AbstractFormController` that provides a + wizard-style interface for editing the contents of a command object across multiple + display pages. Supports multiple user actions: finish, cancel, or page change, all of + which are easily specified in request parameters from the view. + +These command controllers are quite powerful, but they do require a detailed +understanding of how they operate in order to use them efficiently. Carefully review the +javadocs for this entire hierarchy and then look at some sample implementations before +you start using them. + + + +[[portlet-controller-wrapping]] +=== PortletWrappingController + +Instead of developing new controllers, it is possible to use existing portlets and map +requests to them from a `DispatcherPortlet`. Using the `PortletWrappingController`, you +can instantiate an existing `Portlet` as a `Controller` as follows: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + config=/WEB-INF/my-portlet-config.xml + + +---- + +This can be very valuable since you can then use interceptors to pre-process and +post-process requests going to these portlets. Since JSR-168 does not support any kind +of filter mechanism, this is quite handy. For example, this can be used to wrap the +Hibernate `OpenSessionInViewInterceptor` around a MyFaces JSF Portlet. + + + + +[[portlet-handlermapping]] +== Handler mappings +Using a handler mapping you can map incoming portlet requests to appropriate handlers. +There are some handler mappings you can use out of the box, for example, the +`PortletModeHandlerMapping`, but let's first examine the general concept of a +`HandlerMapping`. + +Note: We are intentionally using the term "Handler" here instead of "Controller". +`DispatcherPortlet` is designed to be used with other ways to process requests than just +Spring Portlet MVC's own Controllers. A Handler is any Object that can handle portlet +requests. Controllers are an example of Handlers, and they are of course the default. To +use some other framework with `DispatcherPortlet`, a corresponding implementation of +`HandlerAdapter` is all that is needed. + +The functionality a basic `HandlerMapping` provides is the delivering of a +`HandlerExecutionChain`, which must contain the handler that matches the incoming +request, and may also contain a list of handler interceptors that are applied to the +request. When a request comes in, the `DispatcherPortlet` will hand it over to the +handler mapping to let it inspect the request and come up with an appropriate +`HandlerExecutionChain`. Then the `DispatcherPortlet` will execute the handler and +interceptors in the chain (if any). These concepts are all exactly the same as in Spring +Web MVC. + +The concept of configurable handler mappings that can optionally contain interceptors +(executed before or after the actual handler was executed, or both) is extremely +powerful. A lot of supporting functionality can be built into a custom `HandlerMapping`. +Think of a custom handler mapping that chooses a handler not only based on the portlet +mode of the request coming in, but also on a specific state of the session associated +with the request. + +In Spring Web MVC, handler mappings are commonly based on URLs. Since there is really no +such thing as a URL within a Portlet, we must use other mechanisms to control mappings. +The two most common are the portlet mode and a request parameter, but anything available +to the portlet request can be used in a custom handler mapping. + +The rest of this section describes three of Spring Portlet MVC's most commonly used +handler mappings. They all extend `AbstractHandlerMapping` and share the following +properties: + +* `interceptors`: The list of interceptors to use. ++HandlerInterceptor++s are discussed + in <>. +* `defaultHandler`: The default handler to use, when this handler mapping does not + result in a matching handler. +* `order`: Based on the value of the order property (see the + `org.springframework.core.Ordered` interface), Spring will sort all handler mappings + available in the context and apply the first matching handler. +* `lazyInitHandlers`: Allows for lazy initialization of singleton handlers (prototype + handlers are always lazily initialized). Default value is false. This property is + directly implemented in the three concrete Handlers. + + + +[[portlet-handlermapping-portletmode]] +=== PortletModeHandlerMapping + +This is a simple handler mapping that maps incoming requests based on the current mode +of the portlet (e.g. 'view', 'edit', 'help'). An example: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + +---- + + + +[[portlet-handlermapping-parameter]] +=== ParameterHandlerMapping + +If we need to navigate around to multiple controllers without changing portlet mode, the +simplest way to do this is with a request parameter that is used as the key to control +the mapping. + +`ParameterHandlerMapping` uses the value of a specific request parameter to control the +mapping. The default name of the parameter is `'action'`, but can be changed using the +`'parameterName'` property. + +The bean configuration for this mapping will look something like this: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + +---- + + + +[[portlet-handlermapping-portletmodeparameter]] +=== PortletModeParameterHandlerMapping + +The most powerful built-in handler mapping, `PortletModeParameterHandlerMapping` +combines the capabilities of the two previous ones to allow different navigation within +each portlet mode. + +Again the default name of the parameter is "action", but can be changed using the +`parameterName` property. + +By default, the same parameter value may not be used in two different portlet modes. +This is so that if the portal itself changes the portlet mode, the request will no +longer be valid in the mapping. This behavior can be changed by setting the +`allowDupParameters` property to true. However, this is not recommended. + +The bean configuration for this mapping will look something like this: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + + + + + +---- + +This mapping can be chained ahead of a `PortletModeHandlerMapping`, which can then +provide defaults for each mode and an overall default as well. + + + +[[portlet-handlermapping-interceptor]] +=== Adding HandlerInterceptors + +Spring's handler mapping mechanism has a notion of handler interceptors, which can be +extremely useful when you want to apply specific functionality to certain requests, for +example, checking for a principal. Again Spring Portlet MVC implements these concepts in +the same way as Web MVC. + +Interceptors located in the handler mapping must implement `HandlerInterceptor` from the +`org.springframework.web.portlet` package. Just like the servlet version, this interface +defines three methods: one that will be called before the actual handler will be +executed ( `preHandle`), one that will be called after the handler is executed ( +`postHandle`), and one that is called after the complete request has finished ( +`afterCompletion`). These three methods should provide enough flexibility to do all +kinds of pre- and post- processing. + +The `preHandle` method returns a boolean value. You can use this method to break or +continue the processing of the execution chain. When this method returns `true`, the +handler execution chain will continue. When it returns `false`, the `DispatcherPortlet` +assumes the interceptor itself has taken care of requests (and, for example, rendered an +appropriate view) and does not continue executing the other interceptors and the actual +handler in the execution chain. + +The `postHandle` method is only called on a `RenderRequest`. The `preHandle` and +`afterCompletion` methods are called on both an `ActionRequest` and a `RenderRequest`. +If you need to execute logic in these methods for just one type of request, be sure to +check what kind of request it is before processing it. + + + +[[portlet-handlermapping-interceptoradapter]] +=== HandlerInterceptorAdapter + +As with the servlet package, the portlet package has a concrete implementation of +`HandlerInterceptor` called `HandlerInterceptorAdapter`. This class has empty versions +of all the methods so that you can inherit from this class and implement just one or two +methods when that is all you need. + + + +[[portlet-handlermapping-parameterinterceptor]] +=== ParameterMappingInterceptor + +The portlet package also has a concrete interceptor named `ParameterMappingInterceptor` +that is meant to be used directly with `ParameterHandlerMapping` and +`PortletModeParameterHandlerMapping`. This interceptor will cause the parameter that is +being used to control the mapping to be forwarded from an `ActionRequest` to the +subsequent `RenderRequest`. This will help ensure that the `RenderRequest` is mapped to +the same Handler as the `ActionRequest`. This is done in the `preHandle` method of the +interceptor, so you can still modify the parameter value in your handler to change where +the `RenderRequest` will be mapped. + +Be aware that this interceptor is calling `setRenderParameter` on the `ActionResponse`, +which means that you cannot call `sendRedirect` in your handler when using this +interceptor. If you need to do external redirects then you will either need to forward +the mapping parameter manually or write a different interceptor to handle this for you. + + + + +[[portlet-viewresolver]] +== Views and resolving them +As mentioned previously, Spring Portlet MVC directly reuses all the view technologies +from Spring Web MVC. This includes not only the various `View` implementations +themselves, but also the `ViewResolver` implementations. For more information, refer to +<> and <> respectively. + +A few items on using the existing `View` and `ViewResolver` implementations are worth +mentioning: + +* Most portals expect the result of rendering a portlet to be an HTML fragment. So, + things like JSP/JSTL, Velocity, FreeMarker, and XSLT all make sense. But it is + unlikely that views that return other document types will make any sense in a portlet + context. +* There is no such thing as an HTTP redirect from within a portlet (the + `sendRedirect(..)` method of `ActionResponse` cannot be used to stay within the + portal). So, `RedirectView` and use of the `'redirect:'` prefix will __not__ work + correctly from within Portlet MVC. +* It may be possible to use the `'forward:'` prefix from within Portlet MVC. However, + remember that since you are in a portlet, you have no idea what the current URL looks + like. This means you cannot use a relative URL to access other resources in your web + application and that you will have to use an absolute URL. + +Also, for JSP development, the new Spring Taglib and the new Spring Form Taglib both +work in portlet views in exactly the same way that they work in servlet views. + + + + +[[portlet-multipart]] +== Multipart (file upload) support +Spring Portlet MVC has built-in multipart support to handle file uploads in portlet +applications, just like Web MVC does. The design for the multipart support is done with +pluggable `PortletMultipartResolver` objects, defined in the +`org.springframework.web.portlet.multipart` package. Spring provides a +`PortletMultipartResolver` for use with +http://jakarta.apache.org/commons/fileupload[Commons FileUpload]. How uploading files is +supported will be described in the rest of this section. + +By default, no multipart handling will be done by Spring Portlet MVC, as some developers +will want to handle multiparts themselves. You will have to enable it yourself by adding +a multipart resolver to the web application's context. After you have done that, +`DispatcherPortlet` will inspect each request to see if it contains a multipart. If no +multipart is found, the request will continue as expected. However, if a multipart is +found in the request, the `PortletMultipartResolver` that has been declared in your +context will be used. After that, the multipart attribute in your request will be +treated like any other attribute. + +[NOTE] +==== +Any configured `PortletMultipartResolver` bean __must__ have the following id (or name): +" `portletMultipartResolver`". If you have defined your `PortletMultipartResolver` with +any other name, then the `DispatcherPortlet` will __not__ find your +`PortletMultipartResolver`, and consequently no multipart support will be in effect. +==== + + + +[[portlet-multipart-resolver]] +=== Using the PortletMultipartResolver + +The following example shows how to use the `CommonsPortletMultipartResolver`: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + +---- + +Of course you also need to put the appropriate jars in your classpath for the multipart +resolver to work. In the case of the `CommonsMultipartResolver`, you need to use +`commons-fileupload.jar`. Be sure to use at least version 1.1 of Commons FileUpload as +previous versions do not support JSR-168 Portlet applications. + +Now that you have seen how to set Portlet MVC up to handle multipart requests, let's +talk about how to actually use it. When `DispatcherPortlet` detects a multipart request, +it activates the resolver that has been declared in your context and hands over the +request. What the resolver then does is wrap the current `ActionRequest` in a +`MultipartActionRequest` that has support for multipart file uploads. Using the +`MultipartActionRequest` you can get information about the multiparts contained by this +request and actually get access to the multipart files themselves in your controllers. + +Note that you can only receive multipart file uploads as part of an `ActionRequest`, not +as part of a `RenderRequest`. + + + +[[portlet-multipart-forms]] +=== Handling a file upload in a form +After the `PortletMultipartResolver` has finished doing its job, the request will be +processed like any other. To use the `PortletMultipartResolver`, create a form with an +upload field (see example below), then let Spring bind the file onto your form (backing +object). To actually let the user upload a file, we have to create a (JSP/HTML) form: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- +

Please upload a file

+
+ + +
+---- + +As you can see, we've created a field named "file" that matches the property of the bean +that holds the `byte[]` array. Furthermore we've added the encoding attribute ( +`enctype="multipart/form-data"`), which is necessary to let the browser know how to +encode the multipart fields (do not forget this!). + +Just as with any other property that's not automagically convertible to a string or +primitive type, to be able to put binary data in your objects you have to register a +custom editor with the `PortletRequestDataBinder`. There are a couple of editors +available for handling files and setting the results on an object. There's a +`StringMultipartFileEditor` capable of converting files to Strings (using a user-defined +character set), and there is a `ByteArrayMultipartFileEditor` which converts files to +byte arrays. They function analogous to the `CustomDateEditor`. + +So, to be able to upload files using a form, declare the resolver, a mapping to a +controller that will process the bean, and the controller itself. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + + + + + + + + +---- + +After that, create the controller and the actual class to hold the file property. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class FileUploadController extends SimpleFormController { + + public void onSubmitAction(ActionRequest request, ActionResponse response, + Object command, BindException errors) throws Exception { + + // cast the bean + FileUploadBean bean = (FileUploadBean) command; + + // let's see if there's content there + byte[] file = bean.getFile(); + if (file == null) { + // hmm, that's strange, the user did not upload anything + } + + // do something with the file here + } + + protected void initBinder(PortletRequest request, + PortletRequestDataBinder binder) throws Exception { + // to actually be able to convert Multipart instance to byte[] + // we have to register a custom editor + binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor()); + // now Spring knows how to handle multipart object and convert + } + + } + + public class FileUploadBean { + + private byte[] file; + + public void setFile(byte[] file) { + this.file = file; + } + + public byte[] getFile() { + return file; + } + + } +---- + +As you can see, the `FileUploadBean` has a property of type `byte[]` that holds the +file. The controller registers a custom editor to let Spring know how to actually +convert the multipart objects the resolver has found to properties specified by the +bean. In this example, nothing is done with the `byte[]` property of the bean itself, +but in practice you can do whatever you want (save it in a database, mail it to +somebody, etc). + +An equivalent example in which a file is bound straight to a String-typed property on a +form backing object might look like this: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class FileUploadController extends SimpleFormController { + + public void onSubmitAction(ActionRequest request, ActionResponse response, + Object command, BindException errors) throws Exception { + + // cast the bean + FileUploadBean bean = (FileUploadBean) command; + + // let's see if there's content there + String file = bean.getFile(); + if (file == null) { + // hmm, that's strange, the user did not upload anything + } + + // do something with the file here + } + + protected void initBinder(PortletRequest request, + PortletRequestDataBinder binder) throws Exception { + + // to actually be able to convert Multipart instance to a String + // we have to register a custom editor + binder.registerCustomEditor(String.class, new StringMultipartFileEditor()); + // now Spring knows how to handle multipart objects and convert + } + } + + public class FileUploadBean { + + private String file; + + public void setFile(String file) { + this.file = file; + } + + public String getFile() { + return file; + } + } +---- + +Of course, this last example only makes (logical) sense in the context of uploading a +plain text file (it wouldn't work so well in the case of uploading an image file). + +The third (and final) option is where one binds directly to a `MultipartFile` property +declared on the (form backing) object's class. In this case one does not need to +register any custom property editor because there is no type conversion to be performed. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class FileUploadController extends SimpleFormController { + + public void onSubmitAction(ActionRequest request, ActionResponse response, + Object command, BindException errors) throws Exception { + + // cast the bean + FileUploadBean bean = (FileUploadBean) command; + + // let's see if there's content there + MultipartFile file = bean.getFile(); + if (file == null) { + // hmm, that's strange, the user did not upload anything + } + + // do something with the file here + } + } + + public class FileUploadBean { + + private MultipartFile file; + + public void setFile(MultipartFile file) { + this.file = file; + } + + public MultipartFile getFile() { + return file; + } + + } +---- + + + + +[[portlet-exceptionresolver]] +== Handling exceptions +Just like Servlet MVC, Portlet MVC provides ++HandlerExceptionResolver++s to ease the +pain of unexpected exceptions that occur while your request is being processed by a +handler that matched the request. Portlet MVC also provides a portlet-specific, concrete +`SimpleMappingExceptionResolver` that enables you to take the class name of any +exception that might be thrown and map it to a view name. + + + + +[[portlet-annotation]] +== Annotation-based controller configuration +Spring 2.5 introduced an annotation-based programming model for MVC controllers, using +annotations such as `@RequestMapping`, `@RequestParam`, `@ModelAttribute`, etc. This +annotation support is available for both Servlet MVC and Portlet MVC. Controllers +implemented in this style do not have to extend specific base classes or implement +specific interfaces. Furthermore, they do not usually have direct dependencies on +Servlet or Portlet API's, although they can easily get access to Servlet or Portlet +facilities if desired. + +The following sections document these annotations and how they are most commonly used in +a Portlet environment. + + + +[[portlet-ann-setup]] +=== Setting up the dispatcher for annotation support +__`@RequestMapping` will only be processed if a corresponding `HandlerMapping` (for +type level annotations) and/or `HandlerAdapter` (for method level annotations) is +present in the dispatcher.__ This is the case by default in both `DispatcherServlet` and +`DispatcherPortlet`. + +However, if you are defining custom `HandlerMappings` or `HandlerAdapters`, then you +need to make sure that a corresponding custom `DefaultAnnotationHandlerMapping` and/or +`AnnotationMethodHandlerAdapter` is defined as well - provided that you intend to use +`@RequestMapping`. + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + + + // ... (controller bean definitions) ... + + +---- + +Defining a `DefaultAnnotationHandlerMapping` and/or `AnnotationMethodHandlerAdapter` +explicitly also makes sense if you would like to customize the mapping strategy, e.g. +specifying a custom `WebBindingInitializer` (see below). + + + +[[portlet-ann-controller]] +=== Defining a controller with @Controller + +The `@Controller` annotation indicates that a particular class serves the role of a +__controller__. There is no need to extend any controller base class or reference the +Portlet API. You are of course still able to reference Portlet-specific features if you +need to. + +The basic purpose of the `@Controller` annotation is to act as a stereotype for the +annotated class, indicating its role. The dispatcher will scan such annotated classes +for mapped methods, detecting `@RequestMapping` annotations (see the next section). + +Annotated controller beans may be defined explicitly, using a standard Spring bean +definition in the dispatcher's context. However, the `@Controller` stereotype also +allows for autodetection, aligned with Spring 2.5's general support for detecting +component classes in the classpath and auto-registering bean definitions for them. + +To enable autodetection of such annotated controllers, you have to add component +scanning to your configuration. This is easily achieved by using the __spring-context__ +schema as shown in the following XML snippet: + +[source,xml,indent=0] +[subs="verbatim,quotes"] +---- + + + + + + // ... + + +---- + + + +[[portlet-ann-requestmapping]] +=== Mapping requests with @RequestMapping + +The `@RequestMapping` annotation is used to map portlet modes like 'VIEW'/'EDIT' onto an +entire class or a particular handler method. Typically the type-level annotation maps a +specific mode (or mode plus parameter condition) onto a form controller, with additional +method-level annotations 'narrowing' the primary mapping for specific portlet request +parameters. + +[TIP] +=== + +`@RequestMapping` at the type level may be used for plain implementations of the +`Controller` interface as well. In this case, the request processing code would follow +the traditional `handle(Action|Render)Request` signature, while the controller's mapping +would be expressed through an `@RequestMapping` annotation. This works for pre-built +`Controller` base classes, such as `SimpleFormController`, too. + +In the following discussion, we'll focus on controllers that are based on annotated +handler methods. +=== + +The following is an example of a form controller from the PetPortal sample application +using this annotation: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + @RequestMapping("EDIT") + @SessionAttributes("site") + public class PetSitesEditController { + + private Properties petSites; + + public void setPetSites(Properties petSites) { + this.petSites = petSites; + } + + @ModelAttribute("petSites") + public Properties getPetSites() { + return this.petSites; + } + + @RequestMapping // default (action=list) + public String showPetSites() { + return "petSitesEdit"; + } + + @RequestMapping(params = "action=add") // render phase + public String showSiteForm(Model model) { + // Used for the initial form as well as for redisplaying with errors. + if (!model.containsAttribute("site")) { + model.addAttribute("site", new PetSite()); + } + + return "petSitesAdd"; + } + + @RequestMapping(params = "action=add") // action phase + public void populateSite(@ModelAttribute("site") PetSite petSite, + BindingResult result, SessionStatus status, ActionResponse response) { + new PetSiteValidator().validate(petSite, result); + if (!result.hasErrors()) { + this.petSites.put(petSite.getName(), petSite.getUrl()); + status.setComplete(); + response.setRenderParameter("action", "list"); + } + } + + @RequestMapping(params = "action=delete") + public void removeSite(@RequestParam("site") String site, ActionResponse response) { + this.petSites.remove(site); + response.setRenderParameter("action", "list"); + } + } +---- + + + +[[portlet-ann-requestmapping-arguments]] +=== Supported handler method arguments +Handler methods which are annotated with `@RequestMapping` are allowed to have very +flexible signatures. They may have arguments of the following types, in arbitrary order +(except for validation results, which need to follow right after the corresponding +command object, if desired): + +* Request and/or response objects (Portlet API). You may choose any specific + request/response type, e.g. PortletRequest / ActionRequest / RenderRequest. An + explicitly declared action/render argument is also used for mapping specific request + types onto a handler method (in case of no other information given that differentiates + between action and render requests). +* Session object (Portlet API): of type PortletSession. An argument of this type will + enforce the presence of a corresponding session. As a consequence, such an argument + will never be `null`. +* `org.springframework.web.context.request.WebRequest` or + `org.springframework.web.context.request.NativeWebRequest`. Allows for generic request + parameter access as well as request/session attribute access, without ties to the + native Servlet/Portlet API. +* `java.util.Locale` for the current request locale (the portal locale in a Portlet + environment). +* `java.util.TimeZone` / `java.time.ZoneId` for the current request time zone. +* `java.io.InputStream` / `java.io.Reader` for access to the request's content. This + will be the raw InputStream/Reader as exposed by the Portlet API. +* `java.io.OutputStream` / `java.io.Writer` for generating the response's content. This + will be the raw OutputStream/Writer as exposed by the Portlet API. +* `@RequestParam` annotated parameters for access to specific Portlet request + parameters. Parameter values will be converted to the declared method argument type. +* `java.util.Map` / `org.springframework.ui.Model` / `org.springframework.ui.ModelMap` + for enriching the implicit model that will be exposed to the web view. +* Command/form objects to bind parameters to: as bean properties or fields, with + customizable type conversion, depending on `@InitBinder` methods and/or the + HandlerAdapter configuration - see the " `webBindingInitializer`" property on + `AnnotationMethodHandlerAdapter`. Such command objects along with their validation + results will be exposed as model attributes, by default using the non-qualified + command class name in property notation (e.g. "orderAddress" for type + "mypackage.OrderAddress"). Specify a parameter-level `ModelAttribute` annotation for + declaring a specific model attribute name. +* `org.springframework.validation.Errors` / + `org.springframework.validation.BindingResult` validation results for a preceding + command/form object (the immediate preceding argument). +* `org.springframework.web.bind.support.SessionStatus` status handle for marking form + processing as complete (triggering the cleanup of session attributes that have been + indicated by the `@SessionAttributes` annotation at the handler type level). + +The following return types are supported for handler methods: + +* A `ModelAndView` object, with the model implicitly enriched with command objects and + the results of `@ModelAttribute` annotated reference data accessor methods. +* A `Model` object, with the view name implicitly determined through a + `RequestToViewNameTranslator` and the model implicitly enriched with command objects + and the results of `@ModelAttribute` annotated reference data accessor methods. +* A `Map` object for exposing a model, with the view name implicitly determined through + a `RequestToViewNameTranslator` and the model implicitly enriched with command objects + and the results of `@ModelAttribute` annotated reference data accessor methods. +* A `View` object, with the model implicitly determined through command objects and + `@ModelAttribute` annotated reference data accessor methods. The handler method may + also programmatically enrich the model by declaring a `Model` argument (see above). +* A `String` value which is interpreted as view name, with the model implicitly + determined through command objects and `@ModelAttribute` annotated reference data + accessor methods. The handler method may also programmatically enrich the model by + declaring a `Model` argument (see above). +* `void` if the method handles the response itself (e.g. by writing the response content + directly). +* Any other return type will be considered a single model attribute to be exposed to the + view, using the attribute name specified through `@ModelAttribute` at the method level + (or the default attribute name based on the return type's class name otherwise). The + model will be implicitly enriched with command objects and the results of + `@ModelAttribute` annotated reference data accessor methods. + + + +[[portlet-ann-requestparam]] +=== Binding request parameters to method parameters with @RequestParam + +The `@RequestParam` annotation is used to bind request parameters to a method parameter +in your controller. + +The following code snippet from the PetPortal sample application shows the usage: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + @RequestMapping("EDIT") + @SessionAttributes("site") + public class PetSitesEditController { + + // ... + + public void removeSite(@RequestParam("site") String site, ActionResponse response) { + this.petSites.remove(site); + response.setRenderParameter("action", "list"); + } + + // ... + + } +---- + +Parameters using this annotation are required by default, but you can specify that a +parameter is optional by setting `@RequestParam`'s `required` attribute to `false` +(e.g., `@RequestParam(value="id", required=false)`). + + + +[[portlet-ann-modelattrib]] +=== Providing a link to data from the model with @ModelAttribute + +`@ModelAttribute` has two usage scenarios in controllers. When placed on a method +parameter, `@ModelAttribute` is used to map a model attribute to the specific, annotated +method parameter (see the `populateSite()` method below). This is how the controller +gets a reference to the object holding the data entered in the form. In addition, the +parameter can be declared as the specific type of the form backing object rather than as +a generic `java.lang.Object`, thus increasing type safety. + +`@ModelAttribute` is also used at the method level to provide __reference data__ for the +model (see the `getPetSites()` method below). For this usage the method signature can +contain the same types as documented above for the `@RequestMapping` annotation. + +[NOTE] +==== +`@ModelAttribute` annotated methods will be executed __before__ the chosen +`@RequestMapping` annotated handler method. They effectively pre-populate the implicit +model with specific attributes, often loaded from a database. Such an attribute can then +already be accessed through `@ModelAttribute` annotated handler method parameters in the +chosen handler method, potentially with binding and validation applied to it. +==== + +The following code snippet shows these two usages of this annotation: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + @RequestMapping("EDIT") + @SessionAttributes("site") + public class PetSitesEditController { + + // ... + + @ModelAttribute("petSites") + public Properties getPetSites() { + return this.petSites; + } + + @RequestMapping(params = "action=add") // action phase + public void populateSite( @ModelAttribute("site") PetSite petSite, BindingResult result, SessionStatus status, ActionResponse response) { + new PetSiteValidator().validate(petSite, result); + if (!result.hasErrors()) { + this.petSites.put(petSite.getName(), petSite.getUrl()); + status.setComplete(); + response.setRenderParameter("action", "list"); + } + } + } +---- + + + +[[portlet-ann-sessionattrib]] +=== Specifying attributes to store in a Session with @SessionAttributes + +The type-level `@SessionAttributes` annotation declares session attributes used by a +specific handler. This will typically list the names of model attributes or types of +model attributes which should be transparently stored in the session or some +conversational storage, serving as form-backing beans between subsequent requests. + +The following code snippet shows the usage of this annotation: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + @RequestMapping("EDIT") + @SessionAttributes("site") + public class PetSitesEditController { + // ... + } +---- + + + +[[portlet-ann-webdatabinder]] +=== Customizing WebDataBinder initialization + +To customize request parameter binding with PropertyEditors, etc. via Spring's +`WebDataBinder`, you can either use `@InitBinder`-annotated methods within your +controller or externalize your configuration by providing a custom +`WebBindingInitializer`. + + +[[portlet-ann-initbinder]] +==== Customizing data binding with @InitBinder + +Annotating controller methods with `@InitBinder` allows you to configure web data +binding directly within your controller class. `@InitBinder` identifies methods which +initialize the `WebDataBinder` which will be used for populating command and form object +arguments of annotated handler methods. + +Such init-binder methods support all arguments that `@RequestMapping` supports, except +for command/form objects and corresponding validation result objects. Init-binder +methods must not have a return value. Thus, they are usually declared as `void`. Typical +arguments include `WebDataBinder` in combination with `WebRequest` or +`java.util.Locale`, allowing code to register context-specific editors. + +The following example demonstrates the use of `@InitBinder` for configuring a +`CustomDateEditor` for all `java.util.Date` form properties. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + public class MyFormController { + + @InitBinder + public void initBinder(WebDataBinder binder) { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + dateFormat.setLenient(false); + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); + } + + // ... + + } +---- + + +[[portlet-ann-webbindinginitializer]] +==== Configuring a custom WebBindingInitializer + +To externalize data binding initialization, you can provide a custom implementation of +the `WebBindingInitializer` interface, which you then enable by supplying a custom bean +configuration for an `AnnotationMethodHandlerAdapter`, thus overriding the default +configuration. + + + + +[[portlet-deployment]] +== Portlet application deployment +The process of deploying a Spring Portlet MVC application is no different than deploying +any JSR-168 Portlet application. However, this area is confusing enough in general that +it is worth talking about here briefly. + +Generally, the portal/portlet container runs in one webapp in your servlet container and +your portlets run in another webapp in your servlet container. In order for the portlet +container webapp to make calls into your portlet webapp it must make cross-context calls +to a well-known servlet that provides access to the portlet services defined in your +`portlet.xml` file. + +The JSR-168 specification does not specify exactly how this should happen, so each +portlet container has its own mechanism for this, which usually involves some kind of +"deployment process" that makes changes to the portlet webapp itself and then registers +the portlets within the portlet container. + +At a minimum, the `web.xml` file in your portlet webapp is modified to inject the +well-known servlet that the portlet container will call. In some cases a single servlet +will service all portlets in the webapp, in other cases there will be an instance of the +servlet for each portlet. + +Some portlet containers will also inject libraries and/or configuration files into the +webapp as well. The portlet container must also make its implementation of the Portlet +JSP Tag Library available to your webapp. + +The bottom line is that it is important to understand the deployment needs of your +target portal and make sure they are met (usually by following the automated deployment +process it provides). Be sure to carefully review the documentation from your portal for +this process. + +Once you have deployed your portlet, review the resulting `web.xml` file for sanity. +Some older portals have been known to corrupt the definition of the +`ViewRendererServlet`, thus breaking the rendering of your portlets. diff --git a/src/asciidoc/web-view.adoc b/src/asciidoc/web-view.adoc index 78d56ddeb67..19f459c3f07 100644 --- a/src/asciidoc/web-view.adoc +++ b/src/asciidoc/web-view.adoc @@ -21,7 +21,7 @@ or JSTL is done using a normal view resolver defined in the `WebApplicationConte Furthermore, of course you need to write some JSPs that will actually render the view. [NOTE] -=== +==== Setting up your application to use JSTL is a common source of error, mainly caused by confusion over the different servlet spec., JSP and JSTL version numbers, what they mean and how to declare the taglibs correctly. The article @@ -30,7 +30,7 @@ to Reference and Use JSTL in your Web Application] provides a useful guide to th pitfalls and how to avoid them. Note that as of Spring 3.0, the minimum supported servlet version is 2.4 (JSP 2.0 and JSTL 1.1), which reduces the scope for confusion somewhat. -=== +==== @@ -857,10 +857,10 @@ applications using Spring. The following describes in a broad way how to do this [NOTE] -=== +==== This section focuses on Spring's support for Tiles v3 in the `org.springframework.web.servlet.view.tiles3` package. -=== +==== [[view-tiles-dependencies]] @@ -921,10 +921,10 @@ With this configuration, `tiles_fr_FR.xml` will be used for requests with the `f and `tiles.xml` will be used by default. [NOTE] -=== +==== Since underscores are used to indicate locales, it is recommended to avoid using them otherwise in the file names for Tiles definitions. -=== +==== [[view-tiles-url]] @@ -1094,10 +1094,10 @@ definition to your `'{asterisk}-servlet.xml'` as shown below: ---- [NOTE] -=== +==== For non web-apps add a `VelocityConfigurationFactoryBean` or a `FreeMarkerConfigurationFactoryBean` to your application context definition file. -=== +==== diff --git a/src/asciidoc/web-websocket.adoc b/src/asciidoc/web-websocket.adoc new file mode 100644 index 00000000000..666b55a04dc --- /dev/null +++ b/src/asciidoc/web-websocket.adoc @@ -0,0 +1,2158 @@ +[[websocket]] += WebSocket Support +This part of the reference documentation covers Spring Framework's support for +WebSocket-style messaging in web applications including use of STOMP as an +application level WebSocket sub-protocol. + +<> establishes a frame of mind in which to think about +WebSocket, covering adoption challenges, design considerations, and thoughts on +when it is a good fit. + +<> reviews the Spring WebSocket API on the server-side, while +<> explains the SockJS protocol and shows how to configure +and use it. + +<> introduces the STOMP messaging protocol. +<> demonstrates how to configure STOMP support in Spring. +<> and the following sections explain how to +write annotated message handling methods, send messages, choose message broker +options, as well as work with the special "user" destinations. Finally, +<> lists three approaches to testing STOMP/WebSocket +applications. + + + +[[websocket-intro]] +== Introduction +The WebSocket protocol http://tools.ietf.org/html/rfc6455[RFC 6455] defines an important +new capability for web applications: full-duplex, two-way communication between client +and server. It is an exciting new capability on the heels of a long history of +techniques to make the web more interactive including Java Applets, XMLHttpRequest, +Adobe Flash, ActiveXObject, various Comet techniques, server-sent events, and others. + +A proper introduction to the WebSocket protocol is beyond the scope of this +document. At a minimum however it's important to understand that HTTP is used only for +the initial handshake, which relies on a mechanism built into HTTP to request +a protocol upgrade (or in this case a protocol switch) to which the server can respond with +HTTP status 101 (switching protocols) if it agrees. Assuming the handshake succeeds +the TCP socket underlying the HTTP upgrade request remains open and both client and +server can use it to send messages to each other. + +Spring Framework 4 includes a new `spring-websocket` module with comprehensive +WebSocket support. It is compatible with the Java WebSocket API standard +(http://jcp.org/en/jsr/detail?id=356[JSR-356]) +and also provides additional value-add as explained in the rest of the introduction. + + + +[[websocket-into-fallback-options]] +=== WebSocket Fallback Options +An important challenge to adoption is the lack of support for WebSocket in some +browsers. Notably the first Internet Explorer version to support WebSocket is +version 10 (see http://caniuse.com/websockets for support by browser versions). +Furthermore, some restrictive proxies may be configured in ways that either +preclude the attempt to do an HTTP upgrade or otherwise break connection after +some time because it has remained opened for too long. A good overview on this +topic from Peter Lubbers is available in the InfoQ article +http://www.infoq.com/articles/Web-Sockets-Proxy-Servers["How HTML5 Web Sockets Interact With Proxy Servers"]. + +Therefore to build a WebSocket application today, fallback options are required in +order to simulate the WebSocket API where necessary. The Spring Framework provides +such transparent fallback options based on the https://github.com/sockjs/sockjs-protocol[SockJS protocol]. +These options can be enabled through configuration and do not require modifying the +application otherwise. + + + +[[websocket-intro-architecture]] +=== A Messaging Architecture +Aside from short-to-midterm adoption challenges, using WebSocket +brings up important design considerations that are important to recognize +early on, especially in contrast to what we know about building web applications today. + +Today REST is a widely accepted, understood, and supported +architecture for building web applications. It is an architecture that relies +on having many URLs (__nouns__), a handful of HTTP methods (__verbs__), and +other principles such as using hypermedia (__links__), remaining stateless, etc. + +By contrast a WebSocket application may use a single URL only for the +initial HTTP handshake. All messages thereafter share and flow on the +same TCP connection. This points to an entirely different, asynchronous, +event-driven, messaging architecture. One that is much closer +to traditional messaging applications (e.g. JMS, AMQP). + +Spring Framework 4 includes a new `spring-messaging` module with key +abstractions from the +http://projects.spring.io/spring-integration/[Spring Integration] project +such as `Message`, `MessageChannel`, `MessageHandler`, and others that can serve as +a foundation for such a messaging architecture. The module also includes a +set of annotations for mapping messages to methods, similar to the Spring MVC +annotation based programming model. + + + +[[websocket-intro-sub-protocol]] +=== Sub-Protocol Support in WebSocket +WebSocket does imply a __messaging architecture__ but does not mandate the +use of any specific __messaging protocol__. It is a very thin layer over TCP +that transforms a stream of bytes into a stream of messages +(either text or binary) and not much more. It is up to applications +to interpret the meaning of a message. + +Unlike HTTP, which is an application-level protocol, in the WebSocket protocol +there is simply not enough information in an incoming message for a framework +or container to know how to route it or process it. Therefore WebSocket is arguably +too low level for anything but a very trivial application. It can be done, but +it will likely lead to creating a framework on top. This is comparable to how +most web applications today are written using a web framework rather than the +Servlet API alone. + +For this reason the WebSocket RFC defines the use of +http://tools.ietf.org/html/rfc6455#section-1.9[sub-protocols]. +During the handshake, the client and server can use the header +`Sec-WebSocket-Protocol` to agree on a sub-protocol, i.e. a higher, application-level +protocol to use. The use of a sub-protocol is not required, but +even if not used, applications will still need to choose a message +format that both the client and server can understand. That format can be custom, +framework-specific, or a standard messaging protocol. + +The Spring Framework provides support for using +http://stomp.github.io/stomp-specification-1.2.html#Abstract[STOMP] -- a simple, messaging protocol +originally created for use in scripting languages with frames inspired +by HTTP. STOMP is widely supported and well suited for use over +WebSocket and over the web. + + + +[[websocket-intro-when-to-use]] +=== Should I Use WebSocket? +With all the design considerations surrounding the use of WebSocket, it is +reasonable to ask, "When is it appropriate to use?". + +The best fit for WebSocket is in web applications where the client and +server need to exchange events at high frequency and with low latency. Prime +candidates include, but are not limited to, applications in finance, games, +collaboration, and others. Such applications are both very sensitive to time +delays and also need to exchange a wide variety of messages at a high +frequency. + +For other application types, however, this may not be the case. +For example, a news or social feed that shows breaking news as it becomes +available may be perfectly okay with simple polling once every few minutes. +Here latency is important, but it is acceptable if the news takes a +few minutes to appear. + +Even in cases where latency is crucial, if the volume of messages is +relatively low (e.g. monitoring network failures) the use of +https://spring.io/blog/2012/05/08/spring-mvc-3-2-preview-techniques-for-real-time-updates[long polling] +should be considered as a relatively simple alternative that +works reliably and is comparable in terms of efficiency (again assuming the volume of +messages is relatively low). + +It is the combination of both low latency and high frequency of messages that can make +the use of the WebSocket protocol critical. Even in such applications, +the choice remains whether all client-server +communication should be done through WebSocket messages as opposed to using +HTTP and REST. The answer is going to vary by application; however, it is likely +that some functionality may be exposed over both WebSocket and as a REST API in +order to provide clients with alternatives. Furthermore, a REST API call may need +to broadcast a message to interested clients connected via WebSocket. + +The Spring Framework allows `@Controller` and `@RestController` classes to have both +HTTP request handling and WebSocket message handling methods. +Furthermore, a Spring MVC request handling method, or any application +method for that matter, can easily broadcast a message to all interested +WebSocket clients or to a specific user. + + + + +[[websocket-server]] +== WebSocket API +The Spring Framework provides a WebSocket API designed to adapt to various WebSocket engines. +Currently the list includes WebSocket runtimes such as Tomcat 7.0.47+, Jetty 9.1+, +GlassFish 4.1+, WebLogic 12.1.3+, and Undertow 1.0+ (and WildFly 8.0+). Additional support +may be added as more WebSocket runtimes become available. + +[NOTE] +==== +As explained in the <>, direct use of a +WebSocket API is too low level for applications -- until assumptions are made about the +format of a message there is little a framework can do to interpret messages or route +them via annotations. This is why applications should consider using a sub-protocol +and Spring's <> support. + +When using a higher level protocol, the details of the WebSocket API become less +relevant, much like the details of TCP communication are not exposed to applications +when using HTTP. Nevertheless this section covers the details of using WebSocket +directly. +==== + + + +[[websocket-server-handler]] +=== Create and Configure a WebSocketHandler +Creating a WebSocket server is as simple as implementing `WebSocketHandler` or more +likely extending either `TextWebSocketHandler` or `BinaryWebSocketHandler`: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + import org.springframework.web.socket.WebSocketHandler; + import org.springframework.web.socket.WebSocketSession; + import org.springframework.web.socket.TextMessage; + + public class MyHandler extends TextWebSocketHandler { + + @Override + public void handleTextMessage(WebSocketSession session, TextMessage message) { + // ... + } + + } +---- + +There is dedicated WebSocket Java-config and XML namespace support for mapping the above +WebSocket handler to a specific URL: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + import org.springframework.web.socket.config.annotation.EnableWebSocket; + import org.springframework.web.socket.config.annotation.WebSocketConfigurer; + import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; + + @Configuration + @EnableWebSocket + public class WebSocketConfig implements WebSocketConfigurer { + + @Override + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + registry.addHandler(myHandler(), "/myHandler"); + } + + @Bean + public WebSocketHandler myHandler() { + return new MyHandler(); + } + + } +---- + +XML configuration equivalent: + +[source,xml,indent=0] +[subs="verbatim,quotes,attributes"] +---- + + + + + + + + + +---- + +The above is for use in Spring MVC applications and should be included in the +configuration of a <>. However, Spring's WebSocket +support does not depend on Spring MVC. It is relatively simple to integrate a `WebSocketHandler` +into other HTTP serving environments with the help of +{javadoc-baseurl}/org/springframework/web/socket/server/support/WebSocketHttpRequestHandler.html[WebSocketHttpRequestHandler]. + + + +[[websocket-server-handshake]] +=== Customizing the WebSocket Handshake +The easiest way to customize the initial HTTP WebSocket handshake request is through +a `HandshakeInterceptor`, which exposes "before" and "after" the handshake methods. +Such an interceptor can be used to preclude the handshake or to make any attributes +available to the `WebSocketSession`. For example, there is a built-in interceptor +for passing HTTP session attributes to the WebSocket session: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Configuration + @EnableWebSocket + public class WebSocketConfig implements WebSocketConfigurer { + + @Override + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + registry.addHandler(new MyHandler(), "/myHandler") + .addInterceptors(new HttpSessionHandshakeInterceptor()); + } + + } +---- + +And the XML configuration equivalent: + +[source,xml,indent=0] +[subs="verbatim,quotes,attributes"] +---- + + + + + + + + + + + + +---- + +A more advanced option is to extend the `DefaultHandshakeHandler` that performs +the steps of the WebSocket handshake, including validating the client origin, +negotiating a sub-protocol, and others. An application may also need to use this +option if it needs to configure a custom `RequestUpgradeStrategy` in order to +adapt to a WebSocket server engine and version that is not yet supported +(also see <> for more on this subject). +Both the Java-config and XML namespace make it possible to configure a custom +`HandshakeHandler`. + + + +[[websocket-server-decorators]] +=== WebSocketHandler Decoration +Spring provides a `WebSocketHandlerDecorator` base class that can be used to decorate +a `WebSocketHandler` with additional behavior. Logging and exception handling +implementations are provided and added by default when using the WebSocket Java-config +or XML namespace. The `ExceptionWebSocketHandlerDecorator` catches all uncaught +exceptions arising from any WebSocketHandler method and closes the WebSocket +session with status `1011` that indicates a server error. + + + +[[websocket-server-deployment]] +=== Deployment Considerations +The Spring WebSocket API is easy to integrate into a Spring MVC application where +the `DispatcherServlet` serves both HTTP WebSocket handshake as well as other +HTTP requests. It is also easy to integrate into other HTTP processing scenarios +by invoking `WebSocketHttpRequestHandler`. This is convenient and easy to +understand. However, special considerations apply with regards to JSR-356 runtimes. + +The Java WebSocket API (JSR-356) provides two deployment mechanisms. The first +involves a Servlet container classpath scan (Servlet 3 feature) at startup; and +the other is a registration API to use at Servlet container initialization. +Neither of these mechanism makes it possible to use a single "front controller" +for all HTTP processing -- including WebSocket handshake and all other HTTP +requests -- such as Spring MVC's `DispatcherServlet`. + +This is a significant limitation of JSR-356 that Spring's WebSocket support +addresses by providing a server-specific `RequestUpgradeStrategy` even when +running in a JSR-356 runtime. + +[NOTE] +==== +A request to overcome the above limitation in the Java WebSocket API has been +created and can be followed at +https://java.net/jira/browse/WEBSOCKET_SPEC-211[WEBSOCKET_SPEC-211]. +Also note that Tomcat and Jetty already provide native API alternatives that +makes it easy to overcome the limitation. We are hopeful that more servers +will follow their example regardless of when it is addressed in the +Java WebSocket API. +==== + +A secondary consideration is that Servlet containers with JSR-356 support are expected +to perform a `ServletContainerInitializer` (SCI) scan that can slow down application +startup, in some cases dramatically. If a significant impact is observed after an +upgrade to a Servlet container version with JSR-356 support, it should +be possible to selectively enable or disable web fragments (and SCI scanning) +through the use of the `` element in `web.xml`: + +[source,xml,indent=0] +[subs="verbatim,quotes,attributes"] +---- + + + + + +---- + +You can then selectively enable web fragments by name, such as Spring's own +`SpringServletContainerInitializer` that provides support for the Servlet 3 +Java initialization API, if required: + +[source,xml,indent=0] +[subs="verbatim,quotes,attributes"] +---- + + + + spring_web + + + +---- + +[[websocket-server-runtime-configuration]] +=== Configuring the WebSocket Engine + +Each underlying WebSocket engine exposes configuration properties that control +runtime characteristics such as the size of message buffer sizes, idle timeout, +and others. + +For Tomcat, WildFly, and GlassFish add a `ServletServerContainerFactoryBean` to your +WebSocket Java config: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Configuration + @EnableWebSocket + public class WebSocketConfig implements WebSocketConfigurer { + + @Bean + public ServletServerContainerFactoryBean createWebSocketContainer() { + ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); + container.setMaxTextMessageBufferSize(8192); + container.setMaxBinaryMessageBufferSize(8192); + return container; + } + + } +---- + +or WebSocket XML namespace: + +[source,xml,indent=0] +[subs="verbatim,quotes,attributes"] +---- + + + + + + + + +---- + +[NOTE] +==== +For client side WebSocket configuration, you should use `WebSocketContainerFactoryBean` +(XML) or `ContainerProvider.getWebSocketContainer()` (Java config). +==== + +For Jetty, you'll need to supply a pre-configured Jetty `WebSocketServerFactory` and plug +that into Spring's `DefaultHandshakeHandler` through your WebSocket Java config: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Configuration + @EnableWebSocket + public class WebSocketConfig implements WebSocketConfigurer { + + @Override + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + registry.addHandler(echoWebSocketHandler(), + "/echo").setHandshakeHandler(handshakeHandler()); + } + + @Bean + public DefaultHandshakeHandler handshakeHandler() { + + WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER); + policy.setInputBufferSize(8192); + policy.setIdleTimeout(600000); + + return new DefaultHandshakeHandler( + new JettyRequestUpgradeStrategy(new WebSocketServerFactory(policy))); + } + + } +---- + +or WebSocket XML namespace: + +[source,xml,indent=0] +[subs="verbatim,quotes,attributes"] +---- + + + + + + + + + + + + + + + + + + + + + + + + + + +---- + +[[websocket-server-allowed-origins]] +=== Configuring allowed origins + +As of Spring Framework 4.1.5, the default behavior for WebSocket and SockJS is to accept +only _same origin_ requests. It is also possible to allow _all_ or a specified list of origins. +This check is mostly designed for browser clients. There is nothing preventing other types +of clients from modifying the `Origin` header value (see +https://tools.ietf.org/html/rfc6454[RFC 6454: The Web Origin Concept] for more details). + +The 3 possible behaviors are: + + * Allow only same origin requests (default): in this mode, when SockJS is enabled, the + Iframe HTTP response header `X-Frame-Options` is set to `SAMEORIGIN`, and JSONP + transport is disabled since it does not allow to check the origin of a request. + As a consequence, IE6 and IE7 are not supported when this mode is enabled. + * Allow a specified list of origins: each provided _allowed origin_ must start with `http://` + or `https://`. In this mode, when SockJS is enabled, both IFrame and JSONP based + transports are disabled. As a consequence, IE6 through IE9 are not supported when this + mode is enabled. + * Allow all origins: to enable this mode, you should provide `{asterisk}` as the allowed origin + value. In this mode, all transports are available. + +WebSocket and SockJS allowed origins can be configured as shown bellow: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + import org.springframework.web.socket.config.annotation.EnableWebSocket; + import org.springframework.web.socket.config.annotation.WebSocketConfigurer; + import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; + + @Configuration + @EnableWebSocket + public class WebSocketConfig implements WebSocketConfigurer { + + @Override + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + registry.addHandler(myHandler(), "/myHandler").setAllowedOrigins("http://mydomain.com"); + } + + @Bean + public WebSocketHandler myHandler() { + return new MyHandler(); + } + + } +---- + +XML configuration equivalent: + +[source,xml,indent=0] +[subs="verbatim,quotes,attributes"] +---- + + + + + + + + + +---- + + +[[websocket-fallback]] +== SockJS Fallback Options +As explained in the <>, WebSocket is not +supported in all browsers yet and may be precluded by restrictive network proxies. +This is why Spring provides fallback options that emulate the WebSocket API as close +as possible based on the https://github.com/sockjs/sockjs-protocol[SockJS protocol] +(version 0.3.3). + +[[websocket-fallback-sockjs-overview]] +=== Overview of SockJS + +The goal of SockJS is to let applications use a WebSocket API but fall back to +non-WebSocket alternatives when necessary at runtime, i.e. without the need to +change application code. + +SockJS consists of: + +* The https://github.com/sockjs/sockjs-protocol[SockJS protocol] +defined in the form of executable +http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html[narrated tests]. +* The https://github.com/sockjs/sockjs-client/tree/v0.3.4[SockJS JavaScript client] - a client library for use in browsers. +* SockJS server implementations including one in the Spring Framework `spring-websocket` module. +* As of 4.1 `spring-websocket` also provides a SockJS Java client. + +SockJS is designed for use in browsers. It goes to great lengths +to support a wide range of browser versions using a variety of techniques. +For the full list of SockJS transport types and browsers see the +https://github.com/sockjs/sockjs-client/tree/v0.3.4[SockJS client] page. Transports +fall in 3 general categories: WebSocket, HTTP Streaming, and HTTP Long Polling. +For an overview of these categories see +https://spring.io/blog/2012/05/08/spring-mvc-3-2-preview-techniques-for-real-time-updates/[this blog post]. + +The SockJS client begins by sending `"GET /info"` to +obtain basic information from the server. After that it must decide what transport +to use. If possible WebSocket is used. If not, in most browsers +there is at least one HTTP streaming option and if not then HTTP (long) +polling is used. + +All transport requests have the following URL structure: +---- +http://host:port/myApp/myEndpoint/{server-id}/{session-id}/{transport} +---- + +* `{server-id}` - useful for routing requests in a cluster but not used otherwise. +* `{session-id}` - correlates HTTP requests belonging to a SockJS session. +* `{transport}` - indicates the transport type, e.g. "websocket", "xhr-streaming", etc. + +The WebSocket transport needs only a single HTTP request to do the WebSocket handshake. +All messages thereafter are exchanged on that socket. + +HTTP transports require more requests. Ajax/XHR streaming for example relies on +one long-running request for server-to-client messages and additional HTTP POST +requests for client-to-server messages. Long polling is similar except it +ends the current request after each server-to-client send. + +SockJS adds minimal message framing. For example the server sends the letter +o+ +("open" frame) initially, messages are sent as +a["message1","message2"]+ +(JSON-encoded array), the letter +h+ ("heartbeat" frame) if no messages flow +for 25 seconds by default, and the letter +c+ ("close" frame) to close the session. + +To learn more, run an example in a browser and watch the HTTP requests. +The SockJS client allows fixing the list of transports so it is possible to +see each transport one at a time. The SockJS client also provides a debug flag +which enables helpful messages in the browser console. On the server side enable +`TRACE` logging for `org.springframework.web.socket`. +For even more detail refer to the SockJS protocol +http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html[narrated test]. + + +[[websocket-fallback-sockjs-enable]] +=== Enable SockJS +SockJS is easy to enable through Java configuration: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Configuration + @EnableWebSocket + public class WebSocketConfig implements WebSocketConfigurer { + + @Override + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + registry.addHandler(myHandler(), "/myHandler").withSockJS(); + } + + @Bean + public WebSocketHandler myHandler() { + return new MyHandler(); + } + + } +---- + +and the XML configuration equivalent: + +[source,xml,indent=0] +[subs="verbatim,quotes,attributes"] +---- + + + + + + + + + + +---- + +The above is for use in Spring MVC applications and should be included in the +configuration of a <>. However, Spring's WebSocket +and SockJS support does not depend on Spring MVC. It is relatively simple to +integrate into other HTTP serving environments with the help of +{javadoc-baseurl}/org/springframework/web/socket/sockjs/support/SockJsHttpRequestHandler.html[SockJsHttpRequestHandler]. + +On the browser side, applications can use the +https://github.com/sockjs/sockjs-client/tree/v0.3.4[sockjs-client] (version 0.3.x) that +emulates the W3C WebSocket API and communicates with the server to select the best +transport option depending on the browser it's running in. Review the +https://github.com/sockjs/sockjs-client/tree/v0.3.4[sockjs-client] page and the list of +transport types supported by browser. The client also provides several +configuration options, for example, to specify which transports to include. + +[[websocket-fallback-xhr-vs-iframe]] +=== HTTP Streaming in IE 8, 9: Ajax/XHR vs IFrame + +Internet Explorer 8 and 9 are and will remain common for some time. They are +a key reason for having SockJS. This section covers important +considerations about running in those browsers. + +The SockJS client supports Ajax/XHR streaming in IE 8 and 9 via Microsoft's +http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx[XDomainRequest]. +That works across domains but does not support sending cookies. +Cookies are very often essential for Java applications. +However since the SockJS client can be used with many server +types (not just Java ones), it needs to know whether cookies matter. +If so the SockJS client prefers Ajax/XHR for streaming or otherwise it +relies on a iframe-based technique. + +The very first `"/info"` request from the SockJS client is a request for +information that can influence the client's choice of transports. +One of those details is whether the server application relies on cookies, +e.g. for authentication purposes or clustering with sticky sessions. +Spring's SockJS support includes a property called `sessionCookieNeeded`. +It is enabled by default since most Java applications rely on the `JSESSIONID` +cookie. If your application does not need it, you can turn off this option +and the SockJS client should choose `xdr-streaming` in IE 8 and 9. + +If you do use an iframe-based transport, and in any case, it is good to know +that browsers can be instructed to block the use of IFrames on a given page by +setting the HTTP response header `X-Frame-Options` to `DENY`, +`SAMEORIGIN`, or `ALLOW-FROM `. This is used to prevent +https://www.owasp.org/index.php/Clickjacking[clickjacking]. + +[NOTE] +==== +Spring Security 3.2+ provides support for setting `X-Frame-Options` on every +response. By default the Spring Security Java config sets it to `DENY`. +In 3.2 the Spring Security XML namespace does not set that header by default +but may be configured to do so, and in the future it may set it by default. + +See http://docs.spring.io/spring-security/site/docs/3.2.2.RELEASE/reference/htmlsingle/#headers[Section 7.1. "Default Security Headers"] +of the Spring Security documentation for details on how to configure the +setting of the `X-Frame-Options` header. You may also check or watch +https://jira.spring.io/browse/SEC-2501[SEC-2501] for additional background. +==== + +If your application adds the `X-Frame-Options` response header (as it should!) +and relies on an iframe-based transport, you will need to set the header value to +`SAMEORIGIN` or `ALLOW-FROM `. Along with that the Spring SockJS +support also needs to know the location of the SockJS client because it is loaded +from the iframe. By default the iframe is set to download the SockJS client +from a CDN location. It is a good idea to configure this option to +a URL from the same origin as the application. + +In Java config this can be done as shown below. The XML namespace provides a +similar option via the `` element: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Configuration + @EnableWebSocket + public class WebSocketConfig implements WebSocketConfigurer { + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + registry.addEndpoint("/portfolio").withSockJS() + .setClientLibraryUrl("http://localhost:8080/myapp/js/sockjs-client.js"); + } + + // ... + + } +---- + +[NOTE] +==== +During initial development, do enable the SockJS client `devel` mode that prevents +the browser from caching SockJS requests (like the iframe) that would otherwise +be cached. For details on how to enable it see the +https://github.com/sockjs/sockjs-client/tree/v0.3.4[SockJS client] page. +==== + +[[websocket-fallback-sockjs-heartbeat]] +=== Heartbeat Messages + +The SockJS protocol requires servers to send heartbeat messages to preclude proxies +from concluding a connection is hung. The Spring SockJS configuration has a property +called `heartbeatTime` that can be used to customize the frequency. By default a +heartbeat is sent after 25 seconds assuming no other messages were sent on that +connection. This 25 seconds value is in line with the following +http://tools.ietf.org/html/rfc6202[IETF recommendation] for public Internet applications. + +[NOTE] +==== +When using STOMP over WebSocket/SockJS, if the STOMP client and server negotiate +heartbeats to be exchanged, the SockJS heartbeats are disabled. +==== + +The Spring SockJS support also allows configuring the `TaskScheduler` to use +for scheduling heartbeats tasks. The task scheduler is backed by a thread pool +with default settings based on the number of available processors. Applications +should consider customizing the settings according to their specific needs. + +[[websocket-fallback-sockjs-servlet3-async]] +=== Servlet 3 Async Requests + +HTTP streaming and HTTP long polling SockJS transports require a connection to remain +open longer than usual. For an overview of these techniques see +https://spring.io/blog/2012/05/08/spring-mvc-3-2-preview-techniques-for-real-time-updates/[this blog post]. + +In Servlet containers this is done through Servlet 3 async support that +allows exiting the Servlet container thread processing a request and continuing +to write to the response from another thread. + +A specific issue is that the Servlet API does not provide notifications for a client +that has gone away, see https://java.net/jira/browse/SERVLET_SPEC-44[SERVLET_SPEC-44]. +However, Servlet containers raise an exception on subsequent attempts to write +to the response. Since Spring's SockJS Service supports sever-sent heartbeats (every +25 seconds by default), that means a client disconnect is usually detected within that +time period or earlier if messages are sent more frequently. + +[NOTE] +==== +As a result network IO failures may occur simply because a client has disconnected, which +can fill the log with unnecessary stack traces. Spring makes a best effort to identify +such network failures that represent client disconnects (specific to each server) and log +a minimal message using the dedicated log category `DISCONNECTED_CLIENT_LOG_CATEGORY` +defined in `AbstractSockJsSession`. If you need to see the stack traces, set that +log category to TRACE. +==== + +[[websocket-fallback-cors]] +=== CORS Headers for SockJS + +If you allow cross-origin requests (see <>), the SockJS protocol +uses CORS for cross-domain support in the XHR streaming and polling transports. Therefore +CORS headers are added automatically unless the presence of CORS headers in the response +is detected. So if an application is already configured to provide CORS support, e.g. +through a Servlet Filter, Spring's SockJsService will skip this part. + +It is also possible to disable the addition of these CORS headers via the +`suppressCors` property in Spring's SockJsService. + +The following is the list of headers and values expected by SockJS: + +* `"Access-Control-Allow-Origin"` - initialized from the value of the "Origin" request header. +* `"Access-Control-Allow-Credentials"` - always set to `true`. +* `"Access-Control-Request-Headers"` - initialized from values from the equivalent request header. +* `"Access-Control-Allow-Methods"` - the HTTP methods a transport supports (see `TransportType` enum). +* `"Access-Control-Max-Age"` - set to 31536000 (1 year). + +For the exact implementation see `addCorsHeaders` in `AbstractSockJsService` as well +as the `TransportType` enum in the source code. + +Alternatively if the CORS configuration allows it consider excluding URLs with the +SockJS endpoint prefix thus letting Spring's `SockJsService` handle it. + + +[[websocket-fallback-sockjs-client]] +=== SockJS Client + +A SockJS Java client is provided in order to connect to remote SockJS endpoints without +using a browser. This can be especially useful when there is a need for bidirectional +communication between 2 servers over a public network, i.e. where network proxies may +preclude the use of the WebSocket protocol. A SockJS Java client is also very useful +for testing purposes, for example to simulate a large number of concurrent users. + +The SockJS Java client supports the "websocket", "xhr-streaming", and "xhr-polling" +transports. The remaining ones only make sense for use in a browser. + +The `WebSocketTransport` can be configured with: + +* `StandardWebSocketClient` in a JSR-356 runtime +* `JettyWebSocketClient` using the Jetty 9+ native WebSocket API +* Any implementation of Spring's `WebSocketClient` + +An `XhrTransport` by definition supports both "xhr-streaming" and "xhr-polling" since +from a client perspective there is no difference other than in the URL used to connect +to the server. At present there are two implementations: + +* `RestTemplateXhrTransport` uses Spring's `RestTemplate` for HTTP requests. +* `JettyXhrTransport` uses Jetty's `HttpClient` for HTTP requests. + +The example below shows how to create a SockJS client and connect to a SockJS endpoint: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + List transports = new ArrayList<>(2); + transports.add(new WebSocketTransport(StandardWebSocketClient())); + transports.add(new RestTemplateXhrTransport()); + + SockJsClient sockJsClient = new SockJsClient(transports); + sockJsClient.doHandshake(new MyWebSocketHandler(), "ws://example.com:8080/sockjs"); +---- + +[NOTE] +==== +SockJS uses JSON formatted arrays for messages. By default Jackson 2 is used and needs +to be on the classpath. Alternatively you can configure a custom implementation of +`SockJsMessageCodec` and configure it on the `SockJsClient`. +==== + +To use the SockJsClient for simulating a large number of concurrent users you will +need to configure the underlying HTTP client (for XHR transports) to allow a sufficient +number of connections and threads. For example with Jetty: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- +HttpClient jettyHttpClient = new HttpClient(); +jettyHttpClient.setMaxConnectionsPerDestination(1000); +jettyHttpClient.setExecutor(new QueuedThreadPool(1000)); +---- + +Consider also customizing these server-side SockJS related properties (see Javadoc for details): + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- +@Configuration +public class WebSocketConfig extends WebSocketMessageBrokerConfigurationSupport { + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + registry.addEndpoint("/sockjs").withSockJS() + .setStreamBytesLimit(512 * 1024) + .setHttpMessageCacheSize(1000) + .setDisconnectDelay(30 * 1000); + } + + // ... + +} +---- + + + + +[[websocket-stomp]] +== STOMP Over WebSocket Messaging Architecture +The WebSocket protocol defines two main types of messages -- text and binary -- +but leaves their content undefined. Instead it's expected that the client and +server may agree on using a sub-protocol, i.e. a higher-level protocol that defines +the message content. Using a sub-protocol is optional but either way the client +and server both need to understand how to interpret messages. + + + +[[websocket-stomp-overview]] +=== Overview of STOMP +http://stomp.github.io/stomp-specification-1.2.html#Abstract[STOMP] is a simple +text-oriented messaging protocol that was originally created for scripting languages +(such as Ruby, Python, and Perl) to connect to enterprise message brokers. It is +designed to address a subset of commonly used patterns in messaging protocols. STOMP +can be used over any reliable 2-way streaming network protocol such as TCP and WebSocket. + +STOMP is a frame based protocol with frames modeled on HTTP. This is the +structure of a frame: + +---- +COMMAND +header1:value1 +header2:value2 + +Body^@ +---- + +For example, a client can use the +SEND+ command to send a message or the ++SUBSCRIBE+ command to express interest in receiving messages. Both of these commands +require a +"destination"+ header that indicates where to send a message, or likewise +what to subscribe to. + +Here is an example of a client sending a request to buy stock shares: + +---- +SEND +destination:/queue/trade +content-type:application/json +content-length:44 + +{"action":"BUY","ticker":"MMM","shares",44}^@ +---- + +Here is an example of a client subscribing to receive stock quotes: +---- +SUBSCRIBE +id:sub-1 +destination:/topic/price.stock.* + +^@ +---- + +[NOTE] +==== +The meaning of a destination is intentionally left opaque in the STOMP spec. It can +be any string, and it's entirely up to STOMP servers to define the semantics and +the syntax of the destinations that they support. It is very common, however, for +destinations to be path-like strings where `"/topic/.."` implies publish-subscribe +(__one-to-many__) and `"/queue/"` implies point-to-point (__one-to-one__) message +exchanges. +==== + +STOMP servers can use the +MESSAGE+ command to broadcast messages to all subscribers. +Here is an example of a server sending a stock quote to a subscribed client: + +---- +MESSAGE +message-id:nxahklf6-1 +subscription:sub-1 +destination:/topic/price.stock.MMM + +{"ticker":"MMM","price":129.45}^@ +---- + +[NOTE] +==== +It is important to know that a server cannot send unsolicited messages. All messages +from a server must be in response to a specific client subscription, and the ++"subscription-id"+ header of the server message must match the +"id"+ header of the +client subscription. +==== + +The above overview is intended to provide the most basic understanding of the +STOMP protocol. It is recommended to review the protocol +http://stomp.github.io/stomp-specification-1.2.html[specification], which is +easy to follow and manageable in terms of size. + +The following summarizes the benefits for an application of using STOMP over WebSocket: + +* Standard message format +* Application-level protocol with support for common messaging patterns +* Client-side support, e.g. https://github.com/jmesnil/stomp-websocket[stomp.js], https://github.com/cujojs/msgs[msgs.js] +* The ability to interpret, route, and process messages on both the client and server-side +* The option to plug in a message broker -- RabbitMQ, ActiveMQ, many others -- to broadcast messages (explained later) + +Most importantly the use of STOMP (vs plain WebSocket) enables the Spring Framework +to provide a programming model for application-level use in the same way that +Spring MVC provides a programming model based on HTTP. + + + +[[websocket-stomp-enable]] +=== Enable STOMP over WebSocket +The Spring Framework provides support for using STOMP over WebSocket through +the +spring-messaging+ and +spring-websocket+ modules. It's easy to enable it. + +Here is an example of configuring a STOMP WebSocket endpoint with SockJS fallback +options. The endpoint is available for clients to connect to a URL path `/app/portfolio`: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; + import org.springframework.web.socket.config.annotation.StompEndpointRegistry; + + @Configuration + @EnableWebSocketMessageBroker + public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + + @Override + public void configureMessageBroker(MessageBrokerRegistry config) { + config.setApplicationDestinationPrefixes("/app"); + config.enableSimpleBroker("/queue", "/topic"); + } + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + registry.addEndpoint("/portfolio").withSockJS(); + } + + // ... + + } +---- + +XML configuration equivalent: + +[source,xml,indent=0] +[subs="verbatim,quotes,attributes"] +---- + + + + + + + + ... + + + +---- + +On the browser side, a client might connect as follows using +https://github.com/jmesnil/stomp-websocket[stomp.js] and the +https://github.com/sockjs/sockjs-client[sockjs-client]: + +[source,javascript,indent=0] +[subs="verbatim,quotes"] +---- + var socket = new SockJS("/spring-websocket-portfolio/portfolio"); + var stompClient = Stomp.over(socket); + + stompClient.connect({}, function(frame) { + } +---- + +Or if connecting via WebSocket (without SockJS): + +[source,javascript,indent=0] +[subs="verbatim,quotes"] +---- + var socket = new WebSocket("/spring-websocket-portfolio/portfolio"); + var stompClient = Stomp.over(socket); + + stompClient.connect({}, function(frame) { + } +---- + +Note that the `stompClient` above does not need to specify `login` and `passcode` headers. +Even if it did, they would be ignored, or rather overridden, on the server side. See the +sections <> and +<> for more information on authentication. + + +[[websocket-stomp-message-flow]] +=== Flow of Messages + +When a STOMP endpoint is configured, the Spring application acts as the STOMP broker +to connected clients. It handles incoming messages and sends messages back. +This section provides a big picture overview of how messages flow inside the application. + +The `spring-messaging` module contains a number of abstractions that originated in the +https://spring.io/spring-integration[Spring Integration] project and are intended +for use as building blocks in messaging applications: + +* {javadoc-baseurl}/org/springframework/messaging/Message.html[Message] -- +a message with headers and a payload. +* {javadoc-baseurl}/org/springframework/messaging/MessageHandler.html[MessageHandler] -- +a contract for handling a message. +* {javadoc-baseurl}/org/springframework/messaging/MessageChannel.html[MessageChannel] -- +a contract for sending a message enabling loose coupling between senders and receivers. +* {javadoc-baseurl}/org/springframework/messaging/SubscribableChannel.html[SubscribableChannel] -- +extends `MessageChannel` and sends messages to registered `MessageHandler` subscribers. +* {javadoc-baseurl}/org/springframework/messaging/support/ExecutorSubscribableChannel.html[ExecutorSubscribableChannel] -- +a concrete implementation of `SubscribableChannel` that can deliver messages +asynchronously via a thread pool. + +The provided STOMP over WebSocket config, both Java and XML, uses the above to +assemble a concrete message flow including the following 3 channels: + +* `"clientInboundChannel"` -- for messages from WebSocket clients. Every incoming +WebSocket message carrying a STOMP frame is sent through this channel. +* `"clientOutboundChannel"` -- for messages to WebSocket clients. Every outgoing +STOMP message from the broker is sent through this channel before getting sent +to a client's WebSocket session. +* `"brokerChannel"` -- for messages to the broker from within the application. +Every message sent from the application to the broker passes through this channel. + +Messages on the `"clientInboundChannel"` can flow to annotated +methods for application handling (e.g. a stock trade execution request) or can +be forwarded to the broker (e.g. client subscribing for stock quotes). +The STOMP destination is used for simple prefix-based routing. For example +the "/app" prefix could route messages to annotated methods while the "/topic" +and "/queue" prefixes could route messages to the broker. + +When a message-handling annotated method has a return type, its return +value is sent as the payload of a Spring `Message` to the `"brokerChannel"`. +The broker in turn broadcasts the message to clients. Sending a message +to a destination can also be done from anywhere in the application with +the help of a messaging template. For example, an HTTP POST handling method +can broadcast a message to connected clients, or a service component may +periodically broadcast stock quotes. + +Below is a simple example to illustrate the flow of messages: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Configuration + @EnableWebSocketMessageBroker + public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + registry.addEndpoint("/portfolio"); + } + + @Override + public void configureMessageBroker(MessageBrokerRegistry registry) { + registry.setApplicationDestinationPrefixes("/app"); + registry.enableSimpleBroker("/topic"); + } + + } + + @Controller + public class GreetingController { + + @MessageMapping("/greeting") { + public String handle(String greeting) { + return "[" + getTimestamp() + ": " + greeting; + } + + } + +---- + +The following explains the message flow for the above example: + +* WebSocket clients connect to the WebSocket endpoint at "/portfolio". +* Subscriptions to "/topic/greeting" pass through the "clientInboundChannel" +and are forwarded to the broker. +* Greetings sent to "/app/greeting" pass through the "clientInboundChannel" +and are forwarded to the `GreetingController`. The controller adds the current +time, and the return value is passed through the "brokerChannel" as a message +to "/topic/greeting" (destination is selected based on a convention but can be +overridden via `@SendTo`). +* The broker in turn broadcasts messages to subscribers, and they pass through +the `"clientOutboundChannel"`. + +The next section provides more details on annotated methods including the +kinds of arguments and return values supported. + + + +[[websocket-stomp-handle-annotations]] +=== Annotation Message Handling + +The `@MessageMapping` annotation is supported on methods of `@Controller` classes. +It can be used for mapping methods to message destinations and can also be combined +with the type-level `@MessageMapping` for expressing shared mappings across all +annotated methods within a controller. + +By default destination mappings are treated as Ant-style, slash-separated, path +patterns, e.g. "/foo*", "/foo/**". etc. They can also contain template variables, +e.g. "/foo/{id}" that can then be referenced via `@DestinationVariable`-annotated +method arguments. + +[NOTE] +==== +Applications can also use dot-separated destinations (vs slash). +See <>. +==== + +The following method arguments are supported for `@MessageMapping` methods: + +* `Message` method argument to get access to the complete message being processed. +* `@Payload`-annotated argument for access to the payload of a message, converted with +a `org.springframework.messaging.converter.MessageConverter`. +The presence of the annotation is not required since it is assumed by default. +Payload method arguments annotated with validation annotations (like `@Validated`) will +be subject to JSR-303 validation. +* `@Header`-annotated arguments for access to a specific header value along with +type conversion using an `org.springframework.core.convert.converter.Converter` +if necessary. +* `@Headers`-annotated method argument that must also be assignable to `java.util.Map` +for access to all headers in the message. +* `MessageHeaders` method argument for getting access to a map of all headers. +* `MessageHeaderAccessor`, `SimpMessageHeaderAccessor`, or `StompHeaderAccessor` +for access to headers via typed accessor methods. +* `@DestinationVariable`-annotated arguments for access to template +variables extracted from the message destination. Values will be converted to +the declared method argument type as necessary. +* `java.security.Principal` method arguments reflecting the user logged in at +the time of the WebSocket HTTP handshake. + +The return value from an `@MessageMapping` method is converted with a +`org.springframework.messaging.converter.MessageConverter` and used as the body +of a new message that is then sent, by default, to the `"brokerChannel"` with +the same destination as the client message but using the prefix `"/topic"` by +default. An `@SendTo` message level annotation can be used to specify any +other destination instead. + +An `@SubscribeMapping` annotation can also be used to map subscription requests +to `@Controller` methods. It is supported on the method level, but can also be +combined with a type level `@MessageMapping` annotation that expresses shared +mappings across all message handling methods within the same controller. + +By default the return value from an `@SubscribeMapping` method is sent as a +message directly back to the connected client and does not pass through the +broker. This is useful for implementing request-reply message interactions; for +example, to fetch application data when the application UI is being initialized. +Or alternatively an `@SubscribeMapping` method can be annotated with `@SendTo` +in which case the resulting message is sent to the `"brokerChannel"` using +the specified target destination. + + +[[websocket-stomp-handle-send]] +=== Sending Messages + +What if you want to send messages to connected clients from any part of the +application? Any application component can send messages to the `"brokerChannel"`. +The easiest way to do that is to have a `SimpMessagingTemplate` injected, and +use it to send messages. Typically it should be easy to have it injected by +type, for example: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + public class GreetingController { + + private SimpMessagingTemplate template; + + @Autowired + public GreetingController(SimpMessagingTemplate template) { + this.template = template; + } + + @RequestMapping(value="/greetings", method=POST) + public void greet(String greeting) { + String text = "[" + getTimestamp() + "]:" + greeting; + this.template.convertAndSend("/topic/greetings", text); + } + + } +---- + +But it can also be qualified by its name "brokerMessagingTemplate" if another +bean of the same type exists. + + +[[websocket-stomp-handle-simple-broker]] +=== Simple Broker + +The built-in, simple message broker handles subscription requests from clients, +stores them in memory, and broadcasts messages to connected clients with matching +destinations. The broker supports path-like destinations, including subscriptions +to Ant-style destination patterns. + +[NOTE] +==== +Applications can also use dot-separated destinations (vs slash). +See <>. +==== + + + + +[[websocket-stomp-handle-broker-relay]] +=== Full-Featured Broker + +The simple broker is great for getting started but supports only a subset of +STOMP commands (e.g. no acks, receipts, etc.), relies on a simple message +sending loop, and is not suitable for clustering. As an alternative, applications +can upgrade to using a full-featured message broker. + +Check the STOMP documentation for your message broker of choice (e.g. +http://www.rabbitmq.com/stomp.html[RabbitMQ], +http://activemq.apache.org/stomp.html[ActiveMQ], etc.), install the broker, +and run it with STOMP support enabled. Then enable the STOMP broker relay in the +Spring configuration instead of the simple broker. + +Below is example configuration that enables a full-featured broker: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Configuration + @EnableWebSocketMessageBroker + public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + registry.addEndpoint("/portfolio").withSockJS(); + } + + @Override + public void configureMessageBroker(MessageBrokerRegistry registry) { + registry.enableStompBrokerRelay("/topic", "/queue"); + registry.setApplicationDestinationPrefixes("/app"); + } + + } +---- + +XML configuration equivalent: + +[source,xml,indent=0] +[subs="verbatim,quotes,attributes"] +---- + + + + + + + + + + +---- + +The "STOMP broker relay" in the above configuration is a Spring +http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/messaging/MessageHandler.html[MessageHandler] +that handles messages by forwarding them to an external message broker. +To do so it establishes TCP connections to the broker, forwards all +messages to it, and then forwards all messages received +from the broker to clients through their WebSocket sessions. Essentially +it acts as a "relay" that forwards messages in both directions. + +[NOTE] +==== +Please add a dependency on `org.projectreactor:reactor-net` for TCP connection management. +==== + +Furthermore, application components (e.g. HTTP request handling methods, +business services, etc.) can also send messages to the broker relay, as described +in <>, in order to broadcast messages to +subscribed WebSocket clients. + +In effect, the broker relay enables robust and scalable message broadcasting. + +[[websocket-stomp-handle-broker-relay-configure]] +=== Connections To Full-Featured Broker + +A STOMP broker relay maintains a single "system" TCP connection to the broker. +This connection is used for messages originating from the server-side application +only, not for receiving messages. You can configure the STOMP credentials +for this connection, i.e. the STOMP frame `login` and `passcode` headers. This +is exposed in both the XML namespace and the Java config as the +++systemLogin++/++systemPasscode++ properties with default values ++guest++/++guest++. + +The STOMP broker relay also creates a separate TCP connection for every connected +WebSocket client. You can configure the STOMP credentials to use for all TCP +connections created on behalf of clients. This is exposed in both the XML namespace +and the Java config as the ++clientLogin++/++clientPasscode++ properties with default +values ++guest++/++guest++. + +[NOTE] +==== +The STOMP broker relay always sets the `login` and `passcode` headers on every `CONNECT` +frame that it forwards to the broker on behalf of clients. Therefore WebSocket clients +need not set those headers; they will be ignored. As the following section explains, +instead WebSocket clients should rely on HTTP authentication to protect the WebSocket +endpoint and establish the client identity. +==== + +The STOMP broker relay also sends and receives heartbeats to and from the message +broker over the "system" TCP connection. You can configure the intervals for sending +and receiving heartbeats (10 seconds each by default). If connectivity to the broker +is lost, the broker relay will continue to try to reconnect, every 5 seconds, +until it succeeds. + +[NOTE] +==== +A Spring bean can implement `ApplicationListener` in order +to receive notifications when the "system" connection to the broker is lost and +re-established. For example a Stock Quote service broadcasting stock quotes can +stop trying to send messages when there is no active "system" connection. +==== + +The STOMP broker relay can also be configured with a `virtualHost` property. +The value of this property will be set as the `host` header of every `CONNECT` frame +and may be useful for example in a cloud environment where the actual host to which +the TCP connection is established is different from the host providing the +cloud-based STOMP service. + +[[websocket-stomp-destination-separator]] +=== Using Dot as Separator in `@MessageMapping` Destinations + +Although slash-separated path patterns are familiar to web developers, in messaging +it is common to use a "." as the separator, for example in the names of topics, queues, +exchanges, etc. Applications can also switch to using "." (dot) instead of "/" (slash) +as the separator in `@MessageMapping` mappings by configuring a custom `AntPathMatcher`. + +In Java config: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Configuration + @EnableWebSocketMessageBroker + public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { + + // ... + + @Override + public void configureMessageBroker(MessageBrokerRegistry registry) { + registry.enableStompBrokerRelay("/queue/", "/topic/"); + registry.setApplicationDestinationPrefixes("/app"); + registry.setPathMatcher(new AntPathMatcher(".")); + } + + } +---- + +In XML config: + +[source,xml,indent=0] +[subs="verbatim,quotes,attributes"] +---- + + + + + + + + + + + + +---- + +And below is a simple example to illustrate a controller with "." separator: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Controller + @MessageMapping("foo") + public class FooController { + + @MessageMapping("bar.{baz}") + public void handleBaz(@DestinationVariable String baz) { + } + + } +---- + +If the application prefix is set to "/app" then the foo method is effectively mapped to "/app/foo.bar.{baz}". + + + + +[[websocket-stomp-authentication]] +=== Authentication + +In a WebSocket-style application it is often useful to know who sent a message. +Therefore some form of authentication is needed to establish the user identity +and associate it with the current session. + +Existing Web applications already use HTTP based authentication. +For example Spring Security can secure the HTTP URLs of the application as usual. +Since a WebSocket session begins with an HTTP handshake, that means URLs mapped +to STOMP/WebSocket are already automatically protected and require authentication. +Moreover the page that opens the WebSocket connection is itself likely protected +and so by the time of the actual handshake, the user should have been authenticated. + +When a WebSocket handshake is made and a new WebSocket session is created, +Spring's WebSocket support automatically propagates the `java.security.Principal` +from the HTTP request to the WebSocket session. After that every message flowing +through the application on that WebSocket session is enriched with +the user information. It's present in the message as a header. +Controller methods can access the current user by adding a method argument of +type `javax.security.Principal`. + +Note that even though the STOMP `CONNECT` frame has "login" and "passcode" headers +that can be used for authentication, Spring's STOMP WebSocket support ignores them +and currently expects users to have been authenticated already via HTTP. + +In some cases it may be useful to assign an identity to a WebSocket session even +when the user has not been formally authenticated. For example, a mobile app might +assign some identity to anonymous users, perhaps based on geographical location. +The do that currently, an application can sub-class `DefaultHandshakeHandler` +and override the `determineUser` method. The custom handshake handler can then +be plugged in (see examples in <>). + + + +[[websocket-stomp-user-destination]] +=== User Destinations + +An application can send messages targeting a specific user, and Spring's STOMP support +recognizes destinations prefixed with `"/user/"` for this purpose. +For example, a client might subscribe to the destination `"/user/queue/position-updates"`. +This destination will be handled by the `UserDestinationMessageHandler` and +transformed into a destination unique to the user session, +e.g. `"/queue/position-updates-user123"`. This provides the convenience of subscribing +to a generically named destination while at the same time ensuring no collisions +with other users subscribing to the same destination so that each user can receive +unique stock position updates. + +On the sending side messages can be sent to a destination such as +`"/user/{username}/queue/position-updates"`, which in turn will be translated +by the `UserDestinationMessageHandler` into one or more destinations, one for each +session associated with the user. This allows any component within the application to +send messages targeting a specific user without necessarily knowing anything more +than their name and the generic destination. This is also supported through an +annotation as well as a messaging template. + +For example, a message-handling method can send messages to the user associated with +the message being handled through the `@SendToUser` annotation: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- +@Controller +public class PortfolioController { + + @MessageMapping("/trade") + @SendToUser("/queue/position-updates") + public TradeResult executeTrade(Trade trade, Principal principal) { + // ... + return tradeResult; + } +} +---- + +If the user has more than one session, by default all of the sessions subscribed +to the given destination are targeted. However sometimes, it may be necessary to +target only the session that sent the message being handled. This can be done by +setting the `broadcast` attribute to false, for example: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- +@Controller +public class MyController { + + @MessageMapping("/action") + public void handleAction() throws Exception{ + // raise MyBusinessException here + } + + @MessageExceptionHandler + @SendToUser(value="/queue/errors", broadcast=false) + public ApplicationError handleException(MyBusinessException exception) { + // ... + return appError; + } +} +---- + + +[NOTE] +==== +While user destinations generally imply an authenticated user, it isn't required +strictly. A WebSocket session that is not associated with an authenticated user +can subscribe to a user destination. In such cases the `@SendToUser` annotation +will behave exactly the same as with `broadcast=false`, i.e. targeting only the +session that sent the message being handled. +==== + +It is also possible to send a message to user destinations from any application +component by injecting the `SimpMessagingTemplate` created by the Java config or +XML namespace, for example (the bean name is `"brokerMessagingTemplate"` if required +for qualification with `@Qualifier`): + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- +@Service +public class TradeServiceImpl implements TradeService { + + private final SimpMessagingTemplate messagingTemplate; + + @Autowired + public TradeServiceImpl(SimpMessagingTemplate messagingTemplate) { + this.messagingTemplate = messagingTemplate; + } + + // ... + + public void afterTradeExecuted(Trade trade) { + this.messagingTemplate.convertAndSendToUser( + trade.getUserName(), "/queue/position-updates", trade.getResult()); + } +} +---- + +[NOTE] +==== +When using user destinations with an external message broker, check the broker +documentation on how to manage inactive queues, so that when the user session is +over, all unique user queues are removed. For example, RabbitMQ creates auto-delete +queues when destinations like `/exchange/amq.direct/position-updates` are used. +So in that case the client could subscribe to `/user/exchange/amq.direct/position-updates`. +Similarly, ActiveMQ has +http://activemq.apache.org/delete-inactive-destinations.html[configuration options] +for purging inactive destinations. +==== + + + + +[[websocket-stomp-appplication-context-events]] +=== Listening To ApplicationContext Events and Intercepting Messages + +Several `ApplicationContext` events (listed below) are published and can be +received by implementing Spring's `ApplicationListener` interface. + +* `BrokerAvailabilityEvent` -- indicates when the broker becomes available/unavailable. +While the "simple" broker becomes available immediately on startup and remains so while +the application is running, the STOMP "broker relay" may lose its connection +to the full featured broker, for example if the broker is restarted. The broker relay +has reconnect logic and will re-establish the "system" connection to the broker +when it comes back, hence this event is published whenever the state changes from connected +to disconnected and vice versa. Components using the `SimpMessagingTemplate` should +subscribe to this event and avoid sending messages at times when the broker is not +available. In any case they should be prepared to handle `MessageDeliveryException` +when sending a message. +* `SessionConnectEvent` -- published when a new STOMP CONNECT is received +indicating the start of a new client session. The event contains the message representing the +connect including the session id, user information (if any), and any custom headers the client +may have sent. This is useful for tracking client sessions. Components subscribed +to this event can wrap the contained message using `SimpMessageHeaderAccessor` or +`StompMessageHeaderAccessor`. +* `SessionConnectedEvent` -- published shortly after a `SessionConnectEvent` when the +broker has sent a STOMP CONNECTED frame in response to the CONNECT. At this point the +STOMP session can be considered fully established. +* `SessionSubscribeEvent` -- published when a new STOMP SUBSCRIBE is received. +* `SessionUnsubscribeEvent` -- published when a new STOMP UNSUBSCRIBE is received. +* `SessionDisconnectEvent` -- published when a STOMP session ends. The DISCONNECT may +have been sent from the client, or it may also be automatically generated when the +WebSocket session is closed. In some cases this event may be published more than once +per session. Components should be idempotent with regard to multiple disconnect events. + +[NOTE] +==== +When using a full-featured broker, the STOMP "broker relay" automatically reconnects the +"system" connection in case the broker becomes temporarily unavailable. Client connections +however are not automatically reconnected. Assuming heartbeats are enabled, the client +will typically notice the broker is not responding within 10 seconds. Clients need to +implement their own reconnect logic. +==== + +Furthermore, an application can directly intercept every incoming and outgoing message by +registering a `ChannelInterceptor` on the respective message channel. For example +to intercept inbound messages: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Configuration + @EnableWebSocketMessageBroker + public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { + + @Override + public void configureClientInboundChannel(ChannelRegistration registration) { + registration.setInterceptors(new MyChannelInterceptor()); + } + } +---- + +A custom `ChannelInterceptor` can extend the empty method base class +`ChannelInterceptorAdapter` and use `StompHeaderAccessor` or `SimpMessageHeaderAccessor` +to access information about the message. + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + public class MyChannelInterceptor extends ChannelInterceptorAdapter { + + @Override + public Message preSend(Message message, MessageChannel channel) { + StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message); + StompCommand command = accessor.getStompCommand(); + // ... + return message; + } + } +---- + + + +[[websocket-stomp-websocket-scope]] +=== WebSocket Scope + +Each WebSocket session has a map of attributes. The map is attached as a header to +inbound client messages and may be accessed from a controller method, for example: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- +@Controller +public class MyController { + + @MessageMapping("/action") + public void handle(SimpMessageHeaderAccessor headerAccessor) { + Map attrs = headerAccessor.getSessionAttributes(); + // ... + } +} +---- + +It is also possible to declare a Spring-managed bean in the `"websocket"` scope. +WebSocket-scoped beans can be injected into controllers and any channel interceptors +registered on the "clientInboundChannel". Those are typically singletons and live +longer than any individual WebSocket session. Therefore you will need to use a +scope proxy mode for WebSocket-scoped beans: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- +@Component +@Scope(value="websocket", proxyMode = ScopedProxyMode.TARGET_CLASS) +public class MyBean { + + @PostConstruct + public void init() { + // Invoked after dependencies injected + } + + // ... + + @PreDestroy + public void destroy() { + // Invoked when the WebSocket session ends + } +} + +@Controller +public class MyController { + + private final MyBean myBean; + + @Autowired + public MyController(MyBean myBean) { + this.myBean = myBean; + } + + @MessageMapping("/action") + public void handle() { + // this.myBean from the current WebSocket session + } +} +---- + +As with any custom scope, Spring initializes a new `MyBean` instance the first +time it is accessed from the controller and stores the instance in the WebSocket +session attributes. The same instance is returned subsequently until the session +ends. WebSocket-scoped beans will have all Spring lifecycle methods invoked as +shown in the examples above. + + + +[[websocket-stomp-configuration-performance]] +=== Configuration and Performance + +There is no silver bullet when it comes to performance. Many factors may +affect it including the size of messages, the volume, whether application +methods perform work that requires blocking, as well as external factors +such as network speed and others. The goal of this section is to provide +an overview of the available configuration options along with some thoughts +on how to reason about scaling. + +In a messaging application messages are passed through channels for asynchronous +executions backed by thread pools. Configuring such an application requires +good knowledge of the channels and the flow of messages. Therefore it is +recommended to review <>. + +The obvious place to start is to configure the thread pools backing the +`"clientInboundChannel"` and the `"clientOutboundChannel"`. By default both +are configured at twice the number of available processors. + +If the handling of messages in annotated methods is mainly CPU bound then the +number of threads for the `"clientInboundChannel"` should remain close to the +number of processors. If the work they do is more IO bound and requires blocking +or waiting on a database or other external system then the thread pool size +will need to be increased. + +[NOTE] +==== +`ThreadPoolExecutor` has 3 important properties. Those are the core and +the max thread pool size as well as the capacity for the queue to store +tasks for which there are no available threads. + +A common point of confusion is that configuring the core pool size (e.g. 10) +and max pool size (e.g. 20) results in a thread pool with 10 to 20 threads. +In fact if the capacity is left at its default value of Integer.MAX_VALUE +then the thread pool will never increase beyond the core pool size since +all additional tasks will be queued. + +Please review the Javadoc of `ThreadPoolExecutor` to learn how these +properties work and understand the various queuing strategies. +==== + +On the `"clientOutboundChannel"` side it is all about sending messages to WebSocket +clients. If clients are on a fast network then the number of threads should +remain close to the number of available processors. If they are slow or on +low bandwidth they will take longer to consume messages and put a burden on the +thread pool. Therefore increasing the thread pool size will be necessary. + +While the workload for the "clientInboundChannel" is possible to predict -- +after all it is based on what the application does -- how to configure the +"clientOutboundChannel" is harder as it is based on factors beyond +the control of the application. For this reason there are two additional +properties related to the sending of messages. Those are the `"sendTimeLimit"` +and the `"sendBufferSizeLimit"`. Those are used to configure how long a +send is allowed to take and how much data can be buffered when sending +messages to a client. + +The general idea is that at any given time only a single thread may be used +to send to a client. All additional messages meanwhile get buffered and you +can use these properties to decide how long sending a message is allowed to +take and how much data can be buffered in the mean time. Please review the +Javadoc and documentation of the XML schema for this configuration for +important additional details. + +Here is example configuration: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Configuration + @EnableWebSocketMessageBroker + public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + + @Override + public void configureWebSocketTransport(WebSocketTransportRegistration registration) { + registration.setSendTimeLimit(15 * 1000).setSendBufferSizeLimit(512 * 1024); + } + + // ... + + } +---- + +[source,xml,indent=0] +[subs="verbatim,quotes,attributes"] +---- + + + + + + + + +---- + +The WebSocket transport configuration shown above can also be used to configure the +maximum allowed size for incoming STOMP messages. Although in theory a WebSocket +message can be almost unlimited in size, in practice WebSocket servers impose +limits -- for example, 8K on Tomcat and 64K on Jetty. For this reason STOMP clients +such as stomp.js split larger STOMP messages at 16K boundaries and send them as +multiple WebSocket messages thus requiring the server to buffer and re-assemble. + +Spring's STOMP over WebSocket support does this so applications can configure the +maximum size for STOMP messages irrespective of WebSocket server specific message +sizes. Do keep in mind that the WebSocket message size will be automatically +adjusted if necessary to ensure they can carry 16K WebSocket messages at a +minimum. + +Here is example configuration: + +[source,java,indent=0] +[subs="verbatim,quotes"] +---- + @Configuration + @EnableWebSocketMessageBroker + public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + + @Override + public void configureWebSocketTransport(WebSocketTransportRegistration registration) { + registration.setMessageSizeLimit(128 * 1024); + } + + // ... + + } +---- + +[source,xml,indent=0] +[subs="verbatim,quotes,attributes"] +---- + + + + + + + + +---- + +An important point about scaling is using multiple application instances. +Currently it is not possible to do that with the simple broker. +However when using a full-featured broker such as RabbitMQ, each application +instance connects to the broker and messages broadcast from one application +instance can be broadcast through the broker to WebSocket clients connected +through any other application instances. + + + +[[websocket-stomp-stats]] +=== Runtime Monitoring + +When using `@EnableWebSocketMessageBroker` or `` key +infrastructure components automatically gather stats and counters that provide +important insight into the internal state of the application. The configuration +also declares a bean of type `WebSocketMessageBrokerStats` that gathers all +available information in one place and by default logs it at `INFO` level once +every 30 minutes. This bean can be exported to JMX through Spring's +`MBeanExporter` for viewing at runtime, for example through JDK's `jconsole`. +Below is a summary of the available information. + +Client WebSocket Sessions:: + Current::: indicates how many client sessions there are + currently with the count further broken down by WebSocket vs HTTP + streaming and polling SockJS sessions. + Total::: indicates how many total sessions have been established. + Abnormally Closed::: + Connect Failures:::: these are sessions that got established but were + closed after not having received any messages within 60 seconds. This is + usually an indication of proxy or network issues. + Send Limit Exceeded:::: sessions closed after exceeding the configured send + timeout or the send buffer limits which can occur with slow clients + (see previous section). + Transport Errors:::: sessions closed after a transport error such as + failure to read or write to a WebSocket connection or + HTTP request/response. + STOMP Frames::: the total number of CONNECT, CONNECTED, and DISCONNECT frames + processed indicating how many clients connected on the STOMP level. Note that + the DISCONNECT count may be lower when sessions get closed abnormally or when + clients close without sending a DISCONNECT frame. +STOMP Broker Relay:: + TCP Connections::: indicates how many TCP connections on behalf of client + WebSocket sessions are established to the broker. This should be equal to the + number of client WebSocket sessions + 1 additional shared "system" connection + for sending messages from within the application. + STOMP Frames::: the total number of CONNECT, CONNECTED, and DISCONNECT frames + forwarded to or received from the broker on behalf of clients. Note that a + DISCONNECT frame is sent to the broker regardless of how the client WebSocket + session was closed. Therefore a lower DISCONNECT frame count is an indication + that the broker is pro-actively closing connections, may be because of a + heartbeat that didn't arrive in time, an invalid input frame, or other. +Client Inbound Channel:: stats from thread pool backing the "clientInboundChannel" + providing insight into the health of incoming message processing. Tasks queueing + up here is an indication the application may be too slow to handle messages. + If there I/O bound tasks (e.g. slow database query, HTTP request to 3rd party + REST API, etc) consider increasing the thread pool size. +Client Outbound Channel:: stats from the thread pool backing the "clientOutboundChannel" + providing insight into the health of broadcasting messages to clients. Tasks + queueing up here is an indication clients are too slow to consume messages. + One way to address this is to increase the thread pool size to accommodate the + number of concurrent slow clients expected. Another option is to reduce the + send timeout and send buffer size limits (see the previous section). +SockJS Task Scheduler:: stats from thread pool of the SockJS task scheduler which + is used to send heartbeats. Note that when heartbeats are negotiated on the + STOMP level the SockJS heartbeats are disabled. + +[[websocket-stomp-testing]] +=== Testing Annotated Controller Methods + +There are two main approaches to testing applications using Spring's STOMP over +WebSocket support. The first is to write server-side tests verifying the functionality +of controllers and their annotated message handling methods. The second is to write +full end-to-end tests that involve running a client and a server. + +The two approaches are not mutually exclusive. On the contrary each has a place +in an overall test strategy. Server-side tests are more focused and easier to write +and maintain. End-to-end integration tests on the other hand are more complete and +test much more, but they're also more involved to write and maintain. + +The simplest form of server-side tests is to write controller unit tests. However +this is not useful enough since much of what a controller does depends on its +annotations. Pure unit tests simply can't test that. + +Ideally controllers under test should be invoked as they are at runtime, much like +the approach to testing controllers handling HTTP requests using the Spring MVC Test +framework. i.e. without running a Servlet container but relying on the Spring Framework +to invoke the annotated controllers. Just like with Spring MVC Test here there are two +two possible alternatives, either using a "context-based" or "standalone" setup: + +1. Load the actual Spring configuration with the help of the +Spring TestContext framework, inject "clientInboundChannel" as a test field, and +use it to send messages to be handled by controller methods. + +2. Manually set up the minimum Spring framework infrastructure required to invoke +controllers (namely the `SimpAnnotationMethodMessageHandler`) and pass messages for +controllers directly to it. + +Both of these setup scenarios are demonstrated in the +https://github.com/rstoyanchev/spring-websocket-portfolio/tree/master/src/test/java/org/springframework/samples/portfolio/web[tests for the stock portfolio] +sample application. + +The second approach is to create end-to-end integration tests. For that you will need +to run a WebSocket server in embedded mode and connect to it as a WebSocket client +sending WebSocket messages containing STOMP frames. +The https://github.com/rstoyanchev/spring-websocket-portfolio/tree/master/src/test/java/org/springframework/samples/portfolio/web[tests for the stock portfolio] +sample application also demonstrates this approach using Tomcat as the embedded +WebSocket server and a simple STOMP client for test purposes. \ No newline at end of file diff --git a/src/asciidoc/web.adoc b/src/asciidoc/web.adoc index 10b34996034..ae17eddc960 100644 --- a/src/asciidoc/web.adoc +++ b/src/asciidoc/web.adoc @@ -27,3882 +27,8 @@ include::web-mvc.adoc[leveloffset=+1] include::web-view.adoc[leveloffset=+1] -[[web-integration]] -== Integrating with other web frameworks +include::web-integration.adoc[leveloffset=+1] +include::web-portlet.adoc[leveloffset=+1] -[[intro]] -=== Introduction - -.Spring Web Flow -**** -Spring Web Flow (SWF) aims to be the best solution for the management of web application -page flow. - -SWF integrates with existing frameworks like Spring MVC and JSF, in both Servlet and -Portlet environments. If you have a business process (or processes) that would benefit -from a conversational model as opposed to a purely request model, then SWF may be the -solution. - -SWF allows you to capture logical page flows as self-contained modules that are reusable -in different situations, and as such is ideal for building web application modules that -guide the user through controlled navigations that drive business processes. - -For more information about SWF, consult the -http://projects.spring.io/spring-webflow/[Spring Web Flow website]. -**** - -This chapter details Spring's integration with third party web frameworks, such as -http://www.oracle.com/technetwork/java/javaee/javaserverfaces-139869.html[JSF]. - -One of the core value propositions of the Spring Framework is that of enabling -__choice__. In a general sense, Spring does not force one to use or buy into any -particular architecture, technology, or methodology (although it certainly recommends -some over others). This freedom to pick and choose the architecture, technology, or -methodology that is most relevant to a developer and their development team is -arguably most evident in the web area, where Spring provides its own web framework -(<>), while at the same time providing integration with a number of -popular third party web frameworks. This allows one to continue to leverage any and all -of the skills one may have acquired in a particular web framework such as JSF, while -at the same time being able to enjoy the benefits afforded by Spring in other areas such -as data access, declarative transaction management, and flexible configuration and -application assembly. - -Having dispensed with the woolly sales patter (c.f. the previous paragraph), the -remainder of this chapter will concentrate upon the meaty details of integrating your -favorite web framework with Spring. One thing that is often commented upon by developers -coming to Java from other languages is the seeming super-abundance of web frameworks -available in Java. There are indeed a great number of web frameworks in the Java space; -in fact there are far too many to cover with any semblance of detail in a single -chapter. This chapter thus picks four of the more popular web frameworks in Java, -starting with the Spring configuration that is common to all of the supported web -frameworks, and then detailing the specific integration options for each supported web -framework. - -[NOTE] -==== -Please note that this chapter does not attempt to explain how to use any of the -supported web frameworks. For example, if you want to use JSF for the presentation -layer of your web application, the assumption is that you are already familiar with -JSF itself. If you need further details about any of the supported web frameworks -themselves, please do consult <> at the end of this chapter. -==== - - - - -[[web-integration-common]] -=== Common configuration -Before diving into the integration specifics of each supported web framework, let us -first take a look at the Spring configuration that is __not__ specific to any one web -framework. (This section is equally applicable to Spring's own web framework, Spring -MVC.) - -One of the concepts (for want of a better word) espoused by (Spring's) lightweight -application model is that of a layered architecture. Remember that in a 'classic' -layered architecture, the web layer is but one of many layers; it serves as one of the -entry points into a server side application and it delegates to service objects -(facades) defined in a service layer to satisfy business specific (and -presentation-technology agnostic) use cases. In Spring, these service objects, any other -business-specific objects, data access objects, etc. exist in a distinct 'business -context', which contains __no__ web or presentation layer objects (presentation objects -such as Spring MVC controllers are typically configured in a distinct 'presentation -context'). This section details how one configures a Spring container (a -`WebApplicationContext`) that contains all of the 'business beans' in one's application. - -On to specifics: all that one need do is to declare a -{javadoc-baseurl}/org/springframework/web/context/ContextLoaderListener.html[`ContextLoaderListener`] -in the standard Java EE servlet `web.xml` file of one's web application, and add a -`contextConfigLocation` section (in the same file) that defines which -set of Spring XML configuration files to load. - -Find below the configuration: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - org.springframework.web.context.ContextLoaderListener - ----- - -Find below the configuration: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - contextConfigLocation - /WEB-INF/applicationContext*.xml - ----- - -If you don't specify the `contextConfigLocation` context parameter, the -`ContextLoaderListener` will look for a file called `/WEB-INF/applicationContext.xml` to -load. Once the context files are loaded, Spring creates a -{javadoc-baseurl}/org/springframework/web/context/WebApplicationContext.html[`WebApplicationContext`] -object based on the bean definitions and stores it in the `ServletContext` of the web -application. - -All Java web frameworks are built on top of the Servlet API, and so one can use the -following code snippet to get access to this 'business context' `ApplicationContext` -created by the `ContextLoaderListener`. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext); ----- - -The -{javadoc-baseurl}/org/springframework/web/context/support/WebApplicationContextUtils.html[`WebApplicationContextUtils`] -class is for convenience, so you don't have to remember the name of the `ServletContext` -attribute. Its __getWebApplicationContext()__ method will return `null` if an object -doesn't exist under the `WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE` -key. Rather than risk getting `NullPointerExceptions` in your application, it's better -to use the `getRequiredWebApplicationContext()` method. This method throws an exception -when the `ApplicationContext` is missing. - -Once you have a reference to the `WebApplicationContext`, you can retrieve beans by -their name or type. Most developers retrieve beans by name and then cast them to one of -their implemented interfaces. - -Fortunately, most of the frameworks in this section have simpler ways of looking up -beans. Not only do they make it easy to get beans from a Spring container, but they also -allow you to use dependency injection on their controllers. Each web framework section -has more detail on its specific integration strategies. - - - - -[[jsf]] -=== JavaServer Faces 1.2 -JavaServer Faces (JSF) is the JCP's standard component-based, event-driven web user -interface framework. As of Java EE 5, it is an official part of the Java EE umbrella. - -For a popular JSF runtime as well as for popular JSF component libraries, check out the -http://myfaces.apache.org/[Apache MyFaces project]. The MyFaces project also provides -common JSF extensions such as http://myfaces.apache.org/orchestra/[MyFaces Orchestra]: -a Spring-based JSF extension that provides rich conversation scope support. - -[NOTE] -==== -Spring Web Flow 2.0 provides rich JSF support through its newly established Spring Faces -module, both for JSF-centric usage (as described in this section) and for Spring-centric -usage (using JSF views within a Spring MVC dispatcher). Check out the -http://projects.spring.io/spring-webflow[Spring Web Flow website] for details! -==== - -The key element in Spring's JSF integration is the JSF `ELResolver` mechanism. - -[[jsf-springbeanfaceselresolver]] -==== SpringBeanFacesELResolver (JSF 1.2+) -`SpringBeanFacesELResolver` is a JSF 1.2 compliant `ELResolver` implementation, -integrating with the standard Unified EL as used by JSF 1.2 and JSP 2.1. Like -`SpringBeanVariableResolver`, it delegates to the Spring's 'business context' -`WebApplicationContext` __first__, then to the default resolver of the underlying JSF -implementation. - -Configuration-wise, simply define `SpringBeanFacesELResolver` in your JSF 1.2 -__faces-context.xml__ file: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - org.springframework.web.jsf.el.SpringBeanFacesELResolver - ... - - ----- - - -[[jsf-facescontextutils]] -==== FacesContextUtils -A custom `VariableResolver` works well when mapping one's properties to beans -in __faces-config.xml__, but at times one may need to grab a bean explicitly. The -{javadoc-baseurl}/org/springframework/web/jsf/FacesContextUtils.html[`FacesContextUtils`] -class makes this easy. It is similar to `WebApplicationContextUtils`, except that it -takes a `FacesContext` parameter rather than a `ServletContext` parameter. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - ApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance()); ----- - - - -[[struts]] -=== Apache Struts 2.x -Invented by Craig McClanahan, http://struts.apache.org[Struts] is an open source project -hosted by the Apache Software Foundation. At the time, it greatly simplified the -JSP/Servlet programming paradigm and won over many developers who were using proprietary -frameworks. It simplified the programming model, it was open source (and thus free as in -beer), and it had a large community, which allowed the project to grow and become popular -among Java web developers. - -Check out the Struts -https://struts.apache.org/release/2.3.x/docs/spring-plugin.html[Spring Plugin] for the -built-in Spring integration shipped with Struts. - - - -[[tapestry]] -=== Tapestry 5.x -From the http://tapestry.apache.org/[Tapestry homepage]: - -Tapestry is a "__Component oriented framework for creating dynamic, robust, -highly scalable web applications in Java.__" - -While Spring has its own <>, there are a number of unique -advantages to building an enterprise Java application using a combination of Tapestry -for the web user interface and the Spring container for the lower layers. - -For more information, check out Tapestry's dedicated -https://tapestry.apache.org/integrating-with-spring-framework.html[integration module for -Spring]. - - - -[[web-integration-resources]] -=== Further Resources -Find below links to further resources about the various web frameworks described in this -chapter. - -* The http://www.oracle.com/technetwork/java/javaee/javaserverfaces-139869.html[JSF] homepage -* The http://struts.apache.org/[Struts] homepage -* The http://tapestry.apache.org/[Tapestry] homepage - - - -[[portlet]] -== Portlet MVC Framework - - -[[portlet-introduction]] -=== Introduction - -.JSR-168 The Java Portlet Specification -**** -For more general information about portlet development, please review a whitepaper from -Oracle entitled -http://www.oracle.com/technetwork/java/index-raji-test-141933.html["Introduction -to JSR 168"], and of course the -http://jcp.org/aboutJava/communityprocess/final/jsr168/[JSR-168 Specification] itself. -**** - -In addition to supporting conventional (servlet-based) Web development, Spring also -supports JSR-168 Portlet development. As much as possible, the Portlet MVC framework is -a mirror image of the Web MVC framework, and also uses the same underlying view -abstractions and integration technology. So, be sure to review the chapters entitled -<> and <> before continuing with this chapter. - -[NOTE] -==== -Bear in mind that while the concepts of Spring MVC are the same in Spring Portlet MVC, -there are some notable differences created by the unique workflow of JSR-168 portlets. -==== - -The main way in which portlet workflow differs from servlet workflow is that the request -to the portlet can have two distinct phases: the action phase and the render phase. The -action phase is executed only once and is where any 'backend' changes or actions occur, -such as making changes in a database. The render phase then produces what is displayed -to the user each time the display is refreshed. The critical point here is that for a -single overall request, the action phase is executed only once, but the render phase may -be executed multiple times. This provides (and requires) a clean separation between the -activities that modify the persistent state of your system and the activities that -generate what is displayed to the user. - -.Spring Web Flow -**** -Spring Web Flow (SWF) aims to be the best solution for the management of web application -page flow. - -SWF integrates with existing frameworks like Spring MVC and JSF, in both Servlet and -Portlet environments. If you have a business process (or processes) that would benefit -from a conversational model as opposed to a purely request model, then SWF may be the -solution. - -SWF allows you to capture logical page flows as self-contained modules that are reusable -in different situations, and as such is ideal for building web application modules that -guide the user through controlled navigations that drive business processes. - -For more information about SWF, consult the Spring Web Flow website. -**** - -The dual phases of portlet requests are one of the real strengths of the JSR-168 -specification. For example, dynamic search results can be updated routinely on the -display without the user explicitly rerunning the search. Most other portlet MVC -frameworks attempt to completely hide the two phases from the developer and make it look -as much like traditional servlet development as possible - we think this approach -removes one of the main benefits of using portlets. So, the separation of the two phases -is preserved throughout the Spring Portlet MVC framework. The primary manifestation of -this approach is that where the servlet version of the MVC classes will have one method -that deals with the request, the portlet version of the MVC classes will have two -methods that deal with the request: one for the action phase and one for the render -phase. For example, where the servlet version of `AbstractController` has the -`handleRequestInternal(..)` method, the portlet version of `AbstractController` has -`handleActionRequestInternal(..)` and `handleRenderRequestInternal(..)` methods. - -The framework is designed around a `DispatcherPortlet` that dispatches requests to -handlers, with configurable handler mappings and view resolution, just as the -`DispatcherServlet` in the web framework does. File upload is also supported in the same -way. - -Locale resolution and theme resolution are not supported in Portlet MVC - these areas -are in the purview of the portal/portlet container and are not appropriate at the Spring -level. However, all mechanisms in Spring that depend on the locale (such as -internationalization of messages) will still function properly because -`DispatcherPortlet` exposes the current locale in the same way as `DispatcherServlet`. - - - -[[portlet-introduction-controller]] -==== Controllers - The C in MVC -The default handler is still a very simple `Controller` interface, offering just two -methods: - -* `void handleActionRequest(request,response)` -* `ModelAndView handleRenderRequest(request,response)` - -The framework also includes most of the same controller implementation hierarchy, such -as `AbstractController`, `SimpleFormController`, and so on. Data binding, command object -usage, model handling, and view resolution are all the same as in the servlet framework. - - - -[[portlet-introduction-view]] -==== Views - The V in MVC -All the view rendering capabilities of the servlet framework are used directly via a -special bridge servlet named `ViewRendererServlet`. By using this servlet, the portlet -request is converted into a servlet request and the view can be rendered using the -entire normal servlet infrastructure. This means all the existing renderers, such as -JSP, Velocity, etc., can still be used within the portlet. - - - -[[portlet-introduction-scope]] -==== Web-scoped beans -Spring Portlet MVC supports beans whose lifecycle is scoped to the current HTTP request -or HTTP `Session` (both normal and global). This is not a specific feature of Spring -Portlet MVC itself, but rather of the `WebApplicationContext` container(s) that Spring -Portlet MVC uses. These bean scopes are described in detail in -<> - - - - -[[portlet-dispatcher]] -=== The DispatcherPortlet - -Portlet MVC is a request-driven web MVC framework, designed around a portlet that -dispatches requests to controllers and offers other functionality facilitating the -development of portlet applications. Spring's `DispatcherPortlet` however, does more -than just that. It is completely integrated with the Spring `ApplicationContext` and -allows you to use every other feature Spring has. - -Like ordinary portlets, the `DispatcherPortlet` is declared in the `portlet.xml` file of -your web application: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - sample - org.springframework.web.portlet.DispatcherPortlet - - text/html - view - - - Sample Portlet - - ----- - -The `DispatcherPortlet` now needs to be configured. - -In the Portlet MVC framework, each `DispatcherPortlet` has its own -`WebApplicationContext`, which inherits all the beans already defined in the Root -`WebApplicationContext`. These inherited beans can be overridden in the portlet-specific -scope, and new scope-specific beans can be defined local to a given portlet instance. - -The framework will, on initialization of a `DispatcherPortlet`, look for a file named -`[portlet-name]-portlet.xml` in the `WEB-INF` directory of your web application and -create the beans defined there (overriding the definitions of any beans defined with the -same name in the global scope). - -The config location used by the `DispatcherPortlet` can be modified through a portlet -initialization parameter (see below for details). - -The Spring `DispatcherPortlet` has a few special beans it uses, in order to be able to -process requests and render the appropriate views. These beans are included in the -Spring framework and can be configured in the `WebApplicationContext`, just as any other -bean would be configured. Each of those beans is described in more detail below. Right -now, we'll just mention them, just to let you know they exist and to enable us to go on -talking about the `DispatcherPortlet`. For most of the beans, defaults are provided so -you don't have to worry about configuring them. - -[[portlet-webappctx-special-beans-tbl]] -.Special beans in the WebApplicationContext -[cols="1,4"] -|=== -| Expression| Explanation - -| handler mapping(s) -| (<>) a list of pre- and post-processors and controllers that - will be executed if they match certain criteria (for instance a matching portlet mode - specified with the controller) - -| controller(s) -| (<>) the beans providing the actual functionality (or at least, - access to the functionality) as part of the MVC triad - -| view resolver -| (<>) capable of resolving view names to view definitions - -| multipart resolver -| (<>) offers functionality to process file uploads from HTML forms - -| handler exception resolver -| (<>) offers functionality to map exceptions to views or - implement other more complex exception handling code -|=== - -When a `DispatcherPortlet` is setup for use and a request comes in for that specific -`DispatcherPortlet`, it starts processing the request. The list below describes the -complete process a request goes through if handled by a `DispatcherPortlet`: - -. The locale returned by `PortletRequest.getLocale()` is bound to the request to let -elements in the process resolve the locale to use when processing the request (rendering -the view, preparing data, etc.). -. If a multipart resolver is specified and this is an `ActionRequest`, the request is -inspected for multiparts and if they are found, it is wrapped in a -`MultipartActionRequest` for further processing by other elements in the process. (See -<> for further information about multipart handling). -. An appropriate handler is searched for. If a handler is found, the execution chain -associated with the handler (pre-processors, post-processors, controllers) will be -executed in order to prepare a model. -. If a model is returned, the view is rendered, using the view resolver that has been -configured with the `WebApplicationContext`. If no model is returned (which could be due -to a pre- or post-processor intercepting the request, for example, for security -reasons), no view is rendered, since the request could already have been fulfilled. - -Exceptions that are thrown during processing of the request get picked up by any of the -handler exception resolvers that are declared in the `WebApplicationContext`. Using -these exception resolvers you can define custom behavior in case such exceptions get -thrown. - -You can customize Spring's `DispatcherPortlet` by adding context parameters in the -`portlet.xml` file or portlet init-parameters. The possibilities are listed below. - -[[portlet-dpp-init-params]] -.DispatcherPortlet initialization parameters -[cols="1,4"] -|=== -| Parameter| Explanation - -| `contextClass` -| Class that implements `WebApplicationContext`, which will be used to instantiate the - context used by this portlet. If this parameter isn't specified, the - `XmlPortletApplicationContext` will be used. - -| `contextConfigLocation` -| String which is passed to the context instance (specified by `contextClass`) to - indicate where context(s) can be found. The String is potentially split up into - multiple Strings (using a comma as a delimiter) to support multiple contexts (in case - of multiple context locations, for beans that are defined twice, the latest takes - precedence). - -| `namespace` -| The namespace of the `WebApplicationContext`. Defaults to `[portlet-name]-portlet`. - -| `viewRendererUrl` -| The URL at which `DispatcherPortlet` can access an instance of `ViewRendererServlet` - (see <>). -|=== - - - - -[[portlet-viewservlet]] -=== The ViewRendererServlet - -The rendering process in Portlet MVC is a bit more complex than in Web MVC. In order to -reuse all the <> from Spring Web MVC, we must convert the -`PortletRequest` / `PortletResponse` to `HttpServletRequest` / `HttpServletResponse` and -then call the `render` method of the `View`. To do this, `DispatcherPortlet` uses a -special servlet that exists for just this purpose: the `ViewRendererServlet`. - -In order for `DispatcherPortlet` rendering to work, you must declare an instance of the -`ViewRendererServlet` in the `web.xml` file for your web application as follows: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - ViewRendererServlet - org.springframework.web.servlet.ViewRendererServlet - - - - ViewRendererServlet - /WEB-INF/servlet/view - ----- - -To perform the actual rendering, `DispatcherPortlet` does the following: - -. Binds the `WebApplicationContext` to the request as an attribute under the same -`WEB_APPLICATION_CONTEXT_ATTRIBUTE` key that `DispatcherServlet` uses. -. Binds the `Model` and `View` objects to the request to make them available to the -`ViewRendererServlet`. -. Constructs a `PortletRequestDispatcher` and performs an `include` using the `/WEB- -INF/servlet/view` URL that is mapped to the `ViewRendererServlet`. - -The `ViewRendererServlet` is then able to call the `render` method on the `View` with -the appropriate arguments. - -The actual URL for the `ViewRendererServlet` can be changed using `DispatcherPortlet`'s -`viewRendererUrl` configuration parameter. - - - - -[[portlet-controller]] -=== Controllers -The controllers in Portlet MVC are very similar to the Web MVC Controllers, and porting -code from one to the other should be simple. - -The basis for the Portlet MVC controller architecture is the -`org.springframework.web.portlet.mvc.Controller` interface, which is listed below. - -[source,java,indent=0] ----- - public interface Controller { - - /** - * Process the render request and return a ModelAndView object which the - * DispatcherPortlet will render. - */ - ModelAndView handleRenderRequest(RenderRequest request, - RenderResponse response) throws Exception; - - /** - * Process the action request. There is nothing to return. - */ - void handleActionRequest(ActionRequest request, - ActionResponse response) throws Exception; - - } ----- - -As you can see, the Portlet `Controller` interface requires two methods that handle the -two phases of a portlet request: the action request and the render request. The action -phase should be capable of handling an action request, and the render phase should be -capable of handling a render request and returning an appropriate model and view. While -the `Controller` interface is quite abstract, Spring Portlet MVC offers several -controllers that already contain a lot of the functionality you might need; most of -these are very similar to controllers from Spring Web MVC. The `Controller` interface -just defines the most common functionality required of every controller: handling an -action request, handling a render request, and returning a model and a view. - - - -[[portlet-controller-abstractcontroller]] -==== AbstractController and PortletContentGenerator - -Of course, just a `Controller` interface isn't enough. To provide a basic -infrastructure, all of Spring Portlet MVC's ++Controller++s inherit from -`AbstractController`, a class offering access to Spring's `ApplicationContext` and -control over caching. - -[[portlet-ac-features]] -.Features offered by the AbstractController -[cols="1,4"] -|=== -| Parameter| Explanation - -| `requireSession` -| Indicates whether or not this `Controller` requires a session to do its work. This - feature is offered to all controllers. If a session is not present when such a - controller receives a request, the user is informed using a `SessionRequiredException`. - -| `synchronizeSession` -| Use this if you want handling by this controller to be synchronized on the user's - session. To be more specific, the extending controller will override the - `handleRenderRequestInternal(..)` and `handleActionRequestInternal(..)` methods, which - will be synchronized on the user's session if you specify this variable. - -| `renderWhenMinimized` -| If you want your controller to actually render the view when the portlet is in a - minimized state, set this to true. By default, this is set to false so that portlets - that are in a minimized state don't display any content. - -| `cacheSeconds` -| When you want a controller to override the default cache expiration defined for the - portlet, specify a positive integer here. By default it is set to `-1`, which does not - change the default caching. Setting it to `0` will ensure the result is never cached. -|=== - -The `requireSession` and `cacheSeconds` properties are declared on the -`PortletContentGenerator` class, which is the superclass of `AbstractController`) but -are included here for completeness. - -When using the `AbstractController` as a base class for your controllers (which is not -recommended since there are a lot of other controllers that might already do the job for -you) you only have to override either the `handleActionRequestInternal(ActionRequest, -ActionResponse)` method or the `handleRenderRequestInternal(RenderRequest, -RenderResponse)` method (or both), implement your logic, and return a `ModelAndView` -object (in the case of `handleRenderRequestInternal`). - -The default implementations of both `handleActionRequestInternal(..)` and -`handleRenderRequestInternal(..)` throw a `PortletException`. This is consistent with -the behavior of `GenericPortlet` from the JSR- 168 Specification API. So you only need -to override the method that your controller is intended to handle. - -Here is short example consisting of a class and a declaration in the web application -context. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - package samples; - - import javax.portlet.RenderRequest; - import javax.portlet.RenderResponse; - - import org.springframework.web.portlet.mvc.AbstractController; - import org.springframework.web.portlet.ModelAndView; - - public class SampleController extends AbstractController { - - public ModelAndView handleRenderRequestInternal(RenderRequest request, RenderResponse response) { - ModelAndView mav = new ModelAndView("foo"); - mav.addObject("message", "Hello World!"); - return mav; - } - - } ----- - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - ----- - -The class above and the declaration in the web application context is all you need -besides setting up a handler mapping (see <>) to get this very -simple controller working. - - - -[[portlet-controller-simple]] -==== Other simple controllers -Although you can extend `AbstractController`, Spring Portlet MVC provides a number of -concrete implementations which offer functionality that is commonly used in simple MVC -applications. - -The `ParameterizableViewController` is basically the same as the example above, except -for the fact that you can specify the view name that it will return in the web -application context (no need to hard-code the view name). - -The `PortletModeNameViewController` uses the current mode of the portlet as the view -name. So, if your portlet is in View mode (i.e. `PortletMode.VIEW`) then it uses "view" -as the view name. - - - -[[portlet-controller-command]] -==== Command Controllers -Spring Portlet MVC has the exact same hierarchy of __command controllers__ as Spring Web -MVC. They provide a way to interact with data objects and dynamically bind parameters -from the `PortletRequest` to the data object specified. Your data objects don't have to -implement a framework-specific interface, so you can directly manipulate your persistent -objects if you desire. Let's examine what command controllers are available, to get an -overview of what you can do with them: - -* `AbstractCommandController` - a command controller you can use to create your own - command controller, capable of binding request parameters to a data object you - specify. This class does not offer form functionality, it does however offer - validation features and lets you specify in the controller itself what to do with the - command object that has been filled with the parameters from the request. -* `AbstractFormController` - an abstract controller offering form submission support. - Using this controller you can model forms and populate them using a command object you - retrieve in the controller. After a user has filled the form, `AbstractFormController` - binds the fields, validates, and hands the object back to the controller to take - appropriate action. Supported features are: invalid form submission (resubmission), - validation, and normal form workflow. You implement methods to determine which views - are used for form presentation and success. Use this controller if you need forms, but - don't want to specify what views you're going to show the user in the application - context. -* `SimpleFormController` - a concrete `AbstractFormController` that provides even more - support when creating a form with a corresponding command object. The - `SimpleFormController` lets you specify a command object, a viewname for the form, a - viewname for the page you want to show the user when form submission has succeeded, - and more. -* `AbstractWizardFormController` -- a concrete `AbstractFormController` that provides a - wizard-style interface for editing the contents of a command object across multiple - display pages. Supports multiple user actions: finish, cancel, or page change, all of - which are easily specified in request parameters from the view. - -These command controllers are quite powerful, but they do require a detailed -understanding of how they operate in order to use them efficiently. Carefully review the -javadocs for this entire hierarchy and then look at some sample implementations before -you start using them. - - - -[[portlet-controller-wrapping]] -==== PortletWrappingController - -Instead of developing new controllers, it is possible to use existing portlets and map -requests to them from a `DispatcherPortlet`. Using the `PortletWrappingController`, you -can instantiate an existing `Portlet` as a `Controller` as follows: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - config=/WEB-INF/my-portlet-config.xml - - ----- - -This can be very valuable since you can then use interceptors to pre-process and -post-process requests going to these portlets. Since JSR-168 does not support any kind -of filter mechanism, this is quite handy. For example, this can be used to wrap the -Hibernate `OpenSessionInViewInterceptor` around a MyFaces JSF Portlet. - - - - -[[portlet-handlermapping]] -=== Handler mappings -Using a handler mapping you can map incoming portlet requests to appropriate handlers. -There are some handler mappings you can use out of the box, for example, the -`PortletModeHandlerMapping`, but let's first examine the general concept of a -`HandlerMapping`. - -Note: We are intentionally using the term "Handler" here instead of "Controller". -`DispatcherPortlet` is designed to be used with other ways to process requests than just -Spring Portlet MVC's own Controllers. A Handler is any Object that can handle portlet -requests. Controllers are an example of Handlers, and they are of course the default. To -use some other framework with `DispatcherPortlet`, a corresponding implementation of -`HandlerAdapter` is all that is needed. - -The functionality a basic `HandlerMapping` provides is the delivering of a -`HandlerExecutionChain`, which must contain the handler that matches the incoming -request, and may also contain a list of handler interceptors that are applied to the -request. When a request comes in, the `DispatcherPortlet` will hand it over to the -handler mapping to let it inspect the request and come up with an appropriate -`HandlerExecutionChain`. Then the `DispatcherPortlet` will execute the handler and -interceptors in the chain (if any). These concepts are all exactly the same as in Spring -Web MVC. - -The concept of configurable handler mappings that can optionally contain interceptors -(executed before or after the actual handler was executed, or both) is extremely -powerful. A lot of supporting functionality can be built into a custom `HandlerMapping`. -Think of a custom handler mapping that chooses a handler not only based on the portlet -mode of the request coming in, but also on a specific state of the session associated -with the request. - -In Spring Web MVC, handler mappings are commonly based on URLs. Since there is really no -such thing as a URL within a Portlet, we must use other mechanisms to control mappings. -The two most common are the portlet mode and a request parameter, but anything available -to the portlet request can be used in a custom handler mapping. - -The rest of this section describes three of Spring Portlet MVC's most commonly used -handler mappings. They all extend `AbstractHandlerMapping` and share the following -properties: - -* `interceptors`: The list of interceptors to use. ++HandlerInterceptor++s are discussed - in <>. -* `defaultHandler`: The default handler to use, when this handler mapping does not - result in a matching handler. -* `order`: Based on the value of the order property (see the - `org.springframework.core.Ordered` interface), Spring will sort all handler mappings - available in the context and apply the first matching handler. -* `lazyInitHandlers`: Allows for lazy initialization of singleton handlers (prototype - handlers are always lazily initialized). Default value is false. This property is - directly implemented in the three concrete Handlers. - - - -[[portlet-handlermapping-portletmode]] -==== PortletModeHandlerMapping - -This is a simple handler mapping that maps incoming requests based on the current mode -of the portlet (e.g. 'view', 'edit', 'help'). An example: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - ----- - - - -[[portlet-handlermapping-parameter]] -==== ParameterHandlerMapping - -If we need to navigate around to multiple controllers without changing portlet mode, the -simplest way to do this is with a request parameter that is used as the key to control -the mapping. - -`ParameterHandlerMapping` uses the value of a specific request parameter to control the -mapping. The default name of the parameter is `'action'`, but can be changed using the -`'parameterName'` property. - -The bean configuration for this mapping will look something like this: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - ----- - - - -[[portlet-handlermapping-portletmodeparameter]] -==== PortletModeParameterHandlerMapping - -The most powerful built-in handler mapping, `PortletModeParameterHandlerMapping` -combines the capabilities of the two previous ones to allow different navigation within -each portlet mode. - -Again the default name of the parameter is "action", but can be changed using the -`parameterName` property. - -By default, the same parameter value may not be used in two different portlet modes. -This is so that if the portal itself changes the portlet mode, the request will no -longer be valid in the mapping. This behavior can be changed by setting the -`allowDupParameters` property to true. However, this is not recommended. - -The bean configuration for this mapping will look something like this: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - - - - - ----- - -This mapping can be chained ahead of a `PortletModeHandlerMapping`, which can then -provide defaults for each mode and an overall default as well. - - - -[[portlet-handlermapping-interceptor]] -==== Adding HandlerInterceptors - -Spring's handler mapping mechanism has a notion of handler interceptors, which can be -extremely useful when you want to apply specific functionality to certain requests, for -example, checking for a principal. Again Spring Portlet MVC implements these concepts in -the same way as Web MVC. - -Interceptors located in the handler mapping must implement `HandlerInterceptor` from the -`org.springframework.web.portlet` package. Just like the servlet version, this interface -defines three methods: one that will be called before the actual handler will be -executed ( `preHandle`), one that will be called after the handler is executed ( -`postHandle`), and one that is called after the complete request has finished ( -`afterCompletion`). These three methods should provide enough flexibility to do all -kinds of pre- and post- processing. - -The `preHandle` method returns a boolean value. You can use this method to break or -continue the processing of the execution chain. When this method returns `true`, the -handler execution chain will continue. When it returns `false`, the `DispatcherPortlet` -assumes the interceptor itself has taken care of requests (and, for example, rendered an -appropriate view) and does not continue executing the other interceptors and the actual -handler in the execution chain. - -The `postHandle` method is only called on a `RenderRequest`. The `preHandle` and -`afterCompletion` methods are called on both an `ActionRequest` and a `RenderRequest`. -If you need to execute logic in these methods for just one type of request, be sure to -check what kind of request it is before processing it. - - - -[[portlet-handlermapping-interceptoradapter]] -==== HandlerInterceptorAdapter - -As with the servlet package, the portlet package has a concrete implementation of -`HandlerInterceptor` called `HandlerInterceptorAdapter`. This class has empty versions -of all the methods so that you can inherit from this class and implement just one or two -methods when that is all you need. - - - -[[portlet-handlermapping-parameterinterceptor]] -==== ParameterMappingInterceptor - -The portlet package also has a concrete interceptor named `ParameterMappingInterceptor` -that is meant to be used directly with `ParameterHandlerMapping` and -`PortletModeParameterHandlerMapping`. This interceptor will cause the parameter that is -being used to control the mapping to be forwarded from an `ActionRequest` to the -subsequent `RenderRequest`. This will help ensure that the `RenderRequest` is mapped to -the same Handler as the `ActionRequest`. This is done in the `preHandle` method of the -interceptor, so you can still modify the parameter value in your handler to change where -the `RenderRequest` will be mapped. - -Be aware that this interceptor is calling `setRenderParameter` on the `ActionResponse`, -which means that you cannot call `sendRedirect` in your handler when using this -interceptor. If you need to do external redirects then you will either need to forward -the mapping parameter manually or write a different interceptor to handle this for you. - - - - -[[portlet-viewresolver]] -=== Views and resolving them -As mentioned previously, Spring Portlet MVC directly reuses all the view technologies -from Spring Web MVC. This includes not only the various `View` implementations -themselves, but also the `ViewResolver` implementations. For more information, refer to -<> and <> respectively. - -A few items on using the existing `View` and `ViewResolver` implementations are worth -mentioning: - -* Most portals expect the result of rendering a portlet to be an HTML fragment. So, - things like JSP/JSTL, Velocity, FreeMarker, and XSLT all make sense. But it is - unlikely that views that return other document types will make any sense in a portlet - context. -* There is no such thing as an HTTP redirect from within a portlet (the - `sendRedirect(..)` method of `ActionResponse` cannot be used to stay within the - portal). So, `RedirectView` and use of the `'redirect:'` prefix will __not__ work - correctly from within Portlet MVC. -* It may be possible to use the `'forward:'` prefix from within Portlet MVC. However, - remember that since you are in a portlet, you have no idea what the current URL looks - like. This means you cannot use a relative URL to access other resources in your web - application and that you will have to use an absolute URL. - -Also, for JSP development, the new Spring Taglib and the new Spring Form Taglib both -work in portlet views in exactly the same way that they work in servlet views. - - - - -[[portlet-multipart]] -=== Multipart (file upload) support -Spring Portlet MVC has built-in multipart support to handle file uploads in portlet -applications, just like Web MVC does. The design for the multipart support is done with -pluggable `PortletMultipartResolver` objects, defined in the -`org.springframework.web.portlet.multipart` package. Spring provides a -`PortletMultipartResolver` for use with -http://jakarta.apache.org/commons/fileupload[Commons FileUpload]. How uploading files is -supported will be described in the rest of this section. - -By default, no multipart handling will be done by Spring Portlet MVC, as some developers -will want to handle multiparts themselves. You will have to enable it yourself by adding -a multipart resolver to the web application's context. After you have done that, -`DispatcherPortlet` will inspect each request to see if it contains a multipart. If no -multipart is found, the request will continue as expected. However, if a multipart is -found in the request, the `PortletMultipartResolver` that has been declared in your -context will be used. After that, the multipart attribute in your request will be -treated like any other attribute. - -[NOTE] -==== -Any configured `PortletMultipartResolver` bean __must__ have the following id (or name): -" `portletMultipartResolver`". If you have defined your `PortletMultipartResolver` with -any other name, then the `DispatcherPortlet` will __not__ find your -`PortletMultipartResolver`, and consequently no multipart support will be in effect. -==== - - - -[[portlet-multipart-resolver]] -==== Using the PortletMultipartResolver - -The following example shows how to use the `CommonsPortletMultipartResolver`: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - ----- - -Of course you also need to put the appropriate jars in your classpath for the multipart -resolver to work. In the case of the `CommonsMultipartResolver`, you need to use -`commons-fileupload.jar`. Be sure to use at least version 1.1 of Commons FileUpload as -previous versions do not support JSR-168 Portlet applications. - -Now that you have seen how to set Portlet MVC up to handle multipart requests, let's -talk about how to actually use it. When `DispatcherPortlet` detects a multipart request, -it activates the resolver that has been declared in your context and hands over the -request. What the resolver then does is wrap the current `ActionRequest` in a -`MultipartActionRequest` that has support for multipart file uploads. Using the -`MultipartActionRequest` you can get information about the multiparts contained by this -request and actually get access to the multipart files themselves in your controllers. - -Note that you can only receive multipart file uploads as part of an `ActionRequest`, not -as part of a `RenderRequest`. - - - -[[portlet-multipart-forms]] -==== Handling a file upload in a form -After the `PortletMultipartResolver` has finished doing its job, the request will be -processed like any other. To use the `PortletMultipartResolver`, create a form with an -upload field (see example below), then let Spring bind the file onto your form (backing -object). To actually let the user upload a file, we have to create a (JSP/HTML) form: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- -

Please upload a file

-
- - -
----- - -As you can see, we've created a field named "file" that matches the property of the bean -that holds the `byte[]` array. Furthermore we've added the encoding attribute ( -`enctype="multipart/form-data"`), which is necessary to let the browser know how to -encode the multipart fields (do not forget this!). - -Just as with any other property that's not automagically convertible to a string or -primitive type, to be able to put binary data in your objects you have to register a -custom editor with the `PortletRequestDataBinder`. There are a couple of editors -available for handling files and setting the results on an object. There's a -`StringMultipartFileEditor` capable of converting files to Strings (using a user-defined -character set), and there is a `ByteArrayMultipartFileEditor` which converts files to -byte arrays. They function analogous to the `CustomDateEditor`. - -So, to be able to upload files using a form, declare the resolver, a mapping to a -controller that will process the bean, and the controller itself. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - - - - - - - - ----- - -After that, create the controller and the actual class to hold the file property. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class FileUploadController extends SimpleFormController { - - public void onSubmitAction(ActionRequest request, ActionResponse response, - Object command, BindException errors) throws Exception { - - // cast the bean - FileUploadBean bean = (FileUploadBean) command; - - // let's see if there's content there - byte[] file = bean.getFile(); - if (file == null) { - // hmm, that's strange, the user did not upload anything - } - - // do something with the file here - } - - protected void initBinder(PortletRequest request, - PortletRequestDataBinder binder) throws Exception { - // to actually be able to convert Multipart instance to byte[] - // we have to register a custom editor - binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor()); - // now Spring knows how to handle multipart object and convert - } - - } - - public class FileUploadBean { - - private byte[] file; - - public void setFile(byte[] file) { - this.file = file; - } - - public byte[] getFile() { - return file; - } - - } ----- - -As you can see, the `FileUploadBean` has a property of type `byte[]` that holds the -file. The controller registers a custom editor to let Spring know how to actually -convert the multipart objects the resolver has found to properties specified by the -bean. In this example, nothing is done with the `byte[]` property of the bean itself, -but in practice you can do whatever you want (save it in a database, mail it to -somebody, etc). - -An equivalent example in which a file is bound straight to a String-typed property on a -form backing object might look like this: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class FileUploadController extends SimpleFormController { - - public void onSubmitAction(ActionRequest request, ActionResponse response, - Object command, BindException errors) throws Exception { - - // cast the bean - FileUploadBean bean = (FileUploadBean) command; - - // let's see if there's content there - String file = bean.getFile(); - if (file == null) { - // hmm, that's strange, the user did not upload anything - } - - // do something with the file here - } - - protected void initBinder(PortletRequest request, - PortletRequestDataBinder binder) throws Exception { - - // to actually be able to convert Multipart instance to a String - // we have to register a custom editor - binder.registerCustomEditor(String.class, new StringMultipartFileEditor()); - // now Spring knows how to handle multipart objects and convert - } - } - - public class FileUploadBean { - - private String file; - - public void setFile(String file) { - this.file = file; - } - - public String getFile() { - return file; - } - } ----- - -Of course, this last example only makes (logical) sense in the context of uploading a -plain text file (it wouldn't work so well in the case of uploading an image file). - -The third (and final) option is where one binds directly to a `MultipartFile` property -declared on the (form backing) object's class. In this case one does not need to -register any custom property editor because there is no type conversion to be performed. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class FileUploadController extends SimpleFormController { - - public void onSubmitAction(ActionRequest request, ActionResponse response, - Object command, BindException errors) throws Exception { - - // cast the bean - FileUploadBean bean = (FileUploadBean) command; - - // let's see if there's content there - MultipartFile file = bean.getFile(); - if (file == null) { - // hmm, that's strange, the user did not upload anything - } - - // do something with the file here - } - } - - public class FileUploadBean { - - private MultipartFile file; - - public void setFile(MultipartFile file) { - this.file = file; - } - - public MultipartFile getFile() { - return file; - } - - } ----- - - - - -[[portlet-exceptionresolver]] -=== Handling exceptions -Just like Servlet MVC, Portlet MVC provides ++HandlerExceptionResolver++s to ease the -pain of unexpected exceptions that occur while your request is being processed by a -handler that matched the request. Portlet MVC also provides a portlet-specific, concrete -`SimpleMappingExceptionResolver` that enables you to take the class name of any -exception that might be thrown and map it to a view name. - - - - -[[portlet-annotation]] -=== Annotation-based controller configuration -Spring 2.5 introduced an annotation-based programming model for MVC controllers, using -annotations such as `@RequestMapping`, `@RequestParam`, `@ModelAttribute`, etc. This -annotation support is available for both Servlet MVC and Portlet MVC. Controllers -implemented in this style do not have to extend specific base classes or implement -specific interfaces. Furthermore, they do not usually have direct dependencies on -Servlet or Portlet API's, although they can easily get access to Servlet or Portlet -facilities if desired. - -The following sections document these annotations and how they are most commonly used in -a Portlet environment. - - - -[[portlet-ann-setup]] -==== Setting up the dispatcher for annotation support -__`@RequestMapping` will only be processed if a corresponding `HandlerMapping` (for -type level annotations) and/or `HandlerAdapter` (for method level annotations) is -present in the dispatcher.__ This is the case by default in both `DispatcherServlet` and -`DispatcherPortlet`. - -However, if you are defining custom `HandlerMappings` or `HandlerAdapters`, then you -need to make sure that a corresponding custom `DefaultAnnotationHandlerMapping` and/or -`AnnotationMethodHandlerAdapter` is defined as well - provided that you intend to use -`@RequestMapping`. - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - - - // ... (controller bean definitions) ... - - ----- - -Defining a `DefaultAnnotationHandlerMapping` and/or `AnnotationMethodHandlerAdapter` -explicitly also makes sense if you would like to customize the mapping strategy, e.g. -specifying a custom `WebBindingInitializer` (see below). - - - -[[portlet-ann-controller]] -==== Defining a controller with @Controller - -The `@Controller` annotation indicates that a particular class serves the role of a -__controller__. There is no need to extend any controller base class or reference the -Portlet API. You are of course still able to reference Portlet-specific features if you -need to. - -The basic purpose of the `@Controller` annotation is to act as a stereotype for the -annotated class, indicating its role. The dispatcher will scan such annotated classes -for mapped methods, detecting `@RequestMapping` annotations (see the next section). - -Annotated controller beans may be defined explicitly, using a standard Spring bean -definition in the dispatcher's context. However, the `@Controller` stereotype also -allows for autodetection, aligned with Spring 2.5's general support for detecting -component classes in the classpath and auto-registering bean definitions for them. - -To enable autodetection of such annotated controllers, you have to add component -scanning to your configuration. This is easily achieved by using the __spring-context__ -schema as shown in the following XML snippet: - -[source,xml,indent=0] -[subs="verbatim,quotes"] ----- - - - - - - // ... - - ----- - - - -[[portlet-ann-requestmapping]] -==== Mapping requests with @RequestMapping - -The `@RequestMapping` annotation is used to map portlet modes like 'VIEW'/'EDIT' onto an -entire class or a particular handler method. Typically the type-level annotation maps a -specific mode (or mode plus parameter condition) onto a form controller, with additional -method-level annotations 'narrowing' the primary mapping for specific portlet request -parameters. - -[TIP] -==== - -`@RequestMapping` at the type level may be used for plain implementations of the -`Controller` interface as well. In this case, the request processing code would follow -the traditional `handle(Action|Render)Request` signature, while the controller's mapping -would be expressed through an `@RequestMapping` annotation. This works for pre-built -`Controller` base classes, such as `SimpleFormController`, too. - -In the following discussion, we'll focus on controllers that are based on annotated -handler methods. -==== - -The following is an example of a form controller from the PetPortal sample application -using this annotation: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Controller - @RequestMapping("EDIT") - @SessionAttributes("site") - public class PetSitesEditController { - - private Properties petSites; - - public void setPetSites(Properties petSites) { - this.petSites = petSites; - } - - @ModelAttribute("petSites") - public Properties getPetSites() { - return this.petSites; - } - - @RequestMapping // default (action=list) - public String showPetSites() { - return "petSitesEdit"; - } - - @RequestMapping(params = "action=add") // render phase - public String showSiteForm(Model model) { - // Used for the initial form as well as for redisplaying with errors. - if (!model.containsAttribute("site")) { - model.addAttribute("site", new PetSite()); - } - - return "petSitesAdd"; - } - - @RequestMapping(params = "action=add") // action phase - public void populateSite(@ModelAttribute("site") PetSite petSite, - BindingResult result, SessionStatus status, ActionResponse response) { - new PetSiteValidator().validate(petSite, result); - if (!result.hasErrors()) { - this.petSites.put(petSite.getName(), petSite.getUrl()); - status.setComplete(); - response.setRenderParameter("action", "list"); - } - } - - @RequestMapping(params = "action=delete") - public void removeSite(@RequestParam("site") String site, ActionResponse response) { - this.petSites.remove(site); - response.setRenderParameter("action", "list"); - } - } ----- - - - -[[portlet-ann-requestmapping-arguments]] -==== Supported handler method arguments -Handler methods which are annotated with `@RequestMapping` are allowed to have very -flexible signatures. They may have arguments of the following types, in arbitrary order -(except for validation results, which need to follow right after the corresponding -command object, if desired): - -* Request and/or response objects (Portlet API). You may choose any specific - request/response type, e.g. PortletRequest / ActionRequest / RenderRequest. An - explicitly declared action/render argument is also used for mapping specific request - types onto a handler method (in case of no other information given that differentiates - between action and render requests). -* Session object (Portlet API): of type PortletSession. An argument of this type will - enforce the presence of a corresponding session. As a consequence, such an argument - will never be `null`. -* `org.springframework.web.context.request.WebRequest` or - `org.springframework.web.context.request.NativeWebRequest`. Allows for generic request - parameter access as well as request/session attribute access, without ties to the - native Servlet/Portlet API. -* `java.util.Locale` for the current request locale (the portal locale in a Portlet - environment). -* `java.util.TimeZone` / `java.time.ZoneId` for the current request time zone. -* `java.io.InputStream` / `java.io.Reader` for access to the request's content. This - will be the raw InputStream/Reader as exposed by the Portlet API. -* `java.io.OutputStream` / `java.io.Writer` for generating the response's content. This - will be the raw OutputStream/Writer as exposed by the Portlet API. -* `@RequestParam` annotated parameters for access to specific Portlet request - parameters. Parameter values will be converted to the declared method argument type. -* `java.util.Map` / `org.springframework.ui.Model` / `org.springframework.ui.ModelMap` - for enriching the implicit model that will be exposed to the web view. -* Command/form objects to bind parameters to: as bean properties or fields, with - customizable type conversion, depending on `@InitBinder` methods and/or the - HandlerAdapter configuration - see the " `webBindingInitializer`" property on - `AnnotationMethodHandlerAdapter`. Such command objects along with their validation - results will be exposed as model attributes, by default using the non-qualified - command class name in property notation (e.g. "orderAddress" for type - "mypackage.OrderAddress"). Specify a parameter-level `ModelAttribute` annotation for - declaring a specific model attribute name. -* `org.springframework.validation.Errors` / - `org.springframework.validation.BindingResult` validation results for a preceding - command/form object (the immediate preceding argument). -* `org.springframework.web.bind.support.SessionStatus` status handle for marking form - processing as complete (triggering the cleanup of session attributes that have been - indicated by the `@SessionAttributes` annotation at the handler type level). - -The following return types are supported for handler methods: - -* A `ModelAndView` object, with the model implicitly enriched with command objects and - the results of `@ModelAttribute` annotated reference data accessor methods. -* A `Model` object, with the view name implicitly determined through a - `RequestToViewNameTranslator` and the model implicitly enriched with command objects - and the results of `@ModelAttribute` annotated reference data accessor methods. -* A `Map` object for exposing a model, with the view name implicitly determined through - a `RequestToViewNameTranslator` and the model implicitly enriched with command objects - and the results of `@ModelAttribute` annotated reference data accessor methods. -* A `View` object, with the model implicitly determined through command objects and - `@ModelAttribute` annotated reference data accessor methods. The handler method may - also programmatically enrich the model by declaring a `Model` argument (see above). -* A `String` value which is interpreted as view name, with the model implicitly - determined through command objects and `@ModelAttribute` annotated reference data - accessor methods. The handler method may also programmatically enrich the model by - declaring a `Model` argument (see above). -* `void` if the method handles the response itself (e.g. by writing the response content - directly). -* Any other return type will be considered a single model attribute to be exposed to the - view, using the attribute name specified through `@ModelAttribute` at the method level - (or the default attribute name based on the return type's class name otherwise). The - model will be implicitly enriched with command objects and the results of - `@ModelAttribute` annotated reference data accessor methods. - - - -[[portlet-ann-requestparam]] -==== Binding request parameters to method parameters with @RequestParam - -The `@RequestParam` annotation is used to bind request parameters to a method parameter -in your controller. - -The following code snippet from the PetPortal sample application shows the usage: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Controller - @RequestMapping("EDIT") - @SessionAttributes("site") - public class PetSitesEditController { - - // ... - - public void removeSite(@RequestParam("site") String site, ActionResponse response) { - this.petSites.remove(site); - response.setRenderParameter("action", "list"); - } - - // ... - - } ----- - -Parameters using this annotation are required by default, but you can specify that a -parameter is optional by setting `@RequestParam`'s `required` attribute to `false` -(e.g., `@RequestParam(value="id", required=false)`). - - - -[[portlet-ann-modelattrib]] -==== Providing a link to data from the model with @ModelAttribute - -`@ModelAttribute` has two usage scenarios in controllers. When placed on a method -parameter, `@ModelAttribute` is used to map a model attribute to the specific, annotated -method parameter (see the `populateSite()` method below). This is how the controller -gets a reference to the object holding the data entered in the form. In addition, the -parameter can be declared as the specific type of the form backing object rather than as -a generic `java.lang.Object`, thus increasing type safety. - -`@ModelAttribute` is also used at the method level to provide __reference data__ for the -model (see the `getPetSites()` method below). For this usage the method signature can -contain the same types as documented above for the `@RequestMapping` annotation. - -[NOTE] -==== -`@ModelAttribute` annotated methods will be executed __before__ the chosen -`@RequestMapping` annotated handler method. They effectively pre-populate the implicit -model with specific attributes, often loaded from a database. Such an attribute can then -already be accessed through `@ModelAttribute` annotated handler method parameters in the -chosen handler method, potentially with binding and validation applied to it. -==== - -The following code snippet shows these two usages of this annotation: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Controller - @RequestMapping("EDIT") - @SessionAttributes("site") - public class PetSitesEditController { - - // ... - - @ModelAttribute("petSites") - public Properties getPetSites() { - return this.petSites; - } - - @RequestMapping(params = "action=add") // action phase - public void populateSite( @ModelAttribute("site") PetSite petSite, BindingResult result, SessionStatus status, ActionResponse response) { - new PetSiteValidator().validate(petSite, result); - if (!result.hasErrors()) { - this.petSites.put(petSite.getName(), petSite.getUrl()); - status.setComplete(); - response.setRenderParameter("action", "list"); - } - } - } ----- - - - -[[portlet-ann-sessionattrib]] -==== Specifying attributes to store in a Session with @SessionAttributes - -The type-level `@SessionAttributes` annotation declares session attributes used by a -specific handler. This will typically list the names of model attributes or types of -model attributes which should be transparently stored in the session or some -conversational storage, serving as form-backing beans between subsequent requests. - -The following code snippet shows the usage of this annotation: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Controller - @RequestMapping("EDIT") - @SessionAttributes("site") - public class PetSitesEditController { - // ... - } ----- - - - -[[portlet-ann-webdatabinder]] -==== Customizing WebDataBinder initialization - -To customize request parameter binding with PropertyEditors, etc. via Spring's -`WebDataBinder`, you can either use `@InitBinder`-annotated methods within your -controller or externalize your configuration by providing a custom -`WebBindingInitializer`. - - -[[portlet-ann-initbinder]] -===== Customizing data binding with @InitBinder - -Annotating controller methods with `@InitBinder` allows you to configure web data -binding directly within your controller class. `@InitBinder` identifies methods which -initialize the `WebDataBinder` which will be used for populating command and form object -arguments of annotated handler methods. - -Such init-binder methods support all arguments that `@RequestMapping` supports, except -for command/form objects and corresponding validation result objects. Init-binder -methods must not have a return value. Thus, they are usually declared as `void`. Typical -arguments include `WebDataBinder` in combination with `WebRequest` or -`java.util.Locale`, allowing code to register context-specific editors. - -The following example demonstrates the use of `@InitBinder` for configuring a -`CustomDateEditor` for all `java.util.Date` form properties. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Controller - public class MyFormController { - - @InitBinder - public void initBinder(WebDataBinder binder) { - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - dateFormat.setLenient(false); - binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); - } - - // ... - - } ----- - - -[[portlet-ann-webbindinginitializer]] -===== Configuring a custom WebBindingInitializer - -To externalize data binding initialization, you can provide a custom implementation of -the `WebBindingInitializer` interface, which you then enable by supplying a custom bean -configuration for an `AnnotationMethodHandlerAdapter`, thus overriding the default -configuration. - - - - -[[portlet-deployment]] -=== Portlet application deployment -The process of deploying a Spring Portlet MVC application is no different than deploying -any JSR-168 Portlet application. However, this area is confusing enough in general that -it is worth talking about here briefly. - -Generally, the portal/portlet container runs in one webapp in your servlet container and -your portlets run in another webapp in your servlet container. In order for the portlet -container webapp to make calls into your portlet webapp it must make cross-context calls -to a well-known servlet that provides access to the portlet services defined in your -`portlet.xml` file. - -The JSR-168 specification does not specify exactly how this should happen, so each -portlet container has its own mechanism for this, which usually involves some kind of -"deployment process" that makes changes to the portlet webapp itself and then registers -the portlets within the portlet container. - -At a minimum, the `web.xml` file in your portlet webapp is modified to inject the -well-known servlet that the portlet container will call. In some cases a single servlet -will service all portlets in the webapp, in other cases there will be an instance of the -servlet for each portlet. - -Some portlet containers will also inject libraries and/or configuration files into the -webapp as well. The portlet container must also make its implementation of the Portlet -JSP Tag Library available to your webapp. - -The bottom line is that it is important to understand the deployment needs of your -target portal and make sure they are met (usually by following the automated deployment -process it provides). Be sure to carefully review the documentation from your portal for -this process. - -Once you have deployed your portlet, review the resulting `web.xml` file for sanity. -Some older portals have been known to corrupt the definition of the -`ViewRendererServlet`, thus breaking the rendering of your portlets. - - - -[[websocket]] -== WebSocket Support -This part of the reference documentation covers Spring Framework's support for -WebSocket-style messaging in web applications including use of STOMP as an -application level WebSocket sub-protocol. - -<> establishes a frame of mind in which to think about -WebSocket, covering adoption challenges, design considerations, and thoughts on -when it is a good fit. - -<> reviews the Spring WebSocket API on the server-side, while -<> explains the SockJS protocol and shows how to configure -and use it. - -<> introduces the STOMP messaging protocol. -<> demonstrates how to configure STOMP support in Spring. -<> and the following sections explain how to -write annotated message handling methods, send messages, choose message broker -options, as well as work with the special "user" destinations. Finally, -<> lists three approaches to testing STOMP/WebSocket -applications. - - - -[[websocket-intro]] -=== Introduction -The WebSocket protocol http://tools.ietf.org/html/rfc6455[RFC 6455] defines an important -new capability for web applications: full-duplex, two-way communication between client -and server. It is an exciting new capability on the heels of a long history of -techniques to make the web more interactive including Java Applets, XMLHttpRequest, -Adobe Flash, ActiveXObject, various Comet techniques, server-sent events, and others. - -A proper introduction to the WebSocket protocol is beyond the scope of this -document. At a minimum however it's important to understand that HTTP is used only for -the initial handshake, which relies on a mechanism built into HTTP to request -a protocol upgrade (or in this case a protocol switch) to which the server can respond with -HTTP status 101 (switching protocols) if it agrees. Assuming the handshake succeeds -the TCP socket underlying the HTTP upgrade request remains open and both client and -server can use it to send messages to each other. - -Spring Framework 4 includes a new `spring-websocket` module with comprehensive -WebSocket support. It is compatible with the Java WebSocket API standard -(http://jcp.org/en/jsr/detail?id=356[JSR-356]) -and also provides additional value-add as explained in the rest of the introduction. - - - -[[websocket-into-fallback-options]] -==== WebSocket Fallback Options -An important challenge to adoption is the lack of support for WebSocket in some -browsers. Notably the first Internet Explorer version to support WebSocket is -version 10 (see http://caniuse.com/websockets for support by browser versions). -Furthermore, some restrictive proxies may be configured in ways that either -preclude the attempt to do an HTTP upgrade or otherwise break connection after -some time because it has remained opened for too long. A good overview on this -topic from Peter Lubbers is available in the InfoQ article -http://www.infoq.com/articles/Web-Sockets-Proxy-Servers["How HTML5 Web Sockets Interact With Proxy Servers"]. - -Therefore to build a WebSocket application today, fallback options are required in -order to simulate the WebSocket API where necessary. The Spring Framework provides -such transparent fallback options based on the https://github.com/sockjs/sockjs-protocol[SockJS protocol]. -These options can be enabled through configuration and do not require modifying the -application otherwise. - - - -[[websocket-intro-architecture]] -==== A Messaging Architecture -Aside from short-to-midterm adoption challenges, using WebSocket -brings up important design considerations that are important to recognize -early on, especially in contrast to what we know about building web applications today. - -Today REST is a widely accepted, understood, and supported -architecture for building web applications. It is an architecture that relies -on having many URLs (__nouns__), a handful of HTTP methods (__verbs__), and -other principles such as using hypermedia (__links__), remaining stateless, etc. - -By contrast a WebSocket application may use a single URL only for the -initial HTTP handshake. All messages thereafter share and flow on the -same TCP connection. This points to an entirely different, asynchronous, -event-driven, messaging architecture. One that is much closer -to traditional messaging applications (e.g. JMS, AMQP). - -Spring Framework 4 includes a new `spring-messaging` module with key -abstractions from the -http://projects.spring.io/spring-integration/[Spring Integration] project -such as `Message`, `MessageChannel`, `MessageHandler`, and others that can serve as -a foundation for such a messaging architecture. The module also includes a -set of annotations for mapping messages to methods, similar to the Spring MVC -annotation based programming model. - - - -[[websocket-intro-sub-protocol]] -==== Sub-Protocol Support in WebSocket -WebSocket does imply a __messaging architecture__ but does not mandate the -use of any specific __messaging protocol__. It is a very thin layer over TCP -that transforms a stream of bytes into a stream of messages -(either text or binary) and not much more. It is up to applications -to interpret the meaning of a message. - -Unlike HTTP, which is an application-level protocol, in the WebSocket protocol -there is simply not enough information in an incoming message for a framework -or container to know how to route it or process it. Therefore WebSocket is arguably -too low level for anything but a very trivial application. It can be done, but -it will likely lead to creating a framework on top. This is comparable to how -most web applications today are written using a web framework rather than the -Servlet API alone. - -For this reason the WebSocket RFC defines the use of -http://tools.ietf.org/html/rfc6455#section-1.9[sub-protocols]. -During the handshake, the client and server can use the header -`Sec-WebSocket-Protocol` to agree on a sub-protocol, i.e. a higher, application-level -protocol to use. The use of a sub-protocol is not required, but -even if not used, applications will still need to choose a message -format that both the client and server can understand. That format can be custom, -framework-specific, or a standard messaging protocol. - -The Spring Framework provides support for using -http://stomp.github.io/stomp-specification-1.2.html#Abstract[STOMP] -- a simple, messaging protocol -originally created for use in scripting languages with frames inspired -by HTTP. STOMP is widely supported and well suited for use over -WebSocket and over the web. - - - -[[websocket-intro-when-to-use]] -==== Should I Use WebSocket? -With all the design considerations surrounding the use of WebSocket, it is -reasonable to ask, "When is it appropriate to use?". - -The best fit for WebSocket is in web applications where the client and -server need to exchange events at high frequency and with low latency. Prime -candidates include, but are not limited to, applications in finance, games, -collaboration, and others. Such applications are both very sensitive to time -delays and also need to exchange a wide variety of messages at a high -frequency. - -For other application types, however, this may not be the case. -For example, a news or social feed that shows breaking news as it becomes -available may be perfectly okay with simple polling once every few minutes. -Here latency is important, but it is acceptable if the news takes a -few minutes to appear. - -Even in cases where latency is crucial, if the volume of messages is -relatively low (e.g. monitoring network failures) the use of -https://spring.io/blog/2012/05/08/spring-mvc-3-2-preview-techniques-for-real-time-updates[long polling] -should be considered as a relatively simple alternative that -works reliably and is comparable in terms of efficiency (again assuming the volume of -messages is relatively low). - -It is the combination of both low latency and high frequency of messages that can make -the use of the WebSocket protocol critical. Even in such applications, -the choice remains whether all client-server -communication should be done through WebSocket messages as opposed to using -HTTP and REST. The answer is going to vary by application; however, it is likely -that some functionality may be exposed over both WebSocket and as a REST API in -order to provide clients with alternatives. Furthermore, a REST API call may need -to broadcast a message to interested clients connected via WebSocket. - -The Spring Framework allows `@Controller` and `@RestController` classes to have both -HTTP request handling and WebSocket message handling methods. -Furthermore, a Spring MVC request handling method, or any application -method for that matter, can easily broadcast a message to all interested -WebSocket clients or to a specific user. - - - - -[[websocket-server]] -=== WebSocket API -The Spring Framework provides a WebSocket API designed to adapt to various WebSocket engines. -Currently the list includes WebSocket runtimes such as Tomcat 7.0.47+, Jetty 9.1+, -GlassFish 4.1+, WebLogic 12.1.3+, and Undertow 1.0+ (and WildFly 8.0+). Additional support -may be added as more WebSocket runtimes become available. - -[NOTE] -==== -As explained in the <>, direct use of a -WebSocket API is too low level for applications -- until assumptions are made about the -format of a message there is little a framework can do to interpret messages or route -them via annotations. This is why applications should consider using a sub-protocol -and Spring's <> support. - -When using a higher level protocol, the details of the WebSocket API become less -relevant, much like the details of TCP communication are not exposed to applications -when using HTTP. Nevertheless this section covers the details of using WebSocket -directly. -==== - - - -[[websocket-server-handler]] -==== Create and Configure a WebSocketHandler -Creating a WebSocket server is as simple as implementing `WebSocketHandler` or more -likely extending either `TextWebSocketHandler` or `BinaryWebSocketHandler`: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - import org.springframework.web.socket.WebSocketHandler; - import org.springframework.web.socket.WebSocketSession; - import org.springframework.web.socket.TextMessage; - - public class MyHandler extends TextWebSocketHandler { - - @Override - public void handleTextMessage(WebSocketSession session, TextMessage message) { - // ... - } - - } ----- - -There is dedicated WebSocket Java-config and XML namespace support for mapping the above -WebSocket handler to a specific URL: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - import org.springframework.web.socket.config.annotation.EnableWebSocket; - import org.springframework.web.socket.config.annotation.WebSocketConfigurer; - import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; - - @Configuration - @EnableWebSocket - public class WebSocketConfig implements WebSocketConfigurer { - - @Override - public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { - registry.addHandler(myHandler(), "/myHandler"); - } - - @Bean - public WebSocketHandler myHandler() { - return new MyHandler(); - } - - } ----- - -XML configuration equivalent: - -[source,xml,indent=0] -[subs="verbatim,quotes,attributes"] ----- - - - - - - - - - ----- - -The above is for use in Spring MVC applications and should be included in the -configuration of a <>. However, Spring's WebSocket -support does not depend on Spring MVC. It is relatively simple to integrate a `WebSocketHandler` -into other HTTP serving environments with the help of -{javadoc-baseurl}/org/springframework/web/socket/server/support/WebSocketHttpRequestHandler.html[WebSocketHttpRequestHandler]. - - - -[[websocket-server-handshake]] -==== Customizing the WebSocket Handshake -The easiest way to customize the initial HTTP WebSocket handshake request is through -a `HandshakeInterceptor`, which exposes "before" and "after" the handshake methods. -Such an interceptor can be used to preclude the handshake or to make any attributes -available to the `WebSocketSession`. For example, there is a built-in interceptor -for passing HTTP session attributes to the WebSocket session: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Configuration - @EnableWebSocket - public class WebSocketConfig implements WebSocketConfigurer { - - @Override - public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { - registry.addHandler(new MyHandler(), "/myHandler") - .addInterceptors(new HttpSessionHandshakeInterceptor()); - } - - } ----- - -And the XML configuration equivalent: - -[source,xml,indent=0] -[subs="verbatim,quotes,attributes"] ----- - - - - - - - - - - - - ----- - -A more advanced option is to extend the `DefaultHandshakeHandler` that performs -the steps of the WebSocket handshake, including validating the client origin, -negotiating a sub-protocol, and others. An application may also need to use this -option if it needs to configure a custom `RequestUpgradeStrategy` in order to -adapt to a WebSocket server engine and version that is not yet supported -(also see <> for more on this subject). -Both the Java-config and XML namespace make it possible to configure a custom -`HandshakeHandler`. - - - -[[websocket-server-decorators]] -==== WebSocketHandler Decoration -Spring provides a `WebSocketHandlerDecorator` base class that can be used to decorate -a `WebSocketHandler` with additional behavior. Logging and exception handling -implementations are provided and added by default when using the WebSocket Java-config -or XML namespace. The `ExceptionWebSocketHandlerDecorator` catches all uncaught -exceptions arising from any WebSocketHandler method and closes the WebSocket -session with status `1011` that indicates a server error. - - - -[[websocket-server-deployment]] -==== Deployment Considerations -The Spring WebSocket API is easy to integrate into a Spring MVC application where -the `DispatcherServlet` serves both HTTP WebSocket handshake as well as other -HTTP requests. It is also easy to integrate into other HTTP processing scenarios -by invoking `WebSocketHttpRequestHandler`. This is convenient and easy to -understand. However, special considerations apply with regards to JSR-356 runtimes. - -The Java WebSocket API (JSR-356) provides two deployment mechanisms. The first -involves a Servlet container classpath scan (Servlet 3 feature) at startup; and -the other is a registration API to use at Servlet container initialization. -Neither of these mechanism makes it possible to use a single "front controller" -for all HTTP processing -- including WebSocket handshake and all other HTTP -requests -- such as Spring MVC's `DispatcherServlet`. - -This is a significant limitation of JSR-356 that Spring's WebSocket support -addresses by providing a server-specific `RequestUpgradeStrategy` even when -running in a JSR-356 runtime. - -[NOTE] -==== -A request to overcome the above limitation in the Java WebSocket API has been -created and can be followed at -https://java.net/jira/browse/WEBSOCKET_SPEC-211[WEBSOCKET_SPEC-211]. -Also note that Tomcat and Jetty already provide native API alternatives that -makes it easy to overcome the limitation. We are hopeful that more servers -will follow their example regardless of when it is addressed in the -Java WebSocket API. -==== - -A secondary consideration is that Servlet containers with JSR-356 support are expected -to perform a `ServletContainerInitializer` (SCI) scan that can slow down application -startup, in some cases dramatically. If a significant impact is observed after an -upgrade to a Servlet container version with JSR-356 support, it should -be possible to selectively enable or disable web fragments (and SCI scanning) -through the use of the `` element in `web.xml`: - -[source,xml,indent=0] -[subs="verbatim,quotes,attributes"] ----- - - - - - ----- - -You can then selectively enable web fragments by name, such as Spring's own -`SpringServletContainerInitializer` that provides support for the Servlet 3 -Java initialization API, if required: - -[source,xml,indent=0] -[subs="verbatim,quotes,attributes"] ----- - - - - spring_web - - - ----- - -[[websocket-server-runtime-configuration]] -==== Configuring the WebSocket Engine - -Each underlying WebSocket engine exposes configuration properties that control -runtime characteristics such as the size of message buffer sizes, idle timeout, -and others. - -For Tomcat, WildFly, and GlassFish add a `ServletServerContainerFactoryBean` to your -WebSocket Java config: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Configuration - @EnableWebSocket - public class WebSocketConfig implements WebSocketConfigurer { - - @Bean - public ServletServerContainerFactoryBean createWebSocketContainer() { - ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); - container.setMaxTextMessageBufferSize(8192); - container.setMaxBinaryMessageBufferSize(8192); - return container; - } - - } ----- - -or WebSocket XML namespace: - -[source,xml,indent=0] -[subs="verbatim,quotes,attributes"] ----- - - - - - - - - ----- - -[NOTE] -==== -For client side WebSocket configuration, you should use `WebSocketContainerFactoryBean` -(XML) or `ContainerProvider.getWebSocketContainer()` (Java config). -==== - -For Jetty, you'll need to supply a pre-configured Jetty `WebSocketServerFactory` and plug -that into Spring's `DefaultHandshakeHandler` through your WebSocket Java config: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Configuration - @EnableWebSocket - public class WebSocketConfig implements WebSocketConfigurer { - - @Override - public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { - registry.addHandler(echoWebSocketHandler(), - "/echo").setHandshakeHandler(handshakeHandler()); - } - - @Bean - public DefaultHandshakeHandler handshakeHandler() { - - WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER); - policy.setInputBufferSize(8192); - policy.setIdleTimeout(600000); - - return new DefaultHandshakeHandler( - new JettyRequestUpgradeStrategy(new WebSocketServerFactory(policy))); - } - - } ----- - -or WebSocket XML namespace: - -[source,xml,indent=0] -[subs="verbatim,quotes,attributes"] ----- - - - - - - - - - - - - - - - - - - - - - - - - - - ----- - -[[websocket-server-allowed-origins]] -==== Configuring allowed origins - -As of Spring Framework 4.1.5, the default behavior for WebSocket and SockJS is to accept -only _same origin_ requests. It is also possible to allow _all_ or a specified list of origins. -This check is mostly designed for browser clients. There is nothing preventing other types -of clients from modifying the `Origin` header value (see -https://tools.ietf.org/html/rfc6454[RFC 6454: The Web Origin Concept] for more details). - -The 3 possible behaviors are: - - * Allow only same origin requests (default): in this mode, when SockJS is enabled, the - Iframe HTTP response header `X-Frame-Options` is set to `SAMEORIGIN`, and JSONP - transport is disabled since it does not allow to check the origin of a request. - As a consequence, IE6 and IE7 are not supported when this mode is enabled. - * Allow a specified list of origins: each provided _allowed origin_ must start with `http://` - or `https://`. In this mode, when SockJS is enabled, both IFrame and JSONP based - transports are disabled. As a consequence, IE6 through IE9 are not supported when this - mode is enabled. - * Allow all origins: to enable this mode, you should provide `{asterisk}` as the allowed origin - value. In this mode, all transports are available. - -WebSocket and SockJS allowed origins can be configured as shown bellow: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - import org.springframework.web.socket.config.annotation.EnableWebSocket; - import org.springframework.web.socket.config.annotation.WebSocketConfigurer; - import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; - - @Configuration - @EnableWebSocket - public class WebSocketConfig implements WebSocketConfigurer { - - @Override - public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { - registry.addHandler(myHandler(), "/myHandler").setAllowedOrigins("http://mydomain.com"); - } - - @Bean - public WebSocketHandler myHandler() { - return new MyHandler(); - } - - } ----- - -XML configuration equivalent: - -[source,xml,indent=0] -[subs="verbatim,quotes,attributes"] ----- - - - - - - - - - ----- - - -[[websocket-fallback]] -=== SockJS Fallback Options -As explained in the <>, WebSocket is not -supported in all browsers yet and may be precluded by restrictive network proxies. -This is why Spring provides fallback options that emulate the WebSocket API as close -as possible based on the https://github.com/sockjs/sockjs-protocol[SockJS protocol] -(version 0.3.3). - -[[websocket-fallback-sockjs-overview]] -==== Overview of SockJS - -The goal of SockJS is to let applications use a WebSocket API but fall back to -non-WebSocket alternatives when necessary at runtime, i.e. without the need to -change application code. - -SockJS consists of: - -* The https://github.com/sockjs/sockjs-protocol[SockJS protocol] -defined in the form of executable -http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html[narrated tests]. -* The https://github.com/sockjs/sockjs-client/tree/v0.3.4[SockJS JavaScript client] - a client library for use in browsers. -* SockJS server implementations including one in the Spring Framework `spring-websocket` module. -* As of 4.1 `spring-websocket` also provides a SockJS Java client. - -SockJS is designed for use in browsers. It goes to great lengths -to support a wide range of browser versions using a variety of techniques. -For the full list of SockJS transport types and browsers see the -https://github.com/sockjs/sockjs-client/tree/v0.3.4[SockJS client] page. Transports -fall in 3 general categories: WebSocket, HTTP Streaming, and HTTP Long Polling. -For an overview of these categories see -https://spring.io/blog/2012/05/08/spring-mvc-3-2-preview-techniques-for-real-time-updates/[this blog post]. - -The SockJS client begins by sending `"GET /info"` to -obtain basic information from the server. After that it must decide what transport -to use. If possible WebSocket is used. If not, in most browsers -there is at least one HTTP streaming option and if not then HTTP (long) -polling is used. - -All transport requests have the following URL structure: ----- -http://host:port/myApp/myEndpoint/{server-id}/{session-id}/{transport} ----- - -* `{server-id}` - useful for routing requests in a cluster but not used otherwise. -* `{session-id}` - correlates HTTP requests belonging to a SockJS session. -* `{transport}` - indicates the transport type, e.g. "websocket", "xhr-streaming", etc. - -The WebSocket transport needs only a single HTTP request to do the WebSocket handshake. -All messages thereafter are exchanged on that socket. - -HTTP transports require more requests. Ajax/XHR streaming for example relies on -one long-running request for server-to-client messages and additional HTTP POST -requests for client-to-server messages. Long polling is similar except it -ends the current request after each server-to-client send. - -SockJS adds minimal message framing. For example the server sends the letter +o+ -("open" frame) initially, messages are sent as +a["message1","message2"]+ -(JSON-encoded array), the letter +h+ ("heartbeat" frame) if no messages flow -for 25 seconds by default, and the letter +c+ ("close" frame) to close the session. - -To learn more, run an example in a browser and watch the HTTP requests. -The SockJS client allows fixing the list of transports so it is possible to -see each transport one at a time. The SockJS client also provides a debug flag -which enables helpful messages in the browser console. On the server side enable -`TRACE` logging for `org.springframework.web.socket`. -For even more detail refer to the SockJS protocol -http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html[narrated test]. - - -[[websocket-fallback-sockjs-enable]] -==== Enable SockJS -SockJS is easy to enable through Java configuration: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Configuration - @EnableWebSocket - public class WebSocketConfig implements WebSocketConfigurer { - - @Override - public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { - registry.addHandler(myHandler(), "/myHandler").withSockJS(); - } - - @Bean - public WebSocketHandler myHandler() { - return new MyHandler(); - } - - } ----- - -and the XML configuration equivalent: - -[source,xml,indent=0] -[subs="verbatim,quotes,attributes"] ----- - - - - - - - - - - ----- - -The above is for use in Spring MVC applications and should be included in the -configuration of a <>. However, Spring's WebSocket -and SockJS support does not depend on Spring MVC. It is relatively simple to -integrate into other HTTP serving environments with the help of -{javadoc-baseurl}/org/springframework/web/socket/sockjs/support/SockJsHttpRequestHandler.html[SockJsHttpRequestHandler]. - -On the browser side, applications can use the -https://github.com/sockjs/sockjs-client/tree/v0.3.4[sockjs-client] (version 0.3.x) that -emulates the W3C WebSocket API and communicates with the server to select the best -transport option depending on the browser it's running in. Review the -https://github.com/sockjs/sockjs-client/tree/v0.3.4[sockjs-client] page and the list of -transport types supported by browser. The client also provides several -configuration options, for example, to specify which transports to include. - -[[websocket-fallback-xhr-vs-iframe]] -==== HTTP Streaming in IE 8, 9: Ajax/XHR vs IFrame - -Internet Explorer 8 and 9 are and will remain common for some time. They are -a key reason for having SockJS. This section covers important -considerations about running in those browsers. - -The SockJS client supports Ajax/XHR streaming in IE 8 and 9 via Microsoft's -http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx[XDomainRequest]. -That works across domains but does not support sending cookies. -Cookies are very often essential for Java applications. -However since the SockJS client can be used with many server -types (not just Java ones), it needs to know whether cookies matter. -If so the SockJS client prefers Ajax/XHR for streaming or otherwise it -relies on a iframe-based technique. - -The very first `"/info"` request from the SockJS client is a request for -information that can influence the client's choice of transports. -One of those details is whether the server application relies on cookies, -e.g. for authentication purposes or clustering with sticky sessions. -Spring's SockJS support includes a property called `sessionCookieNeeded`. -It is enabled by default since most Java applications rely on the `JSESSIONID` -cookie. If your application does not need it, you can turn off this option -and the SockJS client should choose `xdr-streaming` in IE 8 and 9. - -If you do use an iframe-based transport, and in any case, it is good to know -that browsers can be instructed to block the use of IFrames on a given page by -setting the HTTP response header `X-Frame-Options` to `DENY`, -`SAMEORIGIN`, or `ALLOW-FROM `. This is used to prevent -https://www.owasp.org/index.php/Clickjacking[clickjacking]. - -[NOTE] -==== -Spring Security 3.2+ provides support for setting `X-Frame-Options` on every -response. By default the Spring Security Java config sets it to `DENY`. -In 3.2 the Spring Security XML namespace does not set that header by default -but may be configured to do so, and in the future it may set it by default. - -See http://docs.spring.io/spring-security/site/docs/3.2.2.RELEASE/reference/htmlsingle/#headers[Section 7.1. "Default Security Headers"] -of the Spring Security documentation for details on how to configure the -setting of the `X-Frame-Options` header. You may also check or watch -https://jira.spring.io/browse/SEC-2501[SEC-2501] for additional background. -==== - -If your application adds the `X-Frame-Options` response header (as it should!) -and relies on an iframe-based transport, you will need to set the header value to -`SAMEORIGIN` or `ALLOW-FROM `. Along with that the Spring SockJS -support also needs to know the location of the SockJS client because it is loaded -from the iframe. By default the iframe is set to download the SockJS client -from a CDN location. It is a good idea to configure this option to -a URL from the same origin as the application. - -In Java config this can be done as shown below. The XML namespace provides a -similar option via the `` element: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Configuration - @EnableWebSocket - public class WebSocketConfig implements WebSocketConfigurer { - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry.addEndpoint("/portfolio").withSockJS() - .setClientLibraryUrl("http://localhost:8080/myapp/js/sockjs-client.js"); - } - - // ... - - } ----- - -[NOTE] -==== -During initial development, do enable the SockJS client `devel` mode that prevents -the browser from caching SockJS requests (like the iframe) that would otherwise -be cached. For details on how to enable it see the -https://github.com/sockjs/sockjs-client/tree/v0.3.4[SockJS client] page. -==== - -[[websocket-fallback-sockjs-heartbeat]] -==== Heartbeat Messages - -The SockJS protocol requires servers to send heartbeat messages to preclude proxies -from concluding a connection is hung. The Spring SockJS configuration has a property -called `heartbeatTime` that can be used to customize the frequency. By default a -heartbeat is sent after 25 seconds assuming no other messages were sent on that -connection. This 25 seconds value is in line with the following -http://tools.ietf.org/html/rfc6202[IETF recommendation] for public Internet applications. - -[NOTE] -==== -When using STOMP over WebSocket/SockJS, if the STOMP client and server negotiate -heartbeats to be exchanged, the SockJS heartbeats are disabled. -==== - -The Spring SockJS support also allows configuring the `TaskScheduler` to use -for scheduling heartbeats tasks. The task scheduler is backed by a thread pool -with default settings based on the number of available processors. Applications -should consider customizing the settings according to their specific needs. - -[[websocket-fallback-sockjs-servlet3-async]] -==== Servlet 3 Async Requests - -HTTP streaming and HTTP long polling SockJS transports require a connection to remain -open longer than usual. For an overview of these techniques see -https://spring.io/blog/2012/05/08/spring-mvc-3-2-preview-techniques-for-real-time-updates/[this blog post]. - -In Servlet containers this is done through Servlet 3 async support that -allows exiting the Servlet container thread processing a request and continuing -to write to the response from another thread. - -A specific issue is that the Servlet API does not provide notifications for a client -that has gone away, see https://java.net/jira/browse/SERVLET_SPEC-44[SERVLET_SPEC-44]. -However, Servlet containers raise an exception on subsequent attempts to write -to the response. Since Spring's SockJS Service supports sever-sent heartbeats (every -25 seconds by default), that means a client disconnect is usually detected within that -time period or earlier if messages are sent more frequently. - -[NOTE] -==== -As a result network IO failures may occur simply because a client has disconnected, which -can fill the log with unnecessary stack traces. Spring makes a best effort to identify -such network failures that represent client disconnects (specific to each server) and log -a minimal message using the dedicated log category `DISCONNECTED_CLIENT_LOG_CATEGORY` -defined in `AbstractSockJsSession`. If you need to see the stack traces, set that -log category to TRACE. -==== - -[[websocket-fallback-cors]] -==== CORS Headers for SockJS - -If you allow cross-origin requests (see <>), the SockJS protocol -uses CORS for cross-domain support in the XHR streaming and polling transports. Therefore -CORS headers are added automatically unless the presence of CORS headers in the response -is detected. So if an application is already configured to provide CORS support, e.g. -through a Servlet Filter, Spring's SockJsService will skip this part. - -It is also possible to disable the addition of these CORS headers via the -`suppressCors` property in Spring's SockJsService. - -The following is the list of headers and values expected by SockJS: - -* `"Access-Control-Allow-Origin"` - initialized from the value of the "Origin" request header. -* `"Access-Control-Allow-Credentials"` - always set to `true`. -* `"Access-Control-Request-Headers"` - initialized from values from the equivalent request header. -* `"Access-Control-Allow-Methods"` - the HTTP methods a transport supports (see `TransportType` enum). -* `"Access-Control-Max-Age"` - set to 31536000 (1 year). - -For the exact implementation see `addCorsHeaders` in `AbstractSockJsService` as well -as the `TransportType` enum in the source code. - -Alternatively if the CORS configuration allows it consider excluding URLs with the -SockJS endpoint prefix thus letting Spring's `SockJsService` handle it. - - -[[websocket-fallback-sockjs-client]] -==== SockJS Client - -A SockJS Java client is provided in order to connect to remote SockJS endpoints without -using a browser. This can be especially useful when there is a need for bidirectional -communication between 2 servers over a public network, i.e. where network proxies may -preclude the use of the WebSocket protocol. A SockJS Java client is also very useful -for testing purposes, for example to simulate a large number of concurrent users. - -The SockJS Java client supports the "websocket", "xhr-streaming", and "xhr-polling" -transports. The remaining ones only make sense for use in a browser. - -The `WebSocketTransport` can be configured with: - -* `StandardWebSocketClient` in a JSR-356 runtime -* `JettyWebSocketClient` using the Jetty 9+ native WebSocket API -* Any implementation of Spring's `WebSocketClient` - -An `XhrTransport` by definition supports both "xhr-streaming" and "xhr-polling" since -from a client perspective there is no difference other than in the URL used to connect -to the server. At present there are two implementations: - -* `RestTemplateXhrTransport` uses Spring's `RestTemplate` for HTTP requests. -* `JettyXhrTransport` uses Jetty's `HttpClient` for HTTP requests. - -The example below shows how to create a SockJS client and connect to a SockJS endpoint: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - List transports = new ArrayList<>(2); - transports.add(new WebSocketTransport(StandardWebSocketClient())); - transports.add(new RestTemplateXhrTransport()); - - SockJsClient sockJsClient = new SockJsClient(transports); - sockJsClient.doHandshake(new MyWebSocketHandler(), "ws://example.com:8080/sockjs"); ----- - -[NOTE] -==== -SockJS uses JSON formatted arrays for messages. By default Jackson 2 is used and needs -to be on the classpath. Alternatively you can configure a custom implementation of -`SockJsMessageCodec` and configure it on the `SockJsClient`. -==== - -To use the SockJsClient for simulating a large number of concurrent users you will -need to configure the underlying HTTP client (for XHR transports) to allow a sufficient -number of connections and threads. For example with Jetty: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- -HttpClient jettyHttpClient = new HttpClient(); -jettyHttpClient.setMaxConnectionsPerDestination(1000); -jettyHttpClient.setExecutor(new QueuedThreadPool(1000)); ----- - -Consider also customizing these server-side SockJS related properties (see Javadoc for details): - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- -@Configuration -public class WebSocketConfig extends WebSocketMessageBrokerConfigurationSupport { - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry.addEndpoint("/sockjs").withSockJS() - .setStreamBytesLimit(512 * 1024) - .setHttpMessageCacheSize(1000) - .setDisconnectDelay(30 * 1000); - } - - // ... - -} ----- - - - - -[[websocket-stomp]] -=== STOMP Over WebSocket Messaging Architecture -The WebSocket protocol defines two main types of messages -- text and binary -- -but leaves their content undefined. Instead it's expected that the client and -server may agree on using a sub-protocol, i.e. a higher-level protocol that defines -the message content. Using a sub-protocol is optional but either way the client -and server both need to understand how to interpret messages. - - - -[[websocket-stomp-overview]] -==== Overview of STOMP -http://stomp.github.io/stomp-specification-1.2.html#Abstract[STOMP] is a simple -text-oriented messaging protocol that was originally created for scripting languages -(such as Ruby, Python, and Perl) to connect to enterprise message brokers. It is -designed to address a subset of commonly used patterns in messaging protocols. STOMP -can be used over any reliable 2-way streaming network protocol such as TCP and WebSocket. - -STOMP is a frame based protocol with frames modeled on HTTP. This is the -structure of a frame: - ----- -COMMAND -header1:value1 -header2:value2 - -Body^@ ----- - -For example, a client can use the +SEND+ command to send a message or the -+SUBSCRIBE+ command to express interest in receiving messages. Both of these commands -require a +"destination"+ header that indicates where to send a message, or likewise -what to subscribe to. - -Here is an example of a client sending a request to buy stock shares: - ----- -SEND -destination:/queue/trade -content-type:application/json -content-length:44 - -{"action":"BUY","ticker":"MMM","shares",44}^@ ----- - -Here is an example of a client subscribing to receive stock quotes: ----- -SUBSCRIBE -id:sub-1 -destination:/topic/price.stock.* - -^@ ----- - -[NOTE] -==== -The meaning of a destination is intentionally left opaque in the STOMP spec. It can -be any string, and it's entirely up to STOMP servers to define the semantics and -the syntax of the destinations that they support. It is very common, however, for -destinations to be path-like strings where `"/topic/.."` implies publish-subscribe -(__one-to-many__) and `"/queue/"` implies point-to-point (__one-to-one__) message -exchanges. -==== - -STOMP servers can use the +MESSAGE+ command to broadcast messages to all subscribers. -Here is an example of a server sending a stock quote to a subscribed client: - ----- -MESSAGE -message-id:nxahklf6-1 -subscription:sub-1 -destination:/topic/price.stock.MMM - -{"ticker":"MMM","price":129.45}^@ ----- - -[NOTE] -==== -It is important to know that a server cannot send unsolicited messages. All messages -from a server must be in response to a specific client subscription, and the -+"subscription-id"+ header of the server message must match the +"id"+ header of the -client subscription. -==== - -The above overview is intended to provide the most basic understanding of the -STOMP protocol. It is recommended to review the protocol -http://stomp.github.io/stomp-specification-1.2.html[specification], which is -easy to follow and manageable in terms of size. - -The following summarizes the benefits for an application of using STOMP over WebSocket: - -* Standard message format -* Application-level protocol with support for common messaging patterns -* Client-side support, e.g. https://github.com/jmesnil/stomp-websocket[stomp.js], https://github.com/cujojs/msgs[msgs.js] -* The ability to interpret, route, and process messages on both the client and server-side -* The option to plug in a message broker -- RabbitMQ, ActiveMQ, many others -- to broadcast messages (explained later) - -Most importantly the use of STOMP (vs plain WebSocket) enables the Spring Framework -to provide a programming model for application-level use in the same way that -Spring MVC provides a programming model based on HTTP. - - - -[[websocket-stomp-enable]] -==== Enable STOMP over WebSocket -The Spring Framework provides support for using STOMP over WebSocket through -the +spring-messaging+ and +spring-websocket+ modules. It's easy to enable it. - -Here is an example of configuring a STOMP WebSocket endpoint with SockJS fallback -options. The endpoint is available for clients to connect to a URL path `/app/portfolio`: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; - import org.springframework.web.socket.config.annotation.StompEndpointRegistry; - - @Configuration - @EnableWebSocketMessageBroker - public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { - - @Override - public void configureMessageBroker(MessageBrokerRegistry config) { - config.setApplicationDestinationPrefixes("/app"); - config.enableSimpleBroker("/queue", "/topic"); - } - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry.addEndpoint("/portfolio").withSockJS(); - } - - // ... - - } ----- - -XML configuration equivalent: - -[source,xml,indent=0] -[subs="verbatim,quotes,attributes"] ----- - - - - - - - - ... - - - ----- - -On the browser side, a client might connect as follows using -https://github.com/jmesnil/stomp-websocket[stomp.js] and the -https://github.com/sockjs/sockjs-client[sockjs-client]: - -[source,javascript,indent=0] -[subs="verbatim,quotes"] ----- - var socket = new SockJS("/spring-websocket-portfolio/portfolio"); - var stompClient = Stomp.over(socket); - - stompClient.connect({}, function(frame) { - } ----- - -Or if connecting via WebSocket (without SockJS): - -[source,javascript,indent=0] -[subs="verbatim,quotes"] ----- - var socket = new WebSocket("/spring-websocket-portfolio/portfolio"); - var stompClient = Stomp.over(socket); - - stompClient.connect({}, function(frame) { - } ----- - -Note that the `stompClient` above does not need to specify `login` and `passcode` headers. -Even if it did, they would be ignored, or rather overridden, on the server side. See the -sections <> and -<> for more information on authentication. - - -[[websocket-stomp-message-flow]] -==== Flow of Messages - -When a STOMP endpoint is configured, the Spring application acts as the STOMP broker -to connected clients. It handles incoming messages and sends messages back. -This section provides a big picture overview of how messages flow inside the application. - -The `spring-messaging` module contains a number of abstractions that originated in the -https://spring.io/spring-integration[Spring Integration] project and are intended -for use as building blocks in messaging applications: - -* {javadoc-baseurl}/org/springframework/messaging/Message.html[Message] -- -a message with headers and a payload. -* {javadoc-baseurl}/org/springframework/messaging/MessageHandler.html[MessageHandler] -- -a contract for handling a message. -* {javadoc-baseurl}/org/springframework/messaging/MessageChannel.html[MessageChannel] -- -a contract for sending a message enabling loose coupling between senders and receivers. -* {javadoc-baseurl}/org/springframework/messaging/SubscribableChannel.html[SubscribableChannel] -- -extends `MessageChannel` and sends messages to registered `MessageHandler` subscribers. -* {javadoc-baseurl}/org/springframework/messaging/support/ExecutorSubscribableChannel.html[ExecutorSubscribableChannel] -- -a concrete implementation of `SubscribableChannel` that can deliver messages -asynchronously via a thread pool. - -The provided STOMP over WebSocket config, both Java and XML, uses the above to -assemble a concrete message flow including the following 3 channels: - -* `"clientInboundChannel"` -- for messages from WebSocket clients. Every incoming -WebSocket message carrying a STOMP frame is sent through this channel. -* `"clientOutboundChannel"` -- for messages to WebSocket clients. Every outgoing -STOMP message from the broker is sent through this channel before getting sent -to a client's WebSocket session. -* `"brokerChannel"` -- for messages to the broker from within the application. -Every message sent from the application to the broker passes through this channel. - -Messages on the `"clientInboundChannel"` can flow to annotated -methods for application handling (e.g. a stock trade execution request) or can -be forwarded to the broker (e.g. client subscribing for stock quotes). -The STOMP destination is used for simple prefix-based routing. For example -the "/app" prefix could route messages to annotated methods while the "/topic" -and "/queue" prefixes could route messages to the broker. - -When a message-handling annotated method has a return type, its return -value is sent as the payload of a Spring `Message` to the `"brokerChannel"`. -The broker in turn broadcasts the message to clients. Sending a message -to a destination can also be done from anywhere in the application with -the help of a messaging template. For example, an HTTP POST handling method -can broadcast a message to connected clients, or a service component may -periodically broadcast stock quotes. - -Below is a simple example to illustrate the flow of messages: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Configuration - @EnableWebSocketMessageBroker - public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry.addEndpoint("/portfolio"); - } - - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.setApplicationDestinationPrefixes("/app"); - registry.enableSimpleBroker("/topic"); - } - - } - - @Controller - public class GreetingController { - - @MessageMapping("/greeting") { - public String handle(String greeting) { - return "[" + getTimestamp() + ": " + greeting; - } - - } - ----- - -The following explains the message flow for the above example: - -* WebSocket clients connect to the WebSocket endpoint at "/portfolio". -* Subscriptions to "/topic/greeting" pass through the "clientInboundChannel" -and are forwarded to the broker. -* Greetings sent to "/app/greeting" pass through the "clientInboundChannel" -and are forwarded to the `GreetingController`. The controller adds the current -time, and the return value is passed through the "brokerChannel" as a message -to "/topic/greeting" (destination is selected based on a convention but can be -overridden via `@SendTo`). -* The broker in turn broadcasts messages to subscribers, and they pass through -the `"clientOutboundChannel"`. - -The next section provides more details on annotated methods including the -kinds of arguments and return values supported. - - - -[[websocket-stomp-handle-annotations]] -==== Annotation Message Handling - -The `@MessageMapping` annotation is supported on methods of `@Controller` classes. -It can be used for mapping methods to message destinations and can also be combined -with the type-level `@MessageMapping` for expressing shared mappings across all -annotated methods within a controller. - -By default destination mappings are treated as Ant-style, slash-separated, path -patterns, e.g. "/foo*", "/foo/**". etc. They can also contain template variables, -e.g. "/foo/{id}" that can then be referenced via `@DestinationVariable`-annotated -method arguments. - -[NOTE] -==== -Applications can also use dot-separated destinations (vs slash). -See <>. -==== - -The following method arguments are supported for `@MessageMapping` methods: - -* `Message` method argument to get access to the complete message being processed. -* `@Payload`-annotated argument for access to the payload of a message, converted with -a `org.springframework.messaging.converter.MessageConverter`. -The presence of the annotation is not required since it is assumed by default. -Payload method arguments annotated with validation annotations (like `@Validated`) will -be subject to JSR-303 validation. -* `@Header`-annotated arguments for access to a specific header value along with -type conversion using an `org.springframework.core.convert.converter.Converter` -if necessary. -* `@Headers`-annotated method argument that must also be assignable to `java.util.Map` -for access to all headers in the message. -* `MessageHeaders` method argument for getting access to a map of all headers. -* `MessageHeaderAccessor`, `SimpMessageHeaderAccessor`, or `StompHeaderAccessor` -for access to headers via typed accessor methods. -* `@DestinationVariable`-annotated arguments for access to template -variables extracted from the message destination. Values will be converted to -the declared method argument type as necessary. -* `java.security.Principal` method arguments reflecting the user logged in at -the time of the WebSocket HTTP handshake. - -The return value from an `@MessageMapping` method is converted with a -`org.springframework.messaging.converter.MessageConverter` and used as the body -of a new message that is then sent, by default, to the `"brokerChannel"` with -the same destination as the client message but using the prefix `"/topic"` by -default. An `@SendTo` message level annotation can be used to specify any -other destination instead. - -An `@SubscribeMapping` annotation can also be used to map subscription requests -to `@Controller` methods. It is supported on the method level, but can also be -combined with a type level `@MessageMapping` annotation that expresses shared -mappings across all message handling methods within the same controller. - -By default the return value from an `@SubscribeMapping` method is sent as a -message directly back to the connected client and does not pass through the -broker. This is useful for implementing request-reply message interactions; for -example, to fetch application data when the application UI is being initialized. -Or alternatively an `@SubscribeMapping` method can be annotated with `@SendTo` -in which case the resulting message is sent to the `"brokerChannel"` using -the specified target destination. - - -[[websocket-stomp-handle-send]] -==== Sending Messages - -What if you want to send messages to connected clients from any part of the -application? Any application component can send messages to the `"brokerChannel"`. -The easiest way to do that is to have a `SimpMessagingTemplate` injected, and -use it to send messages. Typically it should be easy to have it injected by -type, for example: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Controller - public class GreetingController { - - private SimpMessagingTemplate template; - - @Autowired - public GreetingController(SimpMessagingTemplate template) { - this.template = template; - } - - @RequestMapping(value="/greetings", method=POST) - public void greet(String greeting) { - String text = "[" + getTimestamp() + "]:" + greeting; - this.template.convertAndSend("/topic/greetings", text); - } - - } ----- - -But it can also be qualified by its name "brokerMessagingTemplate" if another -bean of the same type exists. - - -[[websocket-stomp-handle-simple-broker]] -==== Simple Broker - -The built-in, simple message broker handles subscription requests from clients, -stores them in memory, and broadcasts messages to connected clients with matching -destinations. The broker supports path-like destinations, including subscriptions -to Ant-style destination patterns. - -[NOTE] -==== -Applications can also use dot-separated destinations (vs slash). -See <>. -==== - - - - -[[websocket-stomp-handle-broker-relay]] -==== Full-Featured Broker - -The simple broker is great for getting started but supports only a subset of -STOMP commands (e.g. no acks, receipts, etc.), relies on a simple message -sending loop, and is not suitable for clustering. As an alternative, applications -can upgrade to using a full-featured message broker. - -Check the STOMP documentation for your message broker of choice (e.g. -http://www.rabbitmq.com/stomp.html[RabbitMQ], -http://activemq.apache.org/stomp.html[ActiveMQ], etc.), install the broker, -and run it with STOMP support enabled. Then enable the STOMP broker relay in the -Spring configuration instead of the simple broker. - -Below is example configuration that enables a full-featured broker: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Configuration - @EnableWebSocketMessageBroker - public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - registry.addEndpoint("/portfolio").withSockJS(); - } - - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableStompBrokerRelay("/topic", "/queue"); - registry.setApplicationDestinationPrefixes("/app"); - } - - } ----- - -XML configuration equivalent: - -[source,xml,indent=0] -[subs="verbatim,quotes,attributes"] ----- - - - - - - - - - - ----- - -The "STOMP broker relay" in the above configuration is a Spring -http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/messaging/MessageHandler.html[MessageHandler] -that handles messages by forwarding them to an external message broker. -To do so it establishes TCP connections to the broker, forwards all -messages to it, and then forwards all messages received -from the broker to clients through their WebSocket sessions. Essentially -it acts as a "relay" that forwards messages in both directions. - -[NOTE] -==== -Please add a dependency on `org.projectreactor:reactor-net` for TCP connection management. -==== - -Furthermore, application components (e.g. HTTP request handling methods, -business services, etc.) can also send messages to the broker relay, as described -in <>, in order to broadcast messages to -subscribed WebSocket clients. - -In effect, the broker relay enables robust and scalable message broadcasting. - -[[websocket-stomp-handle-broker-relay-configure]] -==== Connections To Full-Featured Broker - -A STOMP broker relay maintains a single "system" TCP connection to the broker. -This connection is used for messages originating from the server-side application -only, not for receiving messages. You can configure the STOMP credentials -for this connection, i.e. the STOMP frame `login` and `passcode` headers. This -is exposed in both the XML namespace and the Java config as the -++systemLogin++/++systemPasscode++ properties with default values ++guest++/++guest++. - -The STOMP broker relay also creates a separate TCP connection for every connected -WebSocket client. You can configure the STOMP credentials to use for all TCP -connections created on behalf of clients. This is exposed in both the XML namespace -and the Java config as the ++clientLogin++/++clientPasscode++ properties with default -values ++guest++/++guest++. - -[NOTE] -==== -The STOMP broker relay always sets the `login` and `passcode` headers on every `CONNECT` -frame that it forwards to the broker on behalf of clients. Therefore WebSocket clients -need not set those headers; they will be ignored. As the following section explains, -instead WebSocket clients should rely on HTTP authentication to protect the WebSocket -endpoint and establish the client identity. -==== - -The STOMP broker relay also sends and receives heartbeats to and from the message -broker over the "system" TCP connection. You can configure the intervals for sending -and receiving heartbeats (10 seconds each by default). If connectivity to the broker -is lost, the broker relay will continue to try to reconnect, every 5 seconds, -until it succeeds. - -[NOTE] -==== -A Spring bean can implement `ApplicationListener` in order -to receive notifications when the "system" connection to the broker is lost and -re-established. For example a Stock Quote service broadcasting stock quotes can -stop trying to send messages when there is no active "system" connection. -==== - -The STOMP broker relay can also be configured with a `virtualHost` property. -The value of this property will be set as the `host` header of every `CONNECT` frame -and may be useful for example in a cloud environment where the actual host to which -the TCP connection is established is different from the host providing the -cloud-based STOMP service. - -[[websocket-stomp-destination-separator]] -==== Using Dot as Separator in `@MessageMapping` Destinations - -Although slash-separated path patterns are familiar to web developers, in messaging -it is common to use a "." as the separator, for example in the names of topics, queues, -exchanges, etc. Applications can also switch to using "." (dot) instead of "/" (slash) -as the separator in `@MessageMapping` mappings by configuring a custom `AntPathMatcher`. - -In Java config: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Configuration - @EnableWebSocketMessageBroker - public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { - - // ... - - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableStompBrokerRelay("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/app"); - registry.setPathMatcher(new AntPathMatcher(".")); - } - - } ----- - -In XML config: - -[source,xml,indent=0] -[subs="verbatim,quotes,attributes"] ----- - - - - - - - - - - - - ----- - -And below is a simple example to illustrate a controller with "." separator: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Controller - @MessageMapping("foo") - public class FooController { - - @MessageMapping("bar.{baz}") - public void handleBaz(@DestinationVariable String baz) { - } - - } ----- - -If the application prefix is set to "/app" then the foo method is effectively mapped to "/app/foo.bar.{baz}". - - - - -[[websocket-stomp-authentication]] -==== Authentication - -In a WebSocket-style application it is often useful to know who sent a message. -Therefore some form of authentication is needed to establish the user identity -and associate it with the current session. - -Existing Web applications already use HTTP based authentication. -For example Spring Security can secure the HTTP URLs of the application as usual. -Since a WebSocket session begins with an HTTP handshake, that means URLs mapped -to STOMP/WebSocket are already automatically protected and require authentication. -Moreover the page that opens the WebSocket connection is itself likely protected -and so by the time of the actual handshake, the user should have been authenticated. - -When a WebSocket handshake is made and a new WebSocket session is created, -Spring's WebSocket support automatically propagates the `java.security.Principal` -from the HTTP request to the WebSocket session. After that every message flowing -through the application on that WebSocket session is enriched with -the user information. It's present in the message as a header. -Controller methods can access the current user by adding a method argument of -type `javax.security.Principal`. - -Note that even though the STOMP `CONNECT` frame has "login" and "passcode" headers -that can be used for authentication, Spring's STOMP WebSocket support ignores them -and currently expects users to have been authenticated already via HTTP. - -In some cases it may be useful to assign an identity to a WebSocket session even -when the user has not been formally authenticated. For example, a mobile app might -assign some identity to anonymous users, perhaps based on geographical location. -The do that currently, an application can sub-class `DefaultHandshakeHandler` -and override the `determineUser` method. The custom handshake handler can then -be plugged in (see examples in <>). - - - -[[websocket-stomp-user-destination]] -==== User Destinations - -An application can send messages targeting a specific user, and Spring's STOMP support -recognizes destinations prefixed with `"/user/"` for this purpose. -For example, a client might subscribe to the destination `"/user/queue/position-updates"`. -This destination will be handled by the `UserDestinationMessageHandler` and -transformed into a destination unique to the user session, -e.g. `"/queue/position-updates-user123"`. This provides the convenience of subscribing -to a generically named destination while at the same time ensuring no collisions -with other users subscribing to the same destination so that each user can receive -unique stock position updates. - -On the sending side messages can be sent to a destination such as -`"/user/{username}/queue/position-updates"`, which in turn will be translated -by the `UserDestinationMessageHandler` into one or more destinations, one for each -session associated with the user. This allows any component within the application to -send messages targeting a specific user without necessarily knowing anything more -than their name and the generic destination. This is also supported through an -annotation as well as a messaging template. - -For example, a message-handling method can send messages to the user associated with -the message being handled through the `@SendToUser` annotation: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- -@Controller -public class PortfolioController { - - @MessageMapping("/trade") - @SendToUser("/queue/position-updates") - public TradeResult executeTrade(Trade trade, Principal principal) { - // ... - return tradeResult; - } -} ----- - -If the user has more than one session, by default all of the sessions subscribed -to the given destination are targeted. However sometimes, it may be necessary to -target only the session that sent the message being handled. This can be done by -setting the `broadcast` attribute to false, for example: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- -@Controller -public class MyController { - - @MessageMapping("/action") - public void handleAction() throws Exception{ - // raise MyBusinessException here - } - - @MessageExceptionHandler - @SendToUser(value="/queue/errors", broadcast=false) - public ApplicationError handleException(MyBusinessException exception) { - // ... - return appError; - } -} ----- - - -[NOTE] -==== -While user destinations generally imply an authenticated user, it isn't required -strictly. A WebSocket session that is not associated with an authenticated user -can subscribe to a user destination. In such cases the `@SendToUser` annotation -will behave exactly the same as with `broadcast=false`, i.e. targeting only the -session that sent the message being handled. -==== - -It is also possible to send a message to user destinations from any application -component by injecting the `SimpMessagingTemplate` created by the Java config or -XML namespace, for example (the bean name is `"brokerMessagingTemplate"` if required -for qualification with `@Qualifier`): - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- -@Service -public class TradeServiceImpl implements TradeService { - - private final SimpMessagingTemplate messagingTemplate; - - @Autowired - public TradeServiceImpl(SimpMessagingTemplate messagingTemplate) { - this.messagingTemplate = messagingTemplate; - } - - // ... - - public void afterTradeExecuted(Trade trade) { - this.messagingTemplate.convertAndSendToUser( - trade.getUserName(), "/queue/position-updates", trade.getResult()); - } -} ----- - -[NOTE] -==== -When using user destinations with an external message broker, check the broker -documentation on how to manage inactive queues, so that when the user session is -over, all unique user queues are removed. For example, RabbitMQ creates auto-delete -queues when destinations like `/exchange/amq.direct/position-updates` are used. -So in that case the client could subscribe to `/user/exchange/amq.direct/position-updates`. -Similarly, ActiveMQ has -http://activemq.apache.org/delete-inactive-destinations.html[configuration options] -for purging inactive destinations. -==== - - - - -[[websocket-stomp-appplication-context-events]] -==== Listening To ApplicationContext Events and Intercepting Messages - -Several `ApplicationContext` events (listed below) are published and can be -received by implementing Spring's `ApplicationListener` interface. - -* `BrokerAvailabilityEvent` -- indicates when the broker becomes available/unavailable. -While the "simple" broker becomes available immediately on startup and remains so while -the application is running, the STOMP "broker relay" may lose its connection -to the full featured broker, for example if the broker is restarted. The broker relay -has reconnect logic and will re-establish the "system" connection to the broker -when it comes back, hence this event is published whenever the state changes from connected -to disconnected and vice versa. Components using the `SimpMessagingTemplate` should -subscribe to this event and avoid sending messages at times when the broker is not -available. In any case they should be prepared to handle `MessageDeliveryException` -when sending a message. -* `SessionConnectEvent` -- published when a new STOMP CONNECT is received -indicating the start of a new client session. The event contains the message representing the -connect including the session id, user information (if any), and any custom headers the client -may have sent. This is useful for tracking client sessions. Components subscribed -to this event can wrap the contained message using `SimpMessageHeaderAccessor` or -`StompMessageHeaderAccessor`. -* `SessionConnectedEvent` -- published shortly after a `SessionConnectEvent` when the -broker has sent a STOMP CONNECTED frame in response to the CONNECT. At this point the -STOMP session can be considered fully established. -* `SessionSubscribeEvent` -- published when a new STOMP SUBSCRIBE is received. -* `SessionUnsubscribeEvent` -- published when a new STOMP UNSUBSCRIBE is received. -* `SessionDisconnectEvent` -- published when a STOMP session ends. The DISCONNECT may -have been sent from the client, or it may also be automatically generated when the -WebSocket session is closed. In some cases this event may be published more than once -per session. Components should be idempotent with regard to multiple disconnect events. - -[NOTE] -==== -When using a full-featured broker, the STOMP "broker relay" automatically reconnects the -"system" connection in case the broker becomes temporarily unavailable. Client connections -however are not automatically reconnected. Assuming heartbeats are enabled, the client -will typically notice the broker is not responding within 10 seconds. Clients need to -implement their own reconnect logic. -==== - -Furthermore, an application can directly intercept every incoming and outgoing message by -registering a `ChannelInterceptor` on the respective message channel. For example -to intercept inbound messages: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Configuration - @EnableWebSocketMessageBroker - public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { - - @Override - public void configureClientInboundChannel(ChannelRegistration registration) { - registration.setInterceptors(new MyChannelInterceptor()); - } - } ----- - -A custom `ChannelInterceptor` can extend the empty method base class -`ChannelInterceptorAdapter` and use `StompHeaderAccessor` or `SimpMessageHeaderAccessor` -to access information about the message. - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - public class MyChannelInterceptor extends ChannelInterceptorAdapter { - - @Override - public Message preSend(Message message, MessageChannel channel) { - StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message); - StompCommand command = accessor.getStompCommand(); - // ... - return message; - } - } ----- - - - -[[websocket-stomp-websocket-scope]] -==== WebSocket Scope - -Each WebSocket session has a map of attributes. The map is attached as a header to -inbound client messages and may be accessed from a controller method, for example: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- -@Controller -public class MyController { - - @MessageMapping("/action") - public void handle(SimpMessageHeaderAccessor headerAccessor) { - Map attrs = headerAccessor.getSessionAttributes(); - // ... - } -} ----- - -It is also possible to declare a Spring-managed bean in the `"websocket"` scope. -WebSocket-scoped beans can be injected into controllers and any channel interceptors -registered on the "clientInboundChannel". Those are typically singletons and live -longer than any individual WebSocket session. Therefore you will need to use a -scope proxy mode for WebSocket-scoped beans: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- -@Component -@Scope(value="websocket", proxyMode = ScopedProxyMode.TARGET_CLASS) -public class MyBean { - - @PostConstruct - public void init() { - // Invoked after dependencies injected - } - - // ... - - @PreDestroy - public void destroy() { - // Invoked when the WebSocket session ends - } -} - -@Controller -public class MyController { - - private final MyBean myBean; - - @Autowired - public MyController(MyBean myBean) { - this.myBean = myBean; - } - - @MessageMapping("/action") - public void handle() { - // this.myBean from the current WebSocket session - } -} ----- - -As with any custom scope, Spring initializes a new `MyBean` instance the first -time it is accessed from the controller and stores the instance in the WebSocket -session attributes. The same instance is returned subsequently until the session -ends. WebSocket-scoped beans will have all Spring lifecycle methods invoked as -shown in the examples above. - - - -[[websocket-stomp-configuration-performance]] -==== Configuration and Performance - -There is no silver bullet when it comes to performance. Many factors may -affect it including the size of messages, the volume, whether application -methods perform work that requires blocking, as well as external factors -such as network speed and others. The goal of this section is to provide -an overview of the available configuration options along with some thoughts -on how to reason about scaling. - -In a messaging application messages are passed through channels for asynchronous -executions backed by thread pools. Configuring such an application requires -good knowledge of the channels and the flow of messages. Therefore it is -recommended to review <>. - -The obvious place to start is to configure the thread pools backing the -`"clientInboundChannel"` and the `"clientOutboundChannel"`. By default both -are configured at twice the number of available processors. - -If the handling of messages in annotated methods is mainly CPU bound then the -number of threads for the `"clientInboundChannel"` should remain close to the -number of processors. If the work they do is more IO bound and requires blocking -or waiting on a database or other external system then the thread pool size -will need to be increased. - -[NOTE] -==== -`ThreadPoolExecutor` has 3 important properties. Those are the core and -the max thread pool size as well as the capacity for the queue to store -tasks for which there are no available threads. - -A common point of confusion is that configuring the core pool size (e.g. 10) -and max pool size (e.g. 20) results in a thread pool with 10 to 20 threads. -In fact if the capacity is left at its default value of Integer.MAX_VALUE -then the thread pool will never increase beyond the core pool size since -all additional tasks will be queued. - -Please review the Javadoc of `ThreadPoolExecutor` to learn how these -properties work and understand the various queuing strategies. -==== - -On the `"clientOutboundChannel"` side it is all about sending messages to WebSocket -clients. If clients are on a fast network then the number of threads should -remain close to the number of available processors. If they are slow or on -low bandwidth they will take longer to consume messages and put a burden on the -thread pool. Therefore increasing the thread pool size will be necessary. - -While the workload for the "clientInboundChannel" is possible to predict -- -after all it is based on what the application does -- how to configure the -"clientOutboundChannel" is harder as it is based on factors beyond -the control of the application. For this reason there are two additional -properties related to the sending of messages. Those are the `"sendTimeLimit"` -and the `"sendBufferSizeLimit"`. Those are used to configure how long a -send is allowed to take and how much data can be buffered when sending -messages to a client. - -The general idea is that at any given time only a single thread may be used -to send to a client. All additional messages meanwhile get buffered and you -can use these properties to decide how long sending a message is allowed to -take and how much data can be buffered in the mean time. Please review the -Javadoc and documentation of the XML schema for this configuration for -important additional details. - -Here is example configuration: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Configuration - @EnableWebSocketMessageBroker - public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { - - @Override - public void configureWebSocketTransport(WebSocketTransportRegistration registration) { - registration.setSendTimeLimit(15 * 1000).setSendBufferSizeLimit(512 * 1024); - } - - // ... - - } ----- - -[source,xml,indent=0] -[subs="verbatim,quotes,attributes"] ----- - - - - - - - - ----- - -The WebSocket transport configuration shown above can also be used to configure the -maximum allowed size for incoming STOMP messages. Although in theory a WebSocket -message can be almost unlimited in size, in practice WebSocket servers impose -limits -- for example, 8K on Tomcat and 64K on Jetty. For this reason STOMP clients -such as stomp.js split larger STOMP messages at 16K boundaries and send them as -multiple WebSocket messages thus requiring the server to buffer and re-assemble. - -Spring's STOMP over WebSocket support does this so applications can configure the -maximum size for STOMP messages irrespective of WebSocket server specific message -sizes. Do keep in mind that the WebSocket message size will be automatically -adjusted if necessary to ensure they can carry 16K WebSocket messages at a -minimum. - -Here is example configuration: - -[source,java,indent=0] -[subs="verbatim,quotes"] ----- - @Configuration - @EnableWebSocketMessageBroker - public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { - - @Override - public void configureWebSocketTransport(WebSocketTransportRegistration registration) { - registration.setMessageSizeLimit(128 * 1024); - } - - // ... - - } ----- - -[source,xml,indent=0] -[subs="verbatim,quotes,attributes"] ----- - - - - - - - - ----- - -An important point about scaling is using multiple application instances. -Currently it is not possible to do that with the simple broker. -However when using a full-featured broker such as RabbitMQ, each application -instance connects to the broker and messages broadcast from one application -instance can be broadcast through the broker to WebSocket clients connected -through any other application instances. - - - -[[websocket-stomp-stats]] -==== Runtime Monitoring - -When using `@EnableWebSocketMessageBroker` or `` key -infrastructure components automatically gather stats and counters that provide -important insight into the internal state of the application. The configuration -also declares a bean of type `WebSocketMessageBrokerStats` that gathers all -available information in one place and by default logs it at `INFO` level once -every 30 minutes. This bean can be exported to JMX through Spring's -`MBeanExporter` for viewing at runtime, for example through JDK's `jconsole`. -Below is a summary of the available information. - -Client WebSocket Sessions:: - Current::: indicates how many client sessions there are - currently with the count further broken down by WebSocket vs HTTP - streaming and polling SockJS sessions. - Total::: indicates how many total sessions have been established. - Abnormally Closed::: - Connect Failures:::: these are sessions that got established but were - closed after not having received any messages within 60 seconds. This is - usually an indication of proxy or network issues. - Send Limit Exceeded:::: sessions closed after exceeding the configured send - timeout or the send buffer limits which can occur with slow clients - (see previous section). - Transport Errors:::: sessions closed after a transport error such as - failure to read or write to a WebSocket connection or - HTTP request/response. - STOMP Frames::: the total number of CONNECT, CONNECTED, and DISCONNECT frames - processed indicating how many clients connected on the STOMP level. Note that - the DISCONNECT count may be lower when sessions get closed abnormally or when - clients close without sending a DISCONNECT frame. -STOMP Broker Relay:: - TCP Connections::: indicates how many TCP connections on behalf of client - WebSocket sessions are established to the broker. This should be equal to the - number of client WebSocket sessions + 1 additional shared "system" connection - for sending messages from within the application. - STOMP Frames::: the total number of CONNECT, CONNECTED, and DISCONNECT frames - forwarded to or received from the broker on behalf of clients. Note that a - DISCONNECT frame is sent to the broker regardless of how the client WebSocket - session was closed. Therefore a lower DISCONNECT frame count is an indication - that the broker is pro-actively closing connections, may be because of a - heartbeat that didn't arrive in time, an invalid input frame, or other. -Client Inbound Channel:: stats from thread pool backing the "clientInboundChannel" - providing insight into the health of incoming message processing. Tasks queueing - up here is an indication the application may be too slow to handle messages. - If there I/O bound tasks (e.g. slow database query, HTTP request to 3rd party - REST API, etc) consider increasing the thread pool size. -Client Outbound Channel:: stats from the thread pool backing the "clientOutboundChannel" - providing insight into the health of broadcasting messages to clients. Tasks - queueing up here is an indication clients are too slow to consume messages. - One way to address this is to increase the thread pool size to accommodate the - number of concurrent slow clients expected. Another option is to reduce the - send timeout and send buffer size limits (see the previous section). -SockJS Task Scheduler:: stats from thread pool of the SockJS task scheduler which - is used to send heartbeats. Note that when heartbeats are negotiated on the - STOMP level the SockJS heartbeats are disabled. - -[[websocket-stomp-testing]] -==== Testing Annotated Controller Methods - -There are two main approaches to testing applications using Spring's STOMP over -WebSocket support. The first is to write server-side tests verifying the functionality -of controllers and their annotated message handling methods. The second is to write -full end-to-end tests that involve running a client and a server. - -The two approaches are not mutually exclusive. On the contrary each has a place -in an overall test strategy. Server-side tests are more focused and easier to write -and maintain. End-to-end integration tests on the other hand are more complete and -test much more, but they're also more involved to write and maintain. - -The simplest form of server-side tests is to write controller unit tests. However -this is not useful enough since much of what a controller does depends on its -annotations. Pure unit tests simply can't test that. - -Ideally controllers under test should be invoked as they are at runtime, much like -the approach to testing controllers handling HTTP requests using the Spring MVC Test -framework. i.e. without running a Servlet container but relying on the Spring Framework -to invoke the annotated controllers. Just like with Spring MVC Test here there are two -two possible alternatives, either using a "context-based" or "standalone" setup: - -1. Load the actual Spring configuration with the help of the -Spring TestContext framework, inject "clientInboundChannel" as a test field, and -use it to send messages to be handled by controller methods. - -2. Manually set up the minimum Spring framework infrastructure required to invoke -controllers (namely the `SimpAnnotationMethodMessageHandler`) and pass messages for -controllers directly to it. - -Both of these setup scenarios are demonstrated in the -https://github.com/rstoyanchev/spring-websocket-portfolio/tree/master/src/test/java/org/springframework/samples/portfolio/web[tests for the stock portfolio] -sample application. - -The second approach is to create end-to-end integration tests. For that you will need -to run a WebSocket server in embedded mode and connect to it as a WebSocket client -sending WebSocket messages containing STOMP frames. -The https://github.com/rstoyanchev/spring-websocket-portfolio/tree/master/src/test/java/org/springframework/samples/portfolio/web[tests for the stock portfolio] -sample application also demonstrates this approach using Tomcat as the embedded -WebSocket server and a simple STOMP client for test purposes. +include::web-websocket.adoc[leveloffset=+1]