Remove admonitions surrounding code snippets

This commit is contained in:
Brian Clozel 2018-11-26 23:15:55 +01:00
parent 8c768e48fa
commit 33cbe2e77a
29 changed files with 139 additions and 3191 deletions

View File

@ -29,7 +29,6 @@ target different advice with 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 follows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -41,7 +40,6 @@ target advices to particular classes and methods. The complete interface follows
}
----
====
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`"
@ -51,7 +49,6 @@ The `ClassFilter` interface is used to restrict the pointcut to a given set of t
classes. If the `matches()` method always returns true, all target classes are
matched. The following listing shows the `ClassFilter` interface definition:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -60,11 +57,9 @@ matched. The following listing shows the `ClassFilter` interface definition:
boolean matches(Class clazz);
}
----
====
The `MethodMatcher` interface is normally more important. The complete interface follows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -77,7 +72,6 @@ The `MethodMatcher` interface is normally more important. The complete interface
boolean matches(Method m, Class targetClass, Object[] args);
}
----
====
The `matches(Method, Class)` method is used to test whether this pointcut ever
matches a given method on a target class. This evaluation can be performed when an AOP
@ -153,7 +147,6 @@ effectively the union of these pointcuts.)
The following example shows how to use `JdkRegexpMethodPointcut`:
====
[source,xml,indent=0]
[subs="verbatim"]
----
@ -167,7 +160,6 @@ The following example shows how to use `JdkRegexpMethodPointcut`:
</property>
</bean>
----
====
Spring provides a convenience class named `RegexpMethodPointcutAdvisor`, which lets us
also reference an `Advice` (remember that an `Advice` can be an interceptor, before advice,
@ -175,7 +167,6 @@ throws advice, and others). Behind the scenes, Spring uses a `JdkRegexpMethodPoi
Using `RegexpMethodPointcutAdvisor` simplifies wiring, as the one bean encapsulates both
pointcut and advice, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim"]
----
@ -192,7 +183,6 @@ pointcut and advice, as the following example shows:
</property>
</bean>
----
====
You can use `RegexpMethodPointcutAdvisor` with any `Advice` type.
@ -239,7 +229,6 @@ Because static pointcuts are most useful, you should probably subclass
abstract method (although you can override other methods to customize behavior). The
following example shows how to subclass `StaticMethodMatcherPointcut`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -250,7 +239,6 @@ following example shows how to subclass `StaticMethodMatcherPointcut`:
}
}
----
====
There are also superclasses for dynamic pointcuts.
@ -313,7 +301,6 @@ Spring is compliant with the AOP `Alliance` interface for around advice that use
interception. Classes that implement `MethodInterceptor` and that implement around advice should also implement the
following interface:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -322,7 +309,6 @@ following interface:
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
@ -331,7 +317,6 @@ point.
The following example shows a simple `MethodInterceptor` implementation:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -345,7 +330,6 @@ The following example shows a simple `MethodInterceptor` implementation:
}
}
----
====
Note the call to the `proceed()` method of `MethodInvocation`. This proceeds down the
interceptor chain towards the join point. Most interceptors invoke this method and
@ -374,7 +358,6 @@ interceptor chain.
The following listing shows the `MethodBeforeAdvice` interface:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -383,7 +366,6 @@ The following listing shows the `MethodBeforeAdvice` interface:
void before(Method m, Object[] args, Object target) throws Throwable;
}
----
====
(Spring's API design would allow for
field before advice, although the usual objects apply to field interception and it is
@ -398,7 +380,6 @@ wrapped in an unchecked exception by the AOP proxy.
The following example shows a before advice in Spring, which counts all method invocations:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -415,7 +396,6 @@ The following example shows a before advice in Spring, which counts all method i
}
}
----
====
TIP: Before advice can be used with any pointcut.
@ -429,13 +409,11 @@ an exception. Spring offers typed throws advice. Note that this means that the
tag interface identifying that the given object implements one or more typed throws
advice methods. These should be in the following form:
====
[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
@ -443,7 +421,6 @@ arguments. The next two listing show classes that are examples of throws advice.
The following advice is invoked if a `RemoteException` is thrown (including from subclasses):
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -454,13 +431,11 @@ The following advice is invoked if a `RemoteException` is thrown (including from
}
}
----
====
Unlike the preceding
advice, the next example declares four arguments, so that it has access to the invoked method, method
arguments, and target object. The following advice is invoked if a `ServletException` is thrown:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -471,13 +446,11 @@ arguments, and target object. The following advice is invoked if a `ServletExcep
}
}
----
====
The final example illustrates how these two methods could be used in a single class
that handles both `RemoteException` and `ServletException`. Any number of throws advice
methods can be combined in a single class. The following listing shows the final example:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -492,7 +465,6 @@ methods can be combined in a single class. The following listing shows the final
}
}
----
====
NOTE: If a throws-advice method throws an exception itself, it overrides the
original exception (that is, it changes the exception thrown to the user). The overriding
@ -511,7 +483,6 @@ TIP: Throws advice can be used with any pointcut.
An after returning advice in Spring must implement the
`org.springframework.aop.AfterReturningAdvice` interface, which the following listing shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -521,7 +492,6 @@ An after returning advice in Spring must implement the
throws Throwable;
}
----
====
An after returning advice has access to the return value (which it cannot modify),
the invoked method, the method's arguments, and the target.
@ -529,7 +499,6 @@ the invoked method, the method's arguments, and the target.
The following after returning advice counts all successful method invocations that have
not thrown exceptions:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -547,7 +516,6 @@ not thrown exceptions:
}
}
----
====
This advice does not change the execution path. If it throws an exception, it is
thrown up the interceptor chain instead of the return value.
@ -563,7 +531,6 @@ Spring treats introduction advice as a special kind of interception advice.
Introduction requires an `IntroductionAdvisor` and an `IntroductionInterceptor` that
implement the following interface:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -572,7 +539,6 @@ implement the following interface:
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
@ -583,7 +549,6 @@ Introduction advice cannot be used with any pointcut, as it applies only at the
rather than the method, level. You can only use introduction advice with the
`IntroductionAdvisor`, which has the following methods:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -599,7 +564,6 @@ rather than the method, level. You can only use introduction advice with the
Class[] getInterfaces();
}
----
====
There is no `MethodMatcher` and, hence, no `Pointcut` associated with introduction
advice. Only class filtering is logical.
@ -612,7 +576,6 @@ introduced interfaces can be implemented by the configured `IntroductionIntercep
Consider an example from the Spring test suite and suppose we want to
introduce the following interface to one or more objects:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -622,7 +585,6 @@ introduce the following interface to one or more objects:
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
@ -659,7 +621,6 @@ to that held in the target object.
The following example shows the example `LockMixin` class:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -688,7 +649,6 @@ The following example shows the example `LockMixin` class:
}
----
====
Often, you need not override the `invoke()` method. The
`DelegatingIntroductionInterceptor` implementation (which calls the `delegate` method if
@ -703,7 +663,6 @@ interceptor (which would be defined as a prototype). In this case, there is no
configuration relevant for a `LockMixin`, so we create it by using `new`.
The following example shows our `LockMixinAdvisor` class:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -714,7 +673,6 @@ The following example shows our `LockMixinAdvisor` class:
}
}
----
====
We can apply this advisor very simply, because it requires no configuration. (However, it
is impossible to use an `IntroductionInterceptor` without an
@ -904,7 +862,6 @@ Consider a simple example of `ProxyFactoryBean` in action. This example involves
The following listing shows the example:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -933,7 +890,6 @@ The following listing shows the example:
</property>
</bean>
----
====
Note that the `interceptorNames` property takes a list of `String`, which holds the bean names of the
interceptors or advisors in the current factory. You can use advisors, interceptors, before, after
@ -948,18 +904,15 @@ an instance of the prototype from the factory. Holding a reference is not suffic
The `person` bean definition shown earlier 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. The following example shows how to do so:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -967,7 +920,6 @@ with an ordinary Java object. The following example shows how to do so:
<property name="person"><ref bean="person"/></property>
</bean>
----
====
The `PersonUser` class in this example exposes a property of type `Person`. As far as
it is concerned, the AOP proxy can be used transparently in place of a "`real`" person
@ -979,7 +931,6 @@ inner bean. Only the `ProxyFactoryBean` definition is different. The
advice is included only for completeness. The following example shows how to use an
anonymous inner bean:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1006,7 +957,6 @@ anonymous inner bean:
</property>
</bean>
----
====
Using an anonymous inner bean has the advantage that there is only one object of type `Person`. This is useful if we want
to prevent users of the application context from obtaining a reference to the un-advised
@ -1060,7 +1010,6 @@ the part before the asterisk are added to the advisor chain. This can come in ha
if you need to add a standard set of "`global`" advisors. The following example defines
two global advisors:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1076,7 +1025,6 @@ two global advisors:
<bean id="global_debug" class="org.springframework.aop.interceptor.DebugInterceptor"/>
<bean id="global_performance" class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor"/>
----
====
@ -1090,7 +1038,6 @@ definitions, can result in much cleaner and more concise proxy definitions.
First, we create a parent, template, bean definition for the proxy, as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1104,14 +1051,12 @@ First, we create a parent, template, bean definition for the proxy, as follows:
</property>
</bean>
----
====
This is never instantiated itself, so it can actually be incomplete. Then, each proxy
that needs to be created is a child bean definition, which wraps the target of the
proxy as an inner bean definition, since the target is never used on its own anyway.
The following example shows such a child bean:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1122,12 +1067,10 @@ The following example shows such a child bean:
</property>
</bean>
----
====
You can override properties from the parent template. In the following example,
we override the transaction propagation settings:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1146,7 +1089,6 @@ we override the transaction propagation settings:
</property>
</bean>
----
====
Note that in the parent bean example, we explicitly marked the parent bean definition as
being abstract by setting the `abstract` attribute to `true`, as described
@ -1171,7 +1113,6 @@ The interfaces implemented by the target object are
automatically proxied. The following listing shows creation of a proxy for a target object, with one
interceptor and one advisor:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1180,7 +1121,6 @@ interceptor and one advisor:
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
@ -1211,7 +1151,6 @@ However you create AOP proxies, you can manipulate them BY using the
interface, no matter which other interfaces it implements. This interface includes the
following methods:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1235,7 +1174,6 @@ following methods:
boolean isFrozen();
----
====
The `getAdvisors()` method returns an `Advisor` for every advisor, interceptor, or
other advice type that has been added to the factory. If you added an `Advisor`, the
@ -1257,7 +1195,6 @@ change. (You can obtain a new proxy from the factory to avoid this problem.)
The following example shows casting an AOP proxy to the `Advised` interface and examining and
manipulating its advice:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1276,7 +1213,6 @@ manipulating its advice:
assertEquals("Added two advisors", oldAdvisorCount + 2, advised.getAdvisors().length);
----
====
NOTE: It is questionable whether it is advisable (no pun intended) to modify advice on a
business object in production, although there are, no doubt, legitimate usage cases.
@ -1333,7 +1269,6 @@ The `BeanNameAutoProxyCreator` class is a `BeanPostProcessor` that automatically
AOP proxies for beans with names that match literal values or wildcards. The following
example shows how to create a `BeanNameAutoProxyCreator` bean:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1346,7 +1281,6 @@ example shows how to create a `BeanNameAutoProxyCreator` bean:
</property>
</bean>
----
====
As with `ProxyFactoryBean`, there is an `interceptorNames` property rather than a list
of interceptors, to allow correct behavior for prototype advisors. Named "`interceptors`"
@ -1398,7 +1332,6 @@ bean`" idiom shown earlier also offers this benefit.)
The following example creates a `DefaultAdvisorAutoProxyCreator` bean and the other
elements discussed in this section:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1416,7 +1349,6 @@ elements discussed in this section:
<bean id="businessObject2" class="com.mycompany.BusinessObject2"/>
----
====
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,
@ -1470,18 +1402,15 @@ Changing the target source's target takes effect immediately. The
You can change the target by using the `swap()` method on HotSwappableTargetSource, as the follow example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
Object oldTarget = swapper.swap(newTarget);
----
====
The following example shows the required XML definitions:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1495,7 +1424,6 @@ The following example shows the required XML definitions:
<property name="targetSource" ref="swapper"/>
</bean>
----
====
The preceding `swap()` call changes the target of the swappable bean. Clients that hold a
reference to that bean are unaware of the change but immediately start hitting
@ -1528,7 +1456,6 @@ NOTE: Commons Pool 1.5+ is also supported but is deprecated as of Spring Framewo
The following listing shows an example configuration:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1547,7 +1474,6 @@ The following listing shows an example configuration:
<property name="interceptorNames" value="myInterceptor"/>
</bean>
----
====
Note that the target object (`businessObjectTarget` in the preceding example) must be a
prototype. This lets the `PoolingTargetSource` implementation create new instances
@ -1565,7 +1491,6 @@ You can configure Spring to be able to cast any pooled object to the
about the configuration and current size of the pool through an introduction. You
need to define an advisor similar to the following:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1574,7 +1499,6 @@ need to define an advisor similar to the following:
<property name="targetMethod" value="getPoolingConfigMixin"/>
</bean>
----
====
This advisor is obtained by calling a convenience method on the
`AbstractPoolingTargetSource` class, hence the use of `MethodInvokingFactoryBean`. This
@ -1583,14 +1507,12 @@ the `ProxyFactoryBean` that exposes the pooled object.
The cast is defined 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 do not believe it should
be the default choice, as most stateless objects are naturally thread safe, and instance
@ -1613,7 +1535,6 @@ use this approach without very good reason.
To do this, you could modify the `poolTargetSource` definition shown earlier as follows
(we also changed the name, for clarity):
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1621,7 +1542,6 @@ To do this, you could modify the `poolTargetSource` definition shown earlier as
<property name="targetBeanName" ref="businessObjectTarget"/>
</bean>
----
====
The only property is the name of the target bean. Inheritance is used in the
`TargetSource` implementations to ensure consistent naming. As with the pooling target
@ -1638,7 +1558,6 @@ facility to transparently store a resource alongside a thread. Setting up a
`ThreadLocalTargetSource` is pretty much the same as was explained for the other types
of target source, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1646,7 +1565,6 @@ of target source, as the following example shows:
<property name="targetBeanName" value="businessObjectTarget"/>
</bean>
----
====
NOTE: `ThreadLocal` instances come with serious issues (potentially resulting in memory leaks) when
incorrectly using them in multi-threaded and multi-classloader environments. You

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,6 @@ To use the tags in the `util` schema, you need to have the following preamble at
of your Spring XML configuration file (the text in the snippet references the
correct schema so that the tags in the `util` namespace are available to you):
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -35,7 +34,6 @@ correct schema so that the tags in the `util` namespace are available to you):
<!-- bean definitions here -->
</beans>
----
====
@ -44,7 +42,6 @@ correct schema so that the tags in the `util` namespace are available to you):
Consider the following bean definition:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -55,7 +52,6 @@ Consider the following bean definition:
</property>
</bean>
----
====
The preceding configuration uses a Spring `FactoryBean` implementation (the
`FieldRetrievingFactoryBean`) to set the value of the `isolation` property on a bean
@ -66,7 +62,6 @@ plumbing to the end user.
The following XML Schema-based version is more concise, clearly expresses the
developer's intent ("`inject this constant value`"), and it reads better:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -76,7 +71,6 @@ developer's intent ("`inject this constant value`"), and it reads better:
</property>
</bean>
----
====
@ -92,7 +86,6 @@ The following example shows how a `static` field is exposed, by using the
{api-spring-framework}/beans/factory/config/FieldRetrievingFactoryBean.html#setStaticField(java.lang.String)[`staticField`]
property:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -101,26 +94,22 @@ property:
<property name="staticField" value="java.sql.Connection.TRANSACTION_SERIALIZABLE"/>
</bean>
----
====
There is also a convenience usage form where the `static` field is specified as the bean
name, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<bean id="java.sql.Connection.TRANSACTION_SERIALIZABLE"
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/>
----
====
This does mean that there is no longer any choice in what the bean `id` is (so any other
bean that refers to it also has to use this longer name), but this form is very
concise to define and very convenient to use as an inner bean since the `id` does not have
to be specified for the bean reference, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -131,7 +120,6 @@ to be specified for the bean reference, as the following example shows:
</property>
</bean>
----
====
You can also access a non-static (instance) field of another bean, as
described in the API documentation for the
@ -144,7 +132,6 @@ anything about the Spring internals (or even about classes such as the
`FieldRetrievingFactoryBean`). The following example enumeration shows how easy injecting an
enum value is:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -156,11 +143,9 @@ enum value is:
EXTENDED
}
----
====
Now consider the following setter of type `PersistenceContextType` and the corresponding bean definition:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -183,7 +168,6 @@ Now consider the following setter of type `PersistenceContextType` and the corre
<property name="persistenceContextType" value="TRANSACTION"/>
</bean>
----
====
@ -192,7 +176,6 @@ Now consider the following setter of type `PersistenceContextType` and the corre
Consider the following example:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -209,7 +192,6 @@ Consider the following example:
<!-- results in 10, which is the value of property 'age' of bean 'testBean' -->
<bean id="testBean.age" class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>
----
====
The preceding configuration uses a Spring `FactoryBean` implementation (the
`PropertyPathFactoryBean`) to create a bean (of type `int`) called `testBean.age` that
@ -217,7 +199,6 @@ has a value equal to the `age` property of the `testBean` bean.
Now consider the following example, which adds a `<util:property-path/>` element:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -234,7 +215,6 @@ Now consider the following example, which adds a `<util:property-path/>` element
<!-- results in 10, which is the value of property 'age' of bean 'testBean' -->
<util:property-path id="name" path="testBean.age"/>
----
====
The value of the `path` attribute of the `<property-path/>` element follows the form of
`beanName.beanProperty`. In this case, it picks up the `age` property of the bean named
@ -250,7 +230,6 @@ argument.
The following example shows a path being used against another bean, by name:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -271,11 +250,9 @@ The following example shows a path being used against another bean, by name:
<property name="propertyPath" value="spouse.age"/>
</bean>
----
====
In the following example, a path is evaluated against an inner bean:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -290,12 +267,10 @@ In the following example, a path is evaluated against an inner bean:
<property name="propertyPath" value="age"/>
</bean>
----
====
There is also a shortcut form, where the bean name is the property path.
The following example shows the shortcut form:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -303,13 +278,11 @@ The following example shows the shortcut form:
<bean id="person.age"
class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>
----
====
This form does mean that there is no choice in the name of the bean. Any reference to it
also has to use the same `id`, which is the path. If used as an inner
bean, there is no need to refer to it at all, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -320,7 +293,6 @@ bean, there is no need to refer to it at all, as the following example shows:
</property>
</bean>
----
====
You can specifically set the result type in the actual definition. This is not necessary
for most use cases, but it can sometimes be useful. See the javadoc for more info on
@ -332,7 +304,6 @@ this feature.
Consider the following example:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -341,7 +312,6 @@ Consider the following example:
<property name="location" value="classpath:com/foo/jdbc-production.properties"/>
</bean>
----
====
The preceding configuration uses a Spring `FactoryBean` implementation (the
`PropertiesFactoryBean`) to instantiate a `java.util.Properties` instance with values
@ -349,14 +319,12 @@ loaded from the supplied <<core.adoc#resources, `Resource`>> location).
The following example uses a `util:properties` element to make a more concise representation:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<!-- creates a java.util.Properties instance with values loaded from the supplied location -->
<util:properties id="jdbcConfiguration" location="classpath:com/foo/jdbc-production.properties"/>
----
====
@ -365,7 +333,6 @@ The following example uses a `util:properties` element to make a more concise re
Consider the following example:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -381,7 +348,6 @@ Consider the following example:
</property>
</bean>
----
====
The preceding configuration uses a Spring `FactoryBean` implementation (the
`ListFactoryBean`) to create a `java.util.List` instance and initialize it with values taken
@ -389,7 +355,6 @@ from the supplied `sourceList`.
The following example uses a `<util:list/>` element to make a more concise representation:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -401,14 +366,12 @@ The following example uses a `<util:list/>` element to make a more concise repre
<value>porfiry@gov.org</value>
</util:list>
----
====
You can also explicitly control the exact type of `List` that is instantiated and
populated by using the `list-class` attribute on the `<util:list/>` element. For
example, if we really need a `java.util.LinkedList` to be instantiated, we could use the
following configuration:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -419,7 +382,6 @@ following configuration:
<value>d'Arcachon@nemesis.org</value>
</util:list>
----
====
If no `list-class` attribute is supplied, the container chooses a `List` implementation.
@ -430,7 +392,6 @@ If no `list-class` attribute is supplied, the container chooses a `List` impleme
Consider the following example:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -446,7 +407,6 @@ Consider the following example:
</property>
</bean>
----
====
The preceding configuration uses a Spring `FactoryBean` implementation (the
`MapFactoryBean`) to create a `java.util.Map` instance initialized with key-value pairs
@ -454,7 +414,6 @@ taken from the supplied `'sourceMap'`.
The following example uses a `<util:map/>` element to make a more concise representation:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -466,14 +425,12 @@ The following example uses a `<util:map/>` element to make a more concise repres
<entry key="porfiry" value="porfiry@gov.org"/>
</util:map>
----
====
You can also explicitly control the exact type of `Map` that is instantiated and
populated by using the `'map-class'` attribute on the `<util:map/>` element. For
example, if we really need a `java.util.TreeMap` to be instantiated, we could use the
following configuration:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -484,7 +441,6 @@ following configuration:
<entry key="porfiry" value="porfiry@gov.org"/>
</util:map>
----
====
If no `'map-class'` attribute is supplied, the container chooses a `Map` implementation.
@ -495,7 +451,6 @@ If no `'map-class'` attribute is supplied, the container chooses a `Map` impleme
Consider the following example:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -511,7 +466,6 @@ Consider the following example:
</property>
</bean>
----
====
The preceding configuration uses a Spring `FactoryBean` implementation (the
`SetFactoryBean`) to create a `java.util.Set` instance initialized with values taken
@ -519,7 +473,6 @@ from the supplied `sourceSet`.
The following example uses a `<util:set/>` element to make a more concise representation:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -531,14 +484,12 @@ The following example uses a `<util:set/>` element to make a more concise repres
<value>porfiry@gov.org</value>
</util:set>
----
====
You can also explicitly control the exact type of `Set` that is instantiated and
populated by using the `set-class` attribute on the `<util:set/>` element. For
example, if we really need a `java.util.TreeSet` to be instantiated, we could use the
following configuration:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -549,7 +500,6 @@ following configuration:
<value>porfiry@gov.org</value>
</util:set>
----
====
If no `set-class` attribute is supplied, the container chooses a `Set` implementation.
@ -568,7 +518,6 @@ the following preamble at the top of your Spring XML configuration file (the tex
snippet references the correct schema so that the tags in the `aop` namespace
are available to you):
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -582,7 +531,6 @@ are available to you):
<!-- bean definitions here -->
</beans>
----
====
@ -595,7 +543,6 @@ a lot of the "`grunt`" work in Spring, such as `BeanfactoryPostProcessors`. The
snippet references the correct schema so that the elements in the `context` namespace are
available to you:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -609,7 +556,6 @@ available to you:
<!-- bean definitions here -->
</beans>
----
====
@ -696,7 +642,6 @@ The following example shows the `<meta/>` element in the context of a surroundin
(note that, without any logic to interpret it, the metadata is effectively useless
as it stands).
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -714,7 +659,7 @@ as it stands).
</beans>
----
<1> This is the example `meta` element
====
In the case of the preceding example, you could assume that there is some logic that
consumes the bean definition and sets up some caching infrastructure that uses the supplied
@ -749,7 +694,6 @@ XML extension (a custom XML element) that lets us configure objects of the type
`SimpleDateFormat` (from the `java.text` package). When we are done,
we will be able to define bean definitions of type `SimpleDateFormat` as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -757,7 +701,6 @@ we will be able to define bean definitions of type `SimpleDateFormat` as follows
pattern="yyyy-MM-dd HH:mm"
lenient="true"/>
----
====
(We include much more detailed
examples follow later in this appendix. The intent of this first simple example is to walk you
@ -772,7 +715,6 @@ Creating an XML configuration extension for use with Spring's IoC container star
authoring an XML Schema to describe the extension. For our example, we use the following schema
to configure `SimpleDateFormat` objects:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -804,14 +746,12 @@ to configure `SimpleDateFormat` objects:
(meaning they have an `id` attribute that we can use as the bean identifier in the
container). We can use this attribute because we imported the Spring-provided
`beans` namespace.
====
The preceding schema lets us configure `SimpleDateFormat` objects directly in an
XML application context file by using the `<myns:dateformat/>` element, as the following
example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -819,12 +759,10 @@ example shows:
pattern="yyyy-MM-dd HH:mm"
lenient="true"/>
----
====
Note that, after we have created the infrastructure classes, the preceding snippet of XML is
essentially the same as the following XML snippet:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -833,7 +771,6 @@ essentially the same as the following XML snippet:
<property name="lenient" value="true"/>
</bean>
----
====
The second of the two preceding snippets
creates a bean in the container (identified by the name `dateFormat` of type
@ -876,7 +813,6 @@ element results in a single `SimpleDateFormat` bean definition). Spring features
number of convenience classes that support this scenario. In the following example, we
use the `NamespaceHandlerSupport` class:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -892,7 +828,6 @@ use the `NamespaceHandlerSupport` class:
}
----
====
You may notice that there is not actually a whole lot of parsing logic
in this class. Indeed, the `NamespaceHandlerSupport` class has a built-in notion of
@ -916,7 +851,6 @@ responsible for parsing one distinct top-level XML element defined in the schema
the parser, we' have access to the XML element (and thus to its subelements, too) so that
we can parse our custom XML content, as you can see in the following example:
====
[source,java,indent=0]
----
package org.springframework.samples.xml;
@ -954,7 +888,7 @@ the basic grunt work of creating a single `BeanDefinition`.
<2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our
single `BeanDefinition` represents.
====
In this simple case, this is all that we need to do. The creation of our single
`BeanDefinition` is handled by the `AbstractSingleBeanDefinitionParser` superclass, as
@ -980,13 +914,11 @@ these special properties files, the formats of which are detailed in the next tw
The properties file called `spring.handlers` contains a mapping of XML Schema URIs to
namespace handler classes. For our example, we need to write the following:
====
[literal]
[subs="verbatim,quotes"]
----
http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.MyNamespaceHandler
----
====
(The `:` character is a valid delimiter in the Java properties format, so
`:` character in the URI needs to be escaped with a backslash.)
@ -1009,13 +941,11 @@ properties file, Spring searches for the schema (in this case,
`myns.xsd` in the `org.springframework.samples.xml` package) on the classpath.
The following snippet shows the line we need to add for our custom schema:
====
[literal]
[subs="verbatim,quotes"]
----
http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd
----
====
(Remember that the `:` character must be escaped.)
@ -1032,7 +962,6 @@ one of the "`custom`" extensions that Spring provides. The following
example uses the custom `<dateformat/>` element developed in the previous steps
in a Spring XML configuration file:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1057,7 +986,6 @@ in a Spring XML configuration file:
</beans>
----
<1> Our custom bean.
====
@ -1074,7 +1002,6 @@ This section presents some more detailed examples of custom XML extensions.
The example presented in this section shows how you to write the various artifacts required
to satisfy a target of the following configuration:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1096,7 +1023,6 @@ to satisfy a target of the following configuration:
</beans>
----
====
The preceding configuration nests custom extensions within each other. The class
that is actually configured by the `<foo:component/>` element is the `Component`
@ -1105,7 +1031,6 @@ setter method for the `components` property. This makes it hard (or rather impos
to configure a bean definition for the `Component` class by using setter injection.
The following listing shows the `Component` class:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1138,12 +1063,11 @@ The following listing shows the `Component` class:
}
----
====
The typical solution to this issue is to create a custom `FactoryBean` that exposes a
setter property for the `components` property. The following listing shows such a custom
`FactoryBean`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
@ -1186,7 +1110,6 @@ setter property for the `components` property. The following listing shows such
}
----
====
This works nicely, but it exposes a lot of Spring plumbing to the
end user. What we are going to do is write a custom extension that hides away all of
@ -1194,7 +1117,6 @@ this Spring plumbing. If we stick to <<xsd-custom-introduction,the steps describ
previously>>, we start off by creating the XSD schema to define the structure of our
custom tag, as the following listing shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1218,11 +1140,9 @@ custom tag, as the following listing shows:
</xsd:schema>
----
====
Again following <<xsd-custom-introduction,the process described earlier>>, we then create a custom `NamespaceHandler`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1238,13 +1158,11 @@ Again following <<xsd-custom-introduction,the process described earlier>>, we th
}
----
====
Next up is the custom `BeanDefinitionParser`. Remember that we are creating
`BeanDefinition` that describes a `ComponentFactoryBean`. The following listing shows our
custom `BeanDefinitionParser`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1295,12 +1213,10 @@ custom `BeanDefinitionParser`:
}
----
====
Finally, the various artifacts need to be registered with the Spring XML infrastructure,
by modifying the `META-INF/spring.handlers` and `META-INF/spring.schemas` files, as follows:
====
[literal]
[subs="verbatim,quotes"]
----
@ -1314,7 +1230,6 @@ http\://www.foo.com/schema/component=com.foo.ComponentNamespaceHandler
# in 'META-INF/spring.schemas'
http\://www.foo.com/schema/component/component.xsd=com/foo/component.xsd
----
====
@ -1333,7 +1248,6 @@ http://jcp.org/en/jsr/detail?id=107[JCache], and you want to ensure that the nam
JCache instance is eagerly started within the surrounding cluster. The following
listing shows such a definition:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1342,7 +1256,6 @@ listing shows such a definition:
<!-- other dependencies here... -->
</bean>
----
====
We can then create another `BeanDefinition` when the
`'jcache:cache-name'` attribute is parsed. This `BeanDefinition` then initializes
@ -1350,7 +1263,6 @@ the named JCache for us. We can also modify the existing `BeanDefinition` for th
`'checkingAccountService'` so that it has a dependency on this new
JCache-initializing `BeanDefinition`. The following listing shows our `JCacheInitializer`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1370,12 +1282,10 @@ JCache-initializing `BeanDefinition`. The following listing shows our `JCacheIni
}
----
====
Now we can move onto the custom extension. First, we need to author the XSD schema that describes the
custom attribute, as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1390,11 +1300,9 @@ custom attribute, as follows:
</xsd:schema>
----
====
Next, we need to create the associated `NamespaceHandler`, as follows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1411,13 +1319,11 @@ Next, we need to create the associated `NamespaceHandler`, as follows:
}
----
====
Next, we need to create the parser. Note that, in this case, because we are going to parse an XML
attribute, we write a `BeanDefinitionDecorator` rather than a `BeanDefinitionParser`.
The following listing shows our `BeanDefinitionDecorator`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1473,12 +1379,10 @@ The following listing shows our `BeanDefinitionDecorator`:
}
----
====
Finally, we need to register the various artifacts with the Spring XML infrastructure
by modifying the `META-INF/spring.handlers` and `META-INF/spring.schemas` files, as follows:
====
[literal]
[subs="verbatim,quotes"]
----
@ -1492,4 +1396,3 @@ http\://www.foo.com/schema/jcache=com.foo.JCacheNamespaceHandler
# in 'META-INF/spring.schemas'
http\://www.foo.com/schema/jcache/jcache.xsd=com/foo/jcache.xsd
----
====

File diff suppressed because it is too large Load Diff

View File

@ -141,7 +141,6 @@ An `Encoder` allocates data buffers that others must read (and release). So an `
doesn't have much to do. However an `Encoder` must take care to release a data buffer if
a serialization error occurs while populating the buffer with data. For example:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -158,7 +157,6 @@ a serialization error occurs while populating the buffer with data. For example:
}
return buffer;
----
====
The consumer of an `Encoder` is responsible for releasing the data buffers it receives.
In a WebFlux application, the output of the `Encoder` is used to write to the HTTP server

View File

@ -65,7 +65,6 @@ The complete language reference can be found in
The following code introduces the SpEL API to evaluate the literal string expression,
`Hello World`.
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -74,7 +73,7 @@ The following code introduces the SpEL API to evaluate the literal string expres
String message = (String) exp.getValue();
----
<1> The value of the message variable is `'Hello World'`.
====
The SpEL classes and interfaces you are most likely to use are located in the
`org.springframework.expression` package and its sub-packages, such as `spel.support`.
@ -91,7 +90,6 @@ and calling constructors.
In the following example of method invocation, we call the `concat` method on the string literal:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -100,11 +98,10 @@ In the following example of method invocation, we call the `concat` method on th
String message = (String) exp.getValue();
----
<1> The value of `message` is now 'Hello World!'.
====
The following example of calling a JavaBean property calls the `String` property `Bytes`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -115,13 +112,12 @@ The following example of calling a JavaBean property calls the `String` property
byte[] bytes = (byte[]) exp.getValue();
----
<1> This line converts the literal to a byte array.
====
SpEL also supports nested properties by using standard dot notation (such as
`prop1.prop2.prop3`) and the setting of property values. Public fields may also be accessed.
The following example shows how to use dot notation to get the length of a literal:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -132,12 +128,11 @@ The following example shows how to use dot notation to get the length of a liter
int length = (Integer) exp.getValue();
----
<1> `'Hello World'.bytes.length` gives the length of the literal.
====
The String's constructor can be called instead of using a string literal, as the following
example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -146,7 +141,7 @@ example shows:
String message = exp.getValue(String.class);
----
<1> Construct a new `String` from the literal and make it be upper case.
====
Note the use of the generic method: `public <T> T getValue(Class<T> desiredResultType)`.
Using this method removes the need to cast the value of the expression to the desired
@ -158,7 +153,6 @@ against a specific object instance (called the root object). The following examp
how to retrieve the `name` property from an instance of the `Inventor` class or
create a boolean condition:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -180,7 +174,6 @@ create a boolean condition:
// result == true
----
<1> Parse `name` as an expression.
====
@ -228,7 +221,6 @@ to set a `List` property. The type of the property is actually `List<Boolean>`.
recognizes that the elements of the list need to be converted to `Boolean` before
being placed in it. The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -248,7 +240,6 @@ being placed in it. The following example shows how to do so:
// b is false
Boolean b = simple.booleanList.get(0);
----
====
@ -265,7 +256,6 @@ and specifying an index that is beyond the end of the current size of the array
list, you can automatically grow the array or list to accommodate that index. The following
example demonstrates how to automatically grow the list:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -289,7 +279,6 @@ example demonstrates how to automatically grow the list:
// demo.list will now be a real collection of 4 entries
// Each entry is a new empty String
----
====
@ -317,11 +306,9 @@ on repeated evaluations.
Consider the following basic expression:
====
----
someArray[0].someProperty.someOtherProperty < 0.1
----
====
Because the preceding expression involves array access, some property de-referencing,
and numeric operations, the performance gain can be very noticeable. In an example
@ -361,7 +348,6 @@ since part of the expression may be running twice.
After selecting a mode, use the `SpelParserConfiguration` to configure the parser. The
following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -376,7 +362,6 @@ following example shows how to do so:
Object payload = expr.getValue(message);
----
====
When you specify the compiler mode, you can also specify a classloader (passing null is allowed).
Compiled expressions are defined in a child classloader created under any that is supplied.
@ -425,7 +410,6 @@ form `#{ <expression string> }`.
A property or constructor argument value can be set by using expressions, as the following
example shows:
====
[source,xml,indent=0]
[subs="verbatim"]
----
@ -435,12 +419,10 @@ example shows:
<!-- other properties -->
</bean>
----
====
The `systemProperties` variable is predefined, so you can use it in your expressions, as
the following example shows:
====
[source,xml,indent=0]
[subs="verbatim"]
----
@ -450,14 +432,12 @@ the following example shows:
<!-- other properties -->
</bean>
----
====
Note that you do not have to prefix the predefined variable with the `#`
symbol in this context.
You can also refer to other bean properties by name, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim"]
----
@ -473,7 +453,6 @@ You can also refer to other bean properties by name, as the following example sh
<!-- other properties -->
</bean>
----
====
@ -485,7 +464,6 @@ parameters.
The following example sets the default value of a field variable:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -504,11 +482,9 @@ The following example sets the default value of a field variable:
}
----
====
The following example shows the equivalent but on a property setter method:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -527,12 +503,10 @@ The following example shows the equivalent but on a property setter method:
}
----
====
Autowired methods and constructors can also use the `@Value` annotation, as the following
examples show:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -571,7 +545,6 @@ examples show:
// ...
}
----
====
@ -611,7 +584,6 @@ The following listing shows simple usage of literals. Typically, they are not us
in isolation like this but, rather, 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"]
----
@ -629,7 +601,6 @@ using a literal on one side of a logical comparison operator.
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 by using Double.parseDouble().
@ -645,7 +616,6 @@ data listed in the <<expressions-example-classes,Classes used in the examples>>
To navigate "`down`" and get Tesla's year of birth and Pupin's city of birth, we use the following
expressions:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -654,13 +624,11 @@ expressions:
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 by using square bracket notation, as the following example
shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -684,13 +652,11 @@ shows:
String invention = parser.parseExpression("Members[0].Inventions[6]").getValue(
context, ieee, String.class);
----
====
The contents of maps are obtained by specifying the literal key value within the
brackets. In the following example, because keys for the `Officers` map are strings, we can specify
string literals:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -707,7 +673,6 @@ string literals:
parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").setValue(
societyContext, "Croatia");
----
====
@ -716,7 +681,6 @@ string literals:
You can directly express lists in an expression by using `{}` notation.
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -725,7 +689,6 @@ You can directly express lists in an expression by using `{}` notation.
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, a constant list is created to represent the
@ -739,7 +702,6 @@ expression (rather than building a new list on each evaluation).
You can also directly express maps in an expression by using `{key:value}` notation. The
following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -748,7 +710,6 @@ following example shows how to do so:
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), a constant map is created
@ -763,7 +724,6 @@ is optional. The examples above do not use quoted keys.
You can build arrays by using the familiar Java syntax, optionally supplying an initializer
to have the array populated at construction time. The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -775,7 +735,6 @@ to have the array populated at construction time. The following example shows ho
// Multi dimensional array
int[][] numbers3 = (int[][]) parser.parseExpression("new int[4][5]").getValue(context);
----
====
You cannot currently supply an initializer when you construct
multi-dimensional array.
@ -789,7 +748,6 @@ You can invoke methods by using typical Java programming syntax. You can also in
on literals. Variable arguments are also supported. The following examples show how to
invoke methods:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -800,7 +758,6 @@ invoke methods:
boolean isMember = parser.parseExpression("isMember('Mihajlo Pupin')").getValue(
societyContext, Boolean.class);
----
====
@ -822,7 +779,6 @@ The relational operators (equal, not equal, less than, less than or equal, great
and greater than or equal) are supported by using standard operator notation. The
following listing shows a few examples of operators:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -835,7 +791,6 @@ following listing shows a few examples of operators:
// evaluates to true
boolean trueValue = parser.parseExpression("'black' < 'block'").getValue(Boolean.class);
----
====
[NOTE]
====
@ -851,7 +806,6 @@ in favor of comparisons against zero (for example, `X > 0` or `X < 0`).
In addition to the standard relational operators, SpEL supports the `instanceof` and regular
expression-based `matches` operator. The following listing shows examples of both:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -867,7 +821,6 @@ expression-based `matches` operator. The following listing shows examples of bot
boolean falseValue = parser.parseExpression(
"'5.0067' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);
----
====
CAUTION: Be careful with primitive types, as they are immediately boxed up to the wrapper type,
so `1 instanceof T(int)` evaluates to `false` while `1 instanceof T(Integer)`
@ -901,7 +854,6 @@ SpEL supports the following logical operators:
The following example shows how to use the logical operators
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -932,7 +884,6 @@ The following example shows how to use the logical operators
String expression = "isMember('Nikola Tesla') and !isMember('Mihajlo Pupin')";
boolean falseValue = parser.parseExpression(expression).getValue(societyContext, Boolean.class);
----
====
[[expressions-operators-mathematical]]
@ -943,7 +894,6 @@ and division operators only on numbers. You can also use
the modulus (%) and exponential power (^) operators. Standard operator precedence is enforced. The
following example shows the mathematical operators in use:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -976,7 +926,6 @@ following example shows the mathematical operators in use:
// Operator precedence
int minusTwentyOne = parser.parseExpression("1+2-3*8").getValue(Integer.class); // -21
----
====
[[expressions-assignment]]
@ -986,7 +935,6 @@ To setting a property, use the assignment operator (`=`). This is typically
done within a call to `setValue` but can also be done inside a call to `getValue`. The
following listing shows both ways to use the assignment operator:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -999,7 +947,6 @@ following listing shows both ways to use the assignment operator:
String aleks = parser.parseExpression(
"Name = 'Aleksandar Seovic'").getValue(context, inventor, String.class);
----
====
@ -1014,7 +961,6 @@ type). Static methods are invoked by using this operator as well. The
fully qualified, but all other type references must be. The following example shows how
to use the `T` operator:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1026,7 +972,6 @@ to use the `T` operator:
"T(java.math.RoundingMode).CEILING < T(java.math.RoundingMode).FLOOR")
.getValue(Boolean.class);
----
====
@ -1037,7 +982,6 @@ You can invoke constructors by using the `new` operator. You should use the full
for all but the primitive types (`int`, `float`, and so on) and String. The following
example shows how to use the `new` operator to invoke constructors:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1050,7 +994,6 @@ example shows how to use the `new` operator to invoke constructors:
"Members.add(new org.spring.samples.spel.inventor.Inventor(
'Albert Einstein', 'German'))").getValue(societyContext);
----
====
@ -1061,7 +1004,6 @@ You can reference variables in the expression by using the `#variableName` synta
are set by using the `setVariable` method on `EvaluationContext` implementations. The
following example shows how to use variables:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1073,7 +1015,6 @@ following example shows how to use variables:
parser.parseExpression("Name = #newName").getValue(context, tesla);
System.out.println(tesla.getName()) // "Mike Tesla"
----
====
[[expressions-this-root]]
@ -1085,7 +1026,6 @@ defined and refers to the root context object. Although `#this` may vary as comp
an expression are evaluated, `#root` always refers to the root. The following examples
show how to use the `#this` and `#root` variables:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1103,7 +1043,6 @@ show how to use the `#this` and `#root` variables:
List<Integer> primesGreaterThanTen = (List<Integer>) parser.parseExpression(
"#primes.?[#this>10]").getValue(context);
----
====
@ -1114,7 +1053,6 @@ You can extend SpEL by registering user-defined functions that can be called wit
expression string. The function is registered through the `EvaluationContext`. The
following example shows how to register a user-defined function:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1123,11 +1061,9 @@ following example shows how to register a user-defined function:
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
context.setVariable("myFunction", method);
----
====
For example, consider the following utility method that reverses a string:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1142,11 +1078,9 @@ For example, consider the following utility method that reverses a string:
}
}
----
====
You can then register and use the preceding method, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1159,7 +1093,6 @@ You can then register and use the preceding method, as the following example sho
String helloWorldReversed = parser.parseExpression(
"#reverseString('hello')").getValue(context, String.class);
----
====
@ -1170,7 +1103,6 @@ If the evaluation context has been configured with a bean resolver, you can
look up beans from an expression by using the `@` symbol. The following example shows how
to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1181,12 +1113,10 @@ to do so:
// This will end up calling resolve(context,"something") on MyBeanResolver during evaluation
Object bean = parser.parseExpression("@something").getValue(context);
----
====
To access a factory bean itself, you should instead prefix the bean name with an `&` symbol.
The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1197,7 +1127,6 @@ The following example shows how to do so:
// This will end up calling resolve(context,"&foo") on MyBeanResolver during evaluation
Object bean = parser.parseExpression("&foo").getValue(context);
----
====
@ -1207,19 +1136,16 @@ The following example shows how to do so:
You can use the ternary operator for performing if-then-else conditional logic inside
the expression. The following listing shows a minimal example:
====
[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 follows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1233,7 +1159,6 @@ realistic example follows:
.getValue(societyContext, String.class);
// queryResultString = "Nikola Tesla is a member of the IEEE Society"
----
====
See the next section on the Elvis operator for an even shorter syntax for the
ternary operator.
@ -1248,19 +1173,16 @@ http://www.groovy-lang.org/operators.html#_elvis_operator[Groovy] language.
With the ternary operator syntax, you usually have to repeat a variable twice, as the
following example shows:
====
[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).
The following example shows how to use the Elvis operator:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1269,11 +1191,9 @@ The following example shows how to use the Elvis operator:
String name = parser.parseExpression("name?:'Unknown'").getValue(String.class);
System.out.println(name); // 'Unknown'
----
====
The following listing shows A more complex example:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1288,14 +1208,12 @@ The following listing shows A more complex example:
name = parser.parseExpression("Name?:'Elvis Presley'").getValue(context, tesla, String.class);
System.out.println(name); // Elvis Presley
----
====
[NOTE]
=====
You can use the Elvis operator to apply default values in expressions. The folloiwng
example shows how to use the Elvis operator in a `@Value` expression:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1303,11 +1221,9 @@ example shows how to use the Elvis operator in a `@Value` expression:
----
This will inject a system property `pop3.port` if it is defined or 25 if not.
====
=====
[[expressions-operator-safe-navigation]]
=== Safe Navigation Operator
@ -1318,7 +1234,6 @@ it is not null before accessing methods or properties of the object. To avoid th
safe navigation operator returns null instead of throwing an exception. The following
example shows how to use the safe navigation operator:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1335,7 +1250,6 @@ example shows how to use the safe navigation operator:
city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);
System.out.println(city); // null - does not throw NullPointerException!!!
----
====
@ -1349,14 +1263,12 @@ Selection uses a syntax of `.?[selectionExpression]`. It filters the collection
returns a new collection that contain a subset of the original elements. For example,
selection lets us easily get a list of Serbian inventors, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
List<Inventor> list = (List<Inventor>) parser.parseExpression(
"Members.?[Nationality == 'Serbian']").getValue(societyContext);
----
====
Selection is possible upon both lists and maps. For a list, the selection
criteria is evaluated against each individual list element. Against a map, the
@ -1367,13 +1279,11 @@ the selection.
The following expression returns a new map that consists 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, you can retrieve only the
first or the last value. To obtain the first entry matching the selection, the syntax is
@ -1391,14 +1301,12 @@ 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. The following example uses projection to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
// returns ['Smiljan', 'Idvor' ]
List placesOfBirth = (List)parser.parseExpression("Members.![placeOfBirth.city]");
----
====
You can also use a map 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
@ -1415,7 +1323,6 @@ Each evaluation block is delimited with prefix and suffix characters that you ca
define. A common choice is to use `#{ }` as the delimiters, as the following example
shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1425,7 +1332,6 @@ shows:
// 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
@ -1434,7 +1340,6 @@ is of the type `ParserContext`. The `ParserContext` interface is used to influen
the expression is parsed in order to support the expression templating functionality.
The definition of `TemplateParserContext` follows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1453,7 +1358,6 @@ The definition of `TemplateParserContext` follows:
}
}
----
====
@ -1464,7 +1368,6 @@ The definition of `TemplateParserContext` follows:
This section lists the classes used in the examples throughout this chapter.
.Inventor.java
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1538,10 +1441,8 @@ This section lists the classes used in the examples throughout this chapter.
}
}
----
====
.PlaceOfBirth.java
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1579,10 +1480,8 @@ This section lists the classes used in the examples throughout this chapter.
}
----
====
.Society.java
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1627,4 +1526,3 @@ This section lists the classes used in the examples throughout this chapter.
}
----
====

View File

@ -37,7 +37,6 @@ Spring's `Resource` interface is meant to be a more capable interface for abstra
access to low-level resources. The following listing shows the `Resource` interface
definition:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -59,13 +58,11 @@ definition:
}
----
====
As the definition of the `Resource` interface shows, it extends the `InputStreamSource`
interface. The following listing shows the definition of the `InputStreamSource`
interface:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -75,7 +72,6 @@ interface:
}
----
====
Some of the most important methods from the `Resource` interface are:
@ -227,7 +223,6 @@ The `ResourceLoader` interface is meant to be implemented by objects that can re
(that is, load) `Resource` instances. The following listing shows the `ResourceLoader`
interface definition:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -237,7 +232,6 @@ interface definition:
}
----
====
All application contexts implement the `ResourceLoader` interface. Therefore, all
application contexts may be used to obtain `Resource` instances.
@ -247,13 +241,11 @@ specified doesn't have a specific prefix, you 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");
----
====
Against a `ClassPathXmlApplicationContext`, that code returns a `ClassPathResource`. If the same method were executed
against a `FileSystemXmlApplicationContext` instance, it would return a
@ -267,19 +259,16 @@ On the other hand, you may also force `ClassPathResource` to be used, regardless
application context type, by specifying the special `classpath:` prefix, as the following
example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
----
====
Similarly, you can force a `UrlResource` to be used by specifying any of the standard
`java.net.URL` prefixes. The following pair of examples use the `file` and `http`
prefixes:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -291,7 +280,6 @@ prefixes:
----
Resource template = ctx.getResource("http://myhost.com/resource/path/myTemplate.txt");
----
====
The following table summarizes the strategy for converting `String` objects to `Resource` objects:
@ -327,7 +315,6 @@ The `ResourceLoaderAware` interface is a special marker interface that identifie
that expect to be provided with a `ResourceLoader` reference. The following listing shows
the definition of the `ResourceLoaderAware` interface:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -336,7 +323,6 @@ the definition of the `ResourceLoaderAware` interface:
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
@ -381,7 +367,6 @@ register and use a special JavaBeans `PropertyEditor`, which can convert `String
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 the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -389,7 +374,6 @@ be configured with a simple string for that resource, as the following example s
<property name="template" value="some/resource/path/myTemplate.txt"/>
</bean>
----
====
Note that the resource path has no prefix. Consequently, because the application context itself is
going to be used as the `ResourceLoader`, the resource itself is loaded through a
@ -400,7 +384,6 @@ If you need to force a specific `Resource` type to be used, you can use a prefix
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"]
----
@ -412,7 +395,6 @@ The following two examples show how to force a `ClassPathResource` and a
----
<property name="template" value="file:///some/resource/path/myTemplate.txt"/>
----
====
@ -437,25 +419,21 @@ that path and used to load the bean definitions depends on and is appropriate to
specific application context. For example, consider the following example, which creates a
`ClassPathXmlApplicationContext`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");
----
====
The bean definitions are loaded from the classpath, because a `ClassPathResource` is
used. However, consider the following example, which creates a `FileSystemXmlApplicationContext`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
ApplicationContext ctx =
new FileSystemXmlApplicationContext("conf/appContext.xml");
----
====
Now the bean definition is loaded from a filesystem location (in this case, relative to
the current working directory).
@ -487,7 +465,6 @@ then derives the path information from the supplied class.
Consider the following directory layout:
====
[literal]
[subs="verbatim,quotes"]
----
@ -497,19 +474,16 @@ com/
daos.xml
MessengerService.class
----
====
The following example shows how a `ClassPathXmlApplicationContext` instance composed of the beans defined in
files named `services.xml` and `daos.xml` (which are on the classpath) can be instantiated:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
ApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] {"services.xml", "daos.xml"}, MessengerService.class);
----
====
See the {api-spring-framework}/jca/context/SpringContextResourceAdapter.html[`ClassPathXmlApplicationContext`]
javadoc for details on the various constructors.
@ -542,7 +516,6 @@ a resource points to just one resource at a time.
Path locations can contain Ant-style patterns, as the following example shows:
====
[literal]
[subs="verbatim"]
----
@ -551,7 +524,6 @@ com/mycompany/**/applicationContext.xml
file:C:/some/path/*-context.xml
classpath:com/mycompany/**/applicationContext.xml
----
====
When the path location contains an Ant-style pattern, the resolver follows a more complex procedure to try to resolve the
wildcard. It produces a `Resource` for the path up to the last non-wildcard segment and
@ -590,14 +562,12 @@ coming from jars be thoroughly tested in your specific environment before you re
When constructing an XML-based application context, a location string may use the
special `classpath*:` prefix, as the following example shows:
====
[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 through a call to
@ -655,13 +625,11 @@ Ant-style patterns with `classpath:` resources are not guaranteed to find matchi
resources if the root package to search is available in multiple class path locations.
Consider the following example of a resource location:
====
[literal]
[subs="verbatim,quotes"]
----
com/mycompany/package1/service-context.xml
----
====
Now consider an Ant-style path that someone might use to try to find that file:
@ -695,7 +663,6 @@ For backwards compatibility (historical) reasons however, this changes when the
to treat all location paths as relative, whether they start with a leading slash or not.
In practice, this means the following examples are equivalent:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -709,12 +676,10 @@ In practice, this means the following examples are equivalent:
ApplicationContext ctx =
new FileSystemXmlApplicationContext("/conf/context.xml");
----
====
The following examples are also equivalent (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"]
----
@ -728,14 +693,12 @@ case is relative and the other absolute):
FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("/some/resource/path/myTemplate.txt");
----
====
In practice, if you need true absolute filesystem paths, you should avoid using
absolute paths with `FileSystemResource` or `FileSystemXmlApplicationContext` and
force the use of a `UrlResource` by using the `file:` URL prefix. The following examples
show how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -750,4 +713,3 @@ show how to do so:
ApplicationContext ctx =
new FileSystemXmlApplicationContext("file:///conf/context.xml");
----
====

View File

@ -53,7 +53,6 @@ validators can report validation failures to the `Errors` object.
Consider the following example of a small data object:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -65,7 +64,6 @@ Consider the following example of a small data object:
// the usual getters and setters...
}
----
====
The next example provides validation behavior for the `Person` class by implementing the
following two methods of the `org.springframework.validation.Validator` interface:
@ -78,7 +76,6 @@ Implementing a `Validator` is fairly straightforward, especially when you know o
`ValidationUtils` helper class that the Spring Framework also provides. The following
example implements `Validator` for `Person` instances:
====
[source,java,indent=0]
[subs="verbatim"]
----
@ -102,7 +99,6 @@ example implements `Validator` for `Person` instances:
}
}
----
====
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
@ -120,7 +116,6 @@ within the `AddressValidator` class without resorting to copy-and-paste, you can
dependency-inject or instantiate an `AddressValidator` within your `CustomerValidator`,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -160,7 +155,6 @@ as the following example shows:
}
}
----
====
Validation errors are reported to the `Errors` object passed to the validator. In the case
of Spring Web MVC, you can use the `<spring:bind/>` tag to inspect the error messages, but
@ -265,7 +259,6 @@ and their default implementations, you should skip ahead to the <<beans-beans-co
The following two example classes use the `BeanWrapper` to get and set
properties:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -318,12 +311,10 @@ properties:
}
}
----
====
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"]
----
@ -342,7 +333,6 @@ the properties of instantiated `Companies` and `Employees`:
// retrieving the salary of the managingDirector through the company
Float salary = (Float) company.getPropertyValue("managingDirector.salary");
----
====
@ -453,7 +443,6 @@ name as that class, with `Editor` appended. For example, one could have the foll
class and package structure, which would be sufficient for the `SomethingEditor` class to be
recognized and used as the `PropertyEditor` for `Something`-typed properties.
====
[literal]
[subs="verbatim,quotes"]
----
@ -463,7 +452,6 @@ com
Something
SomethingEditor // the PropertyEditor for the Something class
----
====
Note that you can also use the standard `BeanInfo` JavaBeans mechanism here as well
(described to some extent
@ -472,7 +460,6 @@ here]). The following example use the `BeanInfo` mechanism to
explicitly register one or more `PropertyEditor` instances with the properties of an
associated class:
====
[literal]
[subs="verbatim,quotes"]
----
@ -482,12 +469,10 @@ com
Something
SomethingBeanInfo // the BeanInfo for the Something class
----
====
The following Java source code for the referenced `SomethingBeanInfo` class
associates a `CustomNumberEditor` with the `age` property of the `Something` class:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -509,7 +494,6 @@ associates a `CustomNumberEditor` with the `age` property of the `Something` cla
}
}
----
====
[[beans-beans-conversion-customeditor-registration]]
@ -549,7 +533,6 @@ support for additional `PropertyEditor` instances to an `ApplicationContext`.
Consider the following example, which defines a user class called `ExoticType` and another class called `DependsOnExoticType`, which needs
`ExoticType` set as a property:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -573,13 +556,11 @@ Consider the following example, which defines a user class called `ExoticType` a
}
}
----
====
When things are properly set up, we want to be able to assign the type property as a
string, which a `PropertyEditor` converts into an actual
`ExoticType` instance. The following bean definition shows how to set up this relationship:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -587,11 +568,9 @@ string, which a `PropertyEditor` converts into an actual
<property name="type" value="aNameForExoticType"/>
</bean>
----
====
The `PropertyEditor` implementation could look similar to the following:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -605,12 +584,10 @@ The `PropertyEditor` implementation could look similar to the following:
}
}
----
====
Finally, the following example shows how to 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"]
----
@ -622,7 +599,6 @@ Finally, the following example shows how to use `CustomEditorConfigurer` to regi
</property>
</bean>
----
====
[[beans-beans-conversion-customeditor-registration-per]]
===== Using `PropertyEditorRegistrar`
@ -643,7 +619,6 @@ instances for each bean creation attempt.
The following example shows how to create your own `PropertyEditorRegistrar` implementation:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -660,7 +635,6 @@ The following example shows how to create your own `PropertyEditorRegistrar` imp
}
}
----
====
See also the `org.springframework.beans.support.ResourceEditorRegistrar` for an example
`PropertyEditorRegistrar` implementation. Notice how in its implementation of the
@ -669,7 +643,6 @@ See also the `org.springframework.beans.support.ResourceEditorRegistrar` for an
The next example shows how to configure a `CustomEditorConfigurer` and inject an instance of our
`CustomPropertyEditorRegistrar` into it:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -684,7 +657,6 @@ The next example shows how to configure a `CustomEditorConfigurer` and inject an
<bean id="customPropertyEditorRegistrar"
class="com.foo.editors.spring.CustomPropertyEditorRegistrar"/>
----
====
Finally (and in a bit of a departure from the focus of this chapter for those of you
using <<web.adoc#mvc,Spring's MVC web framework>>), using `PropertyEditorRegistrars` in
@ -692,7 +664,6 @@ conjunction with data-binding `Controllers` (such as `SimpleFormController`) can
convenient. The following example uses a `PropertyEditorRegistrar` in the
implementation of an `initBinder(..)` method:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -712,7 +683,6 @@ implementation of an `initBinder(..)` method:
// other methods to do with registering a User
}
----
====
This style of `PropertyEditor` registration can lead to concise code (the implementation
of `initBinder(..)` is only one line long) and lets common `PropertyEditor`
@ -740,7 +710,6 @@ application where type conversion is needed.
The SPI to implement type conversion logic is simple and strongly typed, as the following
interface definition shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -751,7 +720,6 @@ interface definition shows:
T convert(S source);
}
----
====
To create your own converter, implement the `Converter` interface and parameterize `S`
as the type you are converting from and `T` as the type you are converting to. You can also transparently apply such a
@ -768,7 +736,6 @@ Several converter implementations are provided in the `core.convert.support` pac
a convenience. These include converters from strings to numbers and other common types.
The following listing shows the `StringToInteger` class, which is a typical `Converter` implementation:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -781,7 +748,6 @@ The following listing shows the `StringToInteger` class, which is a typical `Con
}
}
----
====
@ -792,7 +758,6 @@ When you need to centralize the conversion logic for an entire class hierarchy
(for example, when converting from `String` to `Enum` objects), you can implement
`ConverterFactory`, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -803,7 +768,6 @@ When you need to centralize the conversion logic for an entire class hierarchy
<T extends R> Converter<S, T> getConverter(Class<T> 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<T>)`,
@ -811,7 +775,6 @@ where T is a subclass of R.
Consider the `StringToEnumConverterFactory` as an example:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -837,7 +800,6 @@ Consider the `StringToEnumConverterFactory` as an example:
}
}
----
====
@ -852,7 +814,6 @@ context that you can use when you implement your conversion logic. Such context
type conversion be driven by a field annotation or by generic information declared on a
field signature. The following listing shows the interface definition of `GenericConverter`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -865,7 +826,6 @@ field signature. The following listing shows the interface definition of `Generi
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,
@ -894,7 +854,6 @@ on the target field, or you might want to run a `Converter` only if a specific m
`ConditionalGenericConverter` is the union of the `GenericConverter` and
`ConditionalConverter` interfaces that lets you define such custom matching criteria:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -906,7 +865,6 @@ on the target field, or you might want to run a `Converter` only if a specific m
public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {
}
----
====
A good example of a `ConditionalGenericConverter` is an `EntityConverter` that converts
between a persistent entity identifier and an entity reference. Such an `EntityConverter`
@ -922,7 +880,6 @@ might match only if the target entity type declares a static finder method (for
`ConversionService` defines a unified API for executing type conversion logic at
runtime. Converters are often executed behind the following facade interface:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -940,7 +897,6 @@ runtime. Converters are often executed behind the following facade interface:
}
----
====
Most `ConversionService` implementations also implement `ConverterRegistry`, which
provides an SPI for registering converters. Internally, a `ConversionService`
@ -969,21 +925,18 @@ system is used.
To register a default `ConversionService` with Spring, add the following bean definition
with an `id` of `conversionService`:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean"/>
----
====
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 converters, set the `converters` property. Property values can implement
any of the `Converter`, `ConverterFactory`, or `GenericConverter` interfaces.
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -996,7 +949,6 @@ any of the `Converter`, `ConverterFactory`, or `GenericConverter` interfaces.
</property>
</bean>
----
====
It is also common to use a `ConversionService` within a Spring MVC application. See
<<web.adoc#mvc-config-conversion, Conversion and Formatting>> in the Spring MVC chapter.
@ -1013,7 +965,6 @@ In certain situations, you may wish to apply formatting during conversion. See
To work with a `ConversionService` instance programmatically, you can inject a reference to
it like you would for any other bean. The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1030,7 +981,6 @@ it like you would for any other bean. The following example shows how to do so:
}
}
----
====
For most use cases, you can use the `convert` method that specifies the `targetType`, but it
does not work with more complex types, such as a collection of a parameterized element.
@ -1040,7 +990,6 @@ you need to provide a formal definition of the source and target types.
Fortunately, `TypeDescriptor` provides various options to make doing so straightforward,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1051,7 +1000,6 @@ as the following example shows:
TypeDescriptor.forObject(input), // List<Integer> type descriptor
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class)));
----
====
Note that `DefaultConversionService` automatically registers converters that are
appropriate for most environments. This includes collection converters, scalar
@ -1100,7 +1048,6 @@ provides a unified type conversion API for both SPIs.
The `Formatter` SPI to implement field formatting logic is simple and strongly typed. The
following listing shows the `Formatter` interface definition:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1109,12 +1056,10 @@ following listing shows the `Formatter` interface definition:
public interface Formatter<T> extends Printer<T>, Parser<T> {
}
----
====
`Formatter` extends from the `Printer` and `Parser` building-block interfaces. The
following listing shows the definitions of those two interfaces:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1134,7 +1079,6 @@ following listing shows the definitions of those two interfaces:
T parse(String clientValue, Locale locale) throws ParseException;
}
----
====
To create your own `Formatter`, implement the `Formatter` interface shown earlier.
Parameterize `T` to be the type of object you wish to format -- for example,
@ -1153,7 +1097,6 @@ formatting support based on the http://joda-time.sourceforge.net[Joda-Time libra
The following `DateFormatter` is an example `Formatter` implementation:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1188,7 +1131,6 @@ The following `DateFormatter` is an example `Formatter` implementation:
}
}
----
====
The Spring team welcomes community-driven `Formatter` contributionsSee
https://jira.spring.io/browse/SPR[jira.spring.io] to contribute.
@ -1202,7 +1144,6 @@ Field formatting can be configured by field type or annotation. To bind
an annotation to a `Formatter`, implement `AnnotationFormatterFactory`. The following
listing shows the definition of the `AnnotationFormatterFactory` interface:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1217,7 +1158,6 @@ listing shows the definition of the `AnnotationFormatterFactory` interface:
Parser<?> getParser(A annotation, Class<?> fieldType);
}
----
====
To create an implementation:
. Parameterize A to be the field `annotationType` with which you wish to associate
@ -1230,7 +1170,6 @@ The following example `AnnotationFormatterFactory` implementation binds the `@Nu
annotation to a formatter to let a number style or pattern be
specified:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1267,12 +1206,10 @@ specified:
}
}
----
====
To trigger formatting, you can annotate fields with @NumberFormat, as the following
example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1282,7 +1219,6 @@ example shows:
private BigDecimal decimal;
}
----
====
@ -1297,7 +1233,6 @@ package. You can use `@NumberFormat` to format `Number` fields such as `Double`
The following example uses `@DateTimeFormat` to format a `java.util.Date` as an ISO Date
(yyyy-MM-dd):
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1307,7 +1242,6 @@ The following example uses `@DateTimeFormat` to format a `java.util.Date` as an
private Date date;
}
----
====
@ -1323,7 +1257,6 @@ for use with Spring's `DataBinder` and the Spring Expression Language (SpEL).
The following listing shows the `FormatterRegistry` SPI:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1340,7 +1273,6 @@ The following listing shows the `FormatterRegistry` SPI:
void addFormatterForAnnotation(AnnotationFormatterFactory<?, ?> factory);
}
----
====
As shown in the preceding listing, you can register formatters by field type or by annotation.
@ -1358,7 +1290,6 @@ these rules once, and they are applied whenever formatting is needed.
`FormatterRegistrar` is an SPI for registering formatters and converters through the
FormatterRegistry. The following listing shows its interface definition:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1369,7 +1300,6 @@ FormatterRegistry. The following listing shows its interface definition:
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
@ -1404,7 +1334,6 @@ you use the Joda-Time library.
For example, the following Java configuration registers a global `yyyyMMdd`
format (this example does not depend on the Joda-Time library):
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1429,13 +1358,11 @@ format (this example does not depend on the Joda-Time library):
}
}
----
====
If you prefer XML-based configuration, you can use a
`FormattingConversionServiceFactoryBean`. The following example shows how to do so (this time using Joda
Time):
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1467,7 +1394,6 @@ Time):
</bean>
</beans>
----
====
NOTE: Joda-Time provides separate distinct types to represent `date`, `time`, and `date-time`
values. The `dateFormatter`, `timeFormatter`, and `dateTimeFormatter` properties of the
@ -1504,7 +1430,6 @@ constraints. You can also define your own custom constraints.
Consider the following example, which shows a simple `PersonForm` model with two properties:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1513,12 +1438,10 @@ Consider the following example, which shows a simple `PersonForm` model with two
private int age;
}
----
====
JSR-303 lets you define declarative validation constraints against such properties, as the
following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1532,7 +1455,6 @@ following example shows:
private int age;
}
----
====
When a JSR-303 Validator validates an instance of this class, these constraints
are enforced.
@ -1556,14 +1478,12 @@ wherever validation is needed in your application.
You can use the `LocalValidatorFactoryBean` to configure a default Validator as a Spring bean,
as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
----
====
The basic configuration in the preceding example triggers bean validation to initialize by using its
default bootstrap mechanism. A JSR-303 or JSR-349 provider, such as the Hibernate Validator,
@ -1581,7 +1501,6 @@ these interfaces into beans that need to invoke validation logic.
You can inject a reference to `javax.validation.Validator` if you prefer to work with the Bean
Validation API directly, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1593,12 +1512,10 @@ Validation API directly, as the following example shows:
@Autowired
private Validator validator;
----
====
You can inject a reference to `org.springframework.validation.Validator` if your bean requires
the Spring Validation API, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1611,7 +1528,6 @@ the Spring Validation API, as the following example shows:
private Validator validator;
}
----
====
[[validation-beanvalidation-spring-constraints]]
@ -1636,7 +1552,6 @@ that uses Spring to create `ConstraintValidator` instances. This lets your custo
The following example shows a custom `@Constraint` declaration followed by an associated
`ConstraintValidator` implementation that uses Spring for dependency injection:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1660,7 +1575,6 @@ The following example shows a custom `@Constraint` declaration followed by an as
...
}
----
====
As the preceding example shows, a `ConstraintValidator` implementation can have its dependencies
`@Autowired` as any other Spring bean.
@ -1673,13 +1587,11 @@ You can integrate the method validation feature supported by Bean Validation 1.1
extension, also by Hibernate Validator 4.3) into a Spring context
through a `MethodValidationPostProcessor` bean definition, as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>
----
====
To be eligible for Spring-driven method validation, all target classes need to be annotated with
Spring's `@Validated` annotation. (Optionally, you can also declare the validation groups to use.)
@ -1708,7 +1620,6 @@ configured, you can invoke the `Validator` by calling `binder.validate()`. Any v
The following example shows how to use a `DataBinder` programmatically to invoke validation
logic after binding to a target object:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1725,7 +1636,6 @@ logic after binding to a target object:
// get BindingResult that includes any validation errors
BindingResult results = binder.getBindingResult();
----
====
You can also configure a `DataBinder` with multiple `Validator` instances through
`dataBinder.addValidators` and `dataBinder.replaceValidators`. This is useful when

View File

@ -32,7 +32,6 @@ the following preamble at the top of your Spring XML configuration file. The tex
following snippet references the correct schema so that the tags in the `tx` namespace
are available to you:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -52,7 +51,6 @@ are available to you:
----
<1> Declare usage of the `tx` namespace.
<2> Specify the location (with other schema locations).
====
NOTE: Often, when you use the elements in the `tx` namespace, you are also using the
elements from the `aop` namespace (since the declarative transaction support in Spring is
@ -74,7 +72,6 @@ To use the elements in the `jdbc` schema, you need to have the following preambl
top of your Spring XML configuration file. The text in the following snippet references
the correct schema so that the elements in the `jdbc` namespace are available to you:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -92,4 +89,3 @@ the correct schema so that the elements in the `jdbc` namespace are available to
----
<1> Declare usage of the `jdbc` namespace.
<2> Specify the location (with other schema locations).
====

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,6 @@ To use the elements in the `jee` schema, you need to have the following preamble
of your Spring XML configuration file. The text in the following snippet references the
correct schema so that the elements in the `jee` namespace are available to you:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -34,7 +33,6 @@ correct schema so that the elements in the `jee` namespace are available to you:
<!-- bean definitions here -->
</beans>
----
====
@ -43,7 +41,6 @@ correct schema so that the elements in the `jee` namespace are available to you:
The following example shows how to use JNDI to look up a data source without the `jee` schema:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -55,12 +52,10 @@ The following example shows how to use JNDI to look up a data source without the
<property name="dataSource" ref="**dataSource**"/>
</bean>
----
====
The following example shows how to use JNDI to look up a data source with the `jee`
schema:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -71,7 +66,6 @@ schema:
<property name="dataSource" ref="**dataSource**"/>
</bean>
----
====
@ -81,7 +75,6 @@ schema:
The following example shows how to use JNDI to look up an environment variable without
`jee`:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -94,7 +87,6 @@ The following example shows how to use JNDI to look up an environment variable w
</property>
</bean>
----
====
The following example shows how to use JNDI to look up an environment variable with `jee`:
@ -113,7 +105,6 @@ The following example shows how to use JNDI to look up an environment variable w
The following example shows how to use JNDI to look up multiple environment variables
without `jee`:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -127,12 +118,10 @@ without `jee`:
</property>
</bean>
----
====
The following example shows how to use JNDI to look up multiple environment variables with
`jee`:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -144,7 +133,6 @@ The following example shows how to use JNDI to look up multiple environment vari
</jee:environment>
</jee:jndi-lookup>
----
====
[[xsd-schemas-jee-jndi-lookup-complex]]
@ -153,7 +141,6 @@ The following example shows how to use JNDI to look up multiple environment vari
The following example shows how to use JNDI to look up a data source and a number of
different properties without `jee`:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -166,12 +153,10 @@ different properties without `jee`:
<property name="proxyInterface" value="com.myapp.Thing"/>
</bean>
----
====
The following example shows how to use JNDI to look up a data source and a number of
different properties with `jee`:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -183,7 +168,6 @@ different properties with `jee`:
expected-type="com.myapp.DefaultThing"
proxy-interface="com.myapp.Thing"/>
----
====
@ -195,7 +179,6 @@ The `<jee:local-slsb/>` element configures a reference to a local EJB Stateless
The following example shows how to configures a reference to a local EJB Stateless
SessionBean without `jee`:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -205,19 +188,16 @@ SessionBean without `jee`:
<property name="businessInterface" value="com.foo.service.RentalService"/>
</bean>
----
====
The following example shows how to configures a reference to a local EJB Stateless
SessionBean with `jee`:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<jee:local-slsb id="simpleSlsb" jndi-name="ejb/RentalServiceBean"
business-interface="com.foo.service.RentalService"/>
----
====
@ -229,7 +209,6 @@ The `<jee:local-slsb/>` element configures a reference to a local EJB Stateless
The following example shows how to configures a reference to a local EJB Stateless
SessionBean and a number of properties without `jee`:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -242,12 +221,10 @@ SessionBean and a number of properties without `jee`:
<property name="resourceRef" value="true"/>
</bean>
----
====
The following example shows how to configures a reference to a local EJB Stateless
SessionBean and a number of properties with `jee`:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -258,7 +235,6 @@ SessionBean and a number of properties with `jee`:
lookup-home-on-startup="true"
resource-ref="true">
----
====
[[xsd-schemas-jee-remote-slsb]]
@ -270,7 +246,6 @@ SessionBean.
The following example shows how to configures a reference to a remote EJB Stateless
SessionBean without `jee`:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -285,12 +260,10 @@ SessionBean without `jee`:
<property name="refreshHomeOnConnectFailure" value="true"/>
</bean>
----
====
The following example shows how to configures a reference to a remote EJB Stateless
SessionBean with `jee`:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -303,7 +276,6 @@ SessionBean with `jee`:
home-interface="com.foo.service.RentalService"
refresh-home-on-connect-failure="true">
----
====
@ -321,7 +293,6 @@ the following preamble at the top of your Spring XML configuration file. The tex
following snippet references the correct schema so that the elements in the `jms` namespace
are available to you:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -335,7 +306,6 @@ are available to you:
<!-- bean definitions here -->
</beans>
----
====
@ -359,7 +329,6 @@ To use the elements in the `cache` schema, you need to have the following preamb
top of your Spring XML configuration file. The text in the following snippet references
the correct schema so that the elements in the `cache` namespace are available to you:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -373,4 +342,3 @@ the correct schema so that the elements in the `cache` namespace are available t
<!-- bean definitions here -->
</beans>
----
====

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,6 @@ Note that this interface is defined in plain Java. Dependent objects that are
injected with a reference to the `Messenger` do not know that the underlying
implementation is a Groovy script. The following listing shows the `Messenger` interface:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -54,11 +53,9 @@ implementation is a Groovy script. The following listing shows the `Messenger` i
}
----
====
The following example defines a class that has a dependency on the `Messenger` interface:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -78,11 +75,9 @@ The following example defines a class that has a dependency on the `Messenger` i
}
----
====
The following example implements the `Messenger` interface in Groovy:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -99,7 +94,6 @@ The following example implements the `Messenger` interface in Groovy:
}
----
====
[NOTE]
====
@ -118,7 +112,6 @@ Finally, the following example shows the bean definitions that effect the inject
Groovy-defined `Messenger` implementation into an instance of the
`DefaultBookingService` class:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -141,7 +134,6 @@ Groovy-defined `Messenger` implementation into an instance of the
</beans>
----
====
The `bookingService` bean (a `DefaultBookingService`) can now use its private
`messenger` member variable as normal, because the `Messenger` instance that was injected
@ -244,7 +236,6 @@ So, if we stick with <<dynamic-language-a-first-example,the example>> from earli
chapter, the following example shows what we would change in the Spring XML configuration to effect
refreshable beans:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -263,7 +254,6 @@ refreshable beans:
</beans>
----
====
That really is all you have to do. The `refresh-check-delay` attribute defined on the
`messenger` bean definition is the number of milliseconds after which the bean is
@ -281,7 +271,6 @@ the program resumes execution.
The following listing shows this sample application:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -301,14 +290,12 @@ The following listing shows this sample application:
}
}
----
====
Assume then, for the purposes of this example, that all calls to the
`getMessage()` method of `Messenger` implementations have to be changed such that the
message is surrounded by quotation marks. The following listing shows the changes that you (the developer) should make to the
`Messenger.groovy` source file when the execution of the program is paused:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -328,7 +315,6 @@ message is surrounded by quotation marks. The following listing shows the change
}
}
----
====
When the program runs, the output before the input pause will be `I Can Do The
Frug`. After the change to the source file is made and saved and the program resumes
@ -363,7 +349,6 @@ embedded directly in Spring bean definitions. More specifically, the
inside a Spring configuration file. An example might clarify how the inline script
feature works:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -382,7 +367,6 @@ feature works:
<lang:property name="message" value="I Can Do The Frug" />
</lang:groovy>
----
====
If we put to one side the issues surrounding whether it is good practice to define
dynamic language source inside a Spring configuration file, the `<lang:inline-script/>`
@ -404,7 +388,6 @@ constructors and properties 100% clear, the following mixture of code and config
does not work:
.An approach that cannot work
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -443,7 +426,6 @@ does not work:
</lang>
----
====
In practice this limitation is not as significant as it first appears, since setter
injection is the injection style favored by the overwhelming majority of developers
@ -477,7 +459,6 @@ If you have read this chapter straight from the top, you have already
<<dynamic-language-a-first-example,seen an example>> of a Groovy-dynamic-language-backed
bean. Now consider another example (again using an example from the Spring test suite):
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -489,11 +470,9 @@ bean. Now consider another example (again using an example from the Spring test
}
----
====
The following example implements the `Calculator` interface in Groovy:
====
[source,groovy,indent=0]
[subs="verbatim,quotes"]
----
@ -508,11 +487,9 @@ The following example implements the `Calculator` interface in Groovy:
}
----
====
The following bean definition uses the calculator defined in Groovy:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -521,11 +498,9 @@ The following bean definition uses the calculator defined in Groovy:
<lang:groovy id="calculator" script-source="classpath:calculator.groovy"/>
</beans>
----
====
Finally, the following small application exercises the preceding configuration:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -543,7 +518,6 @@ Finally, the following small application exercises the preceding configuration:
}
}
----
====
The resulting output from running the above program is (unsurprisingly) `10`.
(For more interesting examples,
@ -566,7 +540,6 @@ implementations of this interface could invoke any required initialization metho
set some default property values, or specify a custom `MetaClass`. The following listing
shows the `GroovyObjectCustomizer` interface definition:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -575,7 +548,6 @@ shows the `GroovyObjectCustomizer` interface definition:
void customize(GroovyObject goo);
}
----
====
The Spring Framework instantiates an instance of your Groovy-backed bean and
then passes the created `GroovyObject` to the specified `GroovyObjectCustomizer` (if one
@ -583,7 +555,6 @@ has been defined). You can do whatever you like with the supplied `GroovyObject`
reference. We expect that most people want to set a custom `MetaClass` with this callback,
and the following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -603,7 +574,6 @@ and the following example shows how to do so:
}
----
====
A full discussion of meta-programming in Groovy is beyond the scope of the Spring
reference manual. See the relevant section of the Groovy reference manual or do a
@ -611,7 +581,6 @@ search online. Plenty of articles address this topic. Actually, making use
of a `GroovyObjectCustomizer` is easy if you use the Spring namespace support, as the
following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -623,12 +592,10 @@ following example shows:
script-source="classpath:org/springframework/scripting/groovy/Calculator.groovy"
customizer-ref="tracingCustomizer"/>
----
====
If you do not use the Spring namespace support, you can still use the
`GroovyObjectCustomizer` functionality, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -642,7 +609,6 @@ If you do not use the Spring namespace support, you can still use the
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
----
====
NOTE: As of Spring Framework 4.3.3, you may also specify a Groovy `CompilationCustomizer`
(such as an `ImportCustomizer`) or even a full Groovy `CompilerConfiguration` object
@ -684,7 +650,6 @@ Now we can show a fully working example of using a BeanShell-based bean that imp
the `Messenger` interface that was defined earlier in this chapter. We again show the
definition of the `Messenger` interface:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -696,12 +661,10 @@ definition of the `Messenger` interface:
}
----
====
The following example shows the BeanShell "`implementation`" (we use the term loosely here) of the
`Messenger` interface:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -715,12 +678,10 @@ The following example shows the BeanShell "`implementation`" (we use the term lo
message = aMessage;
}
----
====
The following example shows the Spring XML that defines an "`instance`" of the above "`class`" (again,
we use these terms very loosely here):
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -730,7 +691,6 @@ we use these terms very loosely here):
<lang:property name="message" value="Hello World!" />
</lang:bsh>
----
====
See <<dynamic-language-scenarios>> for some scenarios where you might want to use
BeanShell-based beans.
@ -773,7 +733,6 @@ beans, you have to enable the "`refreshable beans`" functionality. See
The following example shows an `org.springframework.web.servlet.mvc.Controller` implemented
by using the Groovy dynamic language:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -809,7 +768,6 @@ by using the Groovy dynamic language:
<lang:property name="fortuneService" ref="fortuneService"/>
</lang:groovy>
----
====
@ -836,7 +794,6 @@ by using the Groovy dynamic language (see <<core.adoc#validator,
Validation using Springs Validator interface>> for a discussion of the
`Validator` interface):
====
[source,groovy,indent=0]
[subs="verbatim,quotes"]
----
@ -859,7 +816,6 @@ Validation using Springs Validator interface>> for a discussion of the
}
----
====
@ -899,7 +855,6 @@ with "`regular`" beans.)
The following example uses the `scope` attribute to define a Groovy bean scoped as
a <<core.adoc#beans-factory-scopes-prototype,prototype>>:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -920,7 +875,6 @@ a <<core.adoc#beans-factory-scopes-prototype,prototype>>:
</beans>
----
====
See <<core.adoc#beans-factory-scopes,Bean scopes>> in <<core.adoc#beans,The IoC container>>
for a full discussion of the scoping support in the Spring Framework.
@ -943,7 +897,6 @@ the following preamble at the top of your Spring XML configuration file. The tex
following snippet references the correct schema so that the tags in the `lang` namespace
are available to you:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -958,7 +911,6 @@ are available to you:
</beans>
----
====

View File

@ -56,23 +56,19 @@ for their APIs, thus giving a better Kotlin development experience overall.
To retrieve a list of `User` objects in Java, you would normally write the following:
====
[source,java,indent=0]
----
Flux<User> users = client.get().retrieve().bodyToFlux(User.class)
----
====
With Kotlin and the Spring Framework extensions, you can instead write the following:
====
[source,kotlin,indent=0]
----
val users = client.get().retrieve().bodyToFlux<User>()
// or (both are equivalent)
val users : Flux<User> = client.get().retrieve().bodyToFlux()
----
====
As in Java, `users` in Kotlin is strongly typed, but Kotlin's clever type inference allows
for shorter syntax.
@ -176,7 +172,6 @@ This mechanism is very efficient, as it does not require any reflection or CGLIB
In Java, you can, for example, write the following:
====
[source,java,indent=0]
----
GenericApplicationContext context = new GenericApplicationContext();
@ -184,12 +179,10 @@ In Java, you can, for example, write the following:
context.registerBean(Bar.class, () -> new Bar(context.getBean(Foo.class))
);
----
====
In Kotlin, with reified type parameters and `GenericApplicationContext`
Kotlin extensions, you can instead write the following:
====
[source,kotlin,indent=0]
----
val context = GenericApplicationContext().apply {
@ -197,7 +190,6 @@ Kotlin extensions, you can instead write the following:
registerBean { Bar(it.getBean<Foo>()) }
}
----
====
In order to allow a more declarative approach and cleaner syntax, Spring Framework provides
a {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.context.support/-bean-definition-dsl/[Kotlin bean definition DSL]
@ -205,7 +197,6 @@ It declares an `ApplicationContextInitializer` through a clean declarative API,
which lets you deal with profiles and `Environment` for customizing
how beans are registered. The following example creates a `Play` profile:
====
[source,kotlin,indent=0]
----
fun beans() = beans {
@ -237,7 +228,6 @@ how beans are registered. The following example creates a `Play` profile:
}
}
----
====
In the preceding example, `bean<Routes>()` uses autowiring by constructor, and `ref<Routes>()`
is a shortcut for `applicationContext.getBean(Routes::class.java)`.
@ -245,7 +235,6 @@ is a shortcut for `applicationContext.getBean(Routes::class.java)`.
You can then use this `beans()` function to register beans on the application context,
as the following example shows:
====
[source,kotlin,indent=0]
----
val context = GenericApplicationContext().apply {
@ -253,7 +242,6 @@ as the following example shows:
refresh()
}
----
====
NOTE: This DSL is programmatic, meaning it allows custom registration logic of beans
through an `if` expression, a `for` loop, or any other Kotlin constructs.
@ -281,7 +269,6 @@ Spring Framework now comes with a
that lets you use the <<web-reactive#webflux-fn,WebFlux functional
API>> to write clean and idiomatic Kotlin code, as the following example shows:
====
[source,kotlin,indent=0]
----
router {
@ -301,7 +288,6 @@ API>> to write clean and idiomatic Kotlin code, as the following example shows:
resources("/**", ClassPathResource("static/"))
}
----
====
NOTE: This DSL is programmatic, meaning that it allows custom registration logic of beans
through an `if` expression, a `for` loop, or any other Kotlin constructs. That can be useful when you need to register routes
@ -330,7 +316,6 @@ https://github.com/Kotlin/kotlinx.html[kotlinx.html] DSL or by a using Kotlin mu
This can let you write Kotlin templates with full autocompletion and
refactoring support in a supported IDE, as the following example shows:
====
[source,kotlin,indent=0]
----
import io.spring.demo.*
@ -344,7 +329,6 @@ refactoring support in a supported IDE, as the following example shows:
${include("footer")}
"""
----
====
See the https://github.com/sdeleuze/kotlin-script-templating[kotlin-script-templating] example
project for more details.
@ -399,12 +383,10 @@ you can write your Kotlin beans without any additional `open` keyword, as in Jav
In Kotlin, it is convenient and considered to be a best practice to declare read-only properties
within the primary constructor, as in the following example:
====
[source,kotlin,indent=0]
----
class Person(val name: String, val age: Int)
----
====
You can optionally add https://kotlinlang.org/docs/reference/data-classes.html[the `data` keyword]
to make the compiler automatically derive the following members from all properties declared
@ -417,7 +399,6 @@ in the primary constructor:
As the following example shows, this allows for easy changes to individual properties, even if `Person` properties are read-only:
====
[source,kotlin,indent=0]
----
data class Person(val name: String, val age: Int)
@ -425,7 +406,6 @@ As the following example shows, this allows for easy changes to individual prope
val jack = Person(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)
----
====
Common persistence technologies (such as JPA) require a default constructor, preventing this
kind of design. Fortunately, there is now a workaround for this
@ -448,7 +428,6 @@ mappings (such as MongoDB, Redis, Cassandra, and others).
Our recommendation is to try and favor constructor injection with `val` read-only (and non-nullable when possible)
https://kotlinlang.org/docs/reference/properties.html[properties], as the following example shows:
====
[source,kotlin,indent=0]
----
@Component
@ -457,7 +436,6 @@ https://kotlinlang.org/docs/reference/properties.html[properties], as the follow
private val solrClient: SolrClient
)
----
====
NOTE: As of Spring Framework 4.3, classes with a single constructor have their
parameters automatically autowired, that's why there is no need for an
@ -466,7 +444,6 @@ explicit `@Autowired constructor` in the example shown above.
If you really need to use field injection, you can use the `lateinit var` construct,
as the following example shows:
====
[source,kotlin,indent=0]
----
@Component
@ -479,7 +456,6 @@ as the following example shows:
lateinit var solrClient: SolrClient
}
----
====
@ -494,7 +470,6 @@ character by writing `@Value("\${property}")`.
As an alternative, you can customize the properties placeholder prefix by declaring
the following configuration beans:
====
[source,kotlin,indent=0]
----
@Bean
@ -502,12 +477,10 @@ the following configuration beans:
setPlaceholderPrefix("%{")
}
----
====
You can customize existing code (such as Spring Boot actuators or `@LocalServerPort`) that uses the `${...}` syntax,
with configuration beans, as the following example shows:
====
[source,kotlin,indent=0]
----
@Bean
@ -519,7 +492,6 @@ with configuration beans, as the following example shows:
@Bean
fun defaultPropertyConfigurer() = PropertySourcesPlaceholderConfigurer()
----
====
NOTE: If you use Spring Boot, you can use
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties[`@ConfigurationProperties`]
@ -543,7 +515,6 @@ specify it as a `vararg` parameter.
To understand what that means, consider `@RequestMapping` (which is one
of the most widely used Spring annotations) as an example. This Java annotation is declared as follows:
====
[source,java,indent=0]
----
public @interface RequestMapping {
@ -559,7 +530,6 @@ of the most widely used Spring annotations) as an example. This Java annotation
// ...
}
----
====
The typical use case for `@RequestMapping` is to map a handler method to a specific path
and method. In Java, you can specify a single value for the
@ -600,7 +570,6 @@ You can now change the default behavior to `PER_CLASS` thanks to a
The following example `@BeforeAll` and `@AfterAll` annotations on non-static methods:
====
[source]
----
class IntegrationTests {
@ -630,7 +599,6 @@ class IntegrationTests {
}
}
----
====
@ -639,7 +607,6 @@ class IntegrationTests {
You can create specification-like tests with JUnit 5 and Kotlin.
The following example shows how to do so:
====
[source]
----
class SpecificationLikeTests {
@ -663,7 +630,6 @@ class SpecificationLikeTests {
}
}
----
====

View File

@ -27,13 +27,11 @@ a URL to connect to a running server.
The following example shows how to create a server setup to test one `@Controller` at a time:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
client = WebTestClient.bindToController(new TestController()).build();
----
====
The preceding example loads the <<web-reactive.adoc#webflux-config,WebFlux Java configuration>> and
registers the given controller. The resulting WebFlux application is tested
@ -48,14 +46,12 @@ on the builder to customize the default WebFlux Java configuration.
The following example shows how to set up a server from a
<<web-reactive.adoc#webflux-fn,RouterFunction>>:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
RouterFunction<?> route = ...
client = WebTestClient.bindToRouterFunction(route).build();
----
====
Internally, the configuration is passed to `RouterFunctions.toWebHandler`.
The resulting WebFlux application is tested without an HTTP server by using mock
@ -69,7 +65,6 @@ request and response objects.
The following example shows how to setup a server from the Spring configuration of your application or
some subset of it:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -92,7 +87,6 @@ some subset of it:
<1> Specify the configuration to load
<2> Inject the configuration
<3> Create the `WebTestClient`
====
Internally, the configuration is passed to `WebHttpHandlerBuilder` to set up
the request processing chain. See
@ -107,13 +101,11 @@ and response objects.
The following server setup option lets you connect to a running server:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
client = WebTestClient.bindToServer().baseUrl("http://localhost:8080").build();
----
====
@ -125,7 +117,6 @@ options, including base URL, default headers, client filters, and others. These
are readily available following `bindToServer`. For all others, you need to use
`configureClient()` to transition from server to client configuration, as follows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -134,7 +125,6 @@ are readily available following `bindToServer`. For all others, you need to use
.baseUrl("/test")
.build();
----
====
@ -148,7 +138,6 @@ up to the point of performing a request by using `exchange()`. What follows afte
Typically, you start by asserting the response status and headers, as follows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -159,7 +148,6 @@ Typically, you start by asserting the response status and headers, as follows:
.expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8)
// ...
----
====
Then you specify how to decode and consume the response body:
@ -169,7 +157,6 @@ Then you specify how to decode and consume the response body:
Then you can use built-in assertions for the body. The following example shows one way to do so:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -178,11 +165,9 @@ Then you can use built-in assertions for the body. The following example shows o
.expectStatus().isOk()
.expectBodyList(Person.class).hasSize(3).contains(person);
----
====
You can also go beyond the built-in assertions and create your own, as the following example shows:
====
----
client.get().uri("/persons/1")
.exchange()
@ -192,11 +177,9 @@ You can also go beyond the built-in assertions and create your own, as the follo
// custom assertions (e.g. AssertJ)...
});
----
====
You can also exit the workflow and get a result, as follows:
====
----
EntityExchangeResult<Person> result = client.get().uri("/persons/1")
.exchange()
@ -204,7 +187,6 @@ You can also exit the workflow and get a result, as follows:
.expectBody(Person.class)
.returnResult();
----
====
TIP: When you need to decode to a target type with generics, look for the overloaded methods
that accept
@ -219,7 +201,6 @@ instead of `Class<T>`.
If the response has no content (or you do not care if it does) use `Void.class`, which ensures
that resources are released. The following example shows how to do so:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -228,11 +209,9 @@ that resources are released. The following example shows how to do so:
.expectStatus().isNotFound()
.expectBody(Void.class);
----
====
Alternatively, if you want to assert there is no response content, you can use code similar to the following:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -242,7 +221,6 @@ Alternatively, if you want to assert there is no response content, you can use c
.expectStatus().isCreated()
.expectBody().isEmpty();
----
====
@ -253,7 +231,6 @@ When you use `expectBody()`, the response is consumed as a `byte[]`. This is use
raw content assertions. For example, you can use
http://jsonassert.skyscreamer.org[JSONAssert] to verify JSON content, as follows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -263,11 +240,9 @@ http://jsonassert.skyscreamer.org[JSONAssert] to verify JSON content, as follows
.expectBody()
.json("{\"name\":\"Jane\"}")
----
====
You can also use https://github.com/jayway/JsonPath[JSONPath] expressions, as follows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -278,7 +253,6 @@ You can also use https://github.com/jayway/JsonPath[JSONPath] expressions, as fo
.jsonPath("$[0].name").isEqualTo("Jane")
.jsonPath("$[1].name").isEqualTo("Jason");
----
====
@ -289,7 +263,6 @@ To test infinite streams (for example, `"text/event-stream"` or `"application/st
you need to exit the chained API (by using `returnResult`), immediately after the response status
and header assertions, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -300,13 +273,11 @@ and header assertions, as the following example shows:
.returnResult(MyEvent.class);
----
====
Now you can consume the `Flux<T>`, assert decoded objects as they come, and then
cancel at some point when test objectives are met. We recommend using the `StepVerifier`
from the `reactor-test` module to do that, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -319,7 +290,6 @@ from the `reactor-test` module to do that, as the following example shows:
.thenCancel()
.verify();
----
====

File diff suppressed because it is too large Load Diff

View File

@ -43,7 +43,6 @@ set of Spring XML configuration files to load.
Consider the following `<listener/>` configuration:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -51,11 +50,9 @@ Consider the following `<listener/>` configuration:
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
----
====
Further consider the following `<context-param/>` configuration:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -64,7 +61,6 @@ Further consider the following `<context-param/>` configuration:
<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
----
====
If you do not specify the `contextConfigLocation` context parameter, the
`ContextLoaderListener` looks for a file called `/WEB-INF/applicationContext.xml` to
@ -79,13 +75,11 @@ created by the `ContextLoaderListener`.
The following example shows how to get the `WebApplicationContext`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
----
====
The
{api-spring-framework}/web/context/support/WebApplicationContextUtils.html[`WebApplicationContextUtils`]
@ -140,7 +134,6 @@ implementation.
Configuration-wise, you can define `SpringBeanFacesELResolver` in your JSF
`faces-context.xml` file, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -151,7 +144,6 @@ Configuration-wise, you can define `SpringBeanFacesELResolver` in your JSF
</application>
</faces-config>
----
====
@ -166,13 +158,11 @@ takes a `FacesContext` parameter rather than a `ServletContext` parameter.
The following example shows how to use `FacesContextUtils`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
ApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
----
====

View File

@ -4,7 +4,6 @@
`UriComponentsBuilder` helps to build URI's from URI templates with variables, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -21,12 +20,11 @@
<3> Request to have the URI template and URI variables encoded.
<4> Build a `UriComponents`.
<5> Expand variables and obtain the `URI`.
====
The preceding example can be consolidated into one chain and shortened with `buildAndExpand`,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -37,12 +35,10 @@ as the following example shows:
.buildAndExpand("Westin", "123")
.toUri();
----
====
You can shorten it further by going directly to a URI (which implies encoding),
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -51,11 +47,9 @@ as the following example shows:
.queryParam("q", "{q}")
.build("Westin", "123");
----
====
You shorter it further still with a full URI template, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -63,7 +57,6 @@ You shorter it further still with a full URI template, as the following example
.fromUriString("http://example.com/hotels/{hotel}?q={q}")
.build("Westin", "123");
----
====
@ -83,7 +76,6 @@ exposes shared configuration options.
The following example shows how to configure a `RestTemplate`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -96,11 +88,9 @@ The following example shows how to configure a `RestTemplate`:
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);
----
====
The following example configures a `WebClient`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -112,13 +102,11 @@ The following example configures a `WebClient`:
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
----
====
In addition, you can also use `DefaultUriBuilderFactory` directly. It is similar to using
`UriComponentsBuilder` but, instead of static factory methods, it is an actual instance
that holds configuration and preferences, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -129,7 +117,6 @@ that holds configuration and preferences, as the following example shows:
.queryParam("q", "{q}")
.build("Westin", "123");
----
====
@ -157,7 +144,6 @@ URI variables intentionally contain reserved characters.
The following example uses the first option:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -169,12 +155,10 @@ URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
// Result is "/hotel%20list/New%20York?q=foo%2Bbar"
----
====
You can shorten the preceding example by going directly to the URI (which implies encoding),
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -182,24 +166,20 @@ URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
.queryParam("q", "{q}")
.build("New York", "foo+bar")
----
====
You can shorten it further still with a full URI template, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}?q={q}")
.build("New York", "foo+bar")
----
====
The `WebClient` and the `RestTemplate` expand and encode URI templates internally through
the `UriBuilderFactory` strategy. Both can be configured with a custom strategy.
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -214,7 +194,6 @@ as the following example shows:
// Customize the WebClient..
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();
----
====
The `DefaultUriBuilderFactory` implementation uses `UriComponentsBuilder` internally to
expand and encode URI templates. As a factory, it provides a single place to configure

View File

@ -83,7 +83,6 @@ The {api-spring-framework}/web/bind/annotation/CrossOrigin.html[`@CrossOrigin`]
annotation enables cross-origin requests on annotated controller methods, as the
following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -103,7 +102,6 @@ public class AccountController {
}
}
----
====
By default, `@CrossOrigin` allows:
@ -121,7 +119,6 @@ should be used only where appropriate.
`@CrossOrigin` is supported at the class level, too, and inherited by all methods.
The following example specifies a certain domain and sets `maxAge` to an hour:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -141,11 +138,9 @@ public class AccountController {
}
}
----
====
You can use `@CrossOrigin` at both the class and the method level,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
@ -169,8 +164,6 @@ public class AccountController {
----
<1> Using `@CrossOrigin` at the class level.
<2> Using `@CrossOrigin` at the method level.
====
@ -198,7 +191,6 @@ should be used only where appropriate.
To enable CORS in the WebFlux Java configuration, you can use the `CorsRegistry` callback,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -220,7 +212,6 @@ public class WebConfig implements WebFluxConfigurer {
}
}
----
====
@ -236,7 +227,6 @@ good fit with <<webflux-fn,functional endpoints>>.
To configure the filter, you can declare a `CorsWebFilter` bean and pass a
`CorsConfigurationSource` to its constructor, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim"]
----
@ -259,4 +249,3 @@ CorsWebFilter corsFilter() {
return new CorsWebFilter(source);
}
----
====

View File

@ -28,7 +28,6 @@ difference that router functions provide not just data, but also behavior.
`RouterFunctions.route()` provides a router builder that facilitates the creation of routers,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -63,7 +62,6 @@ public class PersonHandler {
}
}
----
====
One way to run a `RouterFunction` is to turn it into an `HttpHandler` and install it
through one of the built-in <<web-reactive.adoc#webflux-httphandler,server adapters>>:
@ -97,62 +95,50 @@ while access to the body is provided through the `body` methods.
The following example extracts the request body to a `Mono<String>`:
====
[source,java]
----
Mono<String> string = request.bodyToMono(String.class);
----
====
The following example extracts the body to a `Flux<Person>`, where `Person` objects are decoded from some
serialized form, such as JSON or XML:
====
[source,java]
----
Flux<Person> people = request.bodyToFlux(Person.class);
----
====
The preceding examples are shortcuts that use the more general `ServerRequest.body(BodyExtractor)`,
which accepts the `BodyExtractor` functional strategy interface. The utility class
`BodyExtractors` provides access to a number of instances. For example, the preceding examples can
also be written as follows:
====
[source,java]
----
Mono<String> string = request.body(BodyExtractors.toMono(String.class));
Flux<Person> people = request.body(BodyExtractors.toFlux(Person.class));
----
====
The following example shows how to access form data:
====
[source,java]
----
Mono<MultiValueMap<String, String> map = request.body(BodyExtractors.toFormData());
----
====
The following example shows how to access multipart data as a map:
====
[source,java]
----
Mono<MultiValueMap<String, Part> map = request.body(BodyExtractors.toMultipartData());
----
====
The following example shows how to access multiparts, one at a time, in streaming fashion:
====
[source,java]
----
Flux<Part> parts = request.body(BodyExtractos.toParts());
----
====
@ -164,23 +150,19 @@ a `build` method to create it. You can use the builder to set the response statu
headers, or to provide a body. The following example creates a 200 (OK) response with JSON
content:
====
[source,java]
----
Mono<Person> person = ...
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person, Person.class);
----
====
The following example shows how to build a 201 (CREATED) response with a `Location` header and no body:
====
[source,java]
----
URI location = ...
ServerResponse.created(location).build();
----
====
@ -189,14 +171,12 @@ ServerResponse.created(location).build();
We can write a handler function as a lambda, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
HandlerFunction<ServerResponse> helloWorld =
request -> ServerResponse.ok().body(fromObject("Hello World"));
----
====
That is convenient, but in an application we need multiple functions, and multiple inline
lambda's can get messy.
@ -204,7 +184,6 @@ Therefore, it is useful to group related handler functions together into a handl
has a similar role as `@Controller` in an annotation-based application.
For example, the following class exposes a reactive `Person` repository:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -248,7 +227,6 @@ when the `Person` has been saved).
<3> `getPerson` is a handler function that returns a single person, identified by the `id` path
variable. We retrieve that `Person` from the repository and create a JSON response, if it is
found. If it is not found, we use `switchIfEmpty(Mono<T>)` to return a 404 Not Found response.
====
@ -324,7 +302,6 @@ and so on.
The following example uses a request predicate to create a constraint based on the `Accept`
header:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -332,7 +309,6 @@ RouterFunction<ServerResponse> route = RouterFunctions.route()
.GET("/hello-world", accept(MediaType.TEXT_PLAIN),
request -> Response.ok().body(fromObject("Hello World")));
----
====
You can compose multiple request predicates together by using:
@ -368,7 +344,6 @@ There are also other ways to compose multiple router functions together:
The following example shows the composition of four routes:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -395,7 +370,6 @@ RouterFunction<ServerResponse> route = route()
`PersonHandler.createPerson`, and
<4> `otherRoute` is a router function that is created elsewhere, and added to the route built.
====
=== Nested Routes
@ -409,7 +383,6 @@ When using annotations, you would remove this duplication by using a type-level
In WebFlux.fn, path predicates can be shared through the `path` method on the router function builder.
For instance, the last few lines of the example above can be improved in the following way by using nested routes:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -420,7 +393,6 @@ RouterFunction<ServerResponse> route = route()
.POST("/person", handler::createPerson))
.build();
----
====
Note that second parameter of `path` is a consumer that takes the a router builder.
@ -429,7 +401,6 @@ the `nest` method on the builder.
The above still contains some duplication in the form of the shared `Accept`-header predicate.
We can further improve by using the `nest` method together with `accept`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -441,7 +412,6 @@ RouterFunction<ServerResponse> route = route()
.POST("/person", handler::createPerson))
.build();
----
====
[[webflux-fn-running]]
@ -478,7 +448,6 @@ starter.
The following example shows a WebFlux Java configuration (see
<<web-reactive.adoc#webflux-dispatcher-handler,DispatcherHandler>> for how to run it):
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -514,7 +483,6 @@ public class WebConfig implements WebFluxConfigurer {
}
}
----
====
@ -529,7 +497,6 @@ The filter will apply to all routes that are built by the builder.
This means that filters defined in nested routes do not apply to "top-level" routes.
For instance, consider the following example:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -547,7 +514,7 @@ RouterFunction<ServerResponse> route = route()
----
<1> The `before` filter that adds a custom request header is only applied to the two GET routes.
<2> The `after` filter that logs the response is applied to all routes, including the nested ones.
====
The `filter` method on the router builder takes a `HandlerFilterFunction`: a
function that takes a `ServerRequest` and `HandlerFunction` and returns a `ServerResponse`.
@ -559,7 +526,6 @@ Now we can add a simple security filter to our route, assuming that we have a `S
can determine whether a particular path is allowed.
The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -582,7 +548,6 @@ RouterFunction<ServerResponse> route = route()
})
.build();
----
====
The preceding example demonstrates that invoking the `next.handle(ServerRequest)` is optional.
We allow only the handler function to be executed when access is allowed.

View File

@ -47,7 +47,6 @@ integration for using Spring WebFlux with FreeMarker templates.
The following example shows how to configure FreeMarker as a view technology:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -70,7 +69,6 @@ The following example shows how to configure FreeMarker as a view technology:
}
}
----
====
Your templates need to be stored in the directory specified by the `FreeMarkerConfigurer`,
shown in the preceding example. Given the preceding configuration, if your controller returns the view name,
@ -89,7 +87,6 @@ the `FreeMarkerConfigurer` bean. The `freemarkerSettings` property requires a
`java.util.Properties` object, and the `freemarkerVariables` property requires a
`java.util.Map`. The following example shows how to use a `FreeMarkerConfigurer`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -111,7 +108,6 @@ the `FreeMarkerConfigurer` bean. The `freemarkerSettings` property requires a
}
}
----
====
See the FreeMarker documentation for details of settings and variables as they apply to
the `Configuration` object.
@ -173,7 +169,6 @@ You can declare a `ScriptTemplateConfigurer` bean to specify the script engine t
the script files to load, what function to call to render templates, and so on.
The following example uses Mustache templates and the Nashorn JavaScript engine:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -197,7 +192,6 @@ The following example uses Mustache templates and the Nashorn JavaScript engine:
}
}
----
====
The `render` function is called with the following parameters:
@ -217,7 +211,6 @@ http://en.wikipedia.org/wiki/Polyfill[polyfill] in order to emulate some
browser facilities not available in the server-side script engine.
The following example shows how to set a custom render function:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -241,7 +234,6 @@ The following example shows how to set a custom render function:
}
}
----
====
NOTE: Setting the `sharedEngine` property to `false` is required when using non-thread-safe
script engines with templating libraries not designed for concurrency, such as Handlebars or
@ -251,13 +243,11 @@ to https://bugs.openjdk.java.net/browse/JDK-8076099[this bug].
`polyfill.js` defines only the `window` object needed by Handlebars to run properly,
as the following snippet shows:
====
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
var window = {};
----
====
This basic `render.js` implementation compiles the template before using it. A production
ready implementation should also store and reused cached templates or pre-compiled templates.
@ -265,7 +255,6 @@ This can be done on the script side, as well as any customization you need (mana
template engine configuration for example).
The following example shows how compile a template:
====
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
@ -274,7 +263,6 @@ The following example shows how compile a template:
return compiledTemplate(model);
}
----
====
Check out the Spring Framework unit tests,
https://github.com/spring-projects/spring-framework/tree/master/spring-webflux/src/test/java/org/springframework/web/reactive/result/view/script[Java], and

View File

@ -38,7 +38,6 @@ You can also use `WebClient.builder()` with further options:
The following example configures <<web-reactive.adoc#webflux-codecs,HTTP codecs>>:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -52,12 +51,10 @@ The following example configures <<web-reactive.adoc#webflux-codecs,HTTP codecs>
.exchangeStrategies(strategies)
.build();
----
====
Once built, a `WebClient` instance is immutable. However, you can clone it and build a
modified copy without affecting the original instance, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -71,7 +68,6 @@ modified copy without affecting the original instance, as the following example
// client2 has filterA, filterB, filterC, filterD
----
====
@ -80,7 +76,6 @@ modified copy without affecting the original instance, as the following example
To customize Reactor Netty settings, simple provide a pre-configured `HttpClient`:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -90,7 +85,6 @@ To customize Reactor Netty settings, simple provide a pre-configured `HttpClient
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
----
====
[[webflux-client-builder-reactor-resources]]
@ -108,7 +102,6 @@ application deployed as a WAR), you can declare a Spring-managed bean of type
Netty global resources are shut down when the Spring `ApplicationContext` is closed,
as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -117,13 +110,11 @@ as the following example shows:
return new ReactorResourceFactory();
}
----
====
You can also choose not to participate in the global Reactor Netty resources. However,
in this mode, the burden is on you to ensure that all Reactor Netty client and server
instances use shared resources, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -150,7 +141,6 @@ instances use shared resources, as the following example shows:
<1> Create resources independent of global ones.
<2> Use the `ReactorClientHttpConnector` constructor with resource factory.
<3> Plug the connector into the `WebClient.Builder`.
====
[[webflux-client-builder-reactor-timeout]]
@ -158,7 +148,6 @@ instances use shared resources, as the following example shows:
To configure a connection timeout:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -168,11 +157,9 @@ HttpClient httpClient = HttpClient.create()
.tcpConfiguration(client ->
client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000));
----
====
To configure a read and/or write timeout values:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -185,7 +172,6 @@ HttpClient httpClient = HttpClient.create()
.addHandlerLast(new ReadTimeoutHandler(10))
.addHandlerLast(new WriteTimeoutHandler(10))));
----
====
@ -194,7 +180,6 @@ HttpClient httpClient = HttpClient.create()
The following example shows how to customize Jetty `HttpClient` settings:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -204,7 +189,6 @@ The following example shows how to customize Jetty `HttpClient` settings:
WebClient webClient = WebClient.builder().clientConnector(connector).build();
----
====
By default, `HttpClient` creates its own resources (`Executor`, `ByteBufferPool`, `Scheduler`),
which remain active until the process exits or `stop()` is called.
@ -214,7 +198,6 @@ ensure that the resources are shut down when the Spring `ApplicationContext` is
declaring a Spring-managed bean of type `JettyResourceFactory`, as the following example
shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -238,7 +221,6 @@ shows:
----
<1> Use the `JettyClientHttpConnector` constructor with resource factory.
<2> Plug the connector into the `WebClient.Builder`.
====
@ -249,7 +231,6 @@ shows:
The `retrieve()` method is the easiest way to get a response body and decode it.
The following example shows how to do so:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -260,11 +241,9 @@ The following example shows how to do so:
.retrieve()
.bodyToMono(Person.class);
----
====
You can also get a stream of objects decoded from the response, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -273,7 +252,6 @@ You can also get a stream of objects decoded from the response, as the following
.retrieve()
.bodyToFlux(Quote.class);
----
====
By default, responses with 4xx or 5xx status codes result in an
`WebClientResponseException` or one of its HTTP status specific sub-classes, such as
@ -281,7 +259,6 @@ By default, responses with 4xx or 5xx status codes result in an
You can also use the `onStatus` method to customize the resulting exception,
as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -292,7 +269,6 @@ as the following example shows:
.onStatus(HttpStatus::is5xxServerError, response -> ...)
.bodyToMono(Person.class);
----
====
When `onStatus` is used, if the response is expected to have content, then the `onStatus`
callback should consume it. If not, the content will be automatically drained to ensure
@ -307,7 +283,6 @@ resources are released.
The `exchange()` method provides more control than the `retrieve` method. The following example is equivalent
to `retrieve()` but also provides access to the `ClientResponse`:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -316,11 +291,9 @@ to `retrieve()` but also provides access to the `ClientResponse`:
.exchange()
.flatMap(response -> response.bodyToMono(Person.class));
----
====
At this level, you can also create a full `ResponseEntity`:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -329,7 +302,6 @@ At this level, you can also create a full `ResponseEntity`:
.exchange()
.flatMap(response -> response.toEntity(Person.class));
----
====
Note that (unlike `retrieve()`), with `exchange()`, there are no automatic error signals for
4xx and 5xx responses. You have to check the status code and decide how to proceed.
@ -348,7 +320,6 @@ is closed and is not placed back in the pool.
The request body can be encoded from an `Object`, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -361,11 +332,9 @@ The request body can be encoded from an `Object`, as the following example shows
.retrieve()
.bodyToMono(Void.class);
----
====
You can also have a stream of objects be encoded, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -378,12 +347,10 @@ You can also have a stream of objects be encoded, as the following example shows
.retrieve()
.bodyToMono(Void.class);
----
====
Alternatively, if you have the actual value, you can use the `syncBody` shortcut method,
as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -396,7 +363,6 @@ as the following example shows:
.retrieve()
.bodyToMono(Void.class);
----
====
@ -407,7 +373,6 @@ To send form data, you can provide a `MultiValueMap<String, String>` as the body
content is automatically set to `application/x-www-form-urlencoded` by the
`FormHttpMessageWriter`. The following example shows how to use `MultiValueMap<String, String>`:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -419,11 +384,9 @@ content is automatically set to `application/x-www-form-urlencoded` by the
.retrieve()
.bodyToMono(Void.class);
----
====
You can also supply form data in-line by using `BodyInserters`, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -435,7 +398,6 @@ You can also supply form data in-line by using `BodyInserters`, as the following
.retrieve()
.bodyToMono(Void.class);
----
====
@ -467,7 +429,6 @@ builder `part` methods.
Once a `MultiValueMap` is prepared, the easiest way to pass it to the the `WebClient` is
through the `syncBody` method, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -479,7 +440,6 @@ through the `syncBody` method, as the following example shows:
.retrieve()
.bodyToMono(Void.class);
----
====
If the `MultiValueMap` contains at least one non-`String` value, which could also
represent regular form data (that is, `application/x-www-form-urlencoded`), you need not
@ -489,7 +449,6 @@ set the `Content-Type` to `multipart/form-data`. This is always the case when us
As an alternative to `MultipartBodyBuilder`, you can also provide multipart content,
inline-style, through the built-in `BodyInserters`, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -501,7 +460,6 @@ inline-style, through the built-in `BodyInserters`, as the following example sho
.retrieve()
.bodyToMono(Void.class);
----
====
@ -512,7 +470,6 @@ inline-style, through the built-in `BodyInserters`, as the following example sho
You can register a client filter (`ExchangeFilterFunction`) through the `WebClient.Builder`
in order to intercept and modify requests, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -527,12 +484,10 @@ WebClient client = WebClient.builder()
})
.build();
----
====
This can be used for cross-cutting concerns, such as authentication. The following example uses
a filter for basic authentication through a static factory method:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -543,13 +498,11 @@ WebClient client = WebClient.builder()
.filter(basicAuthentication("user", "password"))
.build();
----
====
Filters apply globally to every request. To change a filter's behavior for a specific
request, you can add request attributes to the `ClientRequest` that can then be accessed
by all filters in the chain, as the following example shows:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -567,13 +520,11 @@ client.get().uri("http://example.org/")
}
----
====
You can also replicate an existing `WebClient`, insert new filters, or remove already
registered filters. The following example, inserts a basic authentication filter at
index 0:
====
[source,java,intent=0]
[subs="verbatim,quotes"]
----
@ -586,7 +537,6 @@ WebClient client = webClient.mutate()
})
.build();
----
====

View File

@ -26,7 +26,6 @@ server-side applications that handle WebSocket messages.
To create a WebSocket server, you can first create a `WebSocketHandler`.
The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -41,11 +40,9 @@ The following example shows how to do so:
}
}
----
====
Then you can map it to a URL and add a `WebSocketHandlerAdapter`, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -69,7 +66,6 @@ Then you can map it to a URL and add a `WebSocketHandlerAdapter`, as the followi
}
}
----
====
@ -110,7 +106,6 @@ receives a cancellation signal.
The most basic implementation of a handler is one that handles the inbound stream. The
following example shows such an implementation:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -133,7 +128,7 @@ class ExampleHandler implements WebSocketHandler {
<2> Do something with each message.
<3> Perform nested asynchronous operations that use the message content.
<4> Return a `Mono<Void>` that completes when receiving completes.
====
TIP: For nested, asynchronous operations, you may need to call `message.retain()` on underlying
servers that use pooled data buffers (for example, Netty). Otherwise, the data buffer may be
@ -142,7 +137,6 @@ released before you have had a chance to read the data. For more background, see
The following implementation combines the inbound and outbound streams:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -167,12 +161,11 @@ class ExampleHandler implements WebSocketHandler {
<1> Handle the inbound message stream.
<2> Create the outbound message, producing a combined flow.
<3> Return a `Mono<Void>` that does not complete while we continue to receive.
====
Inbound and outbound streams can be independent and be joined only for completion,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -200,7 +193,6 @@ class ExampleHandler implements WebSocketHandler {
<1> Handle inbound message stream.
<2> Send outgoing messages.
<3> Join the streams and return a `Mono<Void>` that completes when either stream ends.
====
@ -243,7 +235,6 @@ The `RequestUpgradeStrategy` for each server exposes WebSocket-related configura
options available for the underlying WebSocket engine. The following example sets
WebSocket options when running on Tomcat:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -263,7 +254,6 @@ WebSocket options when running on Tomcat:
}
}
----
====
Check the upgrade strategy for your server to see what options are available. Currently,
only Tomcat and Jetty expose such options.
@ -296,7 +286,6 @@ API to suspend receiving messages for back pressure.
To start a WebSocket session, you can create an instance of the client and use its `execute`
methods:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -308,7 +297,6 @@ client.execute(url, session ->
.doOnNext(System.out::println)
.then());
----
====
Some clients, such as Jetty, implement `Lifecycle` and need to be stopped and started
before you can use them. All clients have constructor options related to configuration

File diff suppressed because it is too large Load Diff

View File

@ -83,7 +83,6 @@ The {api-spring-framework}/web/bind/annotation/CrossOrigin.html[`@CrossOrigin`]
annotation enables cross-origin requests on annotated controller methods,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -103,7 +102,6 @@ public class AccountController {
}
}
----
====
By default, `@CrossOrigin` allows:
@ -120,7 +118,6 @@ should only be used where appropriate.
`@CrossOrigin` is supported at the class level, too, and is inherited by all methods,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -140,12 +137,10 @@ public class AccountController {
}
}
----
====
You can use `@CrossOrigin` at both the class level and the method level,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -166,7 +161,6 @@ public class AccountController {
}
}
----
====
@ -202,7 +196,6 @@ should only be used where appropriate.
To enable CORS in the MVC Java config, you can use the `CorsRegistry` callback,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -224,7 +217,6 @@ public class WebConfig implements WebMvcConfigurer {
}
}
----
====
@ -234,7 +226,6 @@ public class WebConfig implements WebMvcConfigurer {
To enable CORS in the XML namespace, you can use the `<mvc:cors>` element,
as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim"]
----
@ -252,7 +243,6 @@ as the following example shows:
</mvc:cors>
----
====
@ -272,7 +262,6 @@ for CORS.
To configure the filter, pass a
`CorsConfigurationSource` to its constructor, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim"]
----
@ -291,4 +280,3 @@ source.registerCorsConfiguration("/**", config);
CorsFilter filter = new CorsFilter(source);
----
====

View File

@ -46,7 +46,6 @@ integration for using Spring MVC with FreeMarker templates.
The following example shows how to configure FreeMarker as a view technology:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -69,11 +68,9 @@ The following example shows how to configure FreeMarker as a view technology:
}
}
----
====
The following example shows how to configure the same in XML:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -88,12 +85,10 @@ The following example shows how to configure the same in XML:
<mvc:template-loader-path location="/WEB-INF/freemarker"/>
</mvc:freemarker-configurer>
----
====
Alternatively, you can also declare the `FreeMarkerConfigurer` bean for full control over all
properties, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -101,7 +96,6 @@ properties, as the following example shows:
<property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
</bean>
----
====
Your templates need to be stored in the directory specified by the `FreeMarkerConfigurer`
shown in the preceding example. Given the preceding configuration, if your controller returns a view name
@ -119,7 +113,6 @@ the `FreeMarkerConfigurer` bean. The `freemarkerSettings` property requires a
`java.util.Properties` object, and the `freemarkerVariables` property requires a
`java.util.Map`. The following example shows how to do so:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -134,7 +127,6 @@ the `FreeMarkerConfigurer` bean. The `freemarkerSettings` property requires a
<bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape"/>
----
====
See the FreeMarker documentation for details of settings and variables as they apply to
the `Configuration` object.
@ -173,7 +165,6 @@ controller, you can use code similar to the next example to bind to field values
display error messages for each input field in similar fashion to the JSP equivalent.
The following example shows the `personForm` view that was configured earlier:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -196,7 +187,6 @@ The following example shows the `personForm` view that was configured earlier:
...
</html>
----
====
`<@spring.bind>` requires a 'path' argument, which consists of the name of your command
object (it is 'command', unless you changed it in your `FormController` properties)
@ -318,14 +308,12 @@ time, a class name or style attribute. Note that FreeMarker can specify default
values for the attributes parameter. The following example shows how to use the `formInput`
and `showWErrors` macros:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<@spring.formInput "command.name"/>
<@spring.showErrors "<br>"/>
----
====
The next example shows the output of the form fragment, generating the name field and displaying a
validation error after the form was submitted with no value in the field. Validation
@ -333,7 +321,6 @@ occurs through Spring's Validation framework.
The generated HTML resembles the following example:
====
[source,jsp,indent=0]
[subs="verbatim,quotes"]
----
@ -344,7 +331,6 @@ The generated HTML resembles the following example:
<br>
<br>
----
====
The `formTextarea` macro works the same way as the `formInput` macro and accepts the same
parameter list. Commonly, the second parameter (attributes) is used to pass style
@ -370,7 +356,6 @@ value of 'London' for this field, so no validation is necessary. When the form i
rendered, the entire list of cities to choose from is supplied as reference data in the
model under the name 'cityMap'. The following listing shows the example:
====
[source,jsp,indent=0]
[subs="verbatim,quotes"]
----
@ -378,7 +363,6 @@ model under the name 'cityMap'. The following listing shows the example:
Town:
<@spring.formRadioButtons "command.address.town", cityMap, ""/><br><br>
----
====
The preceding listing renders a line of radio buttons, one for each value in `cityMap`, and uses a
separator of `""`. No additional attributes are supplied (the last parameter to the macro is
@ -387,7 +371,6 @@ keys are what the form actually submits as POSTed request parameters. The map va
labels that the user sees. In the preceding example, given a list of three well known cities
and a default value in the form backing object, the HTML resembles the following:
====
[source,jsp,indent=0]
[subs="verbatim,quotes"]
----
@ -396,12 +379,10 @@ and a default value in the form backing object, the HTML resembles the following
<input type="radio" name="address.town" value="Paris" checked="checked">Paris</input>
<input type="radio" name="address.town" value="New York">New York</input>
----
====
If your application expects to handle cities by internal codes (for example), you can create the map of
codes with suitable keys, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -416,12 +397,10 @@ codes with suitable keys, as the following example shows:
return model;
}
----
====
The code now produces output where the radio values are the relevant codes, but the
user still sees the more user-friendly city names, as follows:
====
[source,jsp,indent=0]
[subs="verbatim,quotes"]
----
@ -430,7 +409,6 @@ user still sees the more user-friendly city names, as follows:
<input type="radio" name="address.town" value="PRS" checked="checked">Paris</input>
<input type="radio" name="address.town" value="NYC">New York</input>
----
====
[[mvc-views-form-macros-html-escaping]]
@ -447,21 +425,18 @@ template processing to provide different behavior for different fields in your f
To switch to XHTML compliance for your tags, specify a value of `true` for a
model or context variable named `xhtmlCompliant`, as the following example shows:
====
[source,jsp,indent=0]
[subs="verbatim,quotes"]
----
<#-- for FreeMarker -->
<#assign xhtmlCompliant = true>
----
====
After processing
this directive, any elements generated by the Spring macros are now XHTML compliant.
In similar fashion, you can specify HTML escaping per field, as the following example shows:
====
[source,jsp,indent=0]
[subs="verbatim,quotes"]
----
@ -474,7 +449,6 @@ In similar fashion, you can specify HTML escaping per field, as the following ex
<#assign htmlEscape = false in spring>
<#-- all future fields will be bound with HTML escaping off -->
----
====
@ -496,7 +470,6 @@ NOTE: The Groovy Markup Template engine requires Groovy 2.3.1+.
The following example shows how to configure the Groovy Markup Template Engine:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -519,11 +492,9 @@ The following example shows how to configure the Groovy Markup Template Engine:
}
}
----
====
The following example shows how to configure the same in XML:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -536,7 +507,6 @@ The following example shows how to configure the same in XML:
<!-- Configure the Groovy Markup Template Engine... -->
<mvc:groovy-configurer resource-loader-path="/WEB-INF/"/>
----
====
@ -546,7 +516,6 @@ The following example shows how to configure the same in XML:
Unlike traditional template engines, Groovy Markup relies on a DSL that uses a builder
syntax. The following example shows a sample template for an HTML page:
====
[source,groovy,indent=0]
[subs="verbatim,quotes"]
----
@ -561,7 +530,6 @@ syntax. The following example shows a sample template for an HTML page:
}
}
----
====
@ -620,7 +588,6 @@ You can declare a `ScriptTemplateConfigurer` bean to specify the script engine t
the script files to load, what function to call to render templates, and so on.
The following example uses Mustache templates and the Nashorn JavaScript engine:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -644,11 +611,9 @@ The following example uses Mustache templates and the Nashorn JavaScript engine:
}
}
----
====
The following example shows the same arrangement in XML:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -662,11 +627,9 @@ The following example shows the same arrangement in XML:
<mvc:script location="mustache.js"/>
</mvc:script-template-configurer>
----
====
The controller would look no different for the Java and XML configurations, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -681,11 +644,9 @@ The controller would look no different for the Java and XML configurations, as t
}
}
----
====
The following example shows the Mustache template:
====
[source,html,indent=0]
[subs="verbatim,quotes"]
----
@ -698,7 +659,6 @@ The following example shows the Mustache template:
</body>
</html>
----
====
The render function is called with the following parameters:
@ -719,7 +679,6 @@ browser facilities that are not available in the server-side script engine.
The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -743,7 +702,6 @@ The following example shows how to do so:
}
}
----
====
NOTE: Setting the `sharedEngine` property to `false` is required when you use non-thread-safe
script engines with templating libraries not designed for concurrency, such as Handlebars or
@ -752,20 +710,17 @@ to https://bugs.openjdk.java.net/browse/JDK-8076099[this bug].
`polyfill.js` defines only the `window` object needed by Handlebars to run properly, as follows:
====
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
var window = {};
----
====
This basic `render.js` implementation compiles the template before using it. A production-ready
implementation should also store any reused cached templates or pre-compiled templates.
You can do so on the script side (and handle any customization you need -- managing
template engine configuration, for example). The following example shows how to do so:
====
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
@ -774,7 +729,6 @@ template engine configuration, for example). The following example shows how to
return compiledTemplate(model);
}
----
====
Check out the Spring Framework unit tests,
https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc/src/test/java/org/springframework/web/servlet/view/script[Java], and
@ -801,7 +755,6 @@ When developing with JSPs, you can declare a `InternalResourceViewResolver` or a
mapped to a class and a URL. With a `ResourceBundleViewResolver`, you
can mix different types of views byusing only one resolver, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -831,7 +784,6 @@ directory so there can be no direct access by clients.
<property name="suffix" value=".jsp"/>
</bean>
----
====
@ -884,14 +836,12 @@ called `spring-form.tld`.
To use the tags from this library, add the following directive to the top of your JSP
page:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
----
where `form` is the tag name prefix you want to use for the tags from this library.
====
[[mvc-view-jsp-formtaglib-formtag]]
@ -907,7 +857,6 @@ such as `firstName` and `lastName`. We can use it as the form-backing object of
form controller, which returns `form.jsp`. The following example shows what `form.jsp` could
look like:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -929,7 +878,6 @@ look like:
</table>
</form:form>
----
====
The `firstName` and `lastName` values are retrieved from the command object placed in
the `PageContext` by the page controller. Keep reading to see more complex examples of
@ -937,7 +885,6 @@ how inner tags are used with the `form` tag.
The following listing shows the generated HTML, which looks like a standard form:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -959,14 +906,12 @@ The following listing shows the generated HTML, which looks like a standard form
</table>
</form>
----
====
The preceding JSP assumes that the variable name of the form-backing object is
`command`. If you have put the form-backing object into the model under another name
(definitely a best practice), you can bind the form to the named variable, as the
following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -988,7 +933,6 @@ following example shows:
</table>
</form:form>
----
====
[[mvc-view-jsp-formtaglib-inputtag]]
@ -1008,7 +952,6 @@ This tag renders an HTML `input` tag with the `type` set to `checkbox`.
Assume that our `User` has preferences such as newsletter subscription and a list of
hobbies. The following example shows the `Preferences` class:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1043,11 +986,9 @@ hobbies. The following example shows the `Preferences` class:
}
}
----
====
The corresponding `form.jsp` could then resemble the following:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1079,7 +1020,6 @@ The corresponding `form.jsp` could then resemble the following:
</table>
</form:form>
----
====
There are three approaches to the `checkbox` tag, which should meet all your checkbox needs.
@ -1095,7 +1035,6 @@ There are three approaches to the `checkbox` tag, which should meet all your che
Note that, regardless of the approach, the same HTML structure is generated. The following
HTML snippet defines some checkboxes:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1111,7 +1050,6 @@ HTML snippet defines some checkboxes:
</td>
</tr>
----
====
You might not expect to see the additional hidden field after each checkbox.
When a checkbox in an HTML page is not checked, its value is not sent to the
@ -1137,7 +1075,6 @@ the available options in the `items` property. Typically, the bound property is
collection so that it can hold multiple values selected by the user. The following example
shows a JSP that uses this tag:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1153,7 +1090,6 @@ shows a JSP that uses this tag:
</table>
</form:form>
----
====
This example assumes that the `interestList` is a `List` available as a model attribute
that contains strings of the values to be selected from. If you use a `Map`,
@ -1171,7 +1107,6 @@ This tag renders an HTML `input` element with the `type` set to `radio`.
A typical usage pattern involves multiple tag instances bound to the same property
but with different values, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1183,7 +1118,6 @@ but with different values, as the following example shows:
</td>
</tr>
----
====
@ -1200,7 +1134,6 @@ entry's value are used as the label to be displayed. You can also use a custom
object where you can provide the property names for the value by using `itemValue` and the
label by using `itemLabel`, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1209,7 +1142,6 @@ label by using `itemLabel`, as the following example shows:
<td><form:radiobuttons path="sex" items="${sexOptions}"/></td>
</tr>
----
====
[[mvc-view-jsp-formtaglib-passwordtag]]
@ -1217,7 +1149,6 @@ label by using `itemLabel`, as the following example shows:
This tag renders an HTML `input` tag with the type set to `password` with the bound value.
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1228,13 +1159,11 @@ This tag renders an HTML `input` tag with the type set to `password` with the bo
</td>
</tr>
----
====
Note that, by default, the password value is not shown. If you do want the
password value to be shown, you can set the value of the `showPassword` attribute to
`true`, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1245,7 +1174,6 @@ password value to be shown, you can set the value of the `showPassword` attribut
</td>
</tr>
----
====
[[mvc-view-jsp-formtaglib-selecttag]]
@ -1256,7 +1184,6 @@ option as well as the use of nested `option` and `options` tags.
Assume that a `User` has a list of skills. The corresponding HTML could be as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1265,12 +1192,10 @@ Assume that a `User` has a list of skills. The corresponding HTML could be as fo
<td><form:select path="skills" items="${skills}"/></td>
</tr>
----
====
If the `User's` skill are in Herbology, the HTML source of the 'Skills' row could be
as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1285,7 +1210,6 @@ as follows:
</td>
</tr>
----
====
@ -1295,7 +1219,6 @@ as follows:
This tag renders an HTML `option` element. It sets `selected`, based on the bound
value. The following HTML shows typical output for it:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1311,12 +1234,10 @@ value. The following HTML shows typical output for it:
</td>
</tr>
----
====
If the `User's` house was in Gryffindor, the HTML source of the 'House' row would be
as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1333,7 +1254,6 @@ as follows:
</tr>
----
<1> Note the addition of a `selected` attribute.
====
@ -1343,7 +1263,6 @@ as follows:
This tag renders a list of HTML `option` elements. It sets the `selected` attribute,
based on the bound value. The following HTML shows typical output for it:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1357,11 +1276,9 @@ based on the bound value. The following HTML shows typical output for it:
</td>
</tr>
----
====
If the `User` lived in the UK, the HTML source of the 'Country' row would be as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1378,7 +1295,7 @@ If the `User` lived in the UK, the HTML source of the 'Country' row would be as
</tr>
----
<1> Note the addition of a `selected` attribute.
====
As the preceding example shows, the combined usage of an `option` tag with the `options` tag
generates the same standard HTML but lets you explicitly specify a value in the
@ -1400,7 +1317,6 @@ the item label property applies to the map value.
This tag renders an HTML `textarea` element. The following HTML shows typical output for it:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1410,7 +1326,6 @@ This tag renders an HTML `textarea` element. The following HTML shows typical ou
<td><form:errors path="notes"/></td>
</tr>
----
====
[[mvc-view-jsp-formtaglib-hiddeninputtag]]
@ -1420,24 +1335,20 @@ This tag renders an HTML `input` tag with the `type` set to `hidden` with the bo
an unbound hidden value, use the HTML `input` tag with the `type` set to `hidden`.
The following HTML shows typical output for it:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<form:hidden path="house"/>
----
====
If we choose to submit the `house` value as a hidden one, the HTML would be as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
<input name="house" type="hidden" value="Gryffindor"/>
----
====
[[mvc-view-jsp-formtaglib-errorstag]]
@ -1451,7 +1362,6 @@ Assume that we want to display all error messages for the `firstName` and `lastN
fields once we submit the form. We have a validator for instances of the `User` class
called `UserValidator`, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1467,11 +1377,9 @@ called `UserValidator`, as the following example shows:
}
}
----
====
The `form.jsp` could be as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1498,12 +1406,10 @@ The `form.jsp` could be as follows:
</table>
</form:form>
----
====
If we submit a form with empty values in the `firstName` and `lastName` fields,
the HTML would be as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1530,7 +1436,6 @@ the HTML would be as follows:
</table>
</form>
----
====
What if we want to display the entire list of errors for a given page? The next example
shows that the `errors` tag also supports some basic wildcarding functionality.
@ -1542,7 +1447,6 @@ shows that the `errors` tag also supports some basic wildcarding functionality.
The following example displays a list of errors at the top of the page, followed by
field-specific errors next to the fields:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1567,11 +1471,9 @@ field-specific errors next to the fields:
</table>
</form:form>
----
====
The HTML would be as follows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1597,7 +1499,6 @@ The HTML would be as follows:
</table>
</form>
----
====
The `spring-form.tld` tag library descriptor (TLD) is included in the `spring-webmvc.jar`.
For a comprehensive reference on individual tags, browse the
@ -1628,7 +1529,6 @@ To support HTTP method conversion, the Spring MVC form tag was updated to suppor
the HTTP method. For example, the following snippet comes from the Pet Clinic
sample:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1636,13 +1536,11 @@ sample:
<p class="submit"><input type="submit" value="Delete Pet"/></p>
</form:form>
----
====
The preceding example perform an HTTP POST, with the "`real`" DELETE method hidden behind a
request parameter. It is picked up by the `HiddenHttpMethodFilter`, which is defined in
web.xml, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1656,11 +1554,9 @@ web.xml, as the following example shows:
<servlet-name>petclinic</servlet-name>
</filter-mapping>
----
====
The following example shows the corresponding `@Controller` method:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1670,7 +1566,6 @@ The following example shows the corresponding `@Controller` method:
return "redirect:/owners/" + ownerId;
}
----
====
[[mvc-view-jsp-formtaglib-html5]]
@ -1715,7 +1610,6 @@ To be able to use Tiles, you have to configure it by using files that contain de
http://tiles.apache.org[]). In Spring, this is done by using the `TilesConfigurer`.
The following example `ApplicationContext` configuration shows how to do so:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1731,7 +1625,6 @@ The following example `ApplicationContext` configuration shows how to do so:
</property>
</bean>
----
====
The preceding example defines five files that contain definitions. The files are all located in
the `WEB-INF/defs` directory. At initialization of the `WebApplicationContext`, the
@ -1744,7 +1637,6 @@ implementations, the `UrlBasedViewResolver` and the `ResourceBundleViewResolver`
You can specify locale-specific Tiles definitions by adding an underscore and then
the locale, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1757,7 +1649,6 @@ the locale, as the following example shows:
</property>
</bean>
----
====
With the preceding configuration, `tiles_fr_FR.xml` is used for requests with the `fr_FR` locale,
and `tiles.xml` is used by default.
@ -1773,7 +1664,6 @@ them otherwise in the file names for Tiles definitions.
The `UrlBasedViewResolver` instantiates the given `viewClass` for each view it has to
resolve. The following bean defines a `UrlBasedViewResolver`:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1781,7 +1671,6 @@ resolve. The following bean defines a `UrlBasedViewResolver`:
<property name="viewClass" value="org.springframework.web.servlet.view.tiles3.TilesView"/>
</bean>
----
====
[[mvc-view-tiles-resource]]
@ -1792,7 +1681,6 @@ view names and view classes that the resolver can use. The following example sho
definition for a `ResourceBundleViewResolver` and the corresponding view names and view
classes (taken from the Pet Clinic sample):
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1815,7 +1703,6 @@ classes (taken from the Pet Clinic sample):
findOwnersForm.url=/WEB-INF/jsp/findOwners.jsp
...
----
====
When you use the `ResourceBundleViewResolver`, you can easily mix
different view technologies.
@ -1845,7 +1732,6 @@ configuration, scoped beans, and so on. Note that you need to define one Spring
for each preparer name (as used in your Tiles definitions). The following example shows
how to define a set a `SpringBeanPreparerFactory` property on a `TilesConfigurer` bean:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -1866,7 +1752,6 @@ how to define a set a `SpringBeanPreparerFactory` property on a `TilesConfigurer
</bean>
----
====
@ -1883,7 +1768,6 @@ package `org.springframework.web.servlet.view.feed`.
optionally override the `buildFeedMetadata()` method (the default implementation is
empty). The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1903,11 +1787,9 @@ empty). The following example shows how to do so:
}
----
====
Similar requirements apply for implementing `AbstractRssFeedView`, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1926,7 +1808,6 @@ Similar requirements apply for implementing `AbstractRssFeedView`, as the follow
}
}
----
====
The `buildFeedItems()` and `buildFeedEntries()` methods pass in the HTTP request, in case
you need to access the Locale. The HTTP response is passed in only for the setting of
@ -1973,7 +1854,6 @@ A simple PDF view for a word list could extend
`org.springframework.web.servlet.view.document.AbstractPdfView` and implement the
`buildPdfDocument()` method, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1989,7 +1869,6 @@ A simple PDF view for a word list could extend
}
}
----
====
A controller can return such a view either from an external view definition
(referencing it by name) or as a `View` instance from the handler method.
@ -2094,7 +1973,6 @@ Configuration is standard for a simple Spring web application: The MVC configura
has to define an `XsltViewResolver` bean and regular MVC annotation configuration.
The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -2112,7 +1990,6 @@ public class WebConfig implements WebMvcConfigurer {
}
}
----
====
@ -2124,7 +2001,6 @@ We also need a Controller that encapsulates our word-generation logic.
The controller logic is encapsulated in a `@Controller` class, with the
handler method being defined as follows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -2149,7 +2025,6 @@ handler method being defined as follows:
}
}
----
====
So far, we have only created a DOM document and added it to the Model map. Note that you
can also load an XML file as a `Resource` and use it instead of a custom DOM document.
@ -2172,7 +2047,6 @@ and end with an `xslt` file extension.
The following example shows an XSLT transform:
====
[source,xml,indent=0]
[subs="verbatim,quotes"]
----
@ -2199,11 +2073,9 @@ The following example shows an XSLT transform:
</xsl:stylesheet>
----
====
The preceding transform is rendered as the following HTML:
====
[source,html,indent=0]
[subs="verbatim,quotes"]
----
@ -2222,4 +2094,3 @@ The preceding transform is rendered as the following HTML:
</body>
</html>
----
====

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,6 @@ A WebSocket interaction begins with an HTTP request that uses the HTTP `Upgrade`
to upgrade or, in this case, to switch to the WebSocket protocol. The following example
shows such an interaction:
====
[source,yaml,indent=0]
[subs="verbatim,quotes"]
----
@ -25,12 +24,11 @@ shows such an interaction:
----
<1> The `Upgrade` header.
<2> Using the `Upgrade` connection.
====
Instead of the usual 200 status code, a server with WebSocket support returns output
similar to the following:
====
[source,yaml,indent=0]
[subs="verbatim,quotes"]
----
@ -41,7 +39,7 @@ similar to the following:
Sec-WebSocket-Protocol: v10.stomp
----
<1> Protocol switch
====
After a successful handshake, the TCP socket underlying the HTTP upgrade request remains
open for both the client and the server to continue to send and receive messages.

View File

@ -29,7 +29,6 @@ Creating a WebSocket server is as simple as implementing `WebSocketHandler` or,
likely, extending either `TextWebSocketHandler` or `BinaryWebSocketHandler`. The following
example uses `TextWebSocketHandler`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -46,12 +45,10 @@ example uses `TextWebSocketHandler`:
}
----
====
There is dedicated WebSocket Java configuration and XML namespace support for mapping the preceding
WebSocket handler to a specific URL, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -75,11 +72,9 @@ WebSocket handler to a specific URL, as the following example shows:
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@ -100,7 +95,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
The preceding example is for use in Spring MVC applications and should be included in the
configuration of a <<mvc-servlet,`DispatcherServlet`>>. However, Spring's WebSocket
@ -126,7 +120,6 @@ You can use such an interceptor to preclude the handshake or to make any attribu
available to the `WebSocketSession`. The following example uses a built-in interceptor
to pass HTTP session attributes to the WebSocket session:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -142,11 +135,9 @@ to pass HTTP session attributes to the WebSocket session:
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@ -170,7 +161,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
A more advanced option is to extend the `DefaultHandshakeHandler` that performs
the steps of the WebSocket handshake, including validating the client origin,
@ -228,7 +218,6 @@ 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 `<absolute-ordering />` element in `web.xml`, as the following example shows:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@ -243,13 +232,11 @@ through the use of the `<absolute-ordering />` element in `web.xml`, as the foll
</web-app>
----
====
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. The following example shows how to do so:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@ -266,7 +253,6 @@ Java initialization API. The following example shows how to do so:
</web-app>
----
====
@ -281,7 +267,6 @@ and others.
For Tomcat, WildFly, and GlassFish, you can add a `ServletServerContainerFactoryBean` to your
WebSocket Java config, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -299,11 +284,9 @@ WebSocket Java config, as the following example shows:
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@ -323,7 +306,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
NOTE: For client-side WebSocket configuration, you should use `WebSocketContainerFactoryBean`
(XML) or `ContainerProvider.getWebSocketContainer()` (Java configuration).
@ -332,7 +314,6 @@ For Jetty, you need to supply a pre-configured Jetty `WebSocketServerFactory` an
that into Spring's `DefaultHandshakeHandler` through your WebSocket Java config.
The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -359,11 +340,9 @@ The following example shows how to do so:
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@ -401,7 +380,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
@ -430,7 +408,6 @@ The three possible behaviors are:
You can configure WebSocket and SockJS allowed origins, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -454,11 +431,9 @@ You can configure WebSocket and SockJS allowed origins, as the following example
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@ -479,7 +454,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
@ -532,7 +506,6 @@ polling is used.
All transport requests have the following URL structure:
====
----
http://host:port/myApp/myEndpoint/{server-id}/{session-id}/{transport}
----
@ -542,7 +515,6 @@ where:
* `{server-id}` is useful for routing requests in a cluster but is not used otherwise.
* `{session-id}` correlates HTTP requests belonging to a SockJS session.
* `{transport}` indicates the transport type (for example, `websocket`, `xhr-streaming`, and others).
====
The WebSocket transport needs only a single HTTP request to do the WebSocket handshake.
All messages thereafter are exchanged on that socket.
@ -572,7 +544,6 @@ http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html[narrated test
You can enable SockJS through Java configuration, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -592,11 +563,9 @@ You can enable SockJS through Java configuration, as the following example shows
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@ -618,7 +587,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
The preceding example is for use in Spring MVC applications and should be included in the
configuration of a <<mvc-servlet,`DispatcherServlet`>>. However, Spring's WebSocket
@ -690,7 +658,6 @@ a URL from the same origin as the application.
The following example shows how to do so in Java configuration:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -708,7 +675,6 @@ The following example shows how to do so in Java configuration:
}
----
====
The XML namespace provides a similar option through the `<websocket:sockjs>` element.
@ -821,7 +787,6 @@ to the server. At present there are two implementations:
The following example shows how to create a SockJS client and connect to a SockJS endpoint:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -832,7 +797,6 @@ The following example shows how to create a SockJS client and connect to a SockJ
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
@ -842,7 +806,6 @@ To use `SockJsClient` to simulate a large number of concurrent users, you
need to configure the underlying HTTP client (for XHR transports) to allow a sufficient
number of connections and threads. The following example shows how to do so with Jetty:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -850,12 +813,10 @@ HttpClient jettyHttpClient = new HttpClient();
jettyHttpClient.setMaxConnectionsPerDestination(1000);
jettyHttpClient.setExecutor(new QueuedThreadPool(1000));
----
====
The following example shows the server-side SockJS-related properties (see javadoc for details)
that you should also consider customizing:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -877,7 +838,6 @@ that you should also consider customizing:
<2> Set the `httpMessageCacheSize` property to 1,000 (the default is `100`).
<3> Set the `disconnectDelay` property to 30 property seconds (the default is five seconds
-- `5 * 1000`).
====
@ -908,7 +868,6 @@ either text or binary.
STOMP is a frame-based protocol whose frames are modeled on HTTP. The following listing shows the structure
of a STOMP frame:
====
----
COMMAND
header1:value1
@ -916,7 +875,6 @@ header2:value2
Body^@
----
====
Clients can use the `SEND` or `SUBSCRIBE` commands to send or subscribe for
messages, along with a `destination` header that describes what the
@ -940,7 +898,6 @@ The following example shows a client subscribing to receive stock quotes, which
the server may emit periodically (for example, via a scheduled task that sends messages
through a `SimpMessagingTemplate` to the broker):
====
----
SUBSCRIBE
id:sub-1
@ -948,12 +905,10 @@ destination:/topic/price.stock.*
^@
----
====
The following example shows a client that sends a trade request, which the server
can handle through an `@MessageMapping` method:
====
----
SEND
destination:/queue/trade
@ -962,7 +917,6 @@ content-length:44
{"action":"BUY","ticker":"MMM","shares",44}^@
----
====
After the execution, the server can
broadcast a trade confirmation message and details down to the client.
@ -977,7 +931,6 @@ exchanges.
STOMP servers can use the `MESSAGE` command to broadcast messages to all subscribers.
The following example shows a server sending a stock quote to a subscribed client:
====
----
MESSAGE
message-id:nxahklf6-1
@ -986,7 +939,6 @@ destination:/topic/price.stock.MMM
{"ticker":"MMM","price":129.45}^@
----
====
A server cannot send unsolicited messages. All messages
from a server must be in response to a specific client subscription, and the
@ -1026,7 +978,6 @@ STOMP over WebSocket support is available in the `spring-messaging` and
`spring-websocket` modules. Once you have those dependencies, you can expose a STOMP
endpoints, over WebSocket with <<websocket-fallback>>, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1056,11 +1007,10 @@ client needs to connect for the WebSocket handshake.
`@MessageMapping` methods in `@Controller` classes.
<3> Use the built-in message broker for subscriptions and broadcasting and
route messages whose destination header begins with `/topic `or `/queue` to the broker.
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@ -1082,7 +1032,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
NOTE: For the built-in simple broker, the `/topic` and `/queue` prefixes do not have any special
meaning. They are merely a convention to differentiate between pub-sub versus point-to-point
@ -1099,7 +1048,6 @@ https://github.com/JSteunou/webstomp-client[JSteunou/webstomp-client] is the mos
actively maintained and evolving successor of that library. The following example code
is based on it:
====
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
@ -1109,11 +1057,9 @@ is based on it:
stompClient.connect({}, function(frame) {
}
----
====
Alternatively, if you connect through WebSocket (without SockJS), you can use the following code:
====
[source,javascript,indent=0]
[subs="verbatim,quotes"]
----
@ -1123,7 +1069,6 @@ Alternatively, if you connect through WebSocket (without SockJS), you can use th
stompClient.connect({}, function(frame) {
}
----
====
Note that `stompClient` in the preceding example 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
@ -1146,7 +1091,6 @@ To configure the underlying WebSocket server, the information in
<<websocket-server-runtime-configuration>> applies. For Jetty, however you need to set
the `HandshakeHandler` and `WebSocketPolicy` through the `StompEndpointRegistry`:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1171,7 +1115,6 @@ the `HandshakeHandler` and `WebSocketPolicy` through the `StompEndpointRegistry`
}
}
----
====
@ -1237,7 +1180,6 @@ to broadcast to subscribed clients.
We can trace the flow through a simple example. Consider the following example, which sets up a server:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1269,7 +1211,6 @@ We can trace the flow through a simple example. Consider the following example,
}
----
====
The preceding example supports the following flow:
@ -1419,7 +1360,6 @@ when a subscription is stored and ready for broadcasts, a client should ask for
receipt if the server supports it (simple broker does not). For example, with the Java
<<websocket-stomp-client, STOMP client>>, you could do the following to add a receipt:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1438,7 +1378,6 @@ receipt if the server supports it (simple broker does not). For example, with th
// Subscription ready...
});
----
====
A server side option is <<websocket-stomp-interceptors,to register>> an
`ExecutorChannelInterceptor` on the `brokerChannel` and implement the `afterMessageHandled`
@ -1453,7 +1392,6 @@ An application can use `@MessageExceptionHandler` methods to handle exceptions f
itself or through a method argument if you want to get access to the exception instance.
The following example declares an exception through a method argument:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1469,7 +1407,6 @@ The following example declares an exception through a method argument:
}
}
----
====
`@MessageExceptionHandler` methods support flexible method signatures and support the same
method argument types and return values as <<websocket-stomp-message-mapping,`@MessageMapping`>> methods.
@ -1490,7 +1427,6 @@ The easiest way to do so is to inject a `SimpMessagingTemplate` and
use it to send messages. Typically, you would inject it by
type, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1512,7 +1448,6 @@ type, as the following example shows:
}
----
====
However, you can also qualify it by its name (`brokerMessagingTemplate`), if another
bean of the same type exists.
@ -1535,7 +1470,6 @@ https://stomp.github.io/stomp-specification-1.2.html#Heart-beating[STOMP heartbe
For that, you can declare your own scheduler or use the one that is automatically
declared and used internally. The following example shows how to declare your own scheduler:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1561,7 +1495,6 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
}
}
----
====
@ -1582,7 +1515,6 @@ and run it with STOMP support enabled. Then you can enable the STOMP broker rela
The following example configuration enables a full-featured broker:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1603,11 +1535,9 @@ The following example configuration enables a full-featured broker:
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@ -1629,7 +1559,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
The STOMP broker relay in the preceding configuration is a Spring
{api-spring-framework}/messaging/MessageHandler.html[`MessageHandler`]
@ -1688,7 +1617,6 @@ connectivity is lost, to the same host and port. If you wish to supply multiple
on each attempt to connect, you can configure a supplier of addresses, instead of a
fixed host and port. The following example shows how to do that:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1711,7 +1639,6 @@ public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
}
}
----
====
You can also configure the STOMP broker relay with a `virtualHost` property.
The value of this property is set as the `host` header of every `CONNECT` frame
@ -1731,7 +1658,6 @@ you are more used to messaging conventions, you can switch to using dot (`.`) as
The following example shows how to do so in Java configuration:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1749,11 +1675,9 @@ The following example shows how to do so in Java configuration:
}
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@ -1779,12 +1703,10 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
After that, a controller can use a dot (`.`) as the separator in `@MessageMapping` methods,
as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1798,7 +1720,6 @@ as the following example shows:
}
}
----
====
The client can now send a message to `/app/red.blue.green123`.
@ -1896,7 +1817,6 @@ the user header on the CONNECT `Message`. Spring notes and saves the authenticat
user and associate it with subsequent STOMP messages on the same session. The following
example shows how register a custom authentication interceptor:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1921,7 +1841,6 @@ example shows how register a custom authentication interceptor:
}
}
----
====
Also, note that, when you use Spring Security's authorization for messages, at present,
you need to ensure that the authentication `ChannelInterceptor` config is ordered
@ -1956,7 +1875,6 @@ A message-handling method can send messages to the user associated with
the message being handled through the `@SendToUser` annotation (also supported on
the class-level to share a common destination), as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1971,14 +1889,12 @@ the class-level to share a common destination), as the following example shows:
}
}
----
====
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. You can do so by
setting the `broadcast` attribute to false, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -1998,7 +1914,6 @@ setting the `broadcast` attribute to false, as the following example shows:
}
}
----
====
NOTE: While user destinations generally imply an authenticated user, it is not strictly required.
A WebSocket session that is not associated with an authenticated user
@ -2011,7 +1926,6 @@ component by, for example, injecting the `SimpMessagingTemplate` created by the
the XML namespace. (The bean name is `"brokerMessagingTemplate"` if required
for qualification with `@Qualifier`.) The following example shows how to do so:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -2033,7 +1947,6 @@ public class TradeServiceImpl implements TradeService {
}
}
----
====
NOTE: When you use user destinations with an external message broker, you should check the broker
documentation on how to manage inactive queues, so that, when the user session is
@ -2063,7 +1976,6 @@ not match the exact order of publication.
If this is an issue, enable the `setPreservePublishOrder` flag, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -2079,11 +1991,9 @@ If this is an issue, enable the `setPreservePublishOrder` flag, as the following
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@ -2102,7 +2012,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
When the flag is set, messages within the same client session are published to the
`clientOutboundChannel` one at a time, so that the order of publication is guaranteed.
@ -2158,7 +2067,6 @@ of a STOMP connection but not for every client message. Applications can also re
`ChannelInterceptor` to intercept any message and in any part of the processing chain.
The following example shows how to intercept inbound messages from clients:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -2172,12 +2080,10 @@ The following example shows how to intercept inbound messages from clients:
}
}
----
====
A custom `ChannelInterceptor` can use `StompHeaderAccessor` or `SimpMessageHeaderAccessor`
to access information about the message, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -2192,7 +2098,6 @@ to access information about the message, as the following example shows:
}
}
----
====
Applications can also implement `ExecutorChannelInterceptor`, which is a sub-interface
of `ChannelInterceptor` with callbacks in the thread in which the messages are handled.
@ -2215,7 +2120,6 @@ Spring provides a STOMP over WebSocket client and a STOMP over TCP client.
To begin, you can create and configure `WebSocketStompClient`, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -2224,7 +2128,6 @@ To begin, you can create and configure `WebSocketStompClient`, as the following
stompClient.setMessageConverter(new StringMessageConverter());
stompClient.setTaskScheduler(taskScheduler); // for heartbeats
----
====
In the preceding example, you could replace `StandardWebSocketClient` with `SockJsClient`,
since that is also an implementation of `WebSocketClient`. The `SockJsClient` can
@ -2233,7 +2136,6 @@ use WebSocket or HTTP-based transport as a fallback. For more details, see
Next, you can establish a connection and provide a handler for the STOMP session, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -2241,11 +2143,9 @@ Next, you can establish a connection and provide a handler for the STOMP session
StompSessionHandler sessionHandler = new MyStompSessionHandler();
stompClient.connect(url, sessionHandler);
----
====
When the session is ready for use, the handler is notified, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -2257,25 +2157,21 @@ public class MyStompSessionHandler extends StompSessionHandlerAdapter {
}
}
----
====
Once the session is established, any payload can be sent and is
serialized with the configured `MessageConverter`, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
session.send("/topic/something", "payload");
----
====
You can also subscribe to destinations. The `subscribe` methods require a handler
for messages on the subscription and returns a `Subscription` handle that you can
use to unsubscribe. For each received message, the handler can specify the target
`Object` type to which the payload should be deserialized, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -2293,7 +2189,6 @@ session.subscribe("/topic/something", new StompFrameHandler() {
});
----
====
To enable STOMP heartbeat, you can configure `WebSocketStompClient` with a `TaskScheduler`
and optionally customize the heartbeat intervals (10 seconds for write inactivity,
@ -2329,7 +2224,6 @@ transport-level errors including `ConnectionLostException`.
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, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -2343,7 +2237,6 @@ public class MyController {
}
}
----
====
You can declare a Spring-managed bean in the `websocket` scope.
You can inject WebSocket-scoped beans into controllers and any channel interceptors
@ -2351,7 +2244,6 @@ registered on the `clientInboundChannel`. Those are typically singletons and liv
longer than any individual WebSocket session. Therefore, you need to use a
scope proxy mode for WebSocket-scoped beans, as the following example shows:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -2388,7 +2280,6 @@ scope proxy mode for WebSocket-scoped beans, as the following example shows:
}
}
----
====
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
@ -2462,7 +2353,6 @@ documentation of the XML schema for important additional details.
The following example shows a possible configuration:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -2479,11 +2369,9 @@ The following example shows a possible configuration:
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@ -2503,7 +2391,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
You can also use the WebSocket transport configuration shown earlier to configure the
maximum allowed size for incoming STOMP messages. In theory, a WebSocket
@ -2521,7 +2408,6 @@ minimum.
The following example shows one possible configuration:
====
[source,java,indent=0]
[subs="verbatim,quotes"]
----
@ -2538,11 +2424,9 @@ The following example shows one possible configuration:
}
----
====
The following example shows the XML configuration equivalent of the preceding example:
====
[source,xml,indent=0]
[subs="verbatim,quotes,attributes"]
----
@ -2562,7 +2446,6 @@ The following example shows the XML configuration equivalent of the preceding ex
</beans>
----
====
An important point about scaling involves using multiple application instances.
Currently, you cannot do that with the simple broker.