Merge branch '5.1.x'

This commit is contained in:
Juergen Hoeller
2019-03-05 14:20:02 +01:00
58 changed files with 1929 additions and 2139 deletions

View File

@@ -1,16 +1,16 @@
[[web-integration]]
= Other Web Frameworks
This chapter details Spring's integration with third party web frameworks.
This chapter details Spring's integration with third-party web frameworks.
One of the core value propositions of the Spring Framework is that of enabling
_choice_. In a general sense, Spring does not force you to use or buy into any
particular architecture, technology, or methodology (although it certainly recommends
some over others). This freedom to pick and choose the architecture, technology, or
methodology that is most relevant to a developer and their development team is
arguably most evident in the web area, where Spring provides its own web framework
(<<mvc,Spring MVC>>) while, at the same time, providing integration with a number of
popular third party web frameworks.
arguably most evident in the web area, where Spring provides its own web frameworks
(<<mvc, Spring MVC>> and <<webflux, Spring WebFlux>>) while, at the same time,
supporting integration with a number of popular third-party web frameworks.
@@ -19,9 +19,8 @@ popular third party web frameworks.
== Common Configuration
Before diving into the integration specifics of each supported web framework, let us
first take a look at the Spring configuration that is not specific to any one web
framework. (This section is equally applicable to Spring's own web framework, Spring
MVC.)
first take a look at common Spring configuration that is not specific to any one web
framework. (This section is equally applicable to Spring's own web framework variants.)
One of the concepts (for want of a better word) espoused by Spring's lightweight
application model is that of a layered architecture. Remember that in a "`classic`"
@@ -90,14 +89,14 @@ key. Rather than risk getting `NullPointerExceptions` in your application, it is
to use the `getRequiredWebApplicationContext()` method. This method throws an exception
when the `ApplicationContext` is missing.
Once you have a reference to the `WebApplicationContext`, you can retrieve beans by
their name or type. Most developers retrieve beans by name and then cast them to one of
their implemented interfaces.
Once you have a reference to the `WebApplicationContext`, you can retrieve beans by their
name or type. Most developers retrieve beans by name and then cast them to one of their
implemented interfaces.
Fortunately, most of the frameworks in this section have simpler ways of looking up
beans. Not only do they make it easy to get beans from a Spring container, but they also
let you use dependency injection on their controllers. Each web framework section
has more detail on its specific integration strategies.
Fortunately, most of the frameworks in this section have simpler ways of looking up beans.
Not only do they make it easy to get beans from a Spring container, but they also let you
use dependency injection on their controllers. Each web framework section has more detail
on its specific integration strategies.
@@ -105,18 +104,14 @@ has more detail on its specific integration strategies.
[[jsf]]
== JSF
JavaServer Faces (JSF) is the JCP's standard component-based, event-driven web user
interface framework. As of Java EE 5, it is an official part of the Java EE umbrella.
JavaServer Faces (JSF) is the JCP's standard component-based, event-driven web
user interface framework. It is an official part of the Java EE umbrella but also
individually usable, e.g. through embedding Mojarra or MyFaces within Tomcat.
For a popular JSF runtime as well as for popular JSF component libraries, check out the
http://myfaces.apache.org/[Apache MyFaces project]. The MyFaces project also provides
common JSF extensions, such as http://myfaces.apache.org/orchestra/[MyFaces Orchestra]
(a Spring-based JSF extension that provides rich conversation scope support).
NOTE: Spring Web Flow 2.0 provides rich JSF support through its newly established Spring Faces
module, both for JSF-centric usage (as described in this section) and for Spring-centric
usage (using JSF views within a Spring MVC dispatcher). See the
http://projects.spring.io/spring-webflow[Spring Web Flow website] for details.
Please note that recent versions of JSF became closely tied to CDI infrastructure
in application servers, with some new JSF functionality only working in such an
environment. Spring's JSF support is not actively evolved anymore and primarily
exists for migration purposes when modernizing older JSF-based applications.
The key element in Spring's JSF integration is the JSF `ELResolver` mechanism.
@@ -125,11 +120,10 @@ The key element in Spring's JSF integration is the JSF `ELResolver` mechanism.
[[jsf-springbeanfaceselresolver]]
=== Spring Bean Resolver
`SpringBeanFacesELResolver` is a JSF 1.2+ compliant `ELResolver` implementation,
integrating with the standard Unified EL as used by JSF 1.2 and JSP 2.1. As
`SpringBeanVariableResolver`, it delegates to Spring's "`business context`"
`WebApplicationContext` first and then to the default resolver of the underlying JSF
implementation.
`SpringBeanFacesELResolver` is a JSF compliant `ELResolver` implementation,
integrating with the standard Unified EL as used by JSF and JSP. It delegates to
Spring's "`business context`" `WebApplicationContext` first and then to the
default resolver of the underlying JSF implementation.
Configuration-wise, you can define `SpringBeanFacesELResolver` in your JSF
`faces-context.xml` file, as the following example shows:
@@ -150,11 +144,11 @@ Configuration-wise, you can define `SpringBeanFacesELResolver` in your JSF
[[jsf-facescontextutils]]
=== Using `FacesContextUtils`
A custom `VariableResolver` works well when mapping your properties to beans
in `faces-config.xml`, but, at times, you may need to explicitly grab a bean. The
{api-spring-framework}/web/jsf/FacesContextUtils.html[`FacesContextUtils`]
class makes this easy. It is similar to `WebApplicationContextUtils`, except that it
takes a `FacesContext` parameter rather than a `ServletContext` parameter.
A custom `ELResolver` works well when mapping your properties to beans in
`faces-config.xml`, but, at times, you may need to explicitly grab a bean.
The {api-spring-framework}/web/jsf/FacesContextUtils.html[`FacesContextUtils`]
class makes this easy. It is similar to `WebApplicationContextUtils`, except that
it takes a `FacesContext` parameter rather than a `ServletContext` parameter.
The following example shows how to use `FacesContextUtils`:
@@ -173,30 +167,29 @@ The following example shows how to use `FacesContextUtils`:
Invented by Craig McClanahan, http://struts.apache.org[Struts] is an open-source project
hosted by the Apache Software Foundation. At the time, it greatly simplified the
JSP/Servlet programming paradigm and won over many developers who were using proprietary
frameworks. It simplified the programming model, it was open source (and thus free, as in
beer), and it had a large community, which let the project grow and become popular
among Java web developers.
frameworks. It simplified the programming model, it was open source (and thus free as in
beer), and it had a large community, which let the project grow and become popular among
Java web developers.
Check out the Struts
As a successor to the original Struts 1.x, check out Struts 2.x and the Struts-provided
https://struts.apache.org/release/2.3.x/docs/spring-plugin.html[Spring Plugin] for the
built-in Spring integration shipped with Struts.
built-in Spring integration.
[[tapestry]]
== Tapestry 5.x
== Apache Tapestry 5.x
http://tapestry.apache.org/[Tapestry] is a ""Component oriented framework for creating dynamic, robust,
highly scalable web applications in Java.""
http://tapestry.apache.org/[Tapestry] is a ""Component oriented framework for creating
dynamic, robust, highly scalable web applications in Java.""
While Spring has its own <<mvc,powerful web layer>>, there are a number of unique
While Spring has its own <<mvc, powerful web layer>>, there are a number of unique
advantages to building an enterprise Java application by using a combination of Tapestry
for the web user interface and the Spring container for the lower layers.
For more information, see Tapestry's dedicated
https://tapestry.apache.org/integrating-with-spring-framework.html[integration module for
Spring].
https://tapestry.apache.org/integrating-with-spring-framework.html[integration module for Spring].
@@ -204,8 +197,8 @@ Spring].
[[web-integration-resources]]
== Further Resources
The following links go to further resources about the various web frameworks described in this
chapter.
The following links go to further resources about the various web frameworks described in
this chapter.
* The http://www.oracle.com/technetwork/java/javaee/javaserverfaces-139869.html[JSF] homepage
* The http://struts.apache.org/[Struts] homepage

View File

@@ -64,10 +64,10 @@ You shorter it further still with a full URI template, as the following example
= UriBuilder
[.small]#Spring MVC and Spring WebFlux#
<<web-uricomponents,`UriComponentsBuilder`>> implements `UriBuilder`. You can create a `UriBuilder`, in turn,
with a `UriBuilderFactory`. Together, `UriBuilderFactory` and `UriBuilder`
provide a pluggable mechanism to build URIs from URI templates, based on shared
configuration, such as a base URL, encoding preferences, and other details.
<<web-uricomponents, `UriComponentsBuilder`>> implements `UriBuilder`. You can create a
`UriBuilder`, in turn, with a `UriBuilderFactory`. Together, `UriBuilderFactory` and
`UriBuilder` provide a pluggable mechanism to build URIs from URI templates, based on
shared configuration, such as a base URL, encoding preferences, and other details.
You can configure `RestTemplate` and `WebClient` with a `UriBuilderFactory`
to customize the preparation of URIs. `DefaultUriBuilderFactory` is a default

View File

@@ -1,6 +1,6 @@
[[webflux-cors]]
= CORS
[.small]#<<web.adoc#mvc-cors,Same as in Spring MVC>>#
[.small]#<<web.adoc#mvc-cors, Same as in Spring MVC>>#
Spring WebFlux lets you handle CORS (Cross-Origin Resource Sharing). This section
describes how to do so.
@@ -10,7 +10,7 @@ describes how to do so.
[[webflux-cors-intro]]
== Introduction
[.small]#<<web.adoc#mvc-cors-intro,Same as in Spring MVC>>#
[.small]#<<web.adoc#mvc-cors-intro, Same as in Spring MVC>>#
For security reasons, browsers prohibit AJAX calls to resources outside the current origin.
For example, you could have your bank account in one tab and evil.com in another. Scripts
@@ -27,7 +27,7 @@ powerful workarounds based on IFRAME or JSONP.
[[webflux-cors-processing]]
== Processing
[.small]#<<web.adoc#mvc-cors-processing,Same as in Spring MVC>>#
[.small]#<<web.adoc#mvc-cors-processing, Same as in Spring MVC>>#
The CORS specification distinguishes between preflight, simple, and actual requests.
To learn how CORS works, you can read
@@ -77,7 +77,7 @@ To learn more from the source or to make advanced customizations, see:
[[webflux-cors-controller]]
== `@CrossOrigin`
[.small]#<<web.adoc#mvc-cors-controller,Same as in Spring MVC>>#
[.small]#<<web.adoc#mvc-cors-controller, Same as in Spring MVC>>#
The {api-spring-framework}/web/bind/annotation/CrossOrigin.html[`@CrossOrigin`]
annotation enables cross-origin requests on annotated controller methods, as the
@@ -169,7 +169,7 @@ public class AccountController {
[[webflux-cors-global]]
== Global Configuration
[.small]#<<web.adoc#mvc-cors-global,Same as in Spring MVC>>#
[.small]#<<web.adoc#mvc-cors-global, Same as in Spring MVC>>#
In addition to fine-grained, controller method-level configuration, you probably want to
define some global CORS configuration, too. You can set URL-based `CorsConfiguration`
@@ -218,11 +218,11 @@ public class WebConfig implements WebFluxConfigurer {
[[webflux-cors-webfilter]]
== CORS `WebFilter`
[.small]#<<web.adoc#mvc-cors-filter,Same as in Spring MVC>>#
[.small]#<<web.adoc#mvc-cors-filter, Same as in Spring MVC>>#
You can apply CORS support through the built-in
{api-spring-framework}/web/cors/reactive/CorsWebFilter.html[`CorsWebFilter`], which is a
good fit with <<webflux-fn,functional endpoints>>.
good fit with <<webflux-fn, functional endpoints>>.
NOTE: If you try to use the `CorsFilter` with Spring Security, keep in mind that Spring
Security has

View File

@@ -64,7 +64,7 @@ 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>>:
through one of the built-in <<web-reactive.adoc#webflux-httphandler, server adapters>>:
* `RouterFunctions.toHttpHandler(RouterFunction)`
* `RouterFunctions.toHttpHandler(RouterFunction, HandlerStrategies)`
@@ -83,7 +83,7 @@ Both request and response provide http://www.reactive-streams.org[Reactive Strea
against the body streams.
The request body is represented with a Reactor `Flux` or `Mono`.
The response body is represented with any Reactive Streams `Publisher`, including `Flux` and `Mono`.
For more on that, see <<web-reactive.adoc#webflux-reactive-libraries,Reactive Libraries>>.
For more on that, see <<web-reactive.adoc#webflux-reactive-libraries, Reactive Libraries>>.
@@ -233,9 +233,9 @@ found. If it is not found, we use `switchIfEmpty(Mono<T>)` to return a 404 Not F
[[webflux-fn-handler-validation]]
=== Validation
A functional endpoint can use Spring's <<core.adoc#validation,validation facilities>> to
A functional endpoint can use Spring's <<core.adoc#validation, validation facilities>> to
apply validation to the request body. For example, given a custom Spring
<<core.adoc#validation,Validator>> implementation for a `Person`:
<<core.adoc#validation, Validator>> implementation for a `Person`:
====
[source,java,indent=0]
@@ -268,7 +268,7 @@ public class PersonHandler {
Handlers can also use the standard bean validation API (JSR-303) by creating and injecting
a global `Validator` instance based on `LocalValidatorFactoryBean`.
See <<core.adoc#validation-beanvalidation,Spring Validation>>.
See <<core.adoc#validation-beanvalidation, Spring Validation>>.
@@ -424,10 +424,10 @@ function to an `HttpHandler` by using one of the following:
* `RouterFunctions.toHttpHandler(RouterFunction, HandlerStrategies)`
You can then use the returned `HttpHandler` with a number of server adapters by following
<<web-reactive.adoc#webflux-httphandler,HttpHandler>> for server-specific instructions.
<<web-reactive.adoc#webflux-httphandler, HttpHandler>> for server-specific instructions.
A more typical option, also used by Spring Boot, is to run with a
<<web-reactive.adoc#webflux-dispatcher-handler,`DispatcherHandler`>>-based setup through the
<<web-reactive.adoc#webflux-dispatcher-handler, `DispatcherHandler`>>-based setup through the
<<web-reactive.adoc#webflux-config>>, which uses Spring configuration to declare the
components required to process requests. The WebFlux Java configuration declares the following
infrastructure components to support functional endpoints:
@@ -446,7 +446,7 @@ any are declared. It is also how functional endpoints are enabled by the Spring
starter.
The following example shows a WebFlux Java configuration (see
<<web-reactive.adoc#webflux-dispatcher-handler,DispatcherHandler>> for how to run it):
<<web-reactive.adoc#webflux-dispatcher-handler, DispatcherHandler>> for how to run it):
[source,java,indent=0]
[subs="verbatim,quotes"]
@@ -555,4 +555,5 @@ We allow only the handler function to be executed when access is allowed.
Besides using the `filter` method on the router function builder, it is possible to apply a
filter to an existing router function via `RouterFunction.filter(HandlerFilterFunction)`.
NOTE: CORS support for functional endpoints is provided through a dedicated <<webflux-cors-webfilter,`CorsWebFilter`>>.
NOTE: CORS support for functional endpoints is provided through a dedicated
<<webflux-cors-webfilter, `CorsWebFilter`>>.

View File

@@ -1,6 +1,6 @@
[[webflux-view]]
= View Technologies
[.small]#<<web.adoc#mvc-view,Same as in Spring MVC>>#
[.small]#<<web.adoc#mvc-view, Same as in Spring MVC>>#
The use of view technologies in Spring WebFlux is pluggable. Whether you decide to
use Thymeleaf, FreeMarker, or some other view technology is primarily a matter of a
@@ -12,7 +12,7 @@ WebFlux. We assume you are already familiar with <<webflux-viewresolution>>.
[[webflux-view-thymeleaf]]
== Thymeleaf
[.small]#<<web.adoc#mvc-view-thymeleaf,Same as in Spring MVC>>#
[.small]#<<web.adoc#mvc-view-thymeleaf, Same as in Spring MVC>>#
Thymeleaf is a modern server-side Java template engine that emphasizes natural HTML
templates that can be previewed in a browser by double-clicking, which is very
@@ -33,7 +33,7 @@ http://forum.thymeleaf.org/Thymeleaf-3-0-8-JUST-PUBLISHED-td4030687.html[announc
[[webflux-view-freemarker]]
== FreeMarker
[.small]#<<web.adoc#mvc-view-freemarker,Same as in Spring MVC>>#
[.small]#<<web.adoc#mvc-view-freemarker, Same as in Spring MVC>>#
http://www.freemarker.org[Apache FreeMarker] is a template engine for generating any
kind of text output from HTML to email and others. The Spring Framework has a built-in
@@ -43,7 +43,7 @@ integration for using Spring WebFlux with FreeMarker templates.
[[webflux-view-freemarker-contextconfig]]
=== View Configuration
[.small]#<<web.adoc#mvc-view-freemarker-contextconfig,Same as in Spring MVC>>#
[.small]#<<web.adoc#mvc-view-freemarker-contextconfig, Same as in Spring MVC>>#
The following example shows how to configure FreeMarker as a view technology:
@@ -79,7 +79,7 @@ shown in the preceding example. Given the preceding configuration, if your contr
[[webflux-views-freemarker]]
=== FreeMarker Configuration
[.small]#<<web.adoc#mvc-views-freemarker,Same as in Spring MVC>>#
[.small]#<<web.adoc#mvc-views-freemarker, Same as in Spring MVC>>#
You can pass FreeMarker 'Settings' and 'SharedVariables' directly to the FreeMarker
`Configuration` object (managed by Spring) by setting the appropriate bean properties on
@@ -117,7 +117,7 @@ the `Configuration` object.
[[webflux-view-script]]
== Script Views
[.small]#<<web.adoc#mvc-view-script,Same as in Spring MVC>>#
[.small]#<<web.adoc#mvc-view-script, Same as in Spring MVC>>#
The Spring Framework has a built-in integration for using Spring WebFlux with any
templating library that can run on top of the
@@ -143,7 +143,7 @@ TIP: The basic rule for integrating any other script engine is that it must impl
[[webflux-view-script-dependencies]]
=== Requirements
[.small]#<<web.adoc#mvc-view-script-dependencies,Same as in Spring MVC>>#
[.small]#<<web.adoc#mvc-view-script-dependencies, Same as in Spring MVC>>#
You need to have the script engine on your classpath, the details of which vary by script engine:
@@ -163,7 +163,7 @@ through http://www.webjars.org/[WebJars].
[[webflux-view-script-integrate]]
=== Script Templates
[.small]#<<web.adoc#mvc-view-script-integrate,Same as in Spring MVC>>#
[.small]#<<web.adoc#mvc-view-script-integrate, Same as in Spring MVC>>#
You can declare a `ScriptTemplateConfigurer` bean to specify the script engine to use,
the script files to load, what function to call to render templates, and so on.
@@ -274,20 +274,20 @@ for more configuration examples.
[[webflux-view-httpmessagewriter]]
== JSON and XML
[.small]#<<web.adoc#mvc-view-jackson,Same as in Spring MVC>>#
[.small]#<<web.adoc#mvc-view-jackson, Same as in Spring MVC>>#
For <<webflux-multiple-representations>> purposes, it is useful to be able to alternate
between rendering a model with an HTML template or as other formats (such as JSON or XML),
depending on the content type requested by the client. To support doing so, Spring WebFlux
provides the `HttpMessageWriterView`, which you can use to plug in any of the available
<<webflux-codecs>> from `spring-web`, such as `Jackson2JsonEncoder`,
`Jackson2SmileEncoder`, or `Jaxb2XmlEncoder`.
<<webflux-codecs>> from `spring-web`, such as `Jackson2JsonEncoder`, `Jackson2SmileEncoder`,
or `Jaxb2XmlEncoder`.
Unlike other view technologies, `HttpMessageWriterView` does not require a `ViewResolver`
but is instead <<webflux-config-view-resolvers,configured>> as a default view. You can
configure one or more such default views, wrapping different `HttpMessageWriter` instances or
`Encoder` instances. The one that matches the requested content type is used at runtime.
but is instead <<webflux-config-view-resolvers, configured>> as a default view. You can
configure one or more such default views, wrapping different `HttpMessageWriter` instances
or `Encoder` instances. The one that matches the requested content type is used at runtime.
In most cases, a model contains multiple attributes. To determine which one
to serialize, you can configure `HttpMessageWriterView` with the name of the model
attribute to use for rendering. If the model contains only one attribute, that one is used.
In most cases, a model contains multiple attributes. To determine which one to serialize,
you can configure `HttpMessageWriterView` with the name of the model attribute to use for
rendering. If the model contains only one attribute, that one is used.

View File

@@ -4,7 +4,7 @@
Spring WebFlux includes a reactive, non-blocking `WebClient` for HTTP requests. The client
has a functional, fluent API with reactive types for declarative composition, see
<<web-reactive.adoc#webflux-reactive-libraries>>. WebFlux client and server rely on the
same non-blocking <<web-reactive.adoc#webflux-codecs,codecs>> to encode and decode request
same non-blocking <<web-reactive.adoc#webflux-codecs, codecs>> to encode and decode request
and response content.
Internally `WebClient` delegates to an HTTP client library. By default, it uses
@@ -36,7 +36,7 @@ You can also use `WebClient.builder()` with further options:
* `exchangeStrategies`: HTTP message reader/writer customizations.
* `clientConnector`: HTTP client library settings.
The following example configures <<web-reactive.adoc#webflux-codecs,HTTP codecs>>:
The following example configures <<web-reactive.adoc#webflux-codecs, HTTP codecs>>:
[source,java,intent=0]
[subs="verbatim,quotes"]

View File

@@ -1,6 +1,6 @@
[[webflux-websocket]]
= WebSockets
[.small]#<<web.adoc#websocket,Same as in the Servlet stack>>#
[.small]#<<web.adoc#websocket, Same as in the Servlet stack>>#
This part of the reference documentation covers support for reactive-stack WebSocket
messaging.
@@ -12,7 +12,7 @@ include::websocket-intro.adoc[leveloffset=+1]
[[webflux-websocket-server]]
== WebSocket API
[.small]#<<web.adoc#websocket-server,Same as in the Servlet stack>>#
[.small]#<<web.adoc#websocket-server, Same as in the Servlet stack>>#
The Spring Framework provides a WebSocket API that you can use to write client- and
server-side applications that handle WebSocket messages.
@@ -21,7 +21,7 @@ server-side applications that handle WebSocket messages.
[[webflux-websocket-server-handler]]
=== Server
[.small]#<<web.adoc#websocket-server-handler,Same as in the Servlet stack>>#
[.small]#<<web.adoc#websocket-server-handler, Same as in the Servlet stack>>#
To create a WebSocket server, you can first create a `WebSocketHandler`.
The following example shows how to do so:
@@ -133,7 +133,7 @@ class ExampleHandler implements WebSocketHandler {
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
released before you have had a chance to read the data. For more background, see
<<core.adoc#databuffers,Data Buffers and Codecs>>.
<<core.adoc#databuffers, Data Buffers and Codecs>>.
The following implementation combines the inbound and outbound streams:
@@ -201,7 +201,7 @@ class ExampleHandler implements WebSocketHandler {
`DataBuffer` is the representation for a byte buffer in WebFlux. The Spring Core part of
the reference has more on that in the section on
<<core#databuffers,Data Buffers and Codecs>>. The key point to understand is that on some
<<core#databuffers, Data Buffers and Codecs>>. The key point to understand is that on some
servers like Netty, byte buffers are pooled and reference counted, and must be released
when consumed to avoid memory leaks.
@@ -214,7 +214,7 @@ subsequently use `DataBufferUtils.release(dataBuffer)` when the buffers are cons
[[webflux-websocket-server-handshake]]
=== Handshake
[.small]#<<web.adoc#websocket-server-handshake,Same as in the Servlet stack>>#
[.small]#<<web.adoc#websocket-server-handshake, Same as in the Servlet stack>>#
`WebSocketHandlerAdapter` delegates to a `WebSocketService`. By default, that is an instance
of `HandshakeWebSocketService`, which performs basic checks on the WebSocket request and
@@ -229,7 +229,7 @@ into the attributes of the `WebSocketSession`.
[[webflux-websocket-server-config]]
=== Server Configation
[.small]#<<web.adoc#websocket-server-runtime-configuration,Same as in the Servlet stack>>#
[.small]#<<web.adoc#websocket-server-runtime-configuration, Same as in the Servlet stack>>#
The `RequestUpgradeStrategy` for each server exposes WebSocket-related configuration
options available for the underlying WebSocket engine. The following example sets
@@ -262,7 +262,7 @@ only Tomcat and Jetty expose such options.
[[webflux-websocket-server-cors]]
=== CORS
[.small]#<<web.adoc#websocket-server-allowed-origins,Same as in the Servlet stack>>#
[.small]#<<web.adoc#websocket-server-allowed-origins, Same as in the Servlet stack>>#
The easiest way to configure CORS and restrict access to a WebSocket endpoint is to
have your `WebSocketHandler` implement `CorsConfigurationSource` and return a

File diff suppressed because it is too large Load Diff

View File

@@ -15,12 +15,12 @@ libraries.
NOTE: As of 5.0, the non-blocking, reactive `WebClient` offers a modern alternative to the
`RestTemplate`, with efficient support for both
<<web-reactive.adoc#webflux-client-synchronous,synchronous and asynchronous>>, as well as
<<web-reactive.adoc#webflux-client-synchronous, synchronous and asynchronous>>, as well as
streaming scenarios. The `RestTemplate` will be deprecated in a future version and will
not have major new features added going forward.
See <<integration.adoc#rest-client-access,REST Endpoints>> for details.
See <<integration.adoc#rest-client-access, REST Endpoints>> for details.
@@ -41,4 +41,4 @@ In contrast to `RestTemplate`, `WebClient` supports the following:
* Synchronous and asynchronous interactions.
* Streaming up to or streaming down from a server.
See <<web-reactive.adoc#webflux-client,WebClient>> for more details.
See <<web-reactive.adoc#webflux-client, WebClient>> for more details.

View File

@@ -1,6 +1,6 @@
[[mvc-cors]]
= CORS
[.small]#<<web-reactive.adoc#webflux-cors,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-cors, Same as in Spring WebFlux>>#
Spring MVC lets you handle CORS (Cross-Origin Resource Sharing). This section
describes how to do so.
@@ -10,7 +10,7 @@ describes how to do so.
[[mvc-cors-intro]]
== Introduction
[.small]#<<web-reactive.adoc#webflux-cors-intro,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-cors-intro, Same as in Spring WebFlux>>#
For security reasons, browsers prohibit AJAX calls to resources outside the current origin.
For example, you could have your bank account in one tab and evil.com in another. Scripts
@@ -27,7 +27,7 @@ powerful workarounds based on IFRAME or JSONP.
[[mvc-cors-processing]]
== Processing
[.small]#<<web-reactive.adoc#webflux-cors-processing,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-cors-processing, Same as in Spring WebFlux>>#
The CORS specification distinguishes between preflight, simple, and actual requests.
To learn how CORS works, you can read
@@ -77,7 +77,7 @@ To learn more from the source or make advanced customizations, check the code be
[[mvc-cors-controller]]
== `@CrossOrigin`
[.small]#<<web-reactive.adoc#webflux-cors-controller,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-cors-controller, Same as in Spring WebFlux>>#
The {api-spring-framework}/web/bind/annotation/CrossOrigin.html[`@CrossOrigin`]
annotation enables cross-origin requests on annotated controller methods,
@@ -167,7 +167,7 @@ public class AccountController {
[[mvc-cors-global]]
== Global Configuration
[.small]#<<web-reactive.adoc#webflux-cors-global,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-cors-global, Same as in Spring WebFlux>>#
In addition to fine-grained, controller method level configuration, you probably want to
define some global CORS configuration, too. You can set URL-based `CorsConfiguration`
@@ -191,7 +191,7 @@ should only be used where appropriate.
[[mvc-cors-global-java]]
=== Java Configuration
[.small]#<<web-reactive.adoc#webflux-cors-global,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-cors-global, Same as in Spring WebFlux>>#
To enable CORS in the MVC Java config, you can use the `CorsRegistry` callback,
as the following example shows:
@@ -249,13 +249,13 @@ as the following example shows:
[[mvc-cors-filter]]
== CORS Filter
[.small]#<<web-reactive.adoc#webflux-cors-webfilter,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-cors-webfilter, Same as in Spring WebFlux>>#
You can apply CORS support through the built-in
{api-spring-framework}/web/filter/CorsFilter.html[`CorsFilter`].
NOTE: If you try to use the `CorsFilter` with Spring Security, keep in mind that Spring
Security has
NOTE: If you try to use the `CorsFilter` with Spring Security, keep in mind that
Spring Security has
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors[built-in support]
for CORS.

View File

@@ -1,26 +1,26 @@
[[testing]]
= Testing
[.small]#<<web-reactive.adoc#webflux-test,Same in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-test, Same in Spring WebFlux>>#
This section summarizes the options available in `spring-test` for Spring MVC applications.
* Servlet API Mocks: Mock implementations of Servlet API contracts for unit testing controllers, filters, and
other web components. See <<testing.adoc#mock-objects-servlet,Servlet API>> mock objects
for more details.
* Servlet API Mocks: Mock implementations of Servlet API contracts for unit testing controllers,
filters, and other web components. See <<testing.adoc#mock-objects-servlet, Servlet API>>
mock objects for more details.
* TestContext Framework: Support for loading Spring configuration in JUnit and TestNG tests, including efficient
caching of the loaded configuration across test methods and support for loading a
`WebApplicationContext` with a `MockServletContext`.
* TestContext Framework: Support for loading Spring configuration in JUnit and TestNG tests,
including efficient caching of the loaded configuration across test methods and support for
loading a `WebApplicationContext` with a `MockServletContext`.
See <<testing.adoc#testcontext-framework,TestContext Framework>> for more details.
* Spring MVC Test: A framework, also known as `MockMvc`, for testing annotated controllers through the
`DispatcherServlet` (that is, supporting annotations), complete with the Spring MVC
infrastructure but without an HTTP server. See
<<testing.adoc#spring-mvc-test-framework,Spring MVC Test>> for more details.
* Spring MVC Test: A framework, also known as `MockMvc`, for testing annotated controllers
through the `DispatcherServlet` (that is, supporting annotations), complete with the
Spring MVC infrastructure but without an HTTP server.
See <<testing.adoc#spring-mvc-test-framework, Spring MVC Test>> for more details.
* Client-side REST: `spring-test` provides a `MockRestServiceServer` that you can use as a mock server for
testing client-side code that internally uses the `RestTemplate`.
See <<testing.adoc#spring-mvc-test-client,Client REST Tests>> for more details.
* Client-side REST: `spring-test` provides a `MockRestServiceServer` that you can use as
a mock server for testing client-side code that internally uses the `RestTemplate`.
See <<testing.adoc#spring-mvc-test-client, Client REST Tests>> for more details.
* `WebTestClient`: Built for testing WebFlux applications, but it can also be used for
end-to-end integration testing, to any server, over an HTTP connection. It is a

View File

@@ -1,18 +1,18 @@
[[mvc-view]]
= View Technologies
[.small]#<<web-reactive.adoc#webflux-view,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-view, Same as in Spring WebFlux>>#
The use of view technologies in Spring MVC is pluggable, whether you decide to
use Thymeleaf, Groovy Markup Templates, JSPs, or other technologies, is primarily a matter of a
configuration change. This chapter covers view technologies integrated with Spring MVC.
We assume you are already familiar with <<mvc-viewresolver>>.
The use of view technologies in Spring MVC is pluggable, whether you decide to use
Thymeleaf, Groovy Markup Templates, JSPs, or other technologies, is primarily a matter
of a configuration change. This chapter covers view technologies integrated with
Spring MVC. We assume you are already familiar with <<mvc-viewresolver>>.
[[mvc-view-thymeleaf]]
== Thymeleaf
[.small]#<<web-reactive.adoc#webflux-view-thymeleaf,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-view-thymeleaf, Same as in Spring WebFlux>>#
Thymeleaf is a modern server-side Java template engine that emphasizes natural HTML
templates that can be previewed in a browser by double-clicking, which is very helpful
@@ -32,7 +32,7 @@ See http://www.thymeleaf.org/documentation.html[Thymeleaf+Spring] for more detai
[[mvc-view-freemarker]]
== FreeMarker
[.small]#<<web-reactive.adoc#webflux-view-freemarker,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-view-freemarker, Same as in Spring WebFlux>>#
http://www.freemarker.org[Apache FreeMarker] is a template engine for generating any
kind of text output from HTML to email and others. The Spring Framework has a built-in
@@ -42,7 +42,7 @@ integration for using Spring MVC with FreeMarker templates.
[[mvc-view-freemarker-contextconfig]]
=== View Configuration
[.small]#<<web-reactive.adoc#webflux-view-freemarker-contextconfig,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-view-freemarker-contextconfig, Same as in Spring WebFlux>>#
The following example shows how to configure FreeMarker as a view technology:
@@ -105,7 +105,7 @@ of `welcome`, the resolver looks for the `/WEB-INF/freemarker/welcome.ftl` templ
[[mvc-views-freemarker]]
=== FreeMarker Configuration
[.small]#<<web-reactive.adoc#webflux-views-freemarker,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-views-freemarker, Same as in Spring WebFlux>>#
You can pass FreeMarker 'Settings' and 'SharedVariables' directly to the FreeMarker
`Configuration` object (which is managed by Spring) by setting the appropriate bean properties on
@@ -536,7 +536,7 @@ syntax. The following example shows a sample template for an HTML page:
[[mvc-view-script]]
== Script Views
[.small]#<<web-reactive.adoc#webflux-view-script,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-view-script, Same as in Spring WebFlux>>#
The Spring Framework has a built-in integration for using Spring MVC with any
templating library that can run on top of the
@@ -562,7 +562,7 @@ TIP: The basic rule for integrating any other script engine is that it must impl
[[mvc-view-script-dependencies]]
=== Requirements
[.small]#<<web-reactive.adoc#webflux-view-script-dependencies,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-view-script-dependencies, Same as in Spring WebFlux>>#
You need to have the script engine on your classpath, the details of which vary by script engine:
@@ -582,7 +582,7 @@ through http://www.webjars.org/[WebJars].
[[mvc-view-script-integrate]]
=== Script Templates
[.small]#<<web-reactive.adoc#webflux-script-integrate,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-script-integrate, Same as in Spring WebFlux>>#
You can declare a `ScriptTemplateConfigurer` bean to specify the script engine to use,
the script files to load, what function to call to render templates, and so on.
@@ -1126,13 +1126,13 @@ but with different values, as the following example shows:
This tag renders multiple HTML `input` elements with the `type` set to `radio`.
As with the <<mvc-view-jsp-formtaglib-checkboxestag,`checkboxes` tag>>, you might want to pass in the available options as
a runtime variable. For this usage, you can use the `radiobuttons` tag. You pass in an
`Array`, a `List`, or a `Map` that contains the available options in the `items` property.
If you use a `Map`, the map entry key is used as the value and the map
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:
As with the <<mvc-view-jsp-formtaglib-checkboxestag, `checkboxes` tag>>, you might want to
pass in the available options as a runtime variable. For this usage, you can use the
`radiobuttons` tag. You pass in an `Array`, a `List`, or a `Map` that contains the
available options in the `items` property. If you use a `Map`, the map entry key is
used as the value and the map 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"]
@@ -1892,7 +1892,7 @@ an external definition (by name) or as a `View` instance from the handler method
[[mvc-view-jackson]]
== Jackson
[.small]#<<web-reactive.adoc#webflux-view-httpmessagewriter,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-view-httpmessagewriter, Same as in Spring WebFlux>>#
Spring offers support for the Jackson JSON library.
@@ -1900,7 +1900,7 @@ Spring offers support for the Jackson JSON library.
[[mvc-view-json-mapping]]
=== Jackson-based JSON MVC Views
[.small]#<<web-reactive.adoc#webflux-view-httpmessagewriter,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-view-httpmessagewriter, Same as in Spring WebFlux>>#
The `MappingJackson2JsonView` uses the Jackson library's `ObjectMapper` to render the response
content as JSON. By default, the entire contents of the model map (with the exception of
@@ -1919,7 +1919,7 @@ serializers and deserializers for specific types.
[[mvc-view-xml-mapping]]
=== Jackson-based XML Views
[.small]#<<web-reactive.adoc#webflux-view-httpmessagewriter,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-view-httpmessagewriter, Same as in Spring WebFlux>>#
`MappingJackson2XmlView` uses the
https://github.com/FasterXML/jackson-dataformat-xml[Jackson XML extension's] `XmlMapper`

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
[[websocket]]
= WebSockets
:doc-spring-security: {doc-root}/spring-security/site/docs/current/reference
[.small]#<<web-reactive.adoc#webflux-websocket,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-websocket, Same as in Spring WebFlux>>#
This part of the reference documentation covers support for Servlet stack, WebSocket
messaging that includes raw WebSocket interactions, WebSocket emulation through SockJS, and
@@ -14,7 +14,7 @@ include::websocket-intro.adoc[leveloffset=+1]
[[websocket-server]]
== WebSocket API
[.small]#<<web-reactive.adoc#webflux-websocket-server,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-websocket-server, Same as in Spring WebFlux>>#
The Spring Framework provides a WebSocket API that you can use to write client- and
server-side applications that handle WebSocket messages.
@@ -23,7 +23,7 @@ server-side applications that handle WebSocket messages.
[[websocket-server-handler]]
=== `WebSocketHandler`
[.small]#<<web-reactive.adoc#webflux-websocket-server-handler,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-websocket-server-handler, Same as in Spring WebFlux>>#
Creating a WebSocket server is as simple as implementing `WebSocketHandler` or, more
likely, extending either `TextWebSocketHandler` or `BinaryWebSocketHandler`. The following
@@ -96,10 +96,10 @@ 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
support does not depend on Spring MVC. It is relatively simple to integrate a `WebSocketHandler`
into other HTTP-serving environments with the help of
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 support does not depend on Spring MVC. It is relatively simple to
integrate a `WebSocketHandler` into other HTTP-serving environments with the help of
{api-spring-framework}/web/socket/server/support/WebSocketHttpRequestHandler.html[`WebSocketHttpRequestHandler`].
When using the `WebSocketHandler` API directly vs indirectly, e.g. through the
@@ -112,7 +112,7 @@ sending. One option is to wrap the `WebSocketSession` with
[[websocket-server-handshake]]
=== WebSocket Handshake
[.small]#<<web-reactive.adoc#webflux-websocket-server-handshake,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-websocket-server-handshake, Same as in Spring WebFlux>>#
The easiest way to customize the initial HTTP WebSocket handshake request is through
a `HandshakeInterceptor`, which exposes methods for "`before`" and "`after`" the handshake.
@@ -258,7 +258,7 @@ Java initialization API. The following example shows how to do so:
[[websocket-server-runtime-configuration]]
=== Server Configuration
[.small]#<<web-reactive.adoc#webflux-websocket-server-config,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-websocket-server-config, Same as in Spring WebFlux>>#
Each underlying WebSocket engine exposes configuration properties that control
runtime characteristics, such as the size of message buffer sizes, idle timeout,
@@ -385,7 +385,7 @@ The following example shows the XML configuration equivalent of the preceding ex
[[websocket-server-allowed-origins]]
=== Allowed Origins
[.small]#<<web-reactive.adoc#webflux-websocket-server-cors,Same as in Spring WebFlux>>#
[.small]#<<web-reactive.adoc#webflux-websocket-server-cors, Same as in Spring WebFlux>>#
As of Spring Framework 4.1.5, the default behavior for WebSocket and SockJS is to accept
only same-origin requests. It is also possible to allow all or a specified list of origins.
@@ -589,7 +589,7 @@ The following example shows the XML configuration equivalent of the preceding ex
----
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
configuration of a <<mvc-servlet, `DispatcherServlet`>>. However, Spring's WebSocket
and SockJS support does not depend on Spring MVC. It is relatively simple to
integrate into other HTTP serving environments with the help of
{api-spring-framework}/web/socket/sockjs/support/SockJsHttpRequestHandler.html[`SockJsHttpRequestHandler`].
@@ -960,7 +960,7 @@ made about HTTP versus raw TCP and how it lets Spring MVC and other web framewor
provide rich functionality. The following is a list of benefits:
* No need to invent a custom messaging protocol and message format.
* STOMP clients, including a <<websocket-stomp-client,Java client>>
* STOMP clients, including a <<websocket-stomp-client, Java client>>
in the Spring Framework, are available.
* You can (optionally) use message brokers (such as RabbitMQ, ActiveMQ, and others) to
manage subscriptions and broadcast messages.
@@ -1070,10 +1070,10 @@ Alternatively, if you connect through WebSocket (without SockJS), you can use th
}
----
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
<<websocket-stomp-handle-broker-relay-configure>> and
<<websocket-stomp-authentication>> for more information on authentication.
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 <<websocket-stomp-handle-broker-relay-configure>>
and <<websocket-stomp-authentication>> for more information on authentication.
For more example code see:
@@ -1197,7 +1197,6 @@ We can trace the flow through a simple example. Consider the following example,
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/topic");
}
}
@Controller
@@ -1207,9 +1206,7 @@ We can trace the flow through a simple example. Consider the following example,
public String handle(String greeting) {
return "[" + getTimestamp() + ": " + greeting;
}
}
----
The preceding example supports the following flow:
@@ -1257,9 +1254,10 @@ level, `@MessageMapping` is used to express shared mappings across all methods i
controller.
By default, the mapping values are Ant-style path patterns (for example `/thing*`, `/thing/**`),
including support for template variables (for example, `/thing/{id}`). The values can be referenced through
`@DestinationVariable` method arguments. Applications can also switch to a dot-separated
destination convention for mappings, as explained in <<websocket-stomp-destination-separator>>.
including support for template variables (for example, `/thing/{id}`). The values can be
referenced through `@DestinationVariable` method arguments. Applications can also switch to
a dot-separated destination convention for mappings, as explained in
<<websocket-stomp-destination-separator>>.
===== Supported Method Arguments
@@ -1337,7 +1335,7 @@ See <<websocket-stomp-handle-send>>.
`@SubscribeMapping` is similar to `@MessageMapping` but narrows the mapping to
subscription messages only. It supports the same
<<websocket-stomp-message-mapping,method arguments>> as `@MessageMapping`. However
<<websocket-stomp-message-mapping, method arguments>> as `@MessageMapping`. However
for the return value, by default, a message is sent directly to the client (through
`clientOutboundChannel`, in response to the subscription) and not to the broker (through
`brokerChannel`, as a broadcast to matching subscriptions). Adding `@SendTo` or
@@ -1348,8 +1346,8 @@ application controllers are mapped to `/app`. In this setup, the broker stores a
subscriptions to `/topic` and `/queue` that are intended for repeated broadcasts, and
there is no need for the application to get involved. A client could also also subscribe to
some `/app` destination, and a controller could return a value in response to that
subscription without involving the broker
without storing or using the subscription again (effectively a one-time request-reply exchange). One use case for this is populating a UI
subscription without involving the broker without storing or using the subscription again
(effectively a one-time request-reply exchange). One use case for this is populating a UI
with initial data on startup.
When is this not useful? Do not try to map broker and controllers to the same destination
@@ -1379,7 +1377,7 @@ receipt if the server supports it (simple broker does not). For example, with th
});
----
A server side option is <<websocket-stomp-interceptors,to register>> an
A server side option is <<websocket-stomp-interceptors, to register>> an
`ExecutorChannelInterceptor` on the `brokerChannel` and implement the `afterMessageHandled`
method that is invoked after messages, including subscriptions, have been handled.
@@ -1408,13 +1406,15 @@ 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.
`@MessageExceptionHandler` methods support flexible method signatures and support
the same method argument types and return values as
<<websocket-stomp-message-mapping, `@MessageMapping`>> methods.
Typically, `@MessageExceptionHandler` methods apply within the `@Controller` class (or
class hierarchy) in which they are declared. If you want such methods to apply more globally
(across controllers), you can declare them in a class marked with `@ControllerAdvice`.
This is comparable to <<web.adoc#mvc-ann-controller-advice,the similar support>> that is available in Spring MVC.
Typically, `@MessageExceptionHandler` methods apply within the `@Controller` class
(or class hierarchy) in which they are declared. If you want such methods to apply
more globally (across controllers), you can declare them in a class marked with
`@ControllerAdvice`. This is comparable to the
<<web.adoc#mvc-ann-controller-advice, similar support>> available in Spring MVC.
@@ -1563,10 +1563,10 @@ The following example shows the XML configuration equivalent of the preceding ex
The STOMP broker relay in the preceding configuration is a Spring
{api-spring-framework}/messaging/MessageHandler.html[`MessageHandler`]
that handles messages by forwarding them to an external message broker.
To do so, it establishes TCP connections to the broker, forwards all
messages to it, and then forwards all messages received
from the broker to clients through their WebSocket sessions. Essentially,
it acts as a "`relay`" that forwards messages in both directions.
To do so, it establishes TCP connections to the broker, forwards all messages to it,
and then forwards all messages received from the broker to clients through their
WebSocket sessions. Essentially, it acts as a "`relay`" that forwards messages
in both directions.
NOTE: Add `io.projectreactor.netty:reactor-netty` and `io.netty:netty-all`
dependencies to your project for TCP connection management.
@@ -2134,7 +2134,8 @@ since that is also an implementation of `WebSocketClient`. The `SockJsClient` ca
use WebSocket or HTTP-based transport as a fallback. For more details, see
<<websocket-fallback-sockjs-client>>.
Next, you can establish a connection and provide a handler for the STOMP session, as the following example shows:
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"]