Consistent use of tabs for sample code in the reference documentation

This commit is contained in:
Juergen Hoeller 2017-11-20 22:28:00 +01:00
parent 08c78554b9
commit 6f24c0de17
18 changed files with 1191 additions and 1213 deletions

View File

@ -4,6 +4,7 @@
:api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework :api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework
:toc: left :toc: left
:toclevels: 4 :toclevels: 4
:tabsize: 4
:docinfo1: :docinfo1:
This part of the reference documentation covers all of those technologies that are This part of the reference documentation covers all of those technologies that are

View File

@ -3822,7 +3822,6 @@ Find below the custom `BeanPostProcessor` implementation class definition:
package scripting; package scripting;
import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.BeansException;
public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor { public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {

View File

@ -1,6 +1,9 @@
[[databuffers]] [[databuffers]]
= Data Buffers and Codecs = Data Buffers and Codecs
== Introduction == Introduction
The `DataBuffer` interface defines an abstraction over byte buffers. The `DataBuffer` interface defines an abstraction over byte buffers.
@ -9,6 +12,9 @@ Netty does not use `ByteBuffer`, but instead offers `ByteBuf` as an alternative.
Spring's `DataBuffer` is a simple abstraction over `ByteBuf` that can also be used on non-Netty Spring's `DataBuffer` is a simple abstraction over `ByteBuf` that can also be used on non-Netty
platforms (i.e. Servlet 3.1+). platforms (i.e. Servlet 3.1+).
== `DataBufferFactory` == `DataBufferFactory`
The `DataBufferFactory` offers functionality to allocate new data buffers, as well as to wrap The `DataBufferFactory` offers functionality to allocate new data buffers, as well as to wrap
@ -25,6 +31,9 @@ to be used on Netty platforms, such as Reactor Netty.
The other implementation, the `DefaultDataBufferFactory`, is used on other platforms, such as The other implementation, the `DefaultDataBufferFactory`, is used on other platforms, such as
Servlet 3.1+ servers. Servlet 3.1+ servers.
== The `DataBuffer` interface == The `DataBuffer` interface
The `DataBuffer` interface is similar to `ByteBuffer`, but offers a number of advantages. The `DataBuffer` interface is similar to `ByteBuffer`, but offers a number of advantages.
@ -54,6 +63,8 @@ Netty platforms, such as Reactor Netty.
The other implementation, the `DefaultDataBuffer`, is used on other platforms, such as Servlet 3.1+ The other implementation, the `DefaultDataBuffer`, is used on other platforms, such as Servlet 3.1+
servers. servers.
=== `PooledDataBuffer` === `PooledDataBuffer`
The `PooledDataBuffer` is an extension to `DataBuffer` that adds methods for reference counting. The `PooledDataBuffer` is an extension to `DataBuffer` that adds methods for reference counting.
@ -67,6 +78,7 @@ buffers.
These methods take a plain `DataBuffer` as parameter, but only call `retain` or `release` if the These methods take a plain `DataBuffer` as parameter, but only call `retain` or `release` if the
passed data buffer is an instance of `PooledDataBuffer`. passed data buffer is an instance of `PooledDataBuffer`.
[[databuffer-reference-counting]] [[databuffer-reference-counting]]
==== Reference Counting ==== Reference Counting
@ -102,7 +114,8 @@ try {
writeDataToBuffer(buffer); <3> writeDataToBuffer(buffer); <3>
putBufferInHttpBody(buffer); putBufferInHttpBody(buffer);
release = false; <4> release = false; <4>
} finally { }
finally {
if (release) { if (release) {
DataBufferUtils.release(buffer); <5> DataBufferUtils.release(buffer); <5>
} }
@ -112,6 +125,7 @@ private void writeDataToBuffer(DataBuffer buffer) throws IOException { <3>
... ...
} }
---- ----
<1> A new buffer is allocated. <1> A new buffer is allocated.
<2> A boolean flag indicates whether the allocated buffer should be released. <2> A boolean flag indicates whether the allocated buffer should be released.
<3> This example method loads data into the buffer. Note that the method can throw an `IOException`, <3> This example method loads data into the buffer. Note that the method can throw an `IOException`,
@ -121,6 +135,8 @@ released as part of sending the HTTP body across the wire.
<5> If an exception did occur, the flag is still set to `true`, and the buffer will be released <5> If an exception did occur, the flag is still set to `true`, and the buffer will be released
here. here.
=== DataBufferUtils === DataBufferUtils
`DataBufferUtils` contains various utility methods that operate on data buffers. `DataBufferUtils` contains various utility methods that operate on data buffers.
@ -129,6 +145,9 @@ It contains methods for reading a `Flux` of `DataBuffer` objects from an `InputS
`DataBufferUtils` also exposes `retain` and `release` methods that operate on plain `DataBuffer` `DataBufferUtils` also exposes `retain` and `release` methods that operate on plain `DataBuffer`
instances (so that casting to a `PooledDataBuffer` is not required). instances (so that casting to a `PooledDataBuffer` is not required).
[codecs] [codecs]
== Codecs == Codecs

View File

@ -4,6 +4,7 @@
:api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework :api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework
:toc: left :toc: left
:toclevels: 4 :toclevels: 4
:tabsize: 4
:docinfo1: :docinfo1:
This part of the reference documentation is concerned with data access and the This part of the reference documentation is concerned with data access and the

View File

@ -6,6 +6,7 @@
:doc-spring-gemfire: {doc-root}/spring-gemfire/docs/current/reference :doc-spring-gemfire: {doc-root}/spring-gemfire/docs/current/reference
:toc: left :toc: left
:toclevels: 4 :toclevels: 4
:tabsize: 4
:docinfo1: :docinfo1:
This part of the reference documentation covers the Spring Framework's integration with This part of the reference documentation covers the Spring Framework's integration with

View File

@ -1,9 +1,10 @@
[[lanugages]] [[languages]]
= Language Support = Language Support
:doc-root: https://docs.spring.io :doc-root: https://docs.spring.io
:api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework :api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework
:toc: left :toc: left
:toclevels: 4 :toclevels: 4
:tabsize: 4
:docinfo1: :docinfo1:

View File

@ -58,14 +58,14 @@ for their APIs, thus giving a better Kotlin development experience overall.
To retrieve a list of `Foo` objects in Java, one would normally write: To retrieve a list of `Foo` objects in Java, one would normally write:
[source,java] [source,java,indent=0]
---- ----
Flux<User> users = client.get().retrieve().bodyToFlux(User.class) Flux<User> users = client.get().retrieve().bodyToFlux(User.class)
---- ----
Whilst with Kotlin and Spring Framework extensions, one is able to write: Whilst with Kotlin and Spring Framework extensions, one is able to write:
[source,kotlin] [source,kotlin,indent=0]
---- ----
val users = client.get().retrieve().bodyToFlux<User>() val users = client.get().retrieve().bodyToFlux<User>()
// or (both are equivalent) // or (both are equivalent)
@ -172,19 +172,18 @@ This mechanism is very efficient as it does not require any reflection or CGLIB
In Java, one may for example write: In Java, one may for example write:
[source,java] [source,java,indent=0]
---- ----
GenericApplicationContext context = new GenericApplicationContext(); GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(Foo.class); context.registerBean(Foo.class);
context.registerBean(Bar.class, () -> new context.registerBean(Bar.class, () -> new Bar(context.getBean(Foo.class))
Bar(context.getBean(Foo.class))
); );
---- ----
Whilst in Kotlin with reified type parameters and `GenericApplicationContext` Whilst in Kotlin with reified type parameters and `GenericApplicationContext`
Kotlin extensions one can instead simply write: Kotlin extensions one can instead simply write:
[source,kotlin] [source,kotlin,indent=0]
---- ----
val context = GenericApplicationContext().apply { val context = GenericApplicationContext().apply {
registerBean<Foo>() registerBean<Foo>()
@ -198,7 +197,7 @@ It declares an `ApplicationContextInitializer` via a clean declarative API
which enables one to deal with profiles and `Environment` for customizing which enables one to deal with profiles and `Environment` for customizing
how beans are registered. how beans are registered.
[source,kotlin] [source,kotlin,indent=0]
---- ----
fun beans() = beans { fun beans() = beans {
bean<UserHandler>() bean<UserHandler>()
@ -235,7 +234,7 @@ is a shortcut for `applicationContext.getBean(Routes::class.java)`.
This `beans()` function can then be used to register beans on the application context. This `beans()` function can then be used to register beans on the application context.
[source,kotlin] [source,kotlin,indent=0]
---- ----
val context = GenericApplicationContext().apply { val context = GenericApplicationContext().apply {
beans().initialize(this) beans().initialize(this)
@ -276,7 +275,7 @@ Spring Framework now comes with a
that allows one to leverage the <<web-reactive#webflux-fn,WebFlux functional that allows one to leverage the <<web-reactive#webflux-fn,WebFlux functional
API>> for writing clean and idiomatic Kotlin code: API>> for writing clean and idiomatic Kotlin code:
[source,kotlin] [source,kotlin,indent=0]
---- ----
router { router {
accept(TEXT_HTML).nest { accept(TEXT_HTML).nest {
@ -326,7 +325,7 @@ https://github.com/Kotlin/kotlinx.html[kotlinx.html] DSL or simply using Kotlin
This can allow one to write Kotlin templates with full autocompletion and This can allow one to write Kotlin templates with full autocompletion and
refactoring support in a supported IDE: refactoring support in a supported IDE:
[source,kotlin] [source,kotlin,indent=0]
---- ----
import io.spring.demo.* import io.spring.demo.*
@ -394,7 +393,7 @@ you will be able to write your Kotlin beans without any additional `open` keywor
In Kotlin, it is very convenient and considered best practice to declare read-only properties In Kotlin, it is very convenient and considered best practice to declare read-only properties
within the primary constructor, as in the following example: within the primary constructor, as in the following example:
[source,kotlin] [source,kotlin,indent=0]
---- ----
class Person(val name: String, val age: Int) class Person(val name: String, val age: Int)
---- ----
@ -410,7 +409,7 @@ in the primary constructor:
This allows for easy changes to individual properties even if `Person` properties are read-only: This allows for easy changes to individual properties even if `Person` properties are read-only:
[source,kotlin] [source,kotlin,indent=0]
---- ----
data class Person(val name: String, val age: Int) data class Person(val name: String, val age: Int)
@ -442,7 +441,7 @@ mappings (like with MongoDB, Redis, Cassandra, etc).
Our recommendation is to try and favor constructor injection with `val` read-only (and non-nullable when possible) 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]. https://kotlinlang.org/docs/reference/properties.html[properties].
[source,kotlin] [source,kotlin,indent=0]
---- ----
@Component @Component
class YourBean( class YourBean(
@ -461,7 +460,7 @@ explicit `@Autowired constructor` in the example shown above.
If one really needs to use field injection, use the `lateinit var` construct, If one really needs to use field injection, use the `lateinit var` construct,
i.e., i.e.,
[source,kotlin] [source,kotlin,indent=0]
---- ----
@Component @Component
class YourBean { class YourBean {
@ -487,7 +486,7 @@ character will need to be escaped by writing `@Value("\${property}")`.
As an alternative, it is possible to customize the properties placeholder prefix by declaring As an alternative, it is possible to customize the properties placeholder prefix by declaring
the following configuration beans: the following configuration beans:
[source,kotlin] [source,kotlin,indent=0]
---- ----
@Bean @Bean
fun propertyConfigurer() = PropertySourcesPlaceholderConfigurer().apply { fun propertyConfigurer() = PropertySourcesPlaceholderConfigurer().apply {
@ -495,11 +494,10 @@ fun propertyConfigurer() = PropertySourcesPlaceholderConfigurer().apply {
} }
---- ----
Existing code (like Spring Boot actuators or `@LocalServerPort`) that Existing code (like Spring Boot actuators or `@LocalServerPort`) that uses the `${...}` syntax,
uses the `${...}` syntax, can be customised with configuration beans, like can be customised with configuration beans, like as follows:
this:
[source,kotlin] [source,kotlin,indent=0]
---- ----
@Bean @Bean
fun kotlinPropertyConfigurer() = PropertySourcesPlaceholderConfigurer().apply { fun kotlinPropertyConfigurer() = PropertySourcesPlaceholderConfigurer().apply {
@ -535,7 +533,7 @@ attribute it is specified as a `vararg` parameter.
To understand what that means, let's take `@RequestMapping`, which is one To understand what that means, let's take `@RequestMapping`, which is one
of the most widely used Spring annotations as an example. This Java annotation is declared as: of the most widely used Spring annotations as an example. This Java annotation is declared as:
[source,java] [source,java,indent=0]
---- ----
public @interface RequestMapping { public @interface RequestMapping {
@ -568,8 +566,8 @@ use a shortcut annotation such as `@GetMapping` or `@PostMapping`, etc.
[NOTE] [NOTE]
==== ====
Remininder: if the `@RequestMapping` `method` attribute is not specified, all HTTP methods will be matched, Reminder: If the `@RequestMapping` `method` attribute is not specified,
not only the `GET` methods. all HTTP methods will be matched, not only the `GET` methods.
==== ====
Improving the syntax and consistency of Kotlin annotation array attributes is discussed in Improving the syntax and consistency of Kotlin annotation array attributes is discussed in

View File

@ -1,10 +1,9 @@
[[overview]]
= Spring Framework Overview
:toc: left :toc: left
:toclevels: 1 :toclevels: 1
:docinfo1: :docinfo1:
[[overview]]
= Spring Framework Overview
Spring makes it easy to create Java enterprise applications. It provides everything you Spring makes it easy to create Java enterprise applications. It provides everything you
need to embrace the Java language in an enterprise environment, with support for Groovy need to embrace the Java language in an enterprise environment, with support for Groovy
and Kotlin as alternative languages on the JVM, and with the flexibility to create many and Kotlin as alternative languages on the JVM, and with the flexibility to create many

View File

@ -83,7 +83,6 @@ some subset of it:
public void setUp() { public void setUp() {
client = WebTestClient.bindToApplicationContext(context).build(); // <3> client = WebTestClient.bindToApplicationContext(context).build(); // <3>
} }
} }
---- ----

View File

@ -5,6 +5,7 @@
:doc-spring-boot: {doc-root}/spring-boot/docs/current/reference :doc-spring-boot: {doc-root}/spring-boot/docs/current/reference
:toc: left :toc: left
:toclevels: 4 :toclevels: 4
:tabsize: 4
:docinfo1: :docinfo1:
The adoption of the test-driven-development (TDD) approach to software The adoption of the test-driven-development (TDD) approach to software
@ -4297,7 +4298,6 @@ class ExampleTests {
.andExpect(content().contentType("application/json")) .andExpect(content().contentType("application/json"))
.andExpect(jsonPath("$.name").value("Lee")); .andExpect(jsonPath("$.name").value("Lee"));
} }
} }
---- ----
@ -4761,7 +4761,7 @@ paging through all messages. How would you go about testing it?
With Spring MVC Test, we can easily test if we are able to create a `Message`. With Spring MVC Test, we can easily test if we are able to create a `Message`.
[source,java] [source,java,indent=0]
---- ----
MockHttpServletRequestBuilder createMessage = post("/messages/") MockHttpServletRequestBuilder createMessage = post("/messages/")
.param("summary", "Spring Rocks") .param("summary", "Spring Rocks")
@ -4775,7 +4775,7 @@ mockMvc.perform(createMessage)
What if we want to test our form view that allows us to create the message? For example, What if we want to test our form view that allows us to create the message? For example,
assume our form looks like the following snippet: assume our form looks like the following snippet:
[source,xml] [source,xml,indent=0]
---- ----
<form id="messageForm" action="/messages/" method="post"> <form id="messageForm" action="/messages/" method="post">
<div class="pull-right"><a href="/messages/">Messages</a></div> <div class="pull-right"><a href="/messages/">Messages</a></div>
@ -4795,7 +4795,7 @@ assume our form looks like the following snippet:
How do we ensure that our form will produce the correct request to create a new message? A How do we ensure that our form will produce the correct request to create a new message? A
naive attempt would look like this: naive attempt would look like this:
[source,java] [source,java,indent=0]
---- ----
mockMvc.perform(get("/messages/form")) mockMvc.perform(get("/messages/form"))
.andExpect(xpath("//input[@name='summary']").exists()) .andExpect(xpath("//input[@name='summary']").exists())
@ -4807,7 +4807,7 @@ This test has some obvious drawbacks. If we update our controller to use the par
form is out of synch with the controller. To resolve this we can combine our two tests. form is out of synch with the controller. To resolve this we can combine our two tests.
[[spring-mvc-test-server-htmlunit-mock-mvc-test]] [[spring-mvc-test-server-htmlunit-mock-mvc-test]]
[source,java] [source,java,indent=0]
---- ----
String summaryParamName = "summary"; String summaryParamName = "summary";
String textParamName = "text"; String textParamName = "text";
@ -4908,7 +4908,7 @@ In order to use HtmlUnit with Apache HttpComponents 4.5+, you will need to use H
We can easily create an HtmlUnit `WebClient` that integrates with `MockMvc` using the We can easily create an HtmlUnit `WebClient` that integrates with `MockMvc` using the
`MockMvcWebClientBuilder` as follows. `MockMvcWebClientBuilder` as follows.
[source,java] [source,java,indent=0]
---- ----
@Autowired @Autowired
WebApplicationContext context; WebApplicationContext context;
@ -4941,7 +4941,7 @@ Now we can use HtmlUnit as we normally would, but without the need to deploy our
application to a Servlet container. For example, we can request the view to create application to a Servlet container. For example, we can request the view to create
a message with the following. a message with the following.
[source,java] [source,java,indent=0]
---- ----
HtmlPage createMsgFormPage = webClient.getPage("http://localhost/messages/form"); HtmlPage createMsgFormPage = webClient.getPage("http://localhost/messages/form");
---- ----
@ -4955,7 +4955,7 @@ illustrated in <<Advanced MockMvcWebClientBuilder>>.
Once we have a reference to the `HtmlPage`, we can then fill out the form and submit Once we have a reference to the `HtmlPage`, we can then fill out the form and submit
it to create a message. it to create a message.
[source,java] [source,java,indent=0]
---- ----
HtmlForm form = createMsgFormPage.getHtmlElementById("messageForm"); HtmlForm form = createMsgFormPage.getHtmlElementById("messageForm");
HtmlTextInput summaryInput = createMsgFormPage.getHtmlElementById("summary"); HtmlTextInput summaryInput = createMsgFormPage.getHtmlElementById("summary");
@ -4969,7 +4969,7 @@ HtmlPage newMessagePage = submit.click();
Finally, we can verify that a new message was created successfully. The following Finally, we can verify that a new message was created successfully. The following
assertions use the http://joel-costigliola.github.io/assertj/[AssertJ] library. assertions use the http://joel-costigliola.github.io/assertj/[AssertJ] library.
[source,java] [source,java,indent=0]
---- ----
assertThat(newMessagePage.getUrl().toString()).endsWith("/messages/123"); assertThat(newMessagePage.getUrl().toString()).endsWith("/messages/123");
String id = newMessagePage.getHtmlElementById("id").getTextContent(); String id = newMessagePage.getHtmlElementById("id").getTextContent();
@ -4999,7 +4999,7 @@ In the examples so far, we have used `MockMvcWebClientBuilder` in the simplest w
by building a `WebClient` based on the `WebApplicationContext` loaded for us by the Spring by building a `WebClient` based on the `WebApplicationContext` loaded for us by the Spring
TestContext Framework. This approach is repeated here. TestContext Framework. This approach is repeated here.
[source,java] [source,java,indent=0]
---- ----
@Autowired @Autowired
WebApplicationContext context; WebApplicationContext context;
@ -5016,7 +5016,7 @@ public void setup() {
We can also specify additional configuration options. We can also specify additional configuration options.
[source,java] [source,java,indent=0]
---- ----
WebClient webClient; WebClient webClient;
@ -5037,7 +5037,7 @@ public void setup() {
As an alternative, we can perform the exact same setup by configuring the `MockMvc` As an alternative, we can perform the exact same setup by configuring the `MockMvc`
instance separately and supplying it to the `MockMvcWebClientBuilder` as follows. instance separately and supplying it to the `MockMvcWebClientBuilder` as follows.
[source,java] [source,java,indent=0]
---- ----
MockMvc mockMvc = MockMvcBuilders MockMvc mockMvc = MockMvcBuilders
.webAppContextSetup(context) .webAppContextSetup(context)
@ -5094,7 +5094,7 @@ be displayed afterwards.
If one of the fields were named "summary", then we might have something like the If one of the fields were named "summary", then we might have something like the
following repeated in multiple places within our tests. following repeated in multiple places within our tests.
[source,java] [source,java,indent=0]
---- ----
HtmlTextInput summaryInput = currentPage.getHtmlElementById("summary"); HtmlTextInput summaryInput = currentPage.getHtmlElementById("summary");
summaryInput.setValueAttribute(summary); summaryInput.setValueAttribute(summary);
@ -5104,7 +5104,7 @@ So what happens if we change the `id` to "smmry"? Doing so would force us to upd
of our tests to incorporate this change! Of course, this violates the _DRY Principle_; so of our tests to incorporate this change! Of course, this violates the _DRY Principle_; so
we should ideally extract this code into its own method as follows. we should ideally extract this code into its own method as follows.
[source,java] [source,java,indent=0]
---- ----
public HtmlPage createMessage(HtmlPage currentPage, String summary, String text) { public HtmlPage createMessage(HtmlPage currentPage, String summary, String text) {
setSummary(currentPage, summary); setSummary(currentPage, summary);
@ -5122,7 +5122,7 @@ This ensures that we do not have to update all of our tests if we change the UI.
We might even take this a step further and place this logic within an Object that We might even take this a step further and place this logic within an Object that
represents the `HtmlPage` we are currently on. represents the `HtmlPage` we are currently on.
[source,java] [source,java,indent=0]
---- ----
public class CreateMessagePage { public class CreateMessagePage {
@ -5171,7 +5171,7 @@ includes a test dependency on `org.seleniumhq.selenium:selenium-htmlunit-driver`
We can easily create a Selenium `WebDriver` that integrates with `MockMvc` using the We can easily create a Selenium `WebDriver` that integrates with `MockMvc` using the
`MockMvcHtmlUnitDriverBuilder` as follows. `MockMvcHtmlUnitDriverBuilder` as follows.
[source,java] [source,java,indent=0]
---- ----
@Autowired @Autowired
WebApplicationContext context; WebApplicationContext context;
@ -5204,14 +5204,14 @@ Now we can use WebDriver as we normally would, but without the need to deploy ou
application to a Servlet container. For example, we can request the view to create application to a Servlet container. For example, we can request the view to create
a message with the following. a message with the following.
[source,java] [source,java,indent=0]
---- ----
CreateMessagePage page = CreateMessagePage.to(driver); CreateMessagePage page = CreateMessagePage.to(driver);
---- ----
We can then fill out the form and submit it to create a message. We can then fill out the form and submit it to create a message.
[source,java] [source,java,indent=0]
---- ----
ViewMessagePage viewMessagePage = ViewMessagePage viewMessagePage =
page.createMessage(ViewMessagePage.class, expectedSummary, expectedText); page.createMessage(ViewMessagePage.class, expectedSummary, expectedText);
@ -5223,7 +5223,7 @@ Pattern_. As we mentioned in <<spring-mvc-test-server-htmlunit-webdriver-why>>,
use the Page Object Pattern with HtmlUnit, but it is much easier with WebDriver. Let's use the Page Object Pattern with HtmlUnit, but it is much easier with WebDriver. Let's
take a look at our new `CreateMessagePage` implementation. take a look at our new `CreateMessagePage` implementation.
[source,java] [source,java,indent=0]
---- ----
public class CreateMessagePage public class CreateMessagePage
extends AbstractPage { // <1> extends AbstractPage { // <1>
@ -5277,7 +5277,7 @@ annotation to look up our submit button using a css selector, *input[type=submit
Finally, we can verify that a new message was created successfully. The following Finally, we can verify that a new message was created successfully. The following
assertions use the https://code.google.com/p/fest/[FEST assertion library]. assertions use the https://code.google.com/p/fest/[FEST assertion library].
[source,java] [source,java,indent=0]
---- ----
assertThat(viewMessagePage.getMessage()).isEqualTo(expectedMessage); assertThat(viewMessagePage.getMessage()).isEqualTo(expectedMessage);
assertThat(viewMessagePage.getSuccess()).isEqualTo("Successfully created a new message"); assertThat(viewMessagePage.getSuccess()).isEqualTo("Successfully created a new message");
@ -5286,7 +5286,7 @@ assertThat(viewMessagePage.getSuccess()).isEqualTo("Successfully created a new m
We can see that our `ViewMessagePage` allows us to interact with our custom domain We can see that our `ViewMessagePage` allows us to interact with our custom domain
model. For example, it exposes a method that returns a `Message` object. model. For example, it exposes a method that returns a `Message` object.
[source,java] [source,java,indent=0]
---- ----
public Message getMessage() throws ParseException { public Message getMessage() throws ParseException {
Message message = new Message(); Message message = new Message();
@ -5302,7 +5302,7 @@ We can then leverage the rich domain objects in our assertions.
Lastly, don't forget to _close_ the `WebDriver` instance when the test is complete. Lastly, don't forget to _close_ the `WebDriver` instance when the test is complete.
[source,java] [source,java,indent=0]
---- ----
@After @After
public void destroy() { public void destroy() {
@ -5322,7 +5322,7 @@ In the examples so far, we have used `MockMvcHtmlUnitDriverBuilder` in the simpl
possible, by building a `WebDriver` based on the `WebApplicationContext` loaded for us by possible, by building a `WebDriver` based on the `WebApplicationContext` loaded for us by
the Spring TestContext Framework. This approach is repeated here. the Spring TestContext Framework. This approach is repeated here.
[source,java] [source,java,indent=0]
---- ----
@Autowired @Autowired
WebApplicationContext context; WebApplicationContext context;
@ -5339,7 +5339,7 @@ public void setup() {
We can also specify additional configuration options. We can also specify additional configuration options.
[source,java] [source,java,indent=0]
---- ----
WebDriver driver; WebDriver driver;
@ -5360,7 +5360,7 @@ public void setup() {
As an alternative, we can perform the exact same setup by configuring the `MockMvc` As an alternative, we can perform the exact same setup by configuring the `MockMvc`
instance separately and supplying it to the `MockMvcHtmlUnitDriverBuilder` as follows. instance separately and supplying it to the `MockMvcHtmlUnitDriverBuilder` as follows.
[source,java] [source,java,indent=0]
---- ----
MockMvc mockMvc = MockMvcBuilders MockMvc mockMvc = MockMvcBuilders
.webAppContextSetup(context) .webAppContextSetup(context)

View File

@ -4,6 +4,7 @@
:api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework :api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework
:toc: left :toc: left
:toclevels: 4 :toclevels: 4
:tabsize: 4
:docinfo1: :docinfo1:
This part of the documentation covers support for reactive stack, web applications built on a This part of the documentation covers support for reactive stack, web applications built on a

View File

@ -4,6 +4,7 @@
:api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework :api-spring-framework: {doc-root}/spring-framework/docs/{spring-version}/javadoc-api/org/springframework
:toc: left :toc: left
:toclevels: 4 :toclevels: 4
:tabsize: 4
:docinfo1: :docinfo1:
This part of the documentation covers support for Servlet stack, web applications built on the This part of the documentation covers support for Servlet stack, web applications built on the

View File

@ -275,7 +275,6 @@ decoding HTTP messages:
WebClient webClient = WebClient.builder() WebClient webClient = WebClient.builder()
.exchangeStrategies(strategies) .exchangeStrategies(strategies)
.build(); .build();
---- ----
The builder can be used to insert <<webflux-client-filter>>. The builder can be used to insert <<webflux-client-filter>>.
@ -307,11 +306,9 @@ build a new `WebClient`, based on, but without affecting the current instance:
---- ----
WebClient client = WebClient.builder() WebClient client = WebClient.builder()
.filter((request, next) -> { .filter((request, next) -> {
ClientRequest filtered = ClientRequest.from(request) ClientRequest filtered = ClientRequest.from(request)
.header("foo", "bar") .header("foo", "bar")
.build(); .build();
return next.exchange(filtered); return next.exchange(filtered);
}) })
.build(); .build();

View File

@ -37,7 +37,6 @@ public class MyWebSocketHandler implements WebSocketHandler {
public Mono<Void> handle(WebSocketSession session) { public Mono<Void> handle(WebSocketSession session) {
// ... // ...
} }
} }
---- ----
@ -67,7 +66,6 @@ static class WebConfig {
public WebSocketHandlerAdapter handlerAdapter() { public WebSocketHandlerAdapter handlerAdapter() {
return new WebSocketHandlerAdapter(); return new WebSocketHandlerAdapter();
} }
} }
---- ----
@ -112,7 +110,6 @@ static class WebConfig {
strategy.setMaxSessionIdleTimeout(0L); strategy.setMaxSessionIdleTimeout(0L);
return new HandshakeWebSocketService(strategy); return new HandshakeWebSocketService(strategy);
} }
} }
---- ----

View File

@ -53,19 +53,16 @@ public class MyWebApplicationInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletCxt) { public void onStartup(ServletContext servletCxt) {
// Load Spring web application configuration // Load Spring web application configuration
AnnotationConfigWebApplicationContext cxt = new AnnotationConfigWebApplicationContext(); AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
cxt.register(AppConfig.class); ac.register(AppConfig.class);
cxt.refresh(); ac.refresh();
// Create DispatcherServlet // Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(cxt); DispatcherServlet servlet = new DispatcherServlet(ac);
// Register and map the Servlet
ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet); ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
registration.setLoadOnStartup(1); registration.setLoadOnStartup(1);
registration.addMapping("/app/*"); registration.addMapping("/app/*");
} }
} }
---- ----
@ -154,12 +151,12 @@ Below is example configuration with a `WebApplicationContext` hierarchy:
@Override @Override
protected Class<?>[] getRootConfigClasses() { protected Class<?>[] getRootConfigClasses() {
return new Class[] { RootConfig.class }; return new Class<?[] { RootConfig.class };
} }
@Override @Override
protected Class<?>[] getServletConfigClasses() { protected Class<?>[] getServletConfigClasses() {
return new Class[] { App1Config.class }; return new Class<?[] { App1Config.class };
} }
@Override @Override
@ -319,7 +316,6 @@ example of registering a `DispatcherServlet`:
registration.setLoadOnStartup(1); registration.setLoadOnStartup(1);
registration.addMapping("/"); registration.addMapping("/");
} }
} }
---- ----
@ -351,7 +347,6 @@ This is recommended for applications that use Java-based Spring configuration:
protected String[] getServletMappings() { protected String[] getServletMappings() {
return new String[] { "/" }; return new String[] { "/" };
} }
} }
---- ----
@ -379,7 +374,6 @@ If using XML-based Spring configuration, you should extend directly from
protected String[] getServletMappings() { protected String[] getServletMappings() {
return new String[] { "/" }; return new String[] { "/" };
} }
} }
---- ----
@ -1933,13 +1927,10 @@ following the `@ModelAttribute` argument:
---- ----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit") @PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(**@ModelAttribute("pet") Pet pet**, BindingResult result) { public String processSubmit(**@ModelAttribute("pet") Pet pet**, BindingResult result) {
if (result.hasErrors()) { if (result.hasErrors()) {
return "petForm"; return "petForm";
} }
// ... // ...
} }
---- ----
@ -1967,7 +1958,6 @@ public Account findAccount(@PathVariable String accountId) {
@PostMapping("update") @PostMapping("update")
public String update(@Valid AccountUpdateForm form, BindingResult result, public String update(@Valid AccountUpdateForm form, BindingResult result,
**@ModelAttribute(binding=false)** Account account) { **@ModelAttribute(binding=false)** Account account) {
// ... // ...
} }
---- ----
@ -1982,14 +1972,11 @@ subsequently reported back to the user:
---- ----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit") @PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(**@ModelAttribute("pet") Pet pet**, BindingResult result) { public String processSubmit(**@ModelAttribute("pet") Pet pet**, BindingResult result) {
new PetValidator().validate(pet, result); new PetValidator().validate(pet, result);
if (result.hasErrors()) { if (result.hasErrors()) {
return "petForm"; return "petForm";
} }
// ... // ...
} }
---- ----
@ -2001,13 +1988,10 @@ annotation:
---- ----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit") @PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(**@Valid @ModelAttribute("pet") Pet pet**, BindingResult result) { public String processSubmit(**@Valid @ModelAttribute("pet") Pet pet**, BindingResult result) {
if (result.hasErrors()) { if (result.hasErrors()) {
return "petForm"; return "petForm";
} }
// ... // ...
} }
---- ----
@ -2327,31 +2311,32 @@ object and converting from an object to the HTTP response body. The
`RequestMappingHandlerAdapter` supports the `@RequestBody` annotation with the following `RequestMappingHandlerAdapter` supports the `@RequestBody` annotation with the following
default `HttpMessageConverters`: default `HttpMessageConverters`:
* `ByteArrayHttpMessageConverter` converts byte arrays. * `ByteArrayHttpMessageConverter` converts byte arrays
* `StringHttpMessageConverter` converts strings. * `StringHttpMessageConverter` converts strings
* `FormHttpMessageConverter` converts form data to/from a MultiValueMap<String, String>. * `FormHttpMessageConverter` converts form data to/from a `MultiValueMap<String, String>`
* `SourceHttpMessageConverter` converts to/from a javax.xml.transform.Source. * `SourceHttpMessageConverter` converts to/from a `javax.xml.transform.Source``
For more information on these converters, see <<integration.adoc#rest-message-conversion, For more information on these converters, see <<integration.adoc#rest-message-conversion,
Message Converters>>. Also note that if using the MVC namespace or the MVC Java config, a Message Converters>>. Also note that if using the MVC namespace or the MVC Java config,
wider range of message converters are registered by default. See <<mvc-config-enable>> for a wider range of message converters are registered by default, including default JSON
more information. and XML payload converters (if e.g. Jackson, Gson and/or JAXB2 are present at runtime).
See <<mvc-config-enable>> for more information on MVC setup options.
If you intend to read and write XML, you will need to configure the For a custom example, if you intend to read and write XML using the `spring-oxm` module,
`MarshallingHttpMessageConverter` with a specific `Marshaller` and an `Unmarshaller` you need to configure the `MarshallingHttpMessageConverter` with a specific `Marshaller`
implementation from the `org.springframework.oxm` package. The example below shows how implementation from the `org.springframework.oxm` package. The example below shows how to
to do that directly in your configuration but if your application is configured through do that directly in your configuration but if your application is configured through the
the MVC namespace or the MVC Java config see <<mvc-config-enable>> instead. MVC namespace or the MVC Java config see <<mvc-config-enable>> instead.
[source,xml,indent=0] [source,xml,indent=0]
[subs="verbatim,quotes"] [subs="verbatim,quotes"]
---- ----
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters"> <property name="messageConverters">
<util:list id="beanList"> <list>
<ref bean="stringHttpMessageConverter"/> <ref bean="stringHttpMessageConverter"/>
<ref bean="marshallingHttpMessageConverter"/> <ref bean="marshallingHttpMessageConverter"/>
</util:list> <list>
</property> </property>
</bean> </bean>
@ -2360,11 +2345,10 @@ the MVC namespace or the MVC Java config see <<mvc-config-enable>> instead.
<bean id="marshallingHttpMessageConverter" <bean id="marshallingHttpMessageConverter"
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter"> class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="castorMarshaller"/> <constructor-arg ref="xstreamMarshaller"/>
<property name="unmarshaller" ref="castorMarshaller"/>
</bean> </bean>
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/> <bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"/>
---- ----
An `@RequestBody` method parameter can be annotated with `@Valid`, in which case it will An `@RequestBody` method parameter can be annotated with `@Valid`, in which case it will
@ -2833,7 +2817,6 @@ Spring MVC also provides a mechanism for building links to controller methods. F
@GetMapping("/bookings/{booking}") @GetMapping("/bookings/{booking}")
public String getBooking(@PathVariable Long booking) { public String getBooking(@PathVariable Long booking) {
// ... // ...
} }
} }
@ -4029,7 +4012,7 @@ In XML use the `<mvc:annotation-driven>` element:
The above registers a number of Spring MVC The above registers a number of Spring MVC
<<mvc-servlet-special-bean-types,infrastructure beans>> also adapting to dependencies <<mvc-servlet-special-bean-types,infrastructure beans>> also adapting to dependencies
available on the classpath -- for JSON, XML, etc. available on the classpath: e.g. payload converters for JSON, XML, etc.
@ -4047,7 +4030,6 @@ In Java config implement `WebMvcConfigurer` interface:
public class WebConfig implements WebMvcConfigurer { public class WebConfig implements WebMvcConfigurer {
// Implement configuration methods... // Implement configuration methods...
} }
---- ----
@ -4079,7 +4061,6 @@ In Java config, register custom formatters and converters:
public void addFormatters(FormatterRegistry registry) { public void addFormatters(FormatterRegistry registry) {
// ... // ...
} }
} }
---- ----
@ -4153,7 +4134,6 @@ In Java config, you can customize the global `Validator` instance:
public Validator getValidator(); { public Validator getValidator(); {
// ... // ...
} }
} }
---- ----
@ -4219,7 +4199,6 @@ In Java config, register interceptors to apply to incoming requests:
registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**"); registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*"); registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
} }
} }
---- ----
@ -4324,7 +4303,6 @@ Below is an example that adds Jackson JSON and XML converters with a customized
converters.add(new MappingJackson2HttpMessageConverter(builder.build())); converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
converters.add(new MappingJackson2XmlHttpMessageConverter(builder.xml().build())); converters.add(new MappingJackson2XmlHttpMessageConverter(builder.xml().build()));
} }
} }
---- ----
@ -4406,7 +4384,6 @@ An example of forwarding a request for `"/"` to a view called `"home"` in Java:
public void addViewControllers(ViewControllerRegistry registry) { public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home"); registry.addViewController("/").setViewName("home");
} }
} }
---- ----
@ -4442,7 +4419,6 @@ JSON rendering:
registry.enableContentNegotiation(new MappingJackson2JsonView()); registry.enableContentNegotiation(new MappingJackson2JsonView());
registry.jsp(); registry.jsp();
} }
} }
---- ----
@ -4506,7 +4482,6 @@ In Java config simply add the respective "Configurer" bean:
configurer.setTemplateLoaderPath("/WEB-INF/"); configurer.setTemplateLoaderPath("/WEB-INF/");
return configurer; return configurer;
} }
} }
---- ----
@ -4541,7 +4516,6 @@ In Java config:
.addResourceLocations("/public", "classpath:/static/") .addResourceLocations("/public", "classpath:/static/")
.setCachePeriod(31556926); .setCachePeriod(31556926);
} }
} }
---- ----
@ -4584,7 +4558,6 @@ For example in Java config;
.resourceChain(true) .resourceChain(true)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**")); .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
} }
} }
---- ----
@ -4647,7 +4620,6 @@ To enable the feature using the default setup use:
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable(); configurer.enable();
} }
} }
---- ----
@ -4797,7 +4769,6 @@ hook of the Spring `ApplicationContext`:
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException { public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
// ... // ...
} }
} }
---- ----

View File

@ -840,7 +840,6 @@ public class WebSocketConfig extends WebSocketMessageBrokerConfigurationSupport
} }
// ... // ...
} }
---- ----
@ -1470,7 +1469,6 @@ In Java config:
registry.setApplicationDestinationPrefixes("/app"); registry.setApplicationDestinationPrefixes("/app");
registry.setPathMatcher(new AntPathMatcher(".")); registry.setPathMatcher(new AntPathMatcher("."));
} }
} }
---- ----
@ -1511,8 +1509,8 @@ And below is a simple example to illustrate a controller with "." separator:
@MessageMapping("bar.{baz}") @MessageMapping("bar.{baz}")
public void handleBaz(@DestinationVariable String baz) { public void handleBaz(@DestinationVariable String baz) {
// ...
} }
} }
---- ----
@ -1619,18 +1617,14 @@ user and associate it with subsequent STOMP messages on the same session:
@Override @Override
public void configureClientInboundChannel(ChannelRegistration registration) { public void configureClientInboundChannel(ChannelRegistration registration) {
registration.setInterceptors(new ChannelInterceptorAdapter() { registration.setInterceptors(new ChannelInterceptorAdapter() {
@Override @Override
public Message<?> preSend(Message<?> message, MessageChannel channel) { public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = StompHeaderAccessor accessor =
MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
if (StompCommand.CONNECT.equals(accessor.getCommand())) { if (StompCommand.CONNECT.equals(accessor.getCommand())) {
Authentication user = ... ; // access authentication header(s) Authentication user = ... ; // access authentication header(s)
accessor.setUser(user); accessor.setUser(user);
} }
return message; return message;
} }
}); });
@ -1711,7 +1705,6 @@ public class MyController {
} }
---- ----
[NOTE] [NOTE]
==== ====
While user destinations generally imply an authenticated user, it isn't required While user destinations generally imply an authenticated user, it isn't required