Browse Source

Merge branch '6.0.x'

Closes gh-30435
pull/30456/head
rstoyanchev 3 years ago
parent
commit
bc7ba8cf2b
  1. 25
      framework-docs/modules/ROOT/pages/core/aop/ataspectj/advice.adoc
  2. 5
      framework-docs/modules/ROOT/pages/core/aop/ataspectj/example.adoc
  3. 5
      framework-docs/modules/ROOT/pages/core/aop/ataspectj/pointcuts.adoc
  4. 7
      framework-docs/modules/ROOT/pages/core/appendix/xml-custom.adoc
  5. 5
      framework-docs/modules/ROOT/pages/core/beans/annotation-config/autowired-qualifiers.adoc
  6. 10
      framework-docs/modules/ROOT/pages/core/beans/annotation-config/resource.adoc
  7. 5
      framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc
  8. 10
      framework-docs/modules/ROOT/pages/core/beans/environment.adoc
  9. 5
      framework-docs/modules/ROOT/pages/core/beans/java/instantiating-container.adoc
  10. 25
      framework-docs/modules/ROOT/pages/core/expressions/evaluation.adoc
  11. 5
      framework-docs/modules/ROOT/pages/data-access/dao.adoc
  12. 5
      framework-docs/modules/ROOT/pages/data-access/jdbc/core.adoc
  13. 10
      framework-docs/modules/ROOT/pages/data-access/jdbc/parameter-handling.adoc
  14. 5
      framework-docs/modules/ROOT/pages/data-access/r2dbc.adoc
  15. 15
      framework-docs/modules/ROOT/pages/rsocket.adoc
  16. 20
      framework-docs/modules/ROOT/pages/testing/annotations/integration-junit-jupiter.adoc
  17. 25
      framework-docs/modules/ROOT/pages/testing/annotations/integration-junit4.adoc
  18. 10
      framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-activeprofiles.adoc
  19. 5
      framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-aftertransaction.adoc
  20. 5
      framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-beforetransaction.adoc
  21. 5
      framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-commit.adoc
  22. 20
      framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-contextconfiguration.adoc
  23. 35
      framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-dirtiescontext.adoc
  24. 5
      framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-dynamicpropertysource.adoc
  25. 5
      framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-rollback.adoc
  26. 5
      framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-sql.adoc
  27. 5
      framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-sqlconfig.adoc
  28. 5
      framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-sqlgroup.adoc
  29. 10
      framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-sqlmergemode.adoc
  30. 7
      framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-testexecutionlisteners.adoc
  31. 10
      framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-testpropertysource.adoc
  32. 10
      framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-webappconfiguration.adoc
  33. 5
      framework-docs/modules/ROOT/pages/testing/spring-mvc-test-framework/async-requests.adoc
  34. 5
      framework-docs/modules/ROOT/pages/testing/spring-mvc-test-framework/server-htmlunit/webdriver.adoc
  35. 6
      framework-docs/modules/ROOT/pages/testing/testcontext-framework/application-events.adoc
  36. 10
      framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management.adoc
  37. 10
      framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management/groovy.adoc
  38. 15
      framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management/inheritance.adoc
  39. 10
      framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management/initializers.adoc
  40. 10
      framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management/javaconfig.adoc
  41. 10
      framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management/property-sources.adoc
  42. 15
      framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management/xml.adoc
  43. 10
      framework-docs/modules/ROOT/pages/testing/webtestclient.adoc
  44. 5
      framework-docs/modules/ROOT/pages/web/webflux-cors.adoc
  45. 30
      framework-docs/modules/ROOT/pages/web/webflux-functional.adoc
  46. 10
      framework-docs/modules/ROOT/pages/web/webflux-webclient/client-builder.adoc
  47. 15
      framework-docs/modules/ROOT/pages/web/webflux-websocket.adoc
  48. 5
      framework-docs/modules/ROOT/pages/web/webflux/caching.adoc
  49. 6
      framework-docs/modules/ROOT/pages/web/webflux/controller/ann-exceptions.adoc
  50. 10
      framework-docs/modules/ROOT/pages/web/webflux/controller/ann-initbinder.adoc
  51. 5
      framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/cookievalue.adoc
  52. 15
      framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/modelattrib-method-args.adoc
  53. 20
      framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/multipart-forms.adoc
  54. 5
      framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/requestattrib.adoc
  55. 5
      framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/requestheader.adoc
  56. 5
      framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/requestparam.adoc
  57. 5
      framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/sessionattribute.adoc
  58. 10
      framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/sessionattributes.adoc
  59. 20
      framework-docs/modules/ROOT/pages/web/webflux/controller/ann-requestmapping.adoc
  60. 5
      framework-docs/modules/ROOT/pages/web/webflux/controller/ann.adoc
  61. 30
      framework-docs/modules/ROOT/pages/web/webmvc-functional.adoc
  62. 5
      framework-docs/modules/ROOT/pages/web/webmvc/mvc-caching.adoc
  63. 10
      framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-initbinder.adoc
  64. 5
      framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/cookievalue.adoc
  65. 25
      framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/modelattrib-method-args.adoc
  66. 5
      framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/requestattrib.adoc
  67. 5
      framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/requestheader.adoc
  68. 5
      framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/requestparam.adoc
  69. 7
      framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/sessionattribute.adoc
  70. 10
      framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/sessionattributes.adoc
  71. 25
      framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-requestmapping.adoc
  72. 5
      framework-docs/modules/ROOT/partials/web/web-uris.adoc
  73. 20
      framework-platform/framework-platform.gradle

25
framework-docs/modules/ROOT/pages/core/aop/ataspectj/advice.adoc

@ -605,11 +605,11 @@ Java:: @@ -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].
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
.Kotlin
----
@Before("com.xyz.Pointcuts.publicMethod() && @annotation(auditable)") // <1>
fun audit(auditable: Auditable) {
@ -618,6 +618,7 @@ Java:: @@ -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].
======
[[aop-ataspectj-advice-params-generics]]
=== Advice Parameters and Generics
@ -770,12 +771,12 @@ Java:: @@ -770,12 +771,12 @@ Java::
// ... use code and bean
}
----
======
<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.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
.Kotlin
----
@Before(
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
@ -787,6 +788,7 @@ Java:: @@ -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].
<2> Declares `bean` and `auditable` as the argument names.
======
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
@ -807,12 +809,12 @@ Java:: @@ -807,12 +809,12 @@ Java::
// ... 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].
<2> Declares `bean` and `auditable` as the argument names.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
.Kotlin
----
@Before(
value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", // <1>
@ -824,6 +826,7 @@ Java:: @@ -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].
<2> Declares `bean` and `auditable` as the argument names.
======
The special treatment given to the first parameter of type `JoinPoint`,
`ProceedingJoinPoint`, or `JoinPoint.StaticPart` is particularly convenient for advice
@ -842,11 +845,11 @@ Java:: @@ -842,11 +845,11 @@ Java::
// ... use jp
}
----
======
<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"]
.Kotlin
----
@Before("com.xyz.Pointcuts.publicMethod()") // <1>
fun audit(jp: JoinPoint) {
@ -854,6 +857,7 @@ Java:: @@ -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].
======
[[aop-ataspectj-advice-proceeding-with-the-call]]
@ -879,11 +883,11 @@ Java:: @@ -879,11 +883,11 @@ Java::
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].
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
.Kotlin
----
@Around("execution(List<Account> find*(..)) && " +
"com.xyz.CommonPointcuts.inDataAccessLayer() && " +
@ -895,6 +899,7 @@ Java:: @@ -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].
======
In many cases, you do this binding anyway (as in the preceding example).

5
framework-docs/modules/ROOT/pages/core/aop/ataspectj/example.adoc

@ -59,11 +59,11 @@ Java:: @@ -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].
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary"]
.Kotlin
----
@Aspect
class ConcurrentOperationExecutor : Ordered {
@ -102,6 +102,7 @@ Java:: @@ -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].
======
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

5
framework-docs/modules/ROOT/pages/core/aop/ataspectj/pointcuts.adoc

@ -167,15 +167,15 @@ Java:: @@ -167,15 +167,15 @@ Java::
public void tradingOperation() {} // <3>
}
----
======
<1> `publicMethod` matches if a method execution join point represents the execution
of any public method.
<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
trading module.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim",role="secondary",chomp="-packages"]
.Kotlin
----
package com.xyz
@ -197,6 +197,7 @@ of any public method. @@ -197,6 +197,7 @@ of any public method.
<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
trading module.
======
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

7
framework-docs/modules/ROOT/pages/core/appendix/xml-custom.adoc

@ -233,14 +233,14 @@ Java:: @@ -233,14 +233,14 @@ Java::
}
----
======
<1> We use the Spring-provided `AbstractSingleBeanDefinitionParser` to handle a lot of
the basic grunt work of creating a single `BeanDefinition`.
<2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our
single `BeanDefinition` represents.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary",chomp="-packages"]
.Kotlin
----
package org.springframework.samples.xml
@ -274,6 +274,7 @@ single `BeanDefinition` represents. @@ -274,6 +274,7 @@ single `BeanDefinition` represents.
the basic grunt work of creating a single `BeanDefinition`.
<2> We supply the `AbstractSingleBeanDefinitionParser` superclass with the type that our
single `BeanDefinition` represents.
======
In this simple case, this is all that we need to do. The creation of our single
@ -540,7 +541,7 @@ Kotlin:: @@ -540,7 +541,7 @@ Kotlin::
fun setChildren(children: List<Component>) {
this.children = children
}
override fun getObject(): Component? {
if (this.children != null && this.children!!.isNotEmpty()) {
for (child in children!!) {

5
framework-docs/modules/ROOT/pages/core/beans/annotation-config/autowired-qualifiers.adoc

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

10
framework-docs/modules/ROOT/pages/core/beans/annotation-config/resource.adoc

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

5
framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc

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

10
framework-docs/modules/ROOT/pages/core/beans/environment.adoc

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

5
framework-docs/modules/ROOT/pages/core/beans/java/instantiating-container.adoc

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

25
framework-docs/modules/ROOT/pages/core/expressions/evaluation.adoc

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

5
framework-docs/modules/ROOT/pages/data-access/dao.adoc

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

5
framework-docs/modules/ROOT/pages/data-access/jdbc/core.adoc

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

10
framework-docs/modules/ROOT/pages/data-access/jdbc/parameter-handling.adoc

@ -89,13 +89,13 @@ Java:: @@ -89,13 +89,13 @@ Java::
blobIs.close();
clobReader.close();
----
======
<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.
<3> Using the method `setBlobAsBinaryStream` to pass in the contents of the BLOB.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val blobIn = File("spring2004.jpg")
val blobIs = FileInputStream(blobIn)
@ -119,6 +119,7 @@ Java:: @@ -119,6 +119,7 @@ Java::
<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.
<3> Using the method `setBlobAsBinaryStream` to pass in the contents of the BLOB.
======
[NOTE]
@ -156,12 +157,12 @@ Java:: @@ -156,12 +157,12 @@ Java::
}
});
----
======
<1> Using the method `getClobAsString` to retrieve the contents of the CLOB.
<2> Using the method `getBlobAsBytes` to retrieve the contents of the BLOB.
Kotlin::
+
[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 clobText = lobHandler.getClobAsString(rs, "a_clob") // <1>
@ -171,6 +172,7 @@ Java:: @@ -171,6 +172,7 @@ Java::
----
<1> Using the method `getClobAsString` to retrieve the contents of the CLOB.
<2> Using the method `getBlobAsBytes` to retrieve the contents of the BLOB.
======
[[jdbc-in-clause]]

5
framework-docs/modules/ROOT/pages/data-access/r2dbc.adoc

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

15
framework-docs/modules/ROOT/pages/rsocket.adoc

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

20
framework-docs/modules/ROOT/pages/testing/annotations/integration-junit-jupiter.adoc

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

25
framework-docs/modules/ROOT/pages/testing/annotations/integration-junit4.adoc

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

10
framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-activeprofiles.adoc

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

5
framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-aftertransaction.adoc

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

5
framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-beforetransaction.adoc

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

5
framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-commit.adoc

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

20
framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-contextconfiguration.adoc

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

35
framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-dirtiescontext.adoc

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

5
framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-dynamicpropertysource.adoc

@ -29,13 +29,13 @@ Java:: @@ -29,13 +29,13 @@ Java::
// tests ...
}
----
======
<1> Annotate a `static` method with `@DynamicPropertySource`.
<2> Accept a `DynamicPropertyRegistry` as an argument.
<3> Register a dynamic `server.port` property to be retrieved lazily from the server.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration
class MyIntegrationTests {
@ -58,6 +58,7 @@ Java:: @@ -58,6 +58,7 @@ Java::
<1> Annotate a `static` method with `@DynamicPropertySource`.
<2> Accept a `DynamicPropertyRegistry` as an argument.
<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.

5
framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-rollback.adoc

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

5
framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-sql.adoc

@ -17,11 +17,11 @@ Java:: @@ -17,11 +17,11 @@ Java::
// run code that relies on the test schema and test data
}
----
======
<1> Run two scripts for this test.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Test
@Sql("/test-schema.sql", "/test-user-data.sql") // <1>
@ -30,6 +30,7 @@ Java:: @@ -30,6 +30,7 @@ Java::
}
----
<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.

5
framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-sqlconfig.adoc

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

5
framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-sqlgroup.adoc

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

10
framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-sqlmergemode.adoc

@ -29,11 +29,11 @@ Java:: @@ -29,11 +29,11 @@ Java::
}
}
----
======
<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"]
.Kotlin
----
@SpringJUnitConfig(TestConfig::class)
@Sql("/test-schema.sql")
@ -48,6 +48,7 @@ Java:: @@ -48,6 +48,7 @@ Java::
}
----
<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.
@ -69,11 +70,11 @@ Java:: @@ -69,11 +70,11 @@ Java::
}
}
----
======
<1> Set the `@Sql` merge mode to `MERGE` for a specific test method.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(TestConfig::class)
@Sql("/test-schema.sql")
@ -88,5 +89,6 @@ Java:: @@ -88,5 +89,6 @@ Java::
}
----
<1> Set the `@Sql` merge mode to `MERGE` for a specific test method.
======

7
framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-testexecutionlisteners.adoc

@ -20,11 +20,11 @@ Java:: @@ -20,11 +20,11 @@ Java::
// class body...
}
----
======
<1> Register two `TestExecutionListener` implementations.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration
@TestExecutionListeners(CustomTestExecutionListener::class, AnotherTestExecutionListener::class) // <1>
@ -33,11 +33,12 @@ Java:: @@ -33,11 +33,12 @@ Java::
}
----
<1> Register two `TestExecutionListener` implementations.
======
By default, `@TestExecutionListeners` provides support for inheriting listeners from
superclasses or enclosing classes. See
xref:testing/testcontext-framework/support-classes.adoc#testcontext-junit-jupiter-nested-test-configuration[`@Nested` test class configuration] and the
xref:testing/testcontext-framework/support-classes.adoc#testcontext-junit-jupiter-nested-test-configuration[`@Nested` test class configuration] and the
{api-spring-framework}/test/context/TestExecutionListeners.html[`@TestExecutionListeners`
javadoc] for an example and further details. If you discover that you need to switch
back to using the default `TestExecutionListener` implementations, see the note

10
framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-testpropertysource.adoc

@ -20,11 +20,11 @@ Java:: @@ -20,11 +20,11 @@ Java::
// class body...
}
----
======
<1> Get properties from `test.properties` in the root of the classpath.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration
@TestPropertySource("/test.properties") // <1>
@ -33,6 +33,7 @@ Java:: @@ -33,6 +33,7 @@ Java::
}
----
<1> Get properties from `test.properties` in the root of the classpath.
======
The following example demonstrates how to declare inlined properties:
@ -49,11 +50,11 @@ Java:: @@ -49,11 +50,11 @@ Java::
// class body...
}
----
======
<1> Declare `timezone` and `port` properties.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ContextConfiguration
@TestPropertySource(properties = ["timezone = GMT", "port: 4242"]) // <1>
@ -62,6 +63,7 @@ Java:: @@ -62,6 +63,7 @@ Java::
}
----
<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.

10
framework-docs/modules/ROOT/pages/testing/annotations/integration-spring/annotation-webappconfiguration.adoc

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

5
framework-docs/modules/ROOT/pages/testing/spring-mvc-test-framework/async-requests.adoc

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

5
framework-docs/modules/ROOT/pages/testing/spring-mvc-test-framework/server-htmlunit/webdriver.adoc

@ -298,7 +298,6 @@ Java:: @@ -298,7 +298,6 @@ Java::
}
}
----
======
<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.
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- @@ -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`
annotation to look up our submit button with a `css` selector (`input[type=submit]`).
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
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. @@ -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]
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]*).
======
--
Finally, we can verify that a new message was created successfully. The following

6
framework-docs/modules/ROOT/pages/testing/testcontext-framework/application-events.adoc

@ -54,14 +54,13 @@ Java:: @@ -54,14 +54,13 @@ Java::
}
}
----
======
<1> Annotate the test class with `@RecordApplicationEvents`.
<2> Inject the `ApplicationEvents` instance for the current test.
<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"]
.Kotlin
----
@SpringJUnitConfig(/* ... */)
@RecordApplicationEvents // <1>
@ -86,6 +85,7 @@ Java:: @@ -86,6 +85,7 @@ Java::
<1> Annotate the test class with `@RecordApplicationEvents`.
<2> Inject the `ApplicationEvents` instance for the current test.
<3> Use the `ApplicationEvents` API to count how many `OrderSubmitted` events were published.
======
See the
{api-spring-framework}/test/context/event/ApplicationEvents.html[`ApplicationEvents`

10
framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management.adoc

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

10
framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management/groovy.adoc

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

15
framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management/inheritance.adoc

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

10
framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management/initializers.adoc

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

10
framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management/javaconfig.adoc

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

10
framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management/property-sources.adoc

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

15
framework-docs/modules/ROOT/pages/testing/testcontext-framework/ctx-management/xml.adoc

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

10
framework-docs/modules/ROOT/pages/testing/webtestclient.adoc

@ -105,13 +105,13 @@ Java:: @@ -105,13 +105,13 @@ Java::
}
}
----
======
<1> Specify the configuration to load
<2> Inject the configuration
<3> Create the `WebTestClient`
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@SpringJUnitConfig(WebConfig::class) // <1>
class MyTests {
@ -127,6 +127,7 @@ Java:: @@ -127,6 +127,7 @@ Java::
<1> Specify the configuration to load
<2> Inject the configuration
<3> Create the `WebTestClient`
======
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]
@ -158,13 +159,13 @@ Java:: @@ -158,13 +159,13 @@ Java::
}
}
----
======
<1> Specify the configuration to load
<2> Inject the configuration
<3> Create the `WebTestClient`
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ExtendWith(SpringExtension.class)
@WebAppConfiguration("classpath:META-INF/web-resources") // <1>
@ -188,6 +189,7 @@ Java:: @@ -188,6 +189,7 @@ Java::
<1> Specify the configuration to load
<2> Inject the configuration
<3> Create the `WebTestClient`
======

5
framework-docs/modules/ROOT/pages/web/webflux-cors.adoc

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

30
framework-docs/modules/ROOT/pages/web/webflux-functional.adoc

@ -67,11 +67,11 @@ Java:: @@ -67,11 +67,11 @@ Java::
}
}
----
======
<1> Create router using `route()`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val repository: PersonRepository = ...
val handler = PersonHandler(repository)
@ -103,6 +103,7 @@ Java:: @@ -103,6 +103,7 @@ Java::
}
----
<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
through one of the built-in xref:web/webflux/reactive-spring.adoc#webflux-httphandler[server adapters]:
@ -436,7 +437,6 @@ public class PersonHandler { @@ -436,7 +437,6 @@ public class PersonHandler {
}
}
----
======
<1> `listPeople` is a handler function that returns all `Person` objects found in the repository as
JSON.
<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). @@ -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
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"]
.Kotlin
----
class PersonHandler(private val repository: PersonRepository) {
@ -479,6 +480,7 @@ Note that `PersonRepository.savePerson(Person)` is a suspending function with no @@ -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
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.
======
--
@ -515,13 +517,13 @@ Java:: @@ -515,13 +517,13 @@ Java::
}
}
----
======
<1> Create `Validator` instance.
<2> Apply validation.
<3> Raise exception for a 400 response.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class PersonHandler(private val repository: PersonRepository) {
@ -548,6 +550,7 @@ Java:: @@ -548,6 +550,7 @@ Java::
<1> Create `Validator` instance.
<2> Apply validation.
<3> Raise exception for a 400 response.
======
Handlers can also use the standard bean validation API (JSR-303) by creating and injecting
a global `Validator` instance based on `LocalValidatorFactoryBean`.
@ -666,7 +669,6 @@ RouterFunction<ServerResponse> route = route() @@ -666,7 +669,6 @@ RouterFunction<ServerResponse> route = route()
.add(otherRoute) // <4>
.build();
----
======
<1> pass:q[`GET /person/{id}`] with an `Accept` header that matches JSON is routed to
`PersonHandler.getPerson`
<2> `GET /person` with an `Accept` header that matches JSON is routed to
@ -675,8 +677,9 @@ RouterFunction<ServerResponse> route = route() @@ -675,8 +677,9 @@ RouterFunction<ServerResponse> route = route()
`PersonHandler.createPerson`, and
<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"]
.Kotlin
----
import org.springframework.http.MediaType.APPLICATION_JSON
@ -698,6 +701,7 @@ RouterFunction<ServerResponse> route = route() @@ -698,6 +701,7 @@ RouterFunction<ServerResponse> route = route()
<3> `POST /person` with no additional predicates is mapped to
`PersonHandler.createPerson`, and
<4> `otherRoute` is a router function that is created elsewhere, and added to the route built.
======
[[nested-routes]]
@ -724,11 +728,11 @@ RouterFunction<ServerResponse> route = route() @@ -724,11 +728,11 @@ RouterFunction<ServerResponse> route = route()
.POST(handler::createPerson))
.build();
----
======
<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"]
.Kotlin
----
val route = coRouter { // <1>
"/person".nest {
@ -739,6 +743,7 @@ RouterFunction<ServerResponse> route = route() @@ -739,6 +743,7 @@ RouterFunction<ServerResponse> route = route()
}
----
<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
the `nest` method on the builder.
@ -918,12 +923,12 @@ Java:: @@ -918,12 +923,12 @@ Java::
.after((request, response) -> logResponse(response)) // <2>
.build();
----
======
<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.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val route = router {
"/person".nest {
@ -942,6 +947,7 @@ Java:: @@ -942,6 +947,7 @@ Java::
----
<1> The `before` filter that adds a custom request header is only applied to the two GET routes.
<2> The `after` filter that logs the response is applied to all routes, including the nested ones.
======
The `filter` method on the router builder takes a `HandlerFilterFunction`: a

10
framework-docs/modules/ROOT/pages/web/webflux-webclient/client-builder.adoc

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

15
framework-docs/modules/ROOT/pages/web/webflux-websocket.adoc

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

5
framework-docs/modules/ROOT/pages/web/webflux/caching.adoc

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

6
framework-docs/modules/ROOT/pages/web/webflux/controller/ann-exceptions.adoc

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

10
framework-docs/modules/ROOT/pages/web/webflux/controller/ann-initbinder.adoc

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

5
framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/cookievalue.adoc

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

15
framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/modelattrib-method-args.adoc

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

20
framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/multipart-forms.adoc

@ -95,12 +95,12 @@ Java:: @@ -95,12 +95,12 @@ Java::
// ...
}
----
======
<1> Using `@RequestPart` to get the metadata.
<2> Using `@RequestPart` to get the file.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@PostMapping("/")
fun handle(@RequestPart("meta-data") Part metadata, // <1>
@ -110,6 +110,7 @@ Java:: @@ -110,6 +110,7 @@ Java::
----
<1> Using `@RequestPart` to get the metadata.
<2> Using `@RequestPart` to get the file.
======
--
@ -128,11 +129,11 @@ Java:: @@ -128,11 +129,11 @@ Java::
// ...
}
----
======
<1> Using `@RequestPart` to get the metadata.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@PostMapping("/")
fun handle(@RequestPart("meta-data") metadata: MetaData): String { // <1>
@ -140,6 +141,7 @@ Java:: @@ -140,6 +141,7 @@ Java::
}
----
<1> Using `@RequestPart` to get the metadata.
======
--
You can use `@RequestPart` in combination with `jakarta.validation.Valid` or Spring's
@ -189,11 +191,11 @@ Java:: @@ -189,11 +191,11 @@ Java::
// ...
}
----
======
<1> Using `@RequestBody`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@PostMapping("/")
fun handle(@RequestBody parts: MultiValueMap<String, Part>): String { // <1>
@ -201,6 +203,7 @@ Java:: @@ -201,6 +203,7 @@ Java::
}
----
<1> Using `@RequestBody`.
======
--
[[partevent]]
@ -250,7 +253,6 @@ Java:: @@ -250,7 +253,6 @@ Java::
}));
}
----
======
<1> Using `@RequestBody`.
<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.
@ -262,8 +264,9 @@ file upload. @@ -262,8 +264,9 @@ file upload.
<5> Handling the file upload.
<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"]
.Kotlin
----
@PostMapping("/")
fun handle(@RequestBody allPartsEvents: Flux<PartEvent>) = { // <1>
@ -299,6 +302,7 @@ file upload. @@ -299,6 +302,7 @@ file upload.
<4> Handling the form field.
<5> Handling the file upload.
<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`.
See xref:web/webflux-webclient/client-body.adoc#webflux-client-body-multipart[Multipart Data].

5
framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/requestattrib.adoc

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

5
framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/requestheader.adoc

@ -34,12 +34,12 @@ Java:: @@ -34,12 +34,12 @@ Java::
//...
}
----
======
<1> Get the value of the `Accept-Encoding` header.
<2> Get the value of the `Keep-Alive` header.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@GetMapping("/demo")
fun handle(
@ -50,6 +50,7 @@ Java:: @@ -50,6 +50,7 @@ Java::
----
<1> Get the value of the `Accept-Encoding` header.
<2> Get the value of the `Keep-Alive` header.
======
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].

5
framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/requestparam.adoc

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

5
framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/sessionattribute.adoc

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

10
framework-docs/modules/ROOT/pages/web/webflux/controller/ann-methods/sessionattributes.adoc

@ -23,11 +23,11 @@ Java:: @@ -23,11 +23,11 @@ Java::
// ...
}
----
======
<1> Using the `@SessionAttributes` annotation.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Controller
@SessionAttributes("pet") // <1>
@ -36,6 +36,7 @@ Java:: @@ -36,6 +36,7 @@ Java::
}
----
<1> Using the `@SessionAttributes` annotation.
======
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
@ -65,12 +66,12 @@ Java:: @@ -65,12 +66,12 @@ Java::
}
}
----
======
<1> Using the `@SessionAttributes` annotation.
<2> Using a `SessionStatus` variable.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Controller
@SessionAttributes("pet") // <1>
@ -90,5 +91,6 @@ Java:: @@ -90,5 +91,6 @@ Java::
----
<1> Using the `@SessionAttributes` annotation.
<2> Using a `SessionStatus` variable.
======

20
framework-docs/modules/ROOT/pages/web/webflux/controller/ann-requestmapping.adoc

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

5
framework-docs/modules/ROOT/pages/web/webflux/controller/ann.adoc

@ -25,11 +25,11 @@ Java:: @@ -25,11 +25,11 @@ Java::
// ...
}
----
======
<1> Scan the `org.example.web` package.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Configuration
@ComponentScan("org.example.web") // <1>
@ -39,6 +39,7 @@ Java:: @@ -39,6 +39,7 @@ Java::
}
----
<1> Scan the `org.example.web` package.
======
`@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

30
framework-docs/modules/ROOT/pages/web/webmvc-functional.adoc

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

5
framework-docs/modules/ROOT/pages/web/webmvc/mvc-caching.adoc

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

10
framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-initbinder.adoc

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

5
framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/cookievalue.adoc

@ -26,11 +26,11 @@ Java:: @@ -26,11 +26,11 @@ Java::
//...
}
----
======
<1> Get the value of the `JSESSIONID` cookie.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@GetMapping("/demo")
fun handle(@CookieValue("JSESSIONID") cookie: String) { // <1>
@ -38,6 +38,7 @@ Java:: @@ -38,6 +38,7 @@ Java::
}
----
<1> Get the value of the `JSESSIONID` cookie.
======
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].

25
framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/modelattrib-method-args.adoc

@ -20,11 +20,11 @@ Java:: @@ -20,11 +20,11 @@ Java::
// method logic...
}
----
======
<1> Bind an instance of `Pet`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String { // <1>
@ -32,6 +32,7 @@ fun processSubmit(@ModelAttribute pet: Pet): String { // <1> @@ -32,6 +32,7 @@ fun processSubmit(@ModelAttribute pet: Pet): String { // <1>
}
----
<1> Bind an instance of `Pet`.
======
The `Pet` instance above is sourced in one of the following ways:
@ -66,11 +67,11 @@ Java:: @@ -66,11 +67,11 @@ Java::
// ...
}
----
======
<1> Bind an instance of `Account` using an explicit attribute name.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@PutMapping("/accounts/{account}")
fun save(@ModelAttribute("account") account: Account): String { // <1>
@ -78,6 +79,7 @@ Java:: @@ -78,6 +79,7 @@ Java::
}
----
<1> Bind an instance of `Account` using an explicit attribute name.
======
After the model attribute instance is obtained, data binding is applied. The
`WebDataBinder` class matches Servlet request parameter names (query parameters and form
@ -104,11 +106,11 @@ Java:: @@ -104,11 +106,11 @@ Java::
// ...
}
----
======
<1> Adding a `BindingResult` next to the `@ModelAttribute`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String { // <1>
@ -119,6 +121,7 @@ Java:: @@ -119,6 +121,7 @@ Java::
}
----
<1> Adding a `BindingResult` next to the `@ModelAttribute`.
======
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,
@ -146,11 +149,11 @@ Java:: @@ -146,11 +149,11 @@ Java::
// ...
}
----
======
<1> Setting `@ModelAttribute(binding=false)`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@ModelAttribute
fun setUpForm(): AccountForm {
@ -169,6 +172,7 @@ Java:: @@ -169,6 +172,7 @@ Java::
}
----
<1> Setting `@ModelAttribute(binding=false)`.
======
You can automatically apply validation after data binding by adding the
`jakarta.validation.Valid` annotation or Spring's `@Validated` annotation
@ -189,11 +193,11 @@ Java:: @@ -189,11 +193,11 @@ Java::
// ...
}
----
======
<1> Validate the `Pet` instance.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@Valid @ModelAttribute("pet") pet: Pet, result: BindingResult): String { // <1>
@ -204,6 +208,7 @@ Java:: @@ -204,6 +208,7 @@ Java::
}
----
<1> Validate the `Pet` instance.
======
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

5
framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/requestattrib.adoc

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

5
framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/requestheader.adoc

@ -34,12 +34,12 @@ Java:: @@ -34,12 +34,12 @@ Java::
//...
}
----
======
<1> Get the value of the `Accept-Encoding` header.
<2> Get the value of the `Keep-Alive` header.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@GetMapping("/demo")
fun handle(
@ -50,6 +50,7 @@ Java:: @@ -50,6 +50,7 @@ Java::
----
<1> Get the value of the `Accept-Encoding` header.
<2> Get the value of the `Keep-Alive` header.
======
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].

5
framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/requestparam.adoc

@ -31,11 +31,11 @@ Java:: @@ -31,11 +31,11 @@ Java::
}
----
======
<1> Using `@RequestParam` to bind `petId`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import org.springframework.ui.set
@ -57,6 +57,7 @@ Java:: @@ -57,6 +57,7 @@ Java::
}
----
<1> Using `@RequestParam` to bind `petId`.
======
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

7
framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/sessionattribute.adoc

@ -19,18 +19,19 @@ Java:: @@ -19,18 +19,19 @@ Java::
// ...
}
----
======
<1> Using a `@SessionAttribute` annotation.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@RequestMapping("/")
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
`org.springframework.web.context.request.WebRequest` or

10
framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-methods/sessionattributes.adoc

@ -23,11 +23,11 @@ Java:: @@ -23,11 +23,11 @@ Java::
// ...
}
----
======
<1> Using the `@SessionAttributes` annotation.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Controller
@SessionAttributes("pet") // <1>
@ -36,6 +36,7 @@ Java:: @@ -36,6 +36,7 @@ Java::
}
----
<1> Using the `@SessionAttributes` annotation.
======
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
@ -64,12 +65,12 @@ Java:: @@ -64,12 +65,12 @@ Java::
}
}
----
======
<1> Storing the `Pet` value in the Servlet session.
<2> Clearing the `Pet` value from the Servlet session.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Controller
@SessionAttributes("pet") // <1>
@ -89,5 +90,6 @@ class EditPetForm { @@ -89,5 +90,6 @@ class EditPetForm {
----
<1> Storing the `Pet` value in the Servlet session.
<2> Clearing the `Pet` value from the Servlet session.
======

25
framework-docs/modules/ROOT/pages/web/webmvc/mvc-controller/ann-requestmapping.adoc

@ -309,11 +309,11 @@ Java:: @@ -309,11 +309,11 @@ Java::
// ...
}
----
======
<1> Using a `consumes` attribute to narrow the mapping by the content type.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@PostMapping("/pets", consumes = ["application/json"]) // <1>
fun addPet(@RequestBody pet: Pet) {
@ -321,6 +321,7 @@ Java:: @@ -321,6 +321,7 @@ Java::
}
----
<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
content type other than `text/plain`.
@ -352,11 +353,11 @@ Java:: @@ -352,11 +353,11 @@ Java::
// ...
}
----
======
<1> Using a `produces` attribute to narrow the mapping by the content type.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@GetMapping("/pets/{petId}", produces = ["application/json"]) // <1>
@ResponseBody
@ -365,6 +366,7 @@ Java:: @@ -365,6 +366,7 @@ Java::
}
----
<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,
`!text/plain` means any content type other than "text/plain".
@ -396,11 +398,11 @@ Java:: @@ -396,11 +398,11 @@ Java::
// ...
}
----
======
<1> Testing whether `myParam` equals `myValue`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@GetMapping("/pets/{petId}", params = ["myParam=myValue"]) // <1>
fun findPet(@PathVariable petId: String) {
@ -408,6 +410,7 @@ Java:: @@ -408,6 +410,7 @@ Java::
}
----
<1> Testing whether `myParam` equals `myValue`.
======
You can also use the same with request header conditions, as the following example shows:
@ -422,11 +425,11 @@ Java:: @@ -422,11 +425,11 @@ Java::
// ...
}
----
======
<1> Testing whether `myHeader` equals `myValue`.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@GetMapping("/pets/{petId}", headers = ["myHeader=myValue"]) // <1>
fun findPet(@PathVariable petId: String) {
@ -434,6 +437,7 @@ Java:: @@ -434,6 +437,7 @@ Java::
}
----
<1> Testing whether `myHeader` equals `myValue`.
======
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]
@ -517,14 +521,14 @@ Java:: @@ -517,14 +521,14 @@ Java::
}
}
----
======
<1> Inject the target handler and the handler mapping for controllers.
<2> Prepare the request mapping meta data.
<3> Get the handler method.
<4> Add the registration.
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Configuration
class MyConfig {
@ -541,6 +545,7 @@ Java:: @@ -541,6 +545,7 @@ Java::
<2> Prepare the request mapping meta data.
<3> Get the handler method.
<4> Add the registration.
======

5
framework-docs/modules/ROOT/partials/web/web-uris.adoc

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

20
framework-platform/framework-platform.gradle

@ -8,10 +8,10 @@ javaPlatform { @@ -8,10 +8,10 @@ javaPlatform {
dependencies {
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: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("org.apache.groovy:groovy-bom:4.0.11"))
api(platform("org.apache.logging.log4j:log4j-bom:2.20.0"))
@ -23,13 +23,13 @@ dependencies { @@ -23,13 +23,13 @@ dependencies {
constraints {
api("com.fasterxml:aalto-xml:1.3.2")
api("com.fasterxml.woodstox:woodstox-core:6.5.0")
api("com.github.ben-manes.caffeine:caffeine:3.1.5")
api("com.fasterxml.woodstox:woodstox-core:6.5.1")
api("com.github.ben-manes.caffeine:caffeine:3.1.6")
api("com.github.librepdf:openpdf:1.3.30")
api("com.google.code.findbugs:findbugs:3.0.1")
api("com.google.code.findbugs:jsr305:3.0.2")
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.h2database:h2:2.1.214")
api("com.jayway.jsonpath:json-path:2.8.0")
@ -45,11 +45,11 @@ dependencies { @@ -45,11 +45,11 @@ dependencies {
api("com.thoughtworks.xstream:xstream:1.4.20")
api("commons-io:commons-io:2.11.0")
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.mockk:mockk:1.13.4")
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-spi-test:1.0.0.RELEASE")
api("io.r2dbc:r2dbc-spi:1.0.0.RELEASE")
@ -89,9 +89,9 @@ dependencies { @@ -89,9 +89,9 @@ dependencies {
api("net.sf.jopt-simple:jopt-simple:5.0.4")
api("net.sourceforge.htmlunit:htmlunit:2.70.0")
api("org.apache-extras.beanshell:bsh:2.0b6")
api("org.apache.activemq:activemq-broker:5.17.2")
api("org.apache.activemq:activemq-kahadb-store:5.17.2")
api("org.apache.activemq:activemq-stomp:5.17.2")
api("org.apache.activemq:activemq-broker:5.17.4")
api("org.apache.activemq:activemq-kahadb-store:5.17.4")
api("org.apache.activemq:activemq-stomp:5.17.4")
api("org.apache.commons:commons-pool2:2.9.0")
api("org.apache.derby:derby:10.16.1.1")
api("org.apache.derby:derbyclient:10.16.1.1")

Loading…
Cancel
Save