Merge branch '6.0.x'

Closes gh-30435
This commit is contained in:
rstoyanchev 2023-05-09 12:16:13 +01:00
commit bc7ba8cf2b
73 changed files with 458 additions and 310 deletions

View File

@ -605,11 +605,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions]. <1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"] [source,kotlin,indent=0,subs="verbatim",role="secondary"]
.Kotlin
---- ----
@Before("com.xyz.Pointcuts.publicMethod() && @annotation(auditable)") // <1> @Before("com.xyz.Pointcuts.publicMethod() && @annotation(auditable)") // <1>
fun audit(auditable: Auditable) { fun audit(auditable: Auditable) {
@ -618,6 +618,7 @@ Java::
} }
---- ----
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions]. <1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
======
[[aop-ataspectj-advice-params-generics]] [[aop-ataspectj-advice-params-generics]]
=== Advice Parameters and Generics === Advice Parameters and Generics
@ -770,12 +771,12 @@ Java::
// ... use code and bean // ... use code and bean
} }
---- ----
======
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions]. <1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
<2> Declares `bean` and `auditable` as the argument names. <2> Declares `bean` and `auditable` as the argument names.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"] [source,kotlin,indent=0,subs="verbatim",role="secondary"]
.Kotlin
---- ----
@Before( @Before(
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1> value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
@ -787,6 +788,7 @@ Java::
---- ----
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions]. <1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
<2> Declares `bean` and `auditable` as the argument names. <2> Declares `bean` and `auditable` as the argument names.
======
If the first parameter is of type `JoinPoint`, `ProceedingJoinPoint`, or If the first parameter is of type `JoinPoint`, `ProceedingJoinPoint`, or
`JoinPoint.StaticPart`, you can omit the name of the parameter from the value of the `JoinPoint.StaticPart`, you can omit the name of the parameter from the value of the
@ -807,12 +809,12 @@ Java::
// ... use code, bean, and jp // ... use code, bean, and jp
} }
---- ----
======
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions]. <1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
<2> Declares `bean` and `auditable` as the argument names. <2> Declares `bean` and `auditable` as the argument names.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"] [source,kotlin,indent=0,subs="verbatim",role="secondary"]
.Kotlin
---- ----
@Before( @Before(
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1> value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
@ -824,6 +826,7 @@ Java::
---- ----
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions]. <1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
<2> Declares `bean` and `auditable` as the argument names. <2> Declares `bean` and `auditable` as the argument names.
======
The special treatment given to the first parameter of type `JoinPoint`, The special treatment given to the first parameter of type `JoinPoint`,
`ProceedingJoinPoint`, or `JoinPoint.StaticPart` is particularly convenient for advice `ProceedingJoinPoint`, or `JoinPoint.StaticPart` is particularly convenient for advice
@ -842,11 +845,11 @@ Java::
// ... use jp // ... use jp
} }
---- ----
======
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions]. <1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"] [source,kotlin,indent=0,subs="verbatim",role="secondary"]
.Kotlin
---- ----
@Before("com.xyz.Pointcuts.publicMethod()") // <1> @Before("com.xyz.Pointcuts.publicMethod()") // <1>
fun audit(jp: JoinPoint) { fun audit(jp: JoinPoint) {
@ -854,6 +857,7 @@ Java::
} }
---- ----
<1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions]. <1> References the `publicMethod` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-pointcuts-combining[Combining Pointcut Expressions].
======
[[aop-ataspectj-advice-proceeding-with-the-call]] [[aop-ataspectj-advice-proceeding-with-the-call]]
@ -879,11 +883,11 @@ Java::
return pjp.proceed(new Object[] {newPattern}); return pjp.proceed(new Object[] {newPattern});
} }
---- ----
======
<1> References the `inDataAccessLayer` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions]. <1> References the `inDataAccessLayer` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions].
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"] [source,kotlin,indent=0,subs="verbatim",role="secondary"]
.Kotlin
---- ----
@Around("execution(List<Account> find*(..)) && " + @Around("execution(List<Account> find*(..)) && " +
"com.xyz.CommonPointcuts.inDataAccessLayer() && " + "com.xyz.CommonPointcuts.inDataAccessLayer() && " +
@ -895,6 +899,7 @@ Java::
} }
---- ----
<1> References the `inDataAccessLayer` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions]. <1> References the `inDataAccessLayer` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions].
======
In many cases, you do this binding anyway (as in the preceding example). In many cases, you do this binding anyway (as in the preceding example).

View File

@ -59,11 +59,11 @@ Java::
} }
} }
---- ----
======
<1> References the `businessService` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions]. <1> References the `businessService` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions].
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"] [source,kotlin,indent=0,subs="verbatim",role="secondary"]
.Kotlin
---- ----
@Aspect @Aspect
class ConcurrentOperationExecutor : Ordered { class ConcurrentOperationExecutor : Ordered {
@ -102,6 +102,7 @@ Java::
} }
---- ----
<1> References the `businessService` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions]. <1> References the `businessService` named pointcut defined in xref:core/aop/ataspectj/pointcuts.adoc#aop-common-pointcuts[Sharing Named Pointcut Definitions].
======
Note that the aspect implements the `Ordered` interface so that we can set the precedence of Note that the aspect implements the `Ordered` interface so that we can set the precedence of
the aspect higher than the transaction advice (we want a fresh transaction each time we the aspect higher than the transaction advice (we want a fresh transaction each time we

View File

@ -167,15 +167,15 @@ Java::
public void tradingOperation() {} // <3> public void tradingOperation() {} // <3>
} }
---- ----
======
<1> `publicMethod` matches if a method execution join point represents the execution <1> `publicMethod` matches if a method execution join point represents the execution
of any public method. of any public method.
<2> `inTrading` matches if a method execution is in the trading module. <2> `inTrading` matches if a method execution is in the trading module.
<3> `tradingOperation` matches if a method execution represents any public method in the <3> `tradingOperation` matches if a method execution represents any public method in the
trading module. trading module.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"] [source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
.Kotlin
---- ----
package com.xyz package com.xyz
@ -197,6 +197,7 @@ of any public method.
<2> `inTrading` matches if a method execution is in the trading module. <2> `inTrading` matches if a method execution is in the trading module.
<3> `tradingOperation` matches if a method execution represents any public method in the <3> `tradingOperation` matches if a method execution represents any public method in the
trading module. trading module.
======
It is a best practice to build more complex pointcut expressions out of smaller _named It is a best practice to build more complex pointcut expressions out of smaller _named
pointcuts_, as shown above. When referring to pointcuts by name, normal Java visibility pointcuts_, as shown above. When referring to pointcuts by name, normal Java visibility

View File

@ -233,14 +233,14 @@ Java::
} }
---- ----
======
<1> We use the Spring-provided `AbstractSingleBeanDefinitionParser` to handle a lot of <1> We use the Spring-provided `AbstractSingleBeanDefinitionParser` to handle a lot of
the basic grunt work of creating a single `BeanDefinition`. the basic grunt work of creating a single `BeanDefinition`.
<2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our <2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our
single `BeanDefinition` represents. single `BeanDefinition` represents.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
---- ----
package org.springframework.samples.xml package org.springframework.samples.xml
@ -274,6 +274,7 @@ single `BeanDefinition` represents.
the basic grunt work of creating a single `BeanDefinition`. the basic grunt work of creating a single `BeanDefinition`.
<2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our <2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our
single `BeanDefinition` represents. single `BeanDefinition` represents.
======
In this simple case, this is all that we need to do. The creation of our single In this simple case, this is all that we need to do. The creation of our single

View File

@ -374,11 +374,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> This line adds the `@Offline` annotation. <1> This line adds the `@Offline` annotation.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
class MovieRecommender { class MovieRecommender {
@ -390,6 +390,7 @@ class MovieRecommender {
} }
---- ----
<1> This line adds the `@Offline` annotation. <1> This line adds the `@Offline` annotation.
======
-- --
Now the bean definition only needs a qualifier `type`, as shown in the following example: Now the bean definition only needs a qualifier `type`, as shown in the following example:

View File

@ -27,11 +27,11 @@ Java::
} }
} }
---- ----
======
<1> This line injects a `@Resource`. <1> This line injects a `@Resource`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
class SimpleMovieLister { class SimpleMovieLister {
@ -40,6 +40,7 @@ class SimpleMovieLister {
} }
---- ----
<1> This line injects a `@Resource`. <1> This line injects a `@Resource`.
======
-- --
@ -118,12 +119,12 @@ Java::
// ... // ...
} }
---- ----
======
<1> The `context` field is injected based on the known resolvable dependency type: <1> The `context` field is injected based on the known resolvable dependency type:
`ApplicationContext`. `ApplicationContext`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
class MovieRecommender { class MovieRecommender {
@ -139,5 +140,6 @@ Java::
---- ----
<1> The `context` field is injected based on the known resolvable dependency type: <1> The `context` field is injected based on the known resolvable dependency type:
`ApplicationContext`. `ApplicationContext`.
======
-- --

View File

@ -70,11 +70,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> The `@Component` causes `@Service` to be treated in the same way as `@Component`. <1> The `@Component` causes `@Service` to be treated in the same way as `@Component`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Target(AnnotationTarget.TYPE) @Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.RUNTIME) @Retention(AnnotationRetention.RUNTIME)
@ -86,6 +86,7 @@ Java::
} }
---- ----
<1> The `@Component` causes `@Service` to be treated in the same way as `@Component`. <1> The `@Component` causes `@Service` to be treated in the same way as `@Component`.
======
You can also combine meta-annotations to create "`composed annotations`". For example, You can also combine meta-annotations to create "`composed annotations`". For example,
the `@RestController` annotation from Spring MVC is composed of `@Controller` and the `@RestController` annotation from Spring MVC is composed of `@Controller` and

View File

@ -184,11 +184,11 @@ Java::
} }
} }
---- ----
======
<1> `@Bean(destroyMethod = "")` disables default destroy method inference. <1> `@Bean(destroyMethod = "")` disables default destroy method inference.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Configuration @Configuration
@Profile("production") @Profile("production")
@ -202,6 +202,7 @@ Java::
} }
---- ----
<1> `@Bean(destroyMethod = "")` disables default destroy method inference. <1> `@Bean(destroyMethod = "")` disables default destroy method inference.
======
-- --
NOTE: As mentioned earlier, with `@Bean` methods, you typically choose to use programmatic NOTE: As mentioned earlier, with `@Bean` methods, you typically choose to use programmatic
@ -294,12 +295,12 @@ Java::
} }
} }
---- ----
======
<1> The `standaloneDataSource` method is available only in the `development` profile. <1> The `standaloneDataSource` method is available only in the `development` profile.
<2> The `jndiDataSource` method is available only in the `production` profile. <2> The `jndiDataSource` method is available only in the `production` profile.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Configuration @Configuration
class AppConfig { class AppConfig {
@ -322,6 +323,7 @@ Java::
---- ----
<1> The `standaloneDataSource` method is available only in the `development` profile. <1> The `standaloneDataSource` method is available only in the `development` profile.
<2> The `jndiDataSource` method is available only in the `production` profile. <2> The `jndiDataSource` method is available only in the `production` profile.
======
-- --
[NOTE] [NOTE]

View File

@ -144,11 +144,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> This annotation enables component scanning. <1> This annotation enables component scanning.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Configuration @Configuration
@ComponentScan(basePackages = ["com.acme"]) // <1> @ComponentScan(basePackages = ["com.acme"]) // <1>
@ -157,6 +157,7 @@ Java::
} }
---- ----
<1> This annotation enables component scanning. <1> This annotation enables component scanning.
======
[TIP] [TIP]

View File

@ -18,17 +18,18 @@ Java::
Expression exp = parser.parseExpression("'Hello World'"); // <1> Expression exp = parser.parseExpression("'Hello World'"); // <1>
String message = (String) exp.getValue(); String message = (String) exp.getValue();
---- ----
======
<1> The value of the message variable is `'Hello World'`. <1> The value of the message variable is `'Hello World'`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
val parser = SpelExpressionParser() val parser = SpelExpressionParser()
val exp = parser.parseExpression("'Hello World'") // <1> val exp = parser.parseExpression("'Hello World'") // <1>
val message = exp.value as String val message = exp.value as String
---- ----
<1> The value of the message variable is `'Hello World'`. <1> The value of the message variable is `'Hello World'`.
======
The SpEL classes and interfaces you are most likely to use are located in the The SpEL classes and interfaces you are most likely to use are located in the
@ -56,17 +57,18 @@ Java::
Expression exp = parser.parseExpression("'Hello World'.concat('!')"); // <1> Expression exp = parser.parseExpression("'Hello World'.concat('!')"); // <1>
String message = (String) exp.getValue(); String message = (String) exp.getValue();
---- ----
======
<1> The value of `message` is now 'Hello World!'. <1> The value of `message` is now 'Hello World!'.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
val parser = SpelExpressionParser() val parser = SpelExpressionParser()
val exp = parser.parseExpression("'Hello World'.concat('!')") // <1> val exp = parser.parseExpression("'Hello World'.concat('!')") // <1>
val message = exp.value as String val message = exp.value as String
---- ----
<1> The value of `message` is now 'Hello World!'. <1> The value of `message` is now 'Hello World!'.
======
The following example of calling a JavaBean property calls the `String` property `Bytes`: The following example of calling a JavaBean property calls the `String` property `Bytes`:
@ -82,11 +84,11 @@ Java::
Expression exp = parser.parseExpression("'Hello World'.bytes"); // <1> Expression exp = parser.parseExpression("'Hello World'.bytes"); // <1>
byte[] bytes = (byte[]) exp.getValue(); byte[] bytes = (byte[]) exp.getValue();
---- ----
======
<1> This line converts the literal to a byte array. <1> This line converts the literal to a byte array.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
val parser = SpelExpressionParser() val parser = SpelExpressionParser()
@ -95,6 +97,7 @@ Java::
val bytes = exp.value as ByteArray val bytes = exp.value as ByteArray
---- ----
<1> This line converts the literal to a byte array. <1> This line converts the literal to a byte array.
======
SpEL also supports nested properties by using the standard dot notation (such as SpEL also supports nested properties by using the standard dot notation (such as
`prop1.prop2.prop3`) and also the corresponding setting of property values. `prop1.prop2.prop3`) and also the corresponding setting of property values.
@ -114,11 +117,11 @@ Java::
Expression exp = parser.parseExpression("'Hello World'.bytes.length"); // <1> Expression exp = parser.parseExpression("'Hello World'.bytes.length"); // <1>
int length = (Integer) exp.getValue(); int length = (Integer) exp.getValue();
---- ----
======
<1> `'Hello World'.bytes.length` gives the length of the literal. <1> `'Hello World'.bytes.length` gives the length of the literal.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
val parser = SpelExpressionParser() val parser = SpelExpressionParser()
@ -127,6 +130,7 @@ Java::
val length = exp.value as Int val length = exp.value as Int
---- ----
<1> `'Hello World'.bytes.length` gives the length of the literal. <1> `'Hello World'.bytes.length` gives the length of the literal.
======
The String's constructor can be called instead of using a string literal, as the following The String's constructor can be called instead of using a string literal, as the following
example shows: example shows:
@ -141,17 +145,18 @@ Java::
Expression exp = parser.parseExpression("new String('hello world').toUpperCase()"); // <1> Expression exp = parser.parseExpression("new String('hello world').toUpperCase()"); // <1>
String message = exp.getValue(String.class); String message = exp.getValue(String.class);
---- ----
======
<1> Construct a new `String` from the literal and make it be upper case. <1> Construct a new `String` from the literal and make it be upper case.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
val parser = SpelExpressionParser() val parser = SpelExpressionParser()
val exp = parser.parseExpression("new String('hello world').toUpperCase()") // <1> val exp = parser.parseExpression("new String('hello world').toUpperCase()") // <1>
val message = exp.getValue(String::class.java) val message = exp.getValue(String::class.java)
---- ----
<1> Construct a new `String` from the literal and make it be upper case. <1> Construct a new `String` from the literal and make it be upper case.
======
Note the use of the generic method: `public <T> T getValue(Class<T> desiredResultType)`. Note the use of the generic method: `public <T> T getValue(Class<T> desiredResultType)`.

View File

@ -63,11 +63,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> The `@Repository` annotation. <1> The `@Repository` annotation.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Repository // <1> @Repository // <1>
class SomeMovieFinder : MovieFinder { class SomeMovieFinder : MovieFinder {
@ -75,6 +75,7 @@ Java::
} }
---- ----
<1> The `@Repository` annotation. <1> The `@Repository` annotation.
======
Any DAO or repository implementation needs access to a persistence resource, Any DAO or repository implementation needs access to a persistence resource,

View File

@ -441,13 +441,13 @@ Java::
// JDBC-backed implementations of the methods on the CorporateEventDao follow... // JDBC-backed implementations of the methods on the CorporateEventDao follow...
} }
---- ----
======
<1> Annotate the class with `@Repository`. <1> Annotate the class with `@Repository`.
<2> Annotate the `DataSource` setter method with `@Autowired`. <2> Annotate the `DataSource` setter method with `@Autowired`.
<3> Create a new `JdbcTemplate` with the `DataSource`. <3> Create a new `JdbcTemplate` with the `DataSource`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Repository // <1> @Repository // <1>
class JdbcCorporateEventDao(dataSource: DataSource) : CorporateEventDao { // <2> class JdbcCorporateEventDao(dataSource: DataSource) : CorporateEventDao { // <2>
@ -460,6 +460,7 @@ Java::
<1> Annotate the class with `@Repository`. <1> Annotate the class with `@Repository`.
<2> Constructor injection of the `DataSource`. <2> Constructor injection of the `DataSource`.
<3> Create a new `JdbcTemplate` with the `DataSource`. <3> Create a new `JdbcTemplate` with the `DataSource`.
======
-- --

View File

@ -89,13 +89,13 @@ Java::
blobIs.close(); blobIs.close();
clobReader.close(); clobReader.close();
---- ----
======
<1> Pass in the `lobHandler` that (in this example) is a plain `DefaultLobHandler`. <1> Pass in the `lobHandler` that (in this example) is a plain `DefaultLobHandler`.
<2> Using the method `setClobAsCharacterStream` to pass in the contents of the CLOB. <2> Using the method `setClobAsCharacterStream` to pass in the contents of the CLOB.
<3> Using the method `setBlobAsBinaryStream` to pass in the contents of the BLOB. <3> Using the method `setBlobAsBinaryStream` to pass in the contents of the BLOB.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
val blobIn = File("spring2004.jpg") val blobIn = File("spring2004.jpg")
val blobIs = FileInputStream(blobIn) val blobIs = FileInputStream(blobIn)
@ -119,6 +119,7 @@ Java::
<1> Pass in the `lobHandler` that (in this example) is a plain `DefaultLobHandler`. <1> Pass in the `lobHandler` that (in this example) is a plain `DefaultLobHandler`.
<2> Using the method `setClobAsCharacterStream` to pass in the contents of the CLOB. <2> Using the method `setClobAsCharacterStream` to pass in the contents of the CLOB.
<3> Using the method `setBlobAsBinaryStream` to pass in the contents of the BLOB. <3> Using the method `setBlobAsBinaryStream` to pass in the contents of the BLOB.
======
[NOTE] [NOTE]
@ -156,12 +157,12 @@ Java::
} }
}); });
---- ----
======
<1> Using the method `getClobAsString` to retrieve the contents of the CLOB. <1> Using the method `getClobAsString` to retrieve the contents of the CLOB.
<2> Using the method `getBlobAsBytes` to retrieve the contents of the BLOB. <2> Using the method `getBlobAsBytes` to retrieve the contents of the BLOB.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
val l = jdbcTemplate.query("select id, a_clob, a_blob from lob_table") { rs, _ -> val l = jdbcTemplate.query("select id, a_clob, a_blob from lob_table") { rs, _ ->
val clobText = lobHandler.getClobAsString(rs, "a_clob") // <1> val clobText = lobHandler.getClobAsString(rs, "a_clob") // <1>
@ -171,6 +172,7 @@ Java::
---- ----
<1> Using the method `getClobAsString` to retrieve the contents of the CLOB. <1> Using the method `getClobAsString` to retrieve the contents of the CLOB.
<2> Using the method `getBlobAsBytes` to retrieve the contents of the BLOB. <2> Using the method `getBlobAsBytes` to retrieve the contents of the BLOB.
======
[[jdbc-in-clause]] [[jdbc-in-clause]]

View File

@ -547,13 +547,13 @@ Java::
// R2DBC-backed implementations of the methods on the CorporateEventDao follow... // R2DBC-backed implementations of the methods on the CorporateEventDao follow...
} }
---- ----
======
<1> Annotate the class with `@Component`. <1> Annotate the class with `@Component`.
<2> Annotate the `ConnectionFactory` setter method with `@Autowired`. <2> Annotate the `ConnectionFactory` setter method with `@Autowired`.
<3> Create a new `DatabaseClient` with the `ConnectionFactory`. <3> Create a new `DatabaseClient` with the `ConnectionFactory`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Component // <1> @Component // <1>
class R2dbcCorporateEventDao(connectionFactory: ConnectionFactory) : CorporateEventDao { // <2> class R2dbcCorporateEventDao(connectionFactory: ConnectionFactory) : CorporateEventDao { // <2>
@ -566,6 +566,7 @@ Java::
<1> Annotate the class with `@Component`. <1> Annotate the class with `@Component`.
<2> Constructor injection of the `ConnectionFactory`. <2> Constructor injection of the `ConnectionFactory`.
<3> Create a new `DatabaseClient` with the `ConnectionFactory`. <3> Create a new `DatabaseClient` with the `ConnectionFactory`.
======
-- --
Regardless of which of the above template initialization styles you choose to use (or Regardless of which of the above template initialization styles you choose to use (or

View File

@ -299,14 +299,14 @@ Java::
.rsocketConnector(connector -> connector.acceptor(responder)) // <3> .rsocketConnector(connector -> connector.acceptor(responder)) // <3>
.tcp("localhost", 7000); .tcp("localhost", 7000);
---- ----
======
<1> Use `PathPatternRouteMatcher`, if `spring-web` is present, for efficient <1> Use `PathPatternRouteMatcher`, if `spring-web` is present, for efficient
route matching. route matching.
<2> Create a responder from a class with `@MessageMapping` and/or `@ConnectMapping` methods. <2> Create a responder from a class with `@MessageMapping` and/or `@ConnectMapping` methods.
<3> Register the responder. <3> Register the responder.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
val strategies = RSocketStrategies.builder() val strategies = RSocketStrategies.builder()
.routeMatcher(PathPatternRouteMatcher()) // <1> .routeMatcher(PathPatternRouteMatcher()) // <1>
@ -323,6 +323,7 @@ Java::
route matching. route matching.
<2> Create a responder from a class with `@MessageMapping` and/or `@ConnectMapping` methods. <2> Create a responder from a class with `@MessageMapping` and/or `@ConnectMapping` methods.
<3> Register the responder. <3> Register the responder.
======
Note the above is only a shortcut designed for programmatic registration of client Note the above is only a shortcut designed for programmatic registration of client
responders. For alternative scenarios, where client responders are in Spring configuration, responders. For alternative scenarios, where client responders are in Spring configuration,
@ -428,12 +429,12 @@ Java::
return ... // <2> return ... // <2>
} }
---- ----
======
<1> Start the request asynchronously, independent from handling. <1> Start the request asynchronously, independent from handling.
<2> Perform handling and return completion `Mono<Void>`. <2> Perform handling and return completion `Mono<Void>`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ConnectMapping @ConnectMapping
suspend fun handle(requester: RSocketRequester) { suspend fun handle(requester: RSocketRequester) {
@ -447,6 +448,7 @@ Java::
---- ----
<1> Start the request asynchronously, independent from handling. <1> Start the request asynchronously, independent from handling.
<2> Perform handling in the suspending function. <2> Perform handling in the suspending function.
======
@ -469,13 +471,13 @@ Java::
.retrieveFlux(AirportLocation.class); // <3> .retrieveFlux(AirportLocation.class); // <3>
---- ----
======
<1> Specify a route to include in the metadata of the request message. <1> Specify a route to include in the metadata of the request message.
<2> Provide data for the request message. <2> Provide data for the request message.
<3> Declare the expected response. <3> Declare the expected response.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
val viewBox: ViewBox = ... val viewBox: ViewBox = ...
@ -486,6 +488,7 @@ Java::
<1> Specify a route to include in the metadata of the request message. <1> Specify a route to include in the metadata of the request message.
<2> Provide data for the request message. <2> Provide data for the request message.
<3> Declare the expected response. <3> Declare the expected response.
======
The interaction type is determined implicitly from the cardinality of the input and The interaction type is determined implicitly from the cardinality of the input and
output. The above example is a `Request-Stream` because one value is sent and a stream output. The above example is a `Request-Stream` because one value is sent and a stream

View File

@ -36,11 +36,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Specify the configuration class. <1> Specify the configuration class.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@SpringJUnitConfig(TestConfig::class) // <1> @SpringJUnitConfig(TestConfig::class) // <1>
class ConfigurationClassJUnitJupiterSpringTests { class ConfigurationClassJUnitJupiterSpringTests {
@ -48,6 +48,7 @@ Java::
} }
---- ----
<1> Specify the configuration class. <1> Specify the configuration class.
======
The following example shows how to use the `@SpringJUnitConfig` annotation to specify the The following example shows how to use the `@SpringJUnitConfig` annotation to specify the
@ -64,11 +65,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Specify the location of a configuration file. <1> Specify the location of a configuration file.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@SpringJUnitConfig(locations = ["/test-config.xml"]) // <1> @SpringJUnitConfig(locations = ["/test-config.xml"]) // <1>
class XmlJUnitJupiterSpringTests { class XmlJUnitJupiterSpringTests {
@ -76,6 +77,7 @@ Java::
} }
---- ----
<1> Specify the location of a configuration file. <1> Specify the location of a configuration file.
======
See xref:testing/testcontext-framework/ctx-management.adoc[Context Management] as well as the javadoc for See xref:testing/testcontext-framework/ctx-management.adoc[Context Management] as well as the javadoc for
@ -109,11 +111,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Specify the configuration class. <1> Specify the configuration class.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@SpringJUnitWebConfig(TestConfig::class) // <1> @SpringJUnitWebConfig(TestConfig::class) // <1>
class ConfigurationClassJUnitJupiterSpringWebTests { class ConfigurationClassJUnitJupiterSpringWebTests {
@ -121,6 +123,7 @@ Java::
} }
---- ----
<1> Specify the configuration class. <1> Specify the configuration class.
======
The following example shows how to use the `@SpringJUnitWebConfig` annotation to specify the The following example shows how to use the `@SpringJUnitWebConfig` annotation to specify the
@ -137,11 +140,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Specify the location of a configuration file. <1> Specify the location of a configuration file.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@SpringJUnitWebConfig(locations = ["/test-config.xml"]) // <1> @SpringJUnitWebConfig(locations = ["/test-config.xml"]) // <1>
class XmlJUnitJupiterSpringWebTests { class XmlJUnitJupiterSpringWebTests {
@ -149,6 +152,7 @@ Java::
} }
---- ----
<1> Specify the location of a configuration file. <1> Specify the location of a configuration file.
======
See xref:testing/testcontext-framework/ctx-management.adoc[Context Management] as well as the javadoc for See xref:testing/testcontext-framework/ctx-management.adoc[Context Management] as well as the javadoc for

View File

@ -39,11 +39,11 @@ Java::
// some logic that should run only on Java VMs from Oracle Corporation // some logic that should run only on Java VMs from Oracle Corporation
} }
---- ----
======
<1> Run this test only when the Java vendor is "Oracle Corporation". <1> Run this test only when the Java vendor is "Oracle Corporation".
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@IfProfileValue(name="java.vendor", value="Oracle Corporation") // <1> @IfProfileValue(name="java.vendor", value="Oracle Corporation") // <1>
@Test @Test
@ -52,6 +52,7 @@ Java::
} }
---- ----
<1> Run this test only when the Java vendor is "Oracle Corporation". <1> Run this test only when the Java vendor is "Oracle Corporation".
======
Alternatively, you can configure `@IfProfileValue` with a list of `values` (with `OR` Alternatively, you can configure `@IfProfileValue` with a list of `values` (with `OR`
@ -70,11 +71,11 @@ Java::
// some logic that should run only for unit and integration test groups // some logic that should run only for unit and integration test groups
} }
---- ----
======
<1> Run this test for unit tests and integration tests. <1> Run this test for unit tests and integration tests.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@IfProfileValue(name="test-groups", values=["unit-tests", "integration-tests"]) // <1> @IfProfileValue(name="test-groups", values=["unit-tests", "integration-tests"]) // <1>
@Test @Test
@ -83,6 +84,7 @@ Java::
} }
---- ----
<1> Run this test for unit tests and integration tests. <1> Run this test for unit tests and integration tests.
======
[[integration-testing-annotations-junit4-profilevaluesourceconfiguration]] [[integration-testing-annotations-junit4-profilevaluesourceconfiguration]]
@ -105,11 +107,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Use a custom profile value source. <1> Use a custom profile value source.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ProfileValueSourceConfiguration(CustomProfileValueSource::class) // <1> @ProfileValueSourceConfiguration(CustomProfileValueSource::class) // <1>
class CustomProfileValueSourceTests { class CustomProfileValueSourceTests {
@ -117,6 +119,7 @@ Java::
} }
---- ----
<1> Use a custom profile value source. <1> Use a custom profile value source.
======
[[integration-testing-annotations-junit4-timed]] [[integration-testing-annotations-junit4-timed]]
@ -141,11 +144,11 @@ Java::
// some logic that should not take longer than 1 second to run // some logic that should not take longer than 1 second to run
} }
---- ----
======
<1> Set the time period for the test to one second. <1> Set the time period for the test to one second.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Timed(millis = 1000) // <1> @Timed(millis = 1000) // <1>
fun testProcessWithOneSecondTimeout() { fun testProcessWithOneSecondTimeout() {
@ -153,6 +156,7 @@ Java::
} }
---- ----
<1> Set the time period for the test to one second. <1> Set the time period for the test to one second.
======
Spring's `@Timed` annotation has different semantics than JUnit 4's `@Test(timeout=...)` Spring's `@Timed` annotation has different semantics than JUnit 4's `@Test(timeout=...)`
@ -186,11 +190,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Repeat this test ten times. <1> Repeat this test ten times.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Repeat(10) // <1> @Repeat(10) // <1>
@Test @Test
@ -199,6 +203,7 @@ Java::
} }
---- ----
<1> Repeat this test ten times. <1> Repeat this test ten times.
======

View File

@ -19,11 +19,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Indicate that the `dev` profile should be active. <1> Indicate that the `dev` profile should be active.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ContextConfiguration @ContextConfiguration
@ActiveProfiles("dev") // <1> @ActiveProfiles("dev") // <1>
@ -32,6 +32,7 @@ Java::
} }
---- ----
<1> Indicate that the `dev` profile should be active. <1> Indicate that the `dev` profile should be active.
======
The following example indicates that both the `dev` and the `integration` profiles should The following example indicates that both the `dev` and the `integration` profiles should
@ -49,11 +50,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Indicate that the `dev` and `integration` profiles should be active. <1> Indicate that the `dev` and `integration` profiles should be active.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ContextConfiguration @ContextConfiguration
@ActiveProfiles(["dev", "integration"]) // <1> @ActiveProfiles(["dev", "integration"]) // <1>
@ -62,6 +63,7 @@ Java::
} }
---- ----
<1> Indicate that the `dev` and `integration` profiles should be active. <1> Indicate that the `dev` and `integration` profiles should be active.
======
NOTE: `@ActiveProfiles` provides support for inheriting active bean definition profiles NOTE: `@ActiveProfiles` provides support for inheriting active bean definition profiles

View File

@ -18,11 +18,11 @@ Java::
// logic to be run after a transaction has ended // logic to be run after a transaction has ended
} }
---- ----
======
<1> Run this method after a transaction. <1> Run this method after a transaction.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@AfterTransaction // <1> @AfterTransaction // <1>
fun afterTransaction() { fun afterTransaction() {
@ -30,5 +30,6 @@ Java::
} }
---- ----
<1> Run this method after a transaction. <1> Run this method after a transaction.
======

View File

@ -20,11 +20,11 @@ Java::
// logic to be run before a transaction is started // logic to be run before a transaction is started
} }
---- ----
======
<1> Run this method before a transaction. <1> Run this method before a transaction.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@BeforeTransaction // <1> @BeforeTransaction // <1>
fun beforeTransaction() { fun beforeTransaction() {
@ -32,5 +32,6 @@ Java::
} }
---- ----
<1> Run this method before a transaction. <1> Run this method before a transaction.
======

View File

@ -21,11 +21,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Commit the result of the test to the database. <1> Commit the result of the test to the database.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Commit // <1> @Commit // <1>
@Test @Test
@ -34,5 +34,6 @@ Java::
} }
---- ----
<1> Commit the result of the test to the database. <1> Commit the result of the test to the database.
======

View File

@ -26,11 +26,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Referring to an XML file. <1> Referring to an XML file.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ContextConfiguration("/test-config.xml") // <1> @ContextConfiguration("/test-config.xml") // <1>
class XmlApplicationContextTests { class XmlApplicationContextTests {
@ -38,6 +38,7 @@ Java::
} }
---- ----
<1> Referring to an XML file. <1> Referring to an XML file.
======
The following example shows a `@ContextConfiguration` annotation that refers to a class: The following example shows a `@ContextConfiguration` annotation that refers to a class:
@ -53,11 +54,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Referring to a class. <1> Referring to a class.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ContextConfiguration(classes = [TestConfig::class]) // <1> @ContextConfiguration(classes = [TestConfig::class]) // <1>
class ConfigClassApplicationContextTests { class ConfigClassApplicationContextTests {
@ -65,6 +66,7 @@ Java::
} }
---- ----
<1> Referring to a class. <1> Referring to a class.
======
As an alternative or in addition to declaring resource locations or component classes, As an alternative or in addition to declaring resource locations or component classes,
@ -82,11 +84,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Declaring an initializer class. <1> Declaring an initializer class.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ContextConfiguration(initializers = [CustomContextInitializer::class]) // <1> @ContextConfiguration(initializers = [CustomContextInitializer::class]) // <1>
class ContextInitializerTests { class ContextInitializerTests {
@ -94,6 +96,7 @@ Java::
} }
---- ----
<1> Declaring an initializer class. <1> Declaring an initializer class.
======
You can optionally use `@ContextConfiguration` to declare the `ContextLoader` strategy as You can optionally use `@ContextConfiguration` to declare the `ContextLoader` strategy as
@ -114,11 +117,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Configuring both a location and a custom loader. <1> Configuring both a location and a custom loader.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ContextConfiguration("/test-context.xml", loader = CustomContextLoader::class) // <1> @ContextConfiguration("/test-context.xml", loader = CustomContextLoader::class) // <1>
class CustomLoaderXmlApplicationContextTests { class CustomLoaderXmlApplicationContextTests {
@ -126,6 +129,7 @@ Java::
} }
---- ----
<1> Configuring both a location and a custom loader. <1> Configuring both a location and a custom loader.
======
NOTE: `@ContextConfiguration` provides support for inheriting resource locations or NOTE: `@ContextConfiguration` provides support for inheriting resource locations or

View File

@ -31,11 +31,11 @@ Java::
// some tests that require a new Spring container // some tests that require a new Spring container
} }
---- ----
======
<1> Dirty the context before the current test class. <1> Dirty the context before the current test class.
+ +
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@DirtiesContext(classMode = BEFORE_CLASS) // <1> @DirtiesContext(classMode = BEFORE_CLASS) // <1>
class FreshContextTests { class FreshContextTests {
@ -43,6 +43,7 @@ Java::
} }
---- ----
<1> Dirty the context before the current test class. <1> Dirty the context before the current test class.
======
* After the current test class, when declared on a class with class mode set to * After the current test class, when declared on a class with class mode set to
`AFTER_CLASS` (i.e., the default class mode). `AFTER_CLASS` (i.e., the default class mode).
@ -58,11 +59,11 @@ Java::
// some tests that result in the Spring container being dirtied // some tests that result in the Spring container being dirtied
} }
---- ----
======
<1> Dirty the context after the current test class. <1> Dirty the context after the current test class.
+ +
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@DirtiesContext // <1> @DirtiesContext // <1>
class ContextDirtyingTests { class ContextDirtyingTests {
@ -70,6 +71,7 @@ Java::
} }
---- ----
<1> Dirty the context after the current test class. <1> Dirty the context after the current test class.
======
* Before each test method in the current test class, when declared on a class with class * Before each test method in the current test class, when declared on a class with class
@ -86,11 +88,11 @@ Java::
// some tests that require a new Spring container // some tests that require a new Spring container
} }
---- ----
======
<1> Dirty the context before each test method. <1> Dirty the context before each test method.
+ +
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@DirtiesContext(classMode = BEFORE_EACH_TEST_METHOD) // <1> @DirtiesContext(classMode = BEFORE_EACH_TEST_METHOD) // <1>
class FreshContextTests { class FreshContextTests {
@ -98,6 +100,7 @@ Java::
} }
---- ----
<1> Dirty the context before each test method. <1> Dirty the context before each test method.
======
* After each test method in the current test class, when declared on a class with class * After each test method in the current test class, when declared on a class with class
@ -114,11 +117,11 @@ Java::
// some tests that result in the Spring container being dirtied // some tests that result in the Spring container being dirtied
} }
---- ----
======
<1> Dirty the context after each test method. <1> Dirty the context after each test method.
+ +
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) // <1> @DirtiesContext(classMode = AFTER_EACH_TEST_METHOD) // <1>
class ContextDirtyingTests { class ContextDirtyingTests {
@ -126,6 +129,7 @@ Java::
} }
---- ----
<1> Dirty the context after each test method. <1> Dirty the context after each test method.
======
* Before the current test, when declared on a method with the method mode set to * Before the current test, when declared on a method with the method mode set to
@ -143,11 +147,11 @@ Java::
// some logic that requires a new Spring container // some logic that requires a new Spring container
} }
---- ----
======
<1> Dirty the context before the current test method. <1> Dirty the context before the current test method.
+ +
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@DirtiesContext(methodMode = BEFORE_METHOD) // <1> @DirtiesContext(methodMode = BEFORE_METHOD) // <1>
@Test @Test
@ -156,6 +160,7 @@ Java::
} }
---- ----
<1> Dirty the context before the current test method. <1> Dirty the context before the current test method.
======
* After the current test, when declared on a method with the method mode set to * After the current test, when declared on a method with the method mode set to
`AFTER_METHOD` (i.e., the default method mode). `AFTER_METHOD` (i.e., the default method mode).
@ -172,11 +177,11 @@ Java::
// some logic that results in the Spring container being dirtied // some logic that results in the Spring container being dirtied
} }
---- ----
======
<1> Dirty the context after the current test method. <1> Dirty the context after the current test method.
+ +
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@DirtiesContext // <1> @DirtiesContext // <1>
@Test @Test
@ -185,6 +190,7 @@ Java::
} }
---- ----
<1> Dirty the context after the current test method. <1> Dirty the context after the current test method.
======
If you use `@DirtiesContext` in a test whose context is configured as part of a context If you use `@DirtiesContext` in a test whose context is configured as part of a context
@ -220,11 +226,11 @@ Java::
} }
} }
---- ----
======
<1> Use the current-level algorithm. <1> Use the current-level algorithm.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ContextHierarchy( @ContextHierarchy(
ContextConfiguration("/parent-config.xml"), ContextConfiguration("/parent-config.xml"),
@ -243,6 +249,7 @@ Java::
} }
---- ----
<1> Use the current-level algorithm. <1> Use the current-level algorithm.
======
For further details regarding the `EXHAUSTIVE` and `CURRENT_LEVEL` algorithms, see the For further details regarding the `EXHAUSTIVE` and `CURRENT_LEVEL` algorithms, see the

View File

@ -29,13 +29,13 @@ Java::
// tests ... // tests ...
} }
---- ----
======
<1> Annotate a `static` method with `@DynamicPropertySource`. <1> Annotate a `static` method with `@DynamicPropertySource`.
<2> Accept a `DynamicPropertyRegistry` as an argument. <2> Accept a `DynamicPropertyRegistry` as an argument.
<3> Register a dynamic `server.port` property to be retrieved lazily from the server. <3> Register a dynamic `server.port` property to be retrieved lazily from the server.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ContextConfiguration @ContextConfiguration
class MyIntegrationTests { class MyIntegrationTests {
@ -58,6 +58,7 @@ Java::
<1> Annotate a `static` method with `@DynamicPropertySource`. <1> Annotate a `static` method with `@DynamicPropertySource`.
<2> Accept a `DynamicPropertyRegistry` as an argument. <2> Accept a `DynamicPropertyRegistry` as an argument.
<3> Register a dynamic `server.port` property to be retrieved lazily from the server. <3> Register a dynamic `server.port` property to be retrieved lazily from the server.
======
See xref:testing/testcontext-framework/ctx-management/dynamic-property-sources.adoc[Context Configuration with Dynamic Property Sources] for further details. See xref:testing/testcontext-framework/ctx-management/dynamic-property-sources.adoc[Context Configuration with Dynamic Property Sources] for further details.

View File

@ -27,11 +27,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Do not roll back the result. <1> Do not roll back the result.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Rollback(false) // <1> @Rollback(false) // <1>
@Test @Test
@ -40,5 +40,6 @@ Java::
} }
---- ----
<1> Do not roll back the result. <1> Do not roll back the result.
======

View File

@ -17,11 +17,11 @@ Java::
// run code that relies on the test schema and test data // run code that relies on the test schema and test data
} }
---- ----
======
<1> Run two scripts for this test. <1> Run two scripts for this test.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Test @Test
@Sql("/test-schema.sql", "/test-user-data.sql") // <1> @Sql("/test-schema.sql", "/test-user-data.sql") // <1>
@ -30,6 +30,7 @@ Java::
} }
---- ----
<1> Run two scripts for this test. <1> Run two scripts for this test.
======
See xref:testing/testcontext-framework/executing-sql.adoc#testcontext-executing-sql-declaratively[Executing SQL scripts declaratively with @Sql] for further details. See xref:testing/testcontext-framework/executing-sql.adoc#testcontext-executing-sql-declaratively[Executing SQL scripts declaratively with @Sql] for further details.

View File

@ -19,11 +19,11 @@ Java::
// run code that relies on the test data // run code that relies on the test data
} }
---- ----
======
<1> Set the comment prefix and the separator in SQL scripts. <1> Set the comment prefix and the separator in SQL scripts.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Test @Test
@Sql("/test-user-data.sql", config = SqlConfig(commentPrefix = "`", separator = "@@")) // <1> @Sql("/test-user-data.sql", config = SqlConfig(commentPrefix = "`", separator = "@@")) // <1>
@ -32,4 +32,5 @@ Java::
} }
---- ----
<1> Set the comment prefix and the separator in SQL scripts. <1> Set the comment prefix and the separator in SQL scripts.
======

View File

@ -22,11 +22,11 @@ Java::
// run code that uses the test schema and test data // run code that uses the test schema and test data
} }
---- ----
======
<1> Declare a group of SQL scripts. <1> Declare a group of SQL scripts.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Test @Test
@SqlGroup( // <1> @SqlGroup( // <1>
@ -37,6 +37,7 @@ Java::
} }
---- ----
<1> Declare a group of SQL scripts. <1> Declare a group of SQL scripts.
======

View File

@ -29,11 +29,11 @@ Java::
} }
} }
---- ----
======
<1> Set the `@Sql` merge mode to `MERGE` for all test methods in the class. <1> Set the `@Sql` merge mode to `MERGE` for all test methods in the class.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@SpringJUnitConfig(TestConfig::class) @SpringJUnitConfig(TestConfig::class)
@Sql("/test-schema.sql") @Sql("/test-schema.sql")
@ -48,6 +48,7 @@ Java::
} }
---- ----
<1> Set the `@Sql` merge mode to `MERGE` for all test methods in the class. <1> Set the `@Sql` merge mode to `MERGE` for all test methods in the class.
======
The following example shows how to use `@SqlMergeMode` at the method level. The following example shows how to use `@SqlMergeMode` at the method level.
@ -69,11 +70,11 @@ Java::
} }
} }
---- ----
======
<1> Set the `@Sql` merge mode to `MERGE` for a specific test method. <1> Set the `@Sql` merge mode to `MERGE` for a specific test method.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@SpringJUnitConfig(TestConfig::class) @SpringJUnitConfig(TestConfig::class)
@Sql("/test-schema.sql") @Sql("/test-schema.sql")
@ -88,5 +89,6 @@ Java::
} }
---- ----
<1> Set the `@Sql` merge mode to `MERGE` for a specific test method. <1> Set the `@Sql` merge mode to `MERGE` for a specific test method.
======

View File

@ -20,11 +20,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Register two `TestExecutionListener` implementations. <1> Register two `TestExecutionListener` implementations.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ContextConfiguration @ContextConfiguration
@TestExecutionListeners(CustomTestExecutionListener::class, AnotherTestExecutionListener::class) // <1> @TestExecutionListeners(CustomTestExecutionListener::class, AnotherTestExecutionListener::class) // <1>
@ -33,6 +33,7 @@ Java::
} }
---- ----
<1> Register two `TestExecutionListener` implementations. <1> Register two `TestExecutionListener` implementations.
======
By default, `@TestExecutionListeners` provides support for inheriting listeners from By default, `@TestExecutionListeners` provides support for inheriting listeners from

View File

@ -20,11 +20,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Get properties from `test.properties` in the root of the classpath. <1> Get properties from `test.properties` in the root of the classpath.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ContextConfiguration @ContextConfiguration
@TestPropertySource("/test.properties") // <1> @TestPropertySource("/test.properties") // <1>
@ -33,6 +33,7 @@ Java::
} }
---- ----
<1> Get properties from `test.properties` in the root of the classpath. <1> Get properties from `test.properties` in the root of the classpath.
======
The following example demonstrates how to declare inlined properties: The following example demonstrates how to declare inlined properties:
@ -49,11 +50,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Declare `timezone` and `port` properties. <1> Declare `timezone` and `port` properties.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ContextConfiguration @ContextConfiguration
@TestPropertySource(properties = ["timezone = GMT", "port: 4242"]) // <1> @TestPropertySource(properties = ["timezone = GMT", "port: 4242"]) // <1>
@ -62,6 +63,7 @@ Java::
} }
---- ----
<1> Declare `timezone` and `port` properties. <1> Declare `timezone` and `port` properties.
======
See xref:testing/testcontext-framework/ctx-management/property-sources.adoc[Context Configuration with Test Property Sources] for examples and further details. See xref:testing/testcontext-framework/ctx-management/property-sources.adoc[Context Configuration with Test Property Sources] for examples and further details.

View File

@ -25,11 +25,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> The `@WebAppConfiguration` annotation. <1> The `@WebAppConfiguration` annotation.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ContextConfiguration @ContextConfiguration
@WebAppConfiguration // <1> @WebAppConfiguration // <1>
@ -38,6 +38,7 @@ Java::
} }
---- ----
<1> The `@WebAppConfiguration` annotation. <1> The `@WebAppConfiguration` annotation.
======
-- --
@ -59,11 +60,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Specifying a classpath resource. <1> Specifying a classpath resource.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ContextConfiguration @ContextConfiguration
@WebAppConfiguration("classpath:test-web-resources") // <1> @WebAppConfiguration("classpath:test-web-resources") // <1>
@ -72,6 +73,7 @@ Java::
} }
---- ----
<1> Specifying a classpath resource. <1> Specifying a classpath resource.
======
-- --

View File

@ -37,15 +37,15 @@ Java::
.andExpect(content().string("body")); .andExpect(content().string("body"));
} }
---- ----
======
<1> Check response status is still unchanged <1> Check response status is still unchanged
<2> Async processing must have started <2> Async processing must have started
<3> Wait and assert the async result <3> Wait and assert the async result
<4> Manually perform an ASYNC dispatch (as there is no running container) <4> Manually perform an ASYNC dispatch (as there is no running container)
<5> Verify the final response <5> Verify the final response
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Test @Test
fun test() { fun test() {
@ -69,5 +69,6 @@ Java::
<3> Wait and assert the async result <3> Wait and assert the async result
<4> Manually perform an ASYNC dispatch (as there is no running container) <4> Manually perform an ASYNC dispatch (as there is no running container)
<5> Verify the final response <5> Verify the final response
======

View File

@ -298,7 +298,6 @@ Java::
} }
} }
---- ----
======
<1> `CreateMessagePage` extends the `AbstractPage`. We do not go over the details of <1> `CreateMessagePage` extends the `AbstractPage`. We do not go over the details of
`AbstractPage`, but, in summary, it contains common functionality for all of our pages. `AbstractPage`, but, in summary, it contains common functionality for all of our pages.
For example, if our application has a navigational bar, global error messages, and other For example, if our application has a navigational bar, global error messages, and other
@ -316,8 +315,9 @@ https://github.com/SeleniumHQ/selenium/wiki/PageFactory#making-the-example-work-
to override the default lookup behavior. Our example shows how to use the `@FindBy` to override the default lookup behavior. Our example shows how to use the `@FindBy`
annotation to look up our submit button with a `css` selector (`input[type=submit]`). annotation to look up our submit button with a `css` selector (`input[type=submit]`).
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
class CreateMessagePage(private val driver: WebDriver) : AbstractPage(driver) { // <1> class CreateMessagePage(private val driver: WebDriver) : AbstractPage(driver) { // <1>
@ -358,6 +358,7 @@ by the `id` or `name` of the element within the HTML page.
https://github.com/SeleniumHQ/selenium/wiki/PageFactory#making-the-example-work-using-annotations[`@FindBy` annotation] https://github.com/SeleniumHQ/selenium/wiki/PageFactory#making-the-example-work-using-annotations[`@FindBy` annotation]
to override the default lookup behavior. Our example shows how to use the `@FindBy` to override the default lookup behavior. Our example shows how to use the `@FindBy`
annotation to look up our submit button with a `css` selector (*input[type=submit]*). annotation to look up our submit button with 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

View File

@ -54,14 +54,13 @@ Java::
} }
} }
---- ----
======
<1> Annotate the test class with `@RecordApplicationEvents`. <1> Annotate the test class with `@RecordApplicationEvents`.
<2> Inject the `ApplicationEvents` instance for the current test. <2> Inject the `ApplicationEvents` instance for the current test.
<3> Use the `ApplicationEvents` API to count how many `OrderSubmitted` events were published. <3> Use the `ApplicationEvents` API to count how many `OrderSubmitted` events were published.
// Don't use "quotes" in the "subs" section because of the asterisks in /* ... */ Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"] [source,kotlin,indent=0,subs="verbatim",role="secondary"]
.Kotlin
---- ----
@SpringJUnitConfig(/* ... */) @SpringJUnitConfig(/* ... */)
@RecordApplicationEvents // <1> @RecordApplicationEvents // <1>
@ -86,6 +85,7 @@ Java::
<1> Annotate the test class with `@RecordApplicationEvents`. <1> Annotate the test class with `@RecordApplicationEvents`.
<2> Inject the `ApplicationEvents` instance for the current test. <2> Inject the `ApplicationEvents` instance for the current test.
<3> Use the `ApplicationEvents` API to count how many `OrderSubmitted` events were published. <3> Use the `ApplicationEvents` API to count how many `OrderSubmitted` events were published.
======
See the See the
{api-spring-framework}/test/context/event/ApplicationEvents.html[`ApplicationEvents` {api-spring-framework}/test/context/event/ApplicationEvents.html[`ApplicationEvents`

View File

@ -31,11 +31,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Injecting the `ApplicationContext`. <1> Injecting the `ApplicationContext`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@SpringJUnitConfig @SpringJUnitConfig
class MyTest { class MyTest {
@ -47,6 +47,7 @@ Java::
} }
---- ----
<1> Injecting the `ApplicationContext`. <1> Injecting the `ApplicationContext`.
======
Similarly, if your test is configured to load a `WebApplicationContext`, you can inject Similarly, if your test is configured to load a `WebApplicationContext`, you can inject
@ -67,12 +68,12 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Configuring the `WebApplicationContext`. <1> Configuring the `WebApplicationContext`.
<2> Injecting the `WebApplicationContext`. <2> Injecting the `WebApplicationContext`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@SpringJUnitWebConfig // <1> @SpringJUnitWebConfig // <1>
class MyWebAppTest { class MyWebAppTest {
@ -84,6 +85,7 @@ Java::
---- ----
<1> Configuring the `WebApplicationContext`. <1> Configuring the `WebApplicationContext`.
<2> Injecting the `WebApplicationContext`. <2> Injecting the `WebApplicationContext`.
======
Dependency injection by using `@Autowired` is provided by the Dependency injection by using `@Autowired` is provided by the

View File

@ -28,11 +28,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Specifying the location of Groovy configuration files. <1> Specifying the location of Groovy configuration files.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ExtendWith(SpringExtension::class) @ExtendWith(SpringExtension::class)
// ApplicationContext will be loaded from "/AppConfig.groovy" and // ApplicationContext will be loaded from "/AppConfig.groovy" and
@ -43,6 +43,7 @@ Java::
} }
---- ----
<1> Specifying the location of Groovy configuration files. <1> Specifying the location of Groovy configuration files.
======
If you omit both the `locations` and `value` attributes from the `@ContextConfiguration` If you omit both the `locations` and `value` attributes from the `@ContextConfiguration`
@ -67,11 +68,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Loading configuration from the default location. <1> Loading configuration from the default location.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ExtendWith(SpringExtension::class) @ExtendWith(SpringExtension::class)
// ApplicationContext will be loaded from // ApplicationContext will be loaded from
@ -82,6 +83,7 @@ Java::
} }
---- ----
<1> Loading configuration from the default location. <1> Loading configuration from the default location.
======
.Declaring XML configuration and Groovy scripts simultaneously .Declaring XML configuration and Groovy scripts simultaneously

View File

@ -47,12 +47,12 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Configuration file defined in the superclass. <1> Configuration file defined in the superclass.
<2> Configuration file defined in the subclass. <2> Configuration file defined in the subclass.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ExtendWith(SpringExtension::class) @ExtendWith(SpringExtension::class)
// ApplicationContext will be loaded from "/base-config.xml" // ApplicationContext will be loaded from "/base-config.xml"
@ -71,6 +71,7 @@ Java::
---- ----
<1> Configuration file defined in the superclass. <1> Configuration file defined in the superclass.
<2> Configuration file defined in the subclass. <2> Configuration file defined in the subclass.
======
Similarly, in the next example, which uses component classes, the `ApplicationContext` Similarly, in the next example, which uses component classes, the `ApplicationContext`
@ -97,12 +98,12 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Configuration class defined in the superclass. <1> Configuration class defined in the superclass.
<2> Configuration class defined in the subclass. <2> Configuration class defined in the subclass.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
// ApplicationContext will be loaded from BaseConfig // ApplicationContext will be loaded from BaseConfig
@SpringJUnitConfig(BaseConfig::class) // <1> @SpringJUnitConfig(BaseConfig::class) // <1>
@ -118,6 +119,7 @@ Java::
---- ----
<1> Configuration class defined in the superclass. <1> Configuration class defined in the superclass.
<2> Configuration class defined in the subclass. <2> Configuration class defined in the subclass.
======
In the next example, which uses context initializers, the `ApplicationContext` for In the next example, which uses context initializers, the `ApplicationContext` for
@ -146,12 +148,12 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Initializer defined in the superclass. <1> Initializer defined in the superclass.
<2> Initializer defined in the subclass. <2> Initializer defined in the subclass.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
// ApplicationContext will be initialized by BaseInitializer // ApplicationContext will be initialized by BaseInitializer
@SpringJUnitConfig(initializers = [BaseInitializer::class]) // <1> @SpringJUnitConfig(initializers = [BaseInitializer::class]) // <1>
@ -168,5 +170,6 @@ Java::
---- ----
<1> Initializer defined in the superclass. <1> Initializer defined in the superclass.
<2> Initializer defined in the subclass. <2> Initializer defined in the subclass.
======

View File

@ -29,11 +29,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Specifying configuration by using a configuration class and an initializer. <1> Specifying configuration by using a configuration class and an initializer.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ExtendWith(SpringExtension::class) @ExtendWith(SpringExtension::class)
// ApplicationContext will be loaded from TestConfig // ApplicationContext will be loaded from TestConfig
@ -46,6 +46,7 @@ Java::
} }
---- ----
<1> Specifying configuration by using a configuration class and an initializer. <1> Specifying configuration by using a configuration class and an initializer.
======
You can also omit the declaration of XML configuration files, Groovy scripts, or You can also omit the declaration of XML configuration files, Groovy scripts, or
@ -68,11 +69,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Specifying configuration by using only an initializer. <1> Specifying configuration by using only an initializer.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ExtendWith(SpringExtension::class) @ExtendWith(SpringExtension::class)
// ApplicationContext will be initialized by EntireAppInitializer // ApplicationContext will be initialized by EntireAppInitializer
@ -83,5 +84,6 @@ Java::
} }
---- ----
<1> Specifying configuration by using only an initializer. <1> Specifying configuration by using only an initializer.
======

View File

@ -19,11 +19,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Specifying component classes. <1> Specifying component classes.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ExtendWith(SpringExtension::class) @ExtendWith(SpringExtension::class)
// ApplicationContext will be loaded from AppConfig and TestConfig // ApplicationContext will be loaded from AppConfig and TestConfig
@ -33,6 +33,7 @@ Java::
} }
---- ----
<1> Specifying component classes. <1> Specifying component classes.
======
[[testcontext-ctx-management-javaconfig-component-classes]] [[testcontext-ctx-management-javaconfig-component-classes]]
@ -100,11 +101,11 @@ Java::
} }
---- ----
======
<1> Loading configuration information from the nested `Config` class. <1> Loading configuration information from the nested `Config` class.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@SpringJUnitConfig <1> @SpringJUnitConfig <1>
// ApplicationContext will be loaded from the nested Config class // ApplicationContext will be loaded from the nested Config class
@ -131,5 +132,6 @@ Java::
} }
---- ----
<1> Loading configuration information from the nested `Config` class. <1> Loading configuration information from the nested `Config` class.
======

View File

@ -52,11 +52,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Specifying a properties file with an absolute path. <1> Specifying a properties file with an absolute path.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ContextConfiguration @ContextConfiguration
@TestPropertySource("/test.properties") // <1> @TestPropertySource("/test.properties") // <1>
@ -65,6 +65,7 @@ Java::
} }
---- ----
<1> Specifying a properties file with an absolute path. <1> Specifying a properties file with an absolute path.
======
You can configure inlined properties in the form of key-value pairs by using the You can configure inlined properties in the form of key-value pairs by using the
@ -93,11 +94,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Setting two properties by using two variations of the key-value syntax. <1> Setting two properties by using two variations of the key-value syntax.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ContextConfiguration @ContextConfiguration
@TestPropertySource(properties = ["timezone = GMT", "port: 4242"]) // <1> @TestPropertySource(properties = ["timezone = GMT", "port: 4242"]) // <1>
@ -106,6 +107,7 @@ Java::
} }
---- ----
<1> Setting two properties by using two variations of the key-value syntax. <1> Setting two properties by using two variations of the key-value syntax.
======
[NOTE] [NOTE]
==== ====

View File

@ -24,11 +24,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Setting the locations attribute to a list of XML files. <1> Setting the locations attribute to a list of XML files.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ExtendWith(SpringExtension::class) @ExtendWith(SpringExtension::class)
// ApplicationContext will be loaded from "/app-config.xml" and // ApplicationContext will be loaded from "/app-config.xml" and
@ -39,6 +39,7 @@ Java::
} }
---- ----
<1> Setting the locations attribute to a list of XML files. <1> Setting the locations attribute to a list of XML files.
======
`@ContextConfiguration` supports an alias for the `locations` attribute through the `@ContextConfiguration` supports an alias for the `locations` attribute through the
@ -59,11 +60,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Specifying XML files without using the `locations` attribute. <1> Specifying XML files without using the `locations` attribute.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ExtendWith(SpringExtension::class) @ExtendWith(SpringExtension::class)
@ContextConfiguration("/app-config.xml", "/test-config.xml") // <1> @ContextConfiguration("/app-config.xml", "/test-config.xml") // <1>
@ -72,6 +73,7 @@ Java::
} }
---- ----
<1> Specifying XML files without using the `locations` attribute. <1> Specifying XML files without using the `locations` attribute.
======
If you omit both the `locations` and the `value` attributes from the If you omit both the `locations` and the `value` attributes from the
@ -96,11 +98,11 @@ Java::
// class body... // class body...
} }
---- ----
======
<1> Loading configuration from the default location. <1> Loading configuration from the default location.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ExtendWith(SpringExtension::class) @ExtendWith(SpringExtension::class)
// ApplicationContext will be loaded from // ApplicationContext will be loaded from
@ -111,5 +113,6 @@ Java::
} }
---- ----
<1> Loading configuration from the default location. <1> Loading configuration from the default location.
======

View File

@ -105,13 +105,13 @@ Java::
} }
} }
---- ----
======
<1> Specify the configuration to load <1> Specify the configuration to load
<2> Inject the configuration <2> Inject the configuration
<3> Create the `WebTestClient` <3> Create the `WebTestClient`
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@SpringJUnitConfig(WebConfig::class) // <1> @SpringJUnitConfig(WebConfig::class) // <1>
class MyTests { class MyTests {
@ -127,6 +127,7 @@ Java::
<1> Specify the configuration to load <1> Specify the configuration to load
<2> Inject the configuration <2> Inject the configuration
<3> Create the `WebTestClient` <3> Create the `WebTestClient`
======
For Spring MVC, use the following where the Spring `ApplicationContext` is passed to For Spring MVC, use the following where the Spring `ApplicationContext` is passed to
{api-spring-framework}/test/web/servlet/setup/MockMvcBuilders.html#webAppContextSetup-org.springframework.web.context.WebApplicationContext-[MockMvcBuilders.webAppContextSetup] {api-spring-framework}/test/web/servlet/setup/MockMvcBuilders.html#webAppContextSetup-org.springframework.web.context.WebApplicationContext-[MockMvcBuilders.webAppContextSetup]
@ -158,13 +159,13 @@ Java::
} }
} }
---- ----
======
<1> Specify the configuration to load <1> Specify the configuration to load
<2> Inject the configuration <2> Inject the configuration
<3> Create the `WebTestClient` <3> Create the `WebTestClient`
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
@WebAppConfiguration("classpath:META-INF/web-resources") // <1> @WebAppConfiguration("classpath:META-INF/web-resources") // <1>
@ -188,6 +189,7 @@ Java::
<1> Specify the configuration to load <1> Specify the configuration to load
<2> Inject the configuration <2> Inject the configuration
<3> Create the `WebTestClient` <3> Create the `WebTestClient`
======

View File

@ -221,12 +221,12 @@ Java::
} }
} }
---- ----
======
<1> Using `@CrossOrigin` at the class level. <1> Using `@CrossOrigin` at the class level.
<2> Using `@CrossOrigin` at the method level. <2> Using `@CrossOrigin` at the method level.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@CrossOrigin(maxAge = 3600) // <1> @CrossOrigin(maxAge = 3600) // <1>
@RestController @RestController
@ -247,6 +247,7 @@ Java::
---- ----
<1> Using `@CrossOrigin` at the class level. <1> Using `@CrossOrigin` at the class level.
<2> Using `@CrossOrigin` at the method level. <2> Using `@CrossOrigin` at the method level.
======
-- --

View File

@ -67,11 +67,11 @@ Java::
} }
} }
---- ----
======
<1> Create router using `route()`. <1> Create router using `route()`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
val repository: PersonRepository = ... val repository: PersonRepository = ...
val handler = PersonHandler(repository) val handler = PersonHandler(repository)
@ -103,6 +103,7 @@ Java::
} }
---- ----
<1> Create router using Coroutines router DSL; a Reactive alternative is also available via `router { }`. <1> Create router using Coroutines router DSL; a Reactive alternative is also available via `router { }`.
======
One way to run a `RouterFunction` is to turn it into an `HttpHandler` and install it One way to run a `RouterFunction` is to turn it into an `HttpHandler` and install it
through one of the built-in xref:web/webflux/reactive-spring.adoc#webflux-httphandler[server adapters]: through one of the built-in xref:web/webflux/reactive-spring.adoc#webflux-httphandler[server adapters]:
@ -436,7 +437,6 @@ public class PersonHandler {
} }
} }
---- ----
======
<1> `listPeople` is a handler function that returns all `Person` objects found in the repository as <1> `listPeople` is a handler function that returns all `Person` objects found in the repository as
JSON. JSON.
<2> `createPerson` is a handler function that stores a new `Person` contained in the request body. <2> `createPerson` is a handler function that stores a new `Person` contained in the request body.
@ -448,8 +448,9 @@ when the `Person` has been saved).
variable. We retrieve that `Person` from the repository and create a JSON response, if it is variable. We retrieve that `Person` from the repository and create a JSON response, if it is
found. If it is not found, we use `switchIfEmpty(Mono<T>)` to return a 404 Not Found response. found. If it is not found, we use `switchIfEmpty(Mono<T>)` to return a 404 Not Found response.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
class PersonHandler(private val repository: PersonRepository) { class PersonHandler(private val repository: PersonRepository) {
@ -479,6 +480,7 @@ Note that `PersonRepository.savePerson(Person)` is a suspending function with no
<3> `getPerson` is a handler function that returns a single person, identified by the `id` path <3> `getPerson` is a handler function that returns a single person, identified by the `id` path
variable. We retrieve that `Person` from the repository and create a JSON response, if it is variable. We retrieve that `Person` from the repository and create a JSON response, if it is
found. If it is not found, we return a 404 Not Found response. found. If it is not found, we return a 404 Not Found response.
======
-- --
@ -515,13 +517,13 @@ Java::
} }
} }
---- ----
======
<1> Create `Validator` instance. <1> Create `Validator` instance.
<2> Apply validation. <2> Apply validation.
<3> Raise exception for a 400 response. <3> Raise exception for a 400 response.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
class PersonHandler(private val repository: PersonRepository) { class PersonHandler(private val repository: PersonRepository) {
@ -548,6 +550,7 @@ Java::
<1> Create `Validator` instance. <1> Create `Validator` instance.
<2> Apply validation. <2> Apply validation.
<3> Raise exception for a 400 response. <3> Raise exception for a 400 response.
======
Handlers can also use the standard bean validation API (JSR-303) by creating and injecting Handlers can also use the standard bean validation API (JSR-303) by creating and injecting
a global `Validator` instance based on `LocalValidatorFactoryBean`. a global `Validator` instance based on `LocalValidatorFactoryBean`.
@ -666,7 +669,6 @@ RouterFunction<ServerResponse> route = route()
.add(otherRoute) // <4> .add(otherRoute) // <4>
.build(); .build();
---- ----
======
<1> pass:q[`GET /person/{id}`] with an `Accept` header that matches JSON is routed to <1> pass:q[`GET /person/{id}`] with an `Accept` header that matches JSON is routed to
`PersonHandler.getPerson` `PersonHandler.getPerson`
<2> `GET /person` with an `Accept` header that matches JSON is routed to <2> `GET /person` with an `Accept` header that matches JSON is routed to
@ -675,8 +677,9 @@ RouterFunction<ServerResponse> route = route()
`PersonHandler.createPerson`, and `PersonHandler.createPerson`, and
<4> `otherRoute` is a router function that is created elsewhere, and added to the route built. <4> `otherRoute` is a router function that is created elsewhere, and added to the route built.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
import org.springframework.http.MediaType.APPLICATION_JSON import org.springframework.http.MediaType.APPLICATION_JSON
@ -698,6 +701,7 @@ RouterFunction<ServerResponse> route = route()
<3> `POST /person` with no additional predicates is mapped to <3> `POST /person` with no additional predicates is mapped to
`PersonHandler.createPerson`, and `PersonHandler.createPerson`, and
<4> `otherRoute` is a router function that is created elsewhere, and added to the route built. <4> `otherRoute` is a router function that is created elsewhere, and added to the route built.
======
[[nested-routes]] [[nested-routes]]
@ -724,11 +728,11 @@ RouterFunction<ServerResponse> route = route()
.POST(handler::createPerson)) .POST(handler::createPerson))
.build(); .build();
---- ----
======
<1> Note that second parameter of `path` is a consumer that takes the router builder. <1> Note that second parameter of `path` is a consumer that takes the router builder.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
val route = coRouter { // <1> val route = coRouter { // <1>
"/person".nest { "/person".nest {
@ -739,6 +743,7 @@ RouterFunction<ServerResponse> route = route()
} }
---- ----
<1> Create router using Coroutines router DSL; a Reactive alternative is also available via `router { }`. <1> Create router using Coroutines router DSL; a Reactive alternative is also available via `router { }`.
======
Though path-based nesting is the most common, you can nest on any kind of predicate by using Though path-based nesting is the most common, you can nest on any kind of predicate by using
the `nest` method on the builder. the `nest` method on the builder.
@ -918,12 +923,12 @@ Java::
.after((request, response) -> logResponse(response)) // <2> .after((request, response) -> logResponse(response)) // <2>
.build(); .build();
---- ----
======
<1> The `before` filter that adds a custom request header is only applied to the two GET routes. <1> The `before` filter that adds a custom request header is only applied to the two GET routes.
<2> The `after` filter that logs the response is applied to all routes, including the nested ones. <2> The `after` filter that logs the response is applied to all routes, including the nested ones.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
val route = router { val route = router {
"/person".nest { "/person".nest {
@ -942,6 +947,7 @@ Java::
---- ----
<1> The `before` filter that adds a custom request header is only applied to the two GET routes. <1> The `before` filter that adds a custom request header is only applied to the two GET routes.
<2> The `after` filter that logs the response is applied to all routes, including the nested ones. <2> The `after` filter that logs the response is applied to all routes, including the nested ones.
======
The `filter` method on the router builder takes a `HandlerFilterFunction`: a The `filter` method on the router builder takes a `HandlerFilterFunction`: a

View File

@ -214,13 +214,13 @@ Java::
return WebClient.builder().clientConnector(connector).build(); // <3> return WebClient.builder().clientConnector(connector).build(); // <3>
} }
---- ----
======
<1> Create resources independent of global ones. <1> Create resources independent of global ones.
<2> Use the `ReactorClientHttpConnector` constructor with resource factory. <2> Use the `ReactorClientHttpConnector` constructor with resource factory.
<3> Plug the connector into the `WebClient.Builder`. <3> Plug the connector into the `WebClient.Builder`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Bean @Bean
fun resourceFactory() = ReactorResourceFactory().apply { fun resourceFactory() = ReactorResourceFactory().apply {
@ -242,6 +242,7 @@ Java::
<1> Create resources independent of global ones. <1> Create resources independent of global ones.
<2> Use the `ReactorClientHttpConnector` constructor with resource factory. <2> Use the `ReactorClientHttpConnector` constructor with resource factory.
<3> Plug the connector into the `WebClient.Builder`. <3> Plug the connector into the `WebClient.Builder`.
======
-- --
@ -483,12 +484,12 @@ Java::
return WebClient.builder().clientConnector(connector).build(); <2> return WebClient.builder().clientConnector(connector).build(); <2>
} }
---- ----
======
<1> Use the `JettyClientHttpConnector` constructor with resource factory. <1> Use the `JettyClientHttpConnector` constructor with resource factory.
<2> Plug the connector into the `WebClient.Builder`. <2> Plug the connector into the `WebClient.Builder`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Bean @Bean
fun resourceFactory() = JettyResourceFactory() fun resourceFactory() = JettyResourceFactory()
@ -506,6 +507,7 @@ Java::
---- ----
<1> Use the `JettyClientHttpConnector` constructor with resource factory. <1> Use the `JettyClientHttpConnector` constructor with resource factory.
<2> Plug the connector into the `WebClient.Builder`. <2> Plug the connector into the `WebClient.Builder`.
======
-- --

View File

@ -194,14 +194,14 @@ Java::
} }
} }
---- ----
======
<1> Access the stream of inbound messages. <1> Access the stream of inbound messages.
<2> Do something with each message. <2> Do something with each message.
<3> Perform nested asynchronous operations that use the message content. <3> Perform nested asynchronous operations that use the message content.
<4> Return a `Mono<Void>` that completes when receiving completes. <4> Return a `Mono<Void>` that completes when receiving completes.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
class ExampleHandler : WebSocketHandler { class ExampleHandler : WebSocketHandler {
@ -221,6 +221,7 @@ Java::
<2> Do something with each message. <2> Do something with each message.
<3> Perform nested asynchronous operations that use the message content. <3> Perform nested asynchronous operations that use the message content.
<4> Return a `Mono<Void>` that completes when receiving completes. <4> Return a `Mono<Void>` that completes when receiving completes.
======
TIP: For nested, asynchronous operations, you may need to call `message.retain()` on underlying TIP: For nested, asynchronous operations, you may need to call `message.retain()` on underlying
@ -254,13 +255,13 @@ Java::
} }
} }
---- ----
======
<1> Handle the inbound message stream. <1> Handle the inbound message stream.
<2> Create the outbound message, producing a combined flow. <2> Create the outbound message, producing a combined flow.
<3> Return a `Mono<Void>` that does not complete while we continue to receive. <3> Return a `Mono<Void>` that does not complete while we continue to receive.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
class ExampleHandler : WebSocketHandler { class ExampleHandler : WebSocketHandler {
@ -282,6 +283,7 @@ Java::
<1> Handle the inbound message stream. <1> Handle the inbound message stream.
<2> Create the outbound message, producing a combined flow. <2> Create the outbound message, producing a combined flow.
<3> Return a `Mono<Void>` that does not complete while we continue to receive. <3> Return a `Mono<Void>` that does not complete while we continue to receive.
======
Inbound and outbound streams can be independent and be joined only for completion, Inbound and outbound streams can be independent and be joined only for completion,
@ -314,13 +316,13 @@ Java::
} }
} }
---- ----
======
<1> Handle inbound message stream. <1> Handle inbound message stream.
<2> Send outgoing messages. <2> Send outgoing messages.
<3> Join the streams and return a `Mono<Void>` that completes when either stream ends. <3> Join the streams and return a `Mono<Void>` that completes when either stream ends.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
class ExampleHandler : WebSocketHandler { class ExampleHandler : WebSocketHandler {
@ -345,6 +347,7 @@ Java::
<1> Handle inbound message stream. <1> Handle inbound message stream.
<2> Send outgoing messages. <2> Send outgoing messages.
<3> Join the streams and return a `Mono<Void>` that completes when either stream ends. <3> Join the streams and return a `Mono<Void>` that completes when either stream ends.
======

View File

@ -145,13 +145,13 @@ Java::
return "myViewName"; return "myViewName";
} }
---- ----
======
<1> Application-specific calculation. <1> Application-specific calculation.
<2> Response has been set to 304 (NOT_MODIFIED). No further processing. <2> Response has been set to 304 (NOT_MODIFIED). No further processing.
<3> Continue with request processing. <3> Continue with request processing.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@RequestMapping @RequestMapping
fun myHandleMethod(exchange: ServerWebExchange, model: Model): String? { fun myHandleMethod(exchange: ServerWebExchange, model: Model): String? {
@ -169,6 +169,7 @@ Java::
<1> Application-specific calculation. <1> Application-specific calculation.
<2> Response has been set to 304 (NOT_MODIFIED). No further processing. <2> Response has been set to 304 (NOT_MODIFIED). No further processing.
<3> Continue with request processing. <3> Continue with request processing.
======
-- --
There are three variants for checking conditional requests against `eTag` values, `lastModified` There are three variants for checking conditional requests against `eTag` values, `lastModified`

View File

@ -24,11 +24,11 @@ Java::
} }
} }
---- ----
======
<1> Declaring an `@ExceptionHandler`. <1> Declaring an `@ExceptionHandler`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Controller @Controller
class SimpleController { class SimpleController {
@ -42,6 +42,8 @@ Java::
} }
---- ----
<1> Declaring an `@ExceptionHandler`. <1> Declaring an `@ExceptionHandler`.
======
The exception can match against a top-level exception being propagated (that is, a direct The exception can match against a top-level exception being propagated (that is, a direct

View File

@ -41,11 +41,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Using the `@InitBinder` annotation. <1> Using the `@InitBinder` annotation.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Controller @Controller
class FormController { class FormController {
@ -61,6 +61,7 @@ Java::
} }
---- ----
<1> Using the `@InitBinder` annotation. <1> Using the `@InitBinder` annotation.
======
-- --
Alternatively, when using a `Formatter`-based setup through a shared Alternatively, when using a `Formatter`-based setup through a shared
@ -85,11 +86,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Adding a custom formatter (a `DateFormatter`, in this case). <1> Adding a custom formatter (a `DateFormatter`, in this case).
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Controller @Controller
class FormController { class FormController {
@ -103,6 +104,7 @@ Java::
} }
---- ----
<1> Adding a custom formatter (a `DateFormatter`, in this case). <1> Adding a custom formatter (a `DateFormatter`, in this case).
======
-- --

View File

@ -26,11 +26,11 @@ Java::
//... //...
} }
---- ----
======
<1> Get the cookie value. <1> Get the cookie value.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@GetMapping("/demo") @GetMapping("/demo")
fun handle(@CookieValue("JSESSIONID") cookie: String) { // <1> fun handle(@CookieValue("JSESSIONID") cookie: String) { // <1>
@ -38,6 +38,7 @@ Java::
} }
---- ----
<1> Get the cookie value. <1> Get the cookie value.
======
Type conversion is applied automatically if the target method parameter type is not Type conversion is applied automatically if the target method parameter type is not

View File

@ -18,16 +18,17 @@ Java::
@PostMapping("/owners/{ownerId}/pets/{petId}/edit") @PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) { } // <1> public String processSubmit(@ModelAttribute Pet pet) { } // <1>
---- ----
======
<1> Bind an instance of `Pet`. <1> Bind an instance of `Pet`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit") @PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String { } // <1> fun processSubmit(@ModelAttribute pet: Pet): String { } // <1>
---- ----
<1> Bind an instance of `Pet`. <1> Bind an instance of `Pet`.
======
The `Pet` instance in the preceding example is resolved as follows: The `Pet` instance in the preceding example is resolved as follows:
@ -63,11 +64,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Adding a `BindingResult`. <1> Adding a `BindingResult`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit") @PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String { // <1> fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String { // <1>
@ -78,6 +79,7 @@ Java::
} }
---- ----
<1> Adding a `BindingResult`. <1> Adding a `BindingResult`.
======
You can automatically apply validation after data binding by adding the You can automatically apply validation after data binding by adding the
`jakarta.validation.Valid` annotation or Spring's `@Validated` annotation (see also `jakarta.validation.Valid` annotation or Spring's `@Validated` annotation (see also
@ -98,11 +100,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Using `@Valid` on a model attribute argument. <1> Using `@Valid` on a model attribute argument.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit") @PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@Valid @ModelAttribute("pet") pet: Pet, result: BindingResult): String { // <1> fun processSubmit(@Valid @ModelAttribute("pet") pet: Pet, result: BindingResult): String { // <1>
@ -113,6 +115,7 @@ Java::
} }
---- ----
<1> Using `@Valid` on a model attribute argument. <1> Using `@Valid` on a model attribute argument.
======
Spring WebFlux, unlike Spring MVC, supports reactive types in the model -- for example, Spring WebFlux, unlike Spring MVC, supports reactive types in the model -- for example,
`Mono<Account>` or `io.reactivex.Single<Account>`. You can declare a `@ModelAttribute` argument `Mono<Account>` or `io.reactivex.Single<Account>`. You can declare a `@ModelAttribute` argument

View File

@ -95,12 +95,12 @@ Java::
// ... // ...
} }
---- ----
======
<1> Using `@RequestPart` to get the metadata. <1> Using `@RequestPart` to get the metadata.
<2> Using `@RequestPart` to get the file. <2> Using `@RequestPart` to get the file.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@PostMapping("/") @PostMapping("/")
fun handle(@RequestPart("meta-data") Part metadata, // <1> fun handle(@RequestPart("meta-data") Part metadata, // <1>
@ -110,6 +110,7 @@ Java::
---- ----
<1> Using `@RequestPart` to get the metadata. <1> Using `@RequestPart` to get the metadata.
<2> Using `@RequestPart` to get the file. <2> Using `@RequestPart` to get the file.
======
-- --
@ -128,11 +129,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Using `@RequestPart` to get the metadata. <1> Using `@RequestPart` to get the metadata.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@PostMapping("/") @PostMapping("/")
fun handle(@RequestPart("meta-data") metadata: MetaData): String { // <1> fun handle(@RequestPart("meta-data") metadata: MetaData): String { // <1>
@ -140,6 +141,7 @@ Java::
} }
---- ----
<1> Using `@RequestPart` to get the metadata. <1> Using `@RequestPart` to get the metadata.
======
-- --
You can use `@RequestPart` in combination with `jakarta.validation.Valid` or Spring's You can use `@RequestPart` in combination with `jakarta.validation.Valid` or Spring's
@ -189,11 +191,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Using `@RequestBody`. <1> Using `@RequestBody`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@PostMapping("/") @PostMapping("/")
fun handle(@RequestBody parts: MultiValueMap<String, Part>): String { // <1> fun handle(@RequestBody parts: MultiValueMap<String, Part>): String { // <1>
@ -201,6 +203,7 @@ Java::
} }
---- ----
<1> Using `@RequestBody`. <1> Using `@RequestBody`.
======
-- --
[[partevent]] [[partevent]]
@ -250,7 +253,6 @@ Java::
})); }));
} }
---- ----
======
<1> Using `@RequestBody`. <1> Using `@RequestBody`.
<2> The final `PartEvent` for a particular part will have `isLast()` set to `true`, and can be <2> The final `PartEvent` for a particular part will have `isLast()` set to `true`, and can be
followed by additional events belonging to subsequent parts. followed by additional events belonging to subsequent parts.
@ -262,8 +264,9 @@ file upload.
<5> Handling the file upload. <5> Handling the file upload.
<6> The body contents must be completely consumed, relayed, or released to avoid memory leaks. <6> The body contents must be completely consumed, relayed, or released to avoid memory leaks.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@PostMapping("/") @PostMapping("/")
fun handle(@RequestBody allPartsEvents: Flux<PartEvent>) = { // <1> fun handle(@RequestBody allPartsEvents: Flux<PartEvent>) = { // <1>
@ -299,6 +302,7 @@ file upload.
<4> Handling the form field. <4> Handling the form field.
<5> Handling the file upload. <5> Handling the file upload.
<6> The body contents must be completely consumed, relayed, or released to avoid memory leaks. <6> The body contents must be completely consumed, relayed, or released to avoid memory leaks.
======
Received part events can also be relayed to another service by using the `WebClient`. Received part events can also be relayed to another service by using the `WebClient`.
See xref:web/webflux-webclient/client-body.adoc#webflux-client-body-multipart[Multipart Data]. See xref:web/webflux-webclient/client-body.adoc#webflux-client-body-multipart[Multipart Data].

View File

@ -18,11 +18,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Using `@RequestAttribute`. <1> Using `@RequestAttribute`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@GetMapping("/") @GetMapping("/")
fun handle(@RequestAttribute client: Client): String { // <1> fun handle(@RequestAttribute client: Client): String { // <1>
@ -30,5 +30,6 @@ Java::
} }
---- ----
<1> Using `@RequestAttribute`. <1> Using `@RequestAttribute`.
======

View File

@ -34,12 +34,12 @@ Java::
//... //...
} }
---- ----
======
<1> Get the value of the `Accept-Encoding` header. <1> Get the value of the `Accept-Encoding` header.
<2> Get the value of the `Keep-Alive` header. <2> Get the value of the `Keep-Alive` header.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@GetMapping("/demo") @GetMapping("/demo")
fun handle( fun handle(
@ -50,6 +50,7 @@ Java::
---- ----
<1> Get the value of the `Accept-Encoding` header. <1> Get the value of the `Accept-Encoding` header.
<2> Get the value of the `Keep-Alive` header. <2> Get the value of the `Keep-Alive` header.
======
Type conversion is applied automatically if the target method parameter type is not Type conversion is applied automatically if the target method parameter type is not
`String`. See xref:web/webflux/controller/ann-methods/typeconversion.adoc[Type Conversion]. `String`. See xref:web/webflux/controller/ann-methods/typeconversion.adoc[Type Conversion].

View File

@ -28,11 +28,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Using `@RequestParam`. <1> Using `@RequestParam`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
import org.springframework.ui.set import org.springframework.ui.set
@ -53,6 +53,7 @@ Java::
} }
---- ----
<1> Using `@RequestParam`. <1> Using `@RequestParam`.
======
TIP: The Servlet API "`request parameter`" concept conflates query parameters, form TIP: The Servlet API "`request parameter`" concept conflates query parameters, form
data, and multiparts into one. However, in WebFlux, each is accessed individually through data, and multiparts into one. However, in WebFlux, each is accessed individually through

View File

@ -18,11 +18,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Using `@SessionAttribute`. <1> Using `@SessionAttribute`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@GetMapping("/") @GetMapping("/")
fun handle(@SessionAttribute user: User): String { // <1> fun handle(@SessionAttribute user: User): String { // <1>
@ -30,6 +30,7 @@ Java::
} }
---- ----
<1> Using `@SessionAttribute`. <1> Using `@SessionAttribute`.
======
For use cases that require adding or removing session attributes, consider injecting For use cases that require adding or removing session attributes, consider injecting
`WebSession` into the controller method. `WebSession` into the controller method.

View File

@ -23,11 +23,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Using the `@SessionAttributes` annotation. <1> Using the `@SessionAttributes` annotation.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Controller @Controller
@SessionAttributes("pet") // <1> @SessionAttributes("pet") // <1>
@ -36,6 +36,7 @@ Java::
} }
---- ----
<1> Using the `@SessionAttributes` annotation. <1> Using the `@SessionAttributes` annotation.
======
On the first request, when a model attribute with the name, `pet`, is added to the model, On the first request, when a model attribute with the name, `pet`, is added to the model,
it is automatically promoted to and saved in the `WebSession`. It remains there until it is automatically promoted to and saved in the `WebSession`. It remains there until
@ -65,12 +66,12 @@ Java::
} }
} }
---- ----
======
<1> Using the `@SessionAttributes` annotation. <1> Using the `@SessionAttributes` annotation.
<2> Using a `SessionStatus` variable. <2> Using a `SessionStatus` variable.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Controller @Controller
@SessionAttributes("pet") // <1> @SessionAttributes("pet") // <1>
@ -90,5 +91,6 @@ Java::
---- ----
<1> Using the `@SessionAttributes` annotation. <1> Using the `@SessionAttributes` annotation.
<2> Using a `SessionStatus` variable. <2> Using a `SessionStatus` variable.
======

View File

@ -155,12 +155,12 @@ Java::
} }
} }
---- ----
======
<1> Class-level URI mapping. <1> Class-level URI mapping.
<2> Method-level URI mapping. <2> Method-level URI mapping.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Controller @Controller
@RequestMapping("/owners/{ownerId}") // <1> @RequestMapping("/owners/{ownerId}") // <1>
@ -174,6 +174,7 @@ Java::
---- ----
<1> Class-level URI mapping. <1> Class-level URI mapping.
<2> Method-level URI mapping. <2> Method-level URI mapping.
======
-- --
@ -352,11 +353,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Check that `myParam` equals `myValue`. <1> Check that `myParam` equals `myValue`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@GetMapping("/pets/{petId}", params = ["myParam=myValue"]) // <1> @GetMapping("/pets/{petId}", params = ["myParam=myValue"]) // <1>
fun findPet(@PathVariable petId: String) { fun findPet(@PathVariable petId: String) {
@ -364,6 +365,7 @@ Java::
} }
---- ----
<1> Check that `myParam` equals `myValue`. <1> Check that `myParam` equals `myValue`.
======
You can also use the same with request header conditions, as the following example shows: You can also use the same with request header conditions, as the following example shows:
@ -378,11 +380,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Check that `myHeader` equals `myValue`. <1> Check that `myHeader` equals `myValue`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@GetMapping("/pets/{petId}", headers = ["myHeader=myValue"]) // <1> @GetMapping("/pets/{petId}", headers = ["myHeader=myValue"]) // <1>
fun findPet(@PathVariable petId: String) { fun findPet(@PathVariable petId: String) {
@ -390,6 +392,7 @@ Java::
} }
---- ----
<1> Check that `myHeader` equals `myValue`. <1> Check that `myHeader` equals `myValue`.
======
@ -466,14 +469,14 @@ Java::
} }
---- ----
======
<1> Inject target handlers and the handler mapping for controllers. <1> Inject target handlers and the handler mapping for controllers.
<2> Prepare the request mapping metadata. <2> Prepare the request mapping metadata.
<3> Get the handler method. <3> Get the handler method.
<4> Add the registration. <4> Add the registration.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Configuration @Configuration
class MyConfig { class MyConfig {
@ -493,6 +496,7 @@ Java::
<2> Prepare the request mapping metadata. <2> Prepare the request mapping metadata.
<3> Get the handler method. <3> Get the handler method.
<4> Add the registration. <4> Add the registration.
======

View File

@ -25,11 +25,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Scan the `org.example.web` package. <1> Scan the `org.example.web` package.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Configuration @Configuration
@ComponentScan("org.example.web") // <1> @ComponentScan("org.example.web") // <1>
@ -39,6 +39,7 @@ Java::
} }
---- ----
<1> Scan the `org.example.web` package. <1> Scan the `org.example.web` package.
======
`@RestController` is a xref:core/beans/classpath-scanning.adoc#beans-meta-annotations[composed annotation] that is `@RestController` is a xref:core/beans/classpath-scanning.adoc#beans-meta-annotations[composed annotation] that is
itself meta-annotated with `@Controller` and `@ResponseBody`, indicating a controller whose itself meta-annotated with `@Controller` and `@ResponseBody`, indicating a controller whose

View File

@ -67,11 +67,11 @@ Java::
} }
} }
---- ----
======
<1> Create router using `route()`. <1> Create router using `route()`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
import org.springframework.web.servlet.function.router import org.springframework.web.servlet.function.router
@ -105,6 +105,7 @@ Java::
} }
---- ----
<1> Create router using the router DSL. <1> Create router using the router DSL.
======
If you register the `RouterFunction` as a bean, for instance by exposing it in a If you register the `RouterFunction` as a bean, for instance by exposing it in a
@ -409,7 +410,6 @@ public class PersonHandler {
} }
---- ----
======
<1> `listPeople` is a handler function that returns all `Person` objects found in the repository as <1> `listPeople` is a handler function that returns all `Person` objects found in the repository as
JSON. JSON.
<2> `createPerson` is a handler function that stores a new `Person` contained in the request body. <2> `createPerson` is a handler function that stores a new `Person` contained in the request body.
@ -417,8 +417,9 @@ JSON.
variable. We retrieve that `Person` from the repository and create a JSON response, if it is variable. We retrieve that `Person` from the repository and create a JSON response, if it is
found. If it is not found, we return a 404 Not Found response. found. If it is not found, we return a 404 Not Found response.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
class PersonHandler(private val repository: PersonRepository) { class PersonHandler(private val repository: PersonRepository) {
@ -447,6 +448,7 @@ JSON.
<3> `getPerson` is a handler function that returns a single person, identified by the `id` path <3> `getPerson` is a handler function that returns a single person, identified by the `id` path
variable. We retrieve that `Person` from the repository and create a JSON response, if it is variable. We retrieve that `Person` from the repository and create a JSON response, if it is
found. If it is not found, we return a 404 Not Found response. found. If it is not found, we return a 404 Not Found response.
======
-- --
@ -485,13 +487,13 @@ Java::
} }
} }
---- ----
======
<1> Create `Validator` instance. <1> Create `Validator` instance.
<2> Apply validation. <2> Apply validation.
<3> Raise exception for a 400 response. <3> Raise exception for a 400 response.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
class PersonHandler(private val repository: PersonRepository) { class PersonHandler(private val repository: PersonRepository) {
@ -518,6 +520,7 @@ Java::
<1> Create `Validator` instance. <1> Create `Validator` instance.
<2> Apply validation. <2> Apply validation.
<3> Raise exception for a 400 response. <3> Raise exception for a 400 response.
======
Handlers can also use the standard bean validation API (JSR-303) by creating and injecting Handlers can also use the standard bean validation API (JSR-303) by creating and injecting
a global `Validator` instance based on `LocalValidatorFactoryBean`. a global `Validator` instance based on `LocalValidatorFactoryBean`.
@ -638,7 +641,6 @@ Java::
.add(otherRoute) // <4> .add(otherRoute) // <4>
.build(); .build();
---- ----
======
<1> pass:q[`GET /person/{id}`] with an `Accept` header that matches JSON is routed to <1> pass:q[`GET /person/{id}`] with an `Accept` header that matches JSON is routed to
`PersonHandler.getPerson` `PersonHandler.getPerson`
<2> `GET /person` with an `Accept` header that matches JSON is routed to <2> `GET /person` with an `Accept` header that matches JSON is routed to
@ -647,8 +649,9 @@ Java::
`PersonHandler.createPerson`, and `PersonHandler.createPerson`, and
<4> `otherRoute` is a router function that is created elsewhere, and added to the route built. <4> `otherRoute` is a router function that is created elsewhere, and added to the route built.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
import org.springframework.http.MediaType.APPLICATION_JSON import org.springframework.http.MediaType.APPLICATION_JSON
import org.springframework.web.servlet.function.router import org.springframework.web.servlet.function.router
@ -671,6 +674,7 @@ Java::
<3> `POST /person` with no additional predicates is mapped to <3> `POST /person` with no additional predicates is mapped to
`PersonHandler.createPerson`, and `PersonHandler.createPerson`, and
<4> `otherRoute` is a router function that is created elsewhere, and added to the route built. <4> `otherRoute` is a router function that is created elsewhere, and added to the route built.
======
[[nested-routes]] [[nested-routes]]
@ -698,11 +702,11 @@ RouterFunction<ServerResponse> route = route()
.POST(handler::createPerson)) .POST(handler::createPerson))
.build(); .build();
---- ----
======
<1> Note that second parameter of `path` is a consumer that takes the router builder. <1> Note that second parameter of `path` is a consumer that takes the router builder.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
import org.springframework.web.servlet.function.router import org.springframework.web.servlet.function.router
@ -715,6 +719,7 @@ RouterFunction<ServerResponse> route = route()
} }
---- ----
<1> Using `nest` DSL. <1> Using `nest` DSL.
======
Though path-based nesting is the most common, you can nest on any kind of predicate by using Though path-based nesting is the most common, you can nest on any kind of predicate by using
the `nest` method on the builder. the `nest` method on the builder.
@ -883,12 +888,12 @@ Java::
.after((request, response) -> logResponse(response)) // <2> .after((request, response) -> logResponse(response)) // <2>
.build(); .build();
---- ----
======
<1> The `before` filter that adds a custom request header is only applied to the two GET routes. <1> The `before` filter that adds a custom request header is only applied to the two GET routes.
<2> The `after` filter that logs the response is applied to all routes, including the nested ones. <2> The `after` filter that logs the response is applied to all routes, including the nested ones.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
import org.springframework.web.servlet.function.router import org.springframework.web.servlet.function.router
@ -909,6 +914,7 @@ Java::
---- ----
<1> The `before` filter that adds a custom request header is only applied to the two GET routes. <1> The `before` filter that adds a custom request header is only applied to the two GET routes.
<2> The `after` filter that logs the response is applied to all routes, including the nested ones. <2> The `after` filter that logs the response is applied to all routes, including the nested ones.
======
The `filter` method on the router builder takes a `HandlerFilterFunction`: a The `filter` method on the router builder takes a `HandlerFilterFunction`: a

View File

@ -154,13 +154,13 @@ Java::
return "myViewName"; return "myViewName";
} }
---- ----
======
<1> Application-specific calculation. <1> Application-specific calculation.
<2> The response has been set to 304 (NOT_MODIFIED) -- no further processing. <2> The response has been set to 304 (NOT_MODIFIED) -- no further processing.
<3> Continue with the request processing. <3> Continue with the request processing.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@RequestMapping @RequestMapping
fun myHandleMethod(request: WebRequest, model: Model): String? { fun myHandleMethod(request: WebRequest, model: Model): String? {
@ -178,6 +178,7 @@ Java::
<1> Application-specific calculation. <1> Application-specific calculation.
<2> The response has been set to 304 (NOT_MODIFIED) -- no further processing. <2> The response has been set to 304 (NOT_MODIFIED) -- no further processing.
<3> Continue with the request processing. <3> Continue with the request processing.
======
-- --

View File

@ -40,11 +40,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Defining an `@InitBinder` method. <1> Defining an `@InitBinder` method.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Controller @Controller
class FormController { class FormController {
@ -60,6 +60,7 @@ Java::
} }
---- ----
<1> Defining an `@InitBinder` method. <1> Defining an `@InitBinder` method.
======
Alternatively, when you use a `Formatter`-based setup through a shared Alternatively, when you use a `Formatter`-based setup through a shared
`FormattingConversionService`, you can re-use the same approach and register `FormattingConversionService`, you can re-use the same approach and register
@ -82,11 +83,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Defining an `@InitBinder` method on a custom formatter. <1> Defining an `@InitBinder` method on a custom formatter.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Controller @Controller
class FormController { class FormController {
@ -100,6 +101,7 @@ Java::
} }
---- ----
<1> Defining an `@InitBinder` method on a custom formatter. <1> Defining an `@InitBinder` method on a custom formatter.
======
[[mvc-ann-initbinder-model-design]] [[mvc-ann-initbinder-model-design]]
== Model Design == Model Design

View File

@ -26,11 +26,11 @@ Java::
//... //...
} }
---- ----
======
<1> Get the value of the `JSESSIONID` cookie. <1> Get the value of the `JSESSIONID` cookie.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@GetMapping("/demo") @GetMapping("/demo")
fun handle(@CookieValue("JSESSIONID") cookie: String) { // <1> fun handle(@CookieValue("JSESSIONID") cookie: String) { // <1>
@ -38,6 +38,7 @@ Java::
} }
---- ----
<1> Get the value of the `JSESSIONID` cookie. <1> Get the value of the `JSESSIONID` cookie.
======
If the target method parameter type is not `String`, type conversion is applied automatically. If the target method parameter type is not `String`, type conversion is applied automatically.
See xref:web/webmvc/mvc-controller/ann-methods/typeconversion.adoc[Type Conversion]. See xref:web/webmvc/mvc-controller/ann-methods/typeconversion.adoc[Type Conversion].

View File

@ -20,11 +20,11 @@ Java::
// method logic... // method logic...
} }
---- ----
======
<1> Bind an instance of `Pet`. <1> Bind an instance of `Pet`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit") @PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String { // <1> fun processSubmit(@ModelAttribute pet: Pet): String { // <1>
@ -32,6 +32,7 @@ fun processSubmit(@ModelAttribute pet: Pet): String { // <1>
} }
---- ----
<1> Bind an instance of `Pet`. <1> Bind an instance of `Pet`.
======
The `Pet` instance above is sourced in one of the following ways: The `Pet` instance above is sourced in one of the following ways:
@ -66,11 +67,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Bind an instance of `Account` using an explicit attribute name. <1> Bind an instance of `Account` using an explicit attribute name.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@PutMapping("/accounts/{account}") @PutMapping("/accounts/{account}")
fun save(@ModelAttribute("account") account: Account): String { // <1> fun save(@ModelAttribute("account") account: Account): String { // <1>
@ -78,6 +79,7 @@ Java::
} }
---- ----
<1> Bind an instance of `Account` using an explicit attribute name. <1> Bind an instance of `Account` using an explicit attribute name.
======
After the model attribute instance is obtained, data binding is applied. The After the model attribute instance is obtained, data binding is applied. The
`WebDataBinder` class matches Servlet request parameter names (query parameters and form `WebDataBinder` class matches Servlet request parameter names (query parameters and form
@ -104,11 +106,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Adding a `BindingResult` next to the `@ModelAttribute`. <1> Adding a `BindingResult` next to the `@ModelAttribute`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit") @PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String { // <1> fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String { // <1>
@ -119,6 +121,7 @@ Java::
} }
---- ----
<1> Adding a `BindingResult` next to the `@ModelAttribute`. <1> Adding a `BindingResult` next to the `@ModelAttribute`.
======
In some cases, you may want access to a model attribute without data binding. For such In some cases, you may want access to a model attribute without data binding. For such
cases, you can inject the `Model` into the controller and access it directly or, cases, you can inject the `Model` into the controller and access it directly or,
@ -146,11 +149,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Setting `@ModelAttribute(binding=false)`. <1> Setting `@ModelAttribute(binding=false)`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@ModelAttribute @ModelAttribute
fun setUpForm(): AccountForm { fun setUpForm(): AccountForm {
@ -169,6 +172,7 @@ Java::
} }
---- ----
<1> Setting `@ModelAttribute(binding=false)`. <1> Setting `@ModelAttribute(binding=false)`.
======
You can automatically apply validation after data binding by adding the You can automatically apply validation after data binding by adding the
`jakarta.validation.Valid` annotation or Spring's `@Validated` annotation `jakarta.validation.Valid` annotation or Spring's `@Validated` annotation
@ -189,11 +193,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Validate the `Pet` instance. <1> Validate the `Pet` instance.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit") @PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@Valid @ModelAttribute("pet") pet: Pet, result: BindingResult): String { // <1> fun processSubmit(@Valid @ModelAttribute("pet") pet: Pet, result: BindingResult): String { // <1>
@ -204,6 +208,7 @@ Java::
} }
---- ----
<1> Validate the `Pet` instance. <1> Validate the `Pet` instance.
======
Note that using `@ModelAttribute` is optional (for example, to set its attributes). Note that using `@ModelAttribute` is optional (for example, to set its attributes).
By default, any argument that is not a simple value type (as determined by By default, any argument that is not a simple value type (as determined by

View File

@ -18,11 +18,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Using the `@RequestAttribute` annotation. <1> Using the `@RequestAttribute` annotation.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@GetMapping("/") @GetMapping("/")
fun handle(@RequestAttribute client: Client): String { // <1> fun handle(@RequestAttribute client: Client): String { // <1>
@ -30,5 +30,6 @@ Java::
} }
---- ----
<1> Using the `@RequestAttribute` annotation. <1> Using the `@RequestAttribute` annotation.
======

View File

@ -34,12 +34,12 @@ Java::
//... //...
} }
---- ----
======
<1> Get the value of the `Accept-Encoding` header. <1> Get the value of the `Accept-Encoding` header.
<2> Get the value of the `Keep-Alive` header. <2> Get the value of the `Keep-Alive` header.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@GetMapping("/demo") @GetMapping("/demo")
fun handle( fun handle(
@ -50,6 +50,7 @@ Java::
---- ----
<1> Get the value of the `Accept-Encoding` header. <1> Get the value of the `Accept-Encoding` header.
<2> Get the value of the `Keep-Alive` header. <2> Get the value of the `Keep-Alive` header.
======
If the target method parameter type is not If the target method parameter type is not
`String`, type conversion is automatically applied. See xref:web/webmvc/mvc-controller/ann-methods/typeconversion.adoc[Type Conversion]. `String`, type conversion is automatically applied. See xref:web/webmvc/mvc-controller/ann-methods/typeconversion.adoc[Type Conversion].

View File

@ -31,11 +31,11 @@ Java::
} }
---- ----
======
<1> Using `@RequestParam` to bind `petId`. <1> Using `@RequestParam` to bind `petId`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
import org.springframework.ui.set import org.springframework.ui.set
@ -57,6 +57,7 @@ Java::
} }
---- ----
<1> Using `@RequestParam` to bind `petId`. <1> Using `@RequestParam` to bind `petId`.
======
By default, method parameters that use this annotation are required, but you can specify that By default, method parameters that use this annotation are required, but you can specify that
a method parameter is optional by setting the `@RequestParam` annotation's `required` flag to a method parameter is optional by setting the `@RequestParam` annotation's `required` flag to

View File

@ -19,18 +19,19 @@ Java::
// ... // ...
} }
---- ----
======
<1> Using a `@SessionAttribute` annotation. <1> Using a `@SessionAttribute` annotation.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@RequestMapping("/") @RequestMapping("/")
fun handle(@SessionAttribute user: User): String { // <1> fun handle(@SessionAttribute user: User): String { // <1>
// ... // ...
} }
---- ----
<1> Using a `@SessionAttribute` annotation. <1> Using a `@SessionAttribute` annotation.======
======
For use cases that require adding or removing session attributes, consider injecting For use cases that require adding or removing session attributes, consider injecting
`org.springframework.web.context.request.WebRequest` or `org.springframework.web.context.request.WebRequest` or

View File

@ -23,11 +23,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Using the `@SessionAttributes` annotation. <1> Using the `@SessionAttributes` annotation.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Controller @Controller
@SessionAttributes("pet") // <1> @SessionAttributes("pet") // <1>
@ -36,6 +36,7 @@ Java::
} }
---- ----
<1> Using the `@SessionAttributes` annotation. <1> Using the `@SessionAttributes` annotation.
======
On the first request, when a model attribute with the name, `pet`, is added to the model, On the first request, when a model attribute with the name, `pet`, is added to the model,
it is automatically promoted to and saved in the HTTP Servlet session. It remains there it is automatically promoted to and saved in the HTTP Servlet session. It remains there
@ -64,12 +65,12 @@ Java::
} }
} }
---- ----
======
<1> Storing the `Pet` value in the Servlet session. <1> Storing the `Pet` value in the Servlet session.
<2> Clearing the `Pet` value from the Servlet session. <2> Clearing the `Pet` value from the Servlet session.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Controller @Controller
@SessionAttributes("pet") // <1> @SessionAttributes("pet") // <1>
@ -89,5 +90,6 @@ class EditPetForm {
---- ----
<1> Storing the `Pet` value in the Servlet session. <1> Storing the `Pet` value in the Servlet session.
<2> Clearing the `Pet` value from the Servlet session. <2> Clearing the `Pet` value from the Servlet session.
======

View File

@ -309,11 +309,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Using a `consumes` attribute to narrow the mapping by the content type. <1> Using a `consumes` attribute to narrow the mapping by the content type.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@PostMapping("/pets", consumes = ["application/json"]) // <1> @PostMapping("/pets", consumes = ["application/json"]) // <1>
fun addPet(@RequestBody pet: Pet) { fun addPet(@RequestBody pet: Pet) {
@ -321,6 +321,7 @@ Java::
} }
---- ----
<1> Using a `consumes` attribute to narrow the mapping by the content type. <1> Using a `consumes` attribute to narrow the mapping by the content type.
======
The `consumes` attribute also supports negation expressions -- for example, `!text/plain` means any The `consumes` attribute also supports negation expressions -- for example, `!text/plain` means any
content type other than `text/plain`. content type other than `text/plain`.
@ -352,11 +353,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Using a `produces` attribute to narrow the mapping by the content type. <1> Using a `produces` attribute to narrow the mapping by the content type.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@GetMapping("/pets/{petId}", produces = ["application/json"]) // <1> @GetMapping("/pets/{petId}", produces = ["application/json"]) // <1>
@ResponseBody @ResponseBody
@ -365,6 +366,7 @@ Java::
} }
---- ----
<1> Using a `produces` attribute to narrow the mapping by the content type. <1> Using a `produces` attribute to narrow the mapping by the content type.
======
The media type can specify a character set. Negated expressions are supported -- for example, The media type can specify a character set. Negated expressions are supported -- for example,
`!text/plain` means any content type other than "text/plain". `!text/plain` means any content type other than "text/plain".
@ -396,11 +398,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Testing whether `myParam` equals `myValue`. <1> Testing whether `myParam` equals `myValue`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@GetMapping("/pets/{petId}", params = ["myParam=myValue"]) // <1> @GetMapping("/pets/{petId}", params = ["myParam=myValue"]) // <1>
fun findPet(@PathVariable petId: String) { fun findPet(@PathVariable petId: String) {
@ -408,6 +410,7 @@ Java::
} }
---- ----
<1> Testing whether `myParam` equals `myValue`. <1> Testing whether `myParam` equals `myValue`.
======
You can also use the same with request header conditions, as the following example shows: You can also use the same with request header conditions, as the following example shows:
@ -422,11 +425,11 @@ Java::
// ... // ...
} }
---- ----
======
<1> Testing whether `myHeader` equals `myValue`. <1> Testing whether `myHeader` equals `myValue`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@GetMapping("/pets/{petId}", headers = ["myHeader=myValue"]) // <1> @GetMapping("/pets/{petId}", headers = ["myHeader=myValue"]) // <1>
fun findPet(@PathVariable petId: String) { fun findPet(@PathVariable petId: String) {
@ -434,6 +437,7 @@ Java::
} }
---- ----
<1> Testing whether `myHeader` equals `myValue`. <1> Testing whether `myHeader` equals `myValue`.
======
TIP: You can match `Content-Type` and `Accept` with the headers condition, but it is better to use TIP: You can match `Content-Type` and `Accept` with the headers condition, but it is better to use
xref:web/webmvc/mvc-controller/ann-requestmapping.adoc#mvc-ann-requestmapping-consumes[consumes] and xref:web/webmvc/mvc-controller/ann-requestmapping.adoc#mvc-ann-requestmapping-produces[produces] xref:web/webmvc/mvc-controller/ann-requestmapping.adoc#mvc-ann-requestmapping-consumes[consumes] and xref:web/webmvc/mvc-controller/ann-requestmapping.adoc#mvc-ann-requestmapping-produces[produces]
@ -517,14 +521,14 @@ Java::
} }
} }
---- ----
======
<1> Inject the target handler and the handler mapping for controllers. <1> Inject the target handler and the handler mapping for controllers.
<2> Prepare the request mapping meta data. <2> Prepare the request mapping meta data.
<3> Get the handler method. <3> Get the handler method.
<4> Add the registration. <4> Add the registration.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
@Configuration @Configuration
class MyConfig { class MyConfig {
@ -541,6 +545,7 @@ Java::
<2> Prepare the request mapping meta data. <2> Prepare the request mapping meta data.
<3> Get the handler method. <3> Get the handler method.
<4> Add the registration. <4> Add the registration.
======

View File

@ -18,15 +18,15 @@ Java::
URI uri = uriComponents.expand("Westin", "123").toUri(); // <5> URI uri = uriComponents.expand("Westin", "123").toUri(); // <5>
---- ----
======
<1> Static factory method with a URI template. <1> Static factory method with a URI template.
<2> Add or replace URI components. <2> Add or replace URI components.
<3> Request to have the URI template and URI variables encoded. <3> Request to have the URI template and URI variables encoded.
<4> Build a `UriComponents`. <4> Build a `UriComponents`.
<5> Expand variables and obtain the `URI`. <5> Expand variables and obtain the `URI`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"] [source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
---- ----
val uriComponents = UriComponentsBuilder val uriComponents = UriComponentsBuilder
.fromUriString("https://example.com/hotels/{hotel}") // <1> .fromUriString("https://example.com/hotels/{hotel}") // <1>
@ -41,6 +41,7 @@ Java::
<3> Request to have the URI template and URI variables encoded. <3> Request to have the URI template and URI variables encoded.
<4> Build a `UriComponents`. <4> Build a `UriComponents`.
<5> Expand variables and obtain the `URI`. <5> Expand variables and obtain the `URI`.
======
The preceding example can be consolidated into one chain and shortened with `buildAndExpand`, The preceding example can be consolidated into one chain and shortened with `buildAndExpand`,
as the following example shows: as the following example shows:

View File

@ -8,10 +8,10 @@ javaPlatform {
dependencies { dependencies {
api(platform("com.fasterxml.jackson:jackson-bom:2.14.3")) api(platform("com.fasterxml.jackson:jackson-bom:2.14.3"))
api(platform("io.micrometer:micrometer-bom:1.10.6")) api(platform("io.micrometer:micrometer-bom:1.10.7"))
api(platform("io.netty:netty-bom:4.1.92.Final")) api(platform("io.netty:netty-bom:4.1.92.Final"))
api(platform("io.netty:netty5-bom:5.0.0.Alpha5")) api(platform("io.netty:netty5-bom:5.0.0.Alpha5"))
api(platform("io.projectreactor:reactor-bom:2022.0.6")) api(platform("io.projectreactor:reactor-bom:2022.0.7"))
api(platform("io.rsocket:rsocket-bom:1.1.3")) api(platform("io.rsocket:rsocket-bom:1.1.3"))
api(platform("org.apache.groovy:groovy-bom:4.0.11")) api(platform("org.apache.groovy:groovy-bom:4.0.11"))
api(platform("org.apache.logging.log4j:log4j-bom:2.20.0")) api(platform("org.apache.logging.log4j:log4j-bom:2.20.0"))
@ -23,13 +23,13 @@ dependencies {
constraints { constraints {
api("com.fasterxml:aalto-xml:1.3.2") api("com.fasterxml:aalto-xml:1.3.2")
api("com.fasterxml.woodstox:woodstox-core:6.5.0") api("com.fasterxml.woodstox:woodstox-core:6.5.1")
api("com.github.ben-manes.caffeine:caffeine:3.1.5") api("com.github.ben-manes.caffeine:caffeine:3.1.6")
api("com.github.librepdf:openpdf:1.3.30") api("com.github.librepdf:openpdf:1.3.30")
api("com.google.code.findbugs:findbugs:3.0.1") api("com.google.code.findbugs:findbugs:3.0.1")
api("com.google.code.findbugs:jsr305:3.0.2") api("com.google.code.findbugs:jsr305:3.0.2")
api("com.google.code.gson:gson:2.10.1") api("com.google.code.gson:gson:2.10.1")
api("com.google.protobuf:protobuf-java-util:3.21.12") api("com.google.protobuf:protobuf-java-util:3.23.0")
api("com.googlecode.protobuf-java-format:protobuf-java-format:1.4") api("com.googlecode.protobuf-java-format:protobuf-java-format:1.4")
api("com.h2database:h2:2.1.214") api("com.h2database:h2:2.1.214")
api("com.jayway.jsonpath:json-path:2.8.0") api("com.jayway.jsonpath:json-path:2.8.0")
@ -45,11 +45,11 @@ dependencies {
api("com.thoughtworks.xstream:xstream:1.4.20") api("com.thoughtworks.xstream:xstream:1.4.20")
api("commons-io:commons-io:2.11.0") api("commons-io:commons-io:2.11.0")
api("de.bechte.junit:junit-hierarchicalcontextrunner:4.12.2") api("de.bechte.junit:junit-hierarchicalcontextrunner:4.12.2")
api("info.picocli:picocli:4.7.1") api("info.picocli:picocli:4.7.3")
api("io.micrometer:context-propagation:1.0.0") api("io.micrometer:context-propagation:1.0.0")
api("io.mockk:mockk:1.13.4") api("io.mockk:mockk:1.13.4")
api("io.projectreactor.netty:reactor-netty5-http:2.0.0-M3") api("io.projectreactor.netty:reactor-netty5-http:2.0.0-M3")
api("io.projectreactor.tools:blockhound:1.0.7.RELEASE") api("io.projectreactor.tools:blockhound:1.0.8.RELEASE")
api("io.r2dbc:r2dbc-h2:1.0.0.RELEASE") api("io.r2dbc:r2dbc-h2:1.0.0.RELEASE")
api("io.r2dbc:r2dbc-spi-test:1.0.0.RELEASE") api("io.r2dbc:r2dbc-spi-test:1.0.0.RELEASE")
api("io.r2dbc:r2dbc-spi:1.0.0.RELEASE") api("io.r2dbc:r2dbc-spi:1.0.0.RELEASE")
@ -89,9 +89,9 @@ dependencies {
api("net.sf.jopt-simple:jopt-simple:5.0.4") api("net.sf.jopt-simple:jopt-simple:5.0.4")
api("net.sourceforge.htmlunit:htmlunit:2.70.0") api("net.sourceforge.htmlunit:htmlunit:2.70.0")
api("org.apache-extras.beanshell:bsh:2.0b6") api("org.apache-extras.beanshell:bsh:2.0b6")
api("org.apache.activemq:activemq-broker:5.17.2") api("org.apache.activemq:activemq-broker:5.17.4")
api("org.apache.activemq:activemq-kahadb-store:5.17.2") api("org.apache.activemq:activemq-kahadb-store:5.17.4")
api("org.apache.activemq:activemq-stomp:5.17.2") api("org.apache.activemq:activemq-stomp:5.17.4")
api("org.apache.commons:commons-pool2:2.9.0") api("org.apache.commons:commons-pool2:2.9.0")
api("org.apache.derby:derby:10.16.1.1") api("org.apache.derby:derby:10.16.1.1")
api("org.apache.derby:derbyclient:10.16.1.1") api("org.apache.derby:derbyclient:10.16.1.1")