Merge branch '6.2.x'

This commit is contained in:
Sam Brannen
2025-04-14 11:32:48 +02:00
39 changed files with 560 additions and 565 deletions

View File

@@ -469,20 +469,20 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
RootBeanDefinition beanDefinition = new RootBeanDefinition(ClientFactoryBean.class);
beanDefinition.setTargetType(ResolvableType.forClassWithGenerics(ClientFactoryBean.class, MyClient.class));
// ...
registry.registerBeanDefinition("myClient", beanDefinition);
RootBeanDefinition beanDefinition = new RootBeanDefinition(ClientFactoryBean.class);
beanDefinition.setTargetType(ResolvableType.forClassWithGenerics(ClientFactoryBean.class, MyClient.class));
// ...
registry.registerBeanDefinition("myClient", beanDefinition);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val beanDefinition = RootBeanDefinition(ClientFactoryBean::class.java)
beanDefinition.setTargetType(ResolvableType.forClassWithGenerics(ClientFactoryBean::class.java, MyClient::class.java));
// ...
registry.registerBeanDefinition("myClient", beanDefinition)
val beanDefinition = RootBeanDefinition(ClientFactoryBean::class.java)
beanDefinition.setTargetType(ResolvableType.forClassWithGenerics(ClientFactoryBean::class.java, MyClient::class.java));
// ...
registry.registerBeanDefinition("myClient", beanDefinition)
----
======

View File

@@ -9,15 +9,15 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
public class MovieRecommender {
@Component
public class MovieRecommender {
private final String catalog;
private final String catalog;
public MovieRecommender(@Value("${catalog.name}") String catalog) {
this.catalog = catalog;
}
}
public MovieRecommender(@Value("${catalog.name}") String catalog) {
this.catalog = catalog;
}
}
----
Kotlin::
@@ -37,9 +37,9 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig { }
@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig { }
----
Kotlin::
@@ -56,7 +56,7 @@ And the following `application.properties` file:
[source,java,indent=0,subs="verbatim,quotes"]
----
catalog.name=MovieCatalog
catalog.name=MovieCatalog
----
In that case, the `catalog` parameter and field will be equal to the `MovieCatalog` value.
@@ -119,15 +119,15 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
public class MovieRecommender {
@Component
public class MovieRecommender {
private final String catalog;
private final String catalog;
public MovieRecommender(@Value("${catalog.name:defaultCatalog}") String catalog) {
this.catalog = catalog;
}
}
public MovieRecommender(@Value("${catalog.name:defaultCatalog}") String catalog) {
this.catalog = catalog;
}
}
----
Kotlin::
@@ -150,16 +150,16 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class AppConfig {
@Configuration
public class AppConfig {
@Bean
public ConversionService conversionService() {
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addConverter(new MyCustomConverter());
return conversionService;
}
}
@Bean
public ConversionService conversionService() {
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
conversionService.addConverter(new MyCustomConverter());
return conversionService;
}
}
----
Kotlin::
@@ -188,15 +188,15 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
public class MovieRecommender {
@Component
public class MovieRecommender {
private final String catalog;
private final String catalog;
public MovieRecommender(@Value("#{systemProperties['user.catalog'] + 'Catalog' }") String catalog) {
this.catalog = catalog;
}
}
public MovieRecommender(@Value("#{systemProperties['user.catalog'] + 'Catalog' }") String catalog) {
this.catalog = catalog;
}
}
----
Kotlin::
@@ -217,16 +217,16 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Component
public class MovieRecommender {
@Component
public class MovieRecommender {
private final Map<String, Integer> countOfMoviesPerCatalog;
private final Map<String, Integer> countOfMoviesPerCatalog;
public MovieRecommender(
@Value("#{{'Thriller': 100, 'Comedy': 300}}") Map<String, Integer> countOfMoviesPerCatalog) {
this.countOfMoviesPerCatalog = countOfMoviesPerCatalog;
}
}
public MovieRecommender(
@Value("#{{'Thriller': 100, 'Comedy': 300}}") Map<String, Integer> countOfMoviesPerCatalog) {
this.countOfMoviesPerCatalog = countOfMoviesPerCatalog;
}
}
----
Kotlin::

View File

@@ -119,7 +119,7 @@ Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
----
======
@@ -309,16 +309,16 @@ Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import org.springframework.beans.factory.getBean
import org.springframework.beans.factory.getBean
// create and configure beans
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
// retrieve configured instance
val service = context.getBean<PetStoreService>("petStore")
// retrieve configured instance
val service = context.getBean<PetStoreService>("petStore")
// use configured instance
var userList = service.getUsernameList()
// use configured instance
var userList = service.getUsernameList()
----
======

View File

@@ -513,7 +513,7 @@ the classes above:
<property name="notificationAddress" value="blockedlist@example.org"/>
</bean>
<!-- optional: a custom ApplicationEventMulticaster definition -->
<!-- optional: a custom ApplicationEventMulticaster definition -->
<bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
<property name="taskExecutor" ref="..."/>
<property name="errorHandler" ref="..."/>

View File

@@ -226,7 +226,7 @@ Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
import org.springframework.beans.factory.getBean
import org.springframework.beans.factory.getBean
fun main() {
val ctx = ClassPathXmlApplicationContext("scripting/beans.xml")

View File

@@ -78,27 +78,27 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
@Configuration
public class DataSourceConfig {
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setDatabaseConfigurer(EmbeddedDatabaseConfigurers
.customizeConfigurer(H2, this::customize))
.addScript("schema.sql")
.build();
}
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setDatabaseConfigurer(EmbeddedDatabaseConfigurers
.customizeConfigurer(H2, this::customize))
.addScript("schema.sql")
.build();
}
private EmbeddedDatabaseConfigurer customize(EmbeddedDatabaseConfigurer defaultConfigurer) {
return new EmbeddedDatabaseConfigurerDelegate(defaultConfigurer) {
@Override
public void configureConnectionProperties(ConnectionProperties properties, String databaseName) {
super.configureConnectionProperties(properties, databaseName);
properties.setDriverClass(CustomDriver.class);
}
};
}
private EmbeddedDatabaseConfigurer customize(EmbeddedDatabaseConfigurer defaultConfigurer) {
return new EmbeddedDatabaseConfigurerDelegate(defaultConfigurer) {
@Override
public void configureConnectionProperties(ConnectionProperties properties, String databaseName) {
super.configureConnectionProperties(properties, databaseName);
properties.setDriverClass(CustomDriver.class);
}
};
}
}
----

View File

@@ -136,7 +136,7 @@ Java::
[source,java,indent=0,subs="verbatim,quotes"]
----
Mono<Void> completion = client.sql("CREATE TABLE person (id VARCHAR(255) PRIMARY KEY, name VARCHAR(255), age INTEGER);")
.then();
.then();
----
Kotlin::
@@ -144,7 +144,7 @@ Kotlin::
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
client.sql("CREATE TABLE person (id VARCHAR(255) PRIMARY KEY, name VARCHAR(255), age INTEGER);")
.await()
.await()
----
======
@@ -173,7 +173,7 @@ Java::
[source,java,indent=0,subs="verbatim,quotes"]
----
Mono<Map<String, Object>> first = client.sql("SELECT id, name FROM person")
.fetch().first();
.fetch().first();
----
Kotlin::
@@ -181,7 +181,7 @@ Kotlin::
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val first = client.sql("SELECT id, name FROM person")
.fetch().awaitSingle()
.fetch().awaitSingle()
----
======
@@ -194,8 +194,8 @@ Java::
[source,java,indent=0,subs="verbatim,quotes"]
----
Mono<Map<String, Object>> first = client.sql("SELECT id, name FROM person WHERE first_name = :fn")
.bind("fn", "Joe")
.fetch().first();
.bind("fn", "Joe")
.fetch().first();
----
Kotlin::
@@ -203,8 +203,8 @@ Kotlin::
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val first = client.sql("SELECT id, name FROM person WHERE first_name = :fn")
.bind("fn", "Joe")
.fetch().awaitSingle()
.bind("fn", "Joe")
.fetch().awaitSingle()
----
======
@@ -240,8 +240,8 @@ Java::
[source,java,indent=0,subs="verbatim,quotes"]
----
Flux<String> names = client.sql("SELECT name FROM person")
.map(row -> row.get("name", String.class))
.all();
.map(row -> row.get("name", String.class))
.all();
----
Kotlin::
@@ -249,8 +249,8 @@ Kotlin::
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val names = client.sql("SELECT name FROM person")
.map{ row: Row -> row.get("name", String.class) }
.flow()
.map{ row: Row -> row.get("name", String.class) }
.flow()
----
======
@@ -301,8 +301,8 @@ Java::
[source,java,indent=0,subs="verbatim,quotes"]
----
Mono<Integer> affectedRows = client.sql("UPDATE person SET first_name = :fn")
.bind("fn", "Joe")
.fetch().rowsUpdated();
.bind("fn", "Joe")
.fetch().rowsUpdated();
----
Kotlin::
@@ -310,8 +310,8 @@ Kotlin::
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val affectedRows = client.sql("UPDATE person SET first_name = :fn")
.bind("fn", "Joe")
.fetch().awaitRowsUpdated()
.bind("fn", "Joe")
.fetch().awaitRowsUpdated()
----
======
@@ -337,9 +337,9 @@ The following example shows parameter binding for a query:
[source,java]
----
db.sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")
.bind("id", "joe")
.bind("name", "Joe")
db.sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")
.bind("id", "joe")
.bind("name", "Joe")
.bind("age", 34);
----
@@ -369,9 +369,9 @@ Indices are zero based.
[source,java]
----
db.sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")
.bind(0, "joe")
.bind(1, "Joe")
db.sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")
.bind(0, "joe")
.bind(1, "Joe")
.bind(2, 34);
----
@@ -379,9 +379,9 @@ In case your application is binding to many parameters, the same can be achieved
[source,java]
----
List<?> values = List.of("joe", "Joe", 34);
db.sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")
.bindValues(values);
List<?> values = List.of("joe", "Joe", 34);
db.sql("INSERT INTO person (id, name, age) VALUES(:id, :name, :age)")
.bindValues(values);
----
@@ -428,7 +428,7 @@ Java::
tuples.add(new Object[] {"Ann", 50});
client.sql("SELECT id, name, state FROM table WHERE (name, age) IN (:tuples)")
.bind("tuples", tuples);
.bind("tuples", tuples);
----
Kotlin::
@@ -440,7 +440,7 @@ Kotlin::
tuples.add(arrayOf("Ann", 50))
client.sql("SELECT id, name, state FROM table WHERE (name, age) IN (:tuples)")
.bind("tuples", tuples)
.bind("tuples", tuples)
----
======
@@ -455,7 +455,7 @@ Java::
[source,java,indent=0,subs="verbatim,quotes"]
----
client.sql("SELECT id, name, state FROM table WHERE age IN (:ages)")
.bind("ages", Arrays.asList(35, 50));
.bind("ages", Arrays.asList(35, 50));
----
Kotlin::
@@ -463,7 +463,7 @@ Kotlin::
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
client.sql("SELECT id, name, state FROM table WHERE age IN (:ages)")
.bind("ages", arrayOf(35, 50))
.bind("ages", arrayOf(35, 50))
----
======
@@ -490,9 +490,9 @@ Java::
[source,java,indent=0,subs="verbatim,quotes"]
----
client.sql("INSERT INTO table (name, state) VALUES(:name, :state)")
.filter((s, next) -> next.execute(s.returnGeneratedValues("id")))
.bind("name", …)
.bind("state", …);
.filter((s, next) -> next.execute(s.returnGeneratedValues("id")))
.bind("name", …)
.bind("state", …);
----
Kotlin::
@@ -516,10 +516,10 @@ Java::
[source,java,indent=0,subs="verbatim,quotes"]
----
client.sql("INSERT INTO table (name, state) VALUES(:name, :state)")
.filter(statement -> s.returnGeneratedValues("id"));
.filter(statement -> s.returnGeneratedValues("id"));
client.sql("SELECT id, name, state FROM table")
.filter(statement -> s.fetchSize(25));
.filter(statement -> s.fetchSize(25));
----
Kotlin::
@@ -527,10 +527,10 @@ Kotlin::
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
client.sql("INSERT INTO table (name, state) VALUES(:name, :state)")
.filter { statement -> s.returnGeneratedValues("id") }
.filter { statement -> s.returnGeneratedValues("id") }
client.sql("SELECT id, name, state FROM table")
.filter { statement -> s.fetchSize(25) }
.filter { statement -> s.fetchSize(25) }
----
======

View File

@@ -30,36 +30,36 @@ Java::
+
[source,java,indent=0,subs="verbatim"]
----
RestClient defaultClient = RestClient.create();
RestClient customClient = RestClient.builder()
.requestFactory(new HttpComponentsClientHttpRequestFactory())
.messageConverters(converters -> converters.add(new MyCustomMessageConverter()))
.baseUrl("https://example.com")
.defaultUriVariables(Map.of("variable", "foo"))
.defaultHeader("My-Header", "Foo")
.defaultCookie("My-Cookie", "Bar")
.requestInterceptor(myCustomInterceptor)
.requestInitializer(myCustomInitializer)
.build();
RestClient defaultClient = RestClient.create();
RestClient customClient = RestClient.builder()
.requestFactory(new HttpComponentsClientHttpRequestFactory())
.messageConverters(converters -> converters.add(new MyCustomMessageConverter()))
.baseUrl("https://example.com")
.defaultUriVariables(Map.of("variable", "foo"))
.defaultHeader("My-Header", "Foo")
.defaultCookie("My-Cookie", "Bar")
.requestInterceptor(myCustomInterceptor)
.requestInitializer(myCustomInitializer)
.build();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim"]
----
val defaultClient = RestClient.create()
val customClient = RestClient.builder()
.requestFactory(HttpComponentsClientHttpRequestFactory())
.messageConverters { converters -> converters.add(MyCustomMessageConverter()) }
.baseUrl("https://example.com")
.defaultUriVariables(mapOf("variable" to "foo"))
.defaultHeader("My-Header", "Foo")
.defaultCookie("My-Cookie", "Bar")
.requestInterceptor(myCustomInterceptor)
.requestInitializer(myCustomInitializer)
.build()
val defaultClient = RestClient.create()
val customClient = RestClient.builder()
.requestFactory(HttpComponentsClientHttpRequestFactory())
.messageConverters { converters -> converters.add(MyCustomMessageConverter()) }
.baseUrl("https://example.com")
.defaultUriVariables(mapOf("variable" to "foo"))
.defaultHeader("My-Header", "Foo")
.defaultCookie("My-Cookie", "Bar")
.requestInterceptor(myCustomInterceptor)
.requestInitializer(myCustomInitializer)
.build()
----
======
@@ -81,20 +81,20 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
int id = 42;
restClient.get()
.uri("https://example.com/orders/{id}", id)
....
int id = 42;
restClient.get()
.uri("https://example.com/orders/{id}", id)
// ...
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val id = 42
restClient.get()
.uri("https://example.com/orders/{id}", id)
...
val id = 42
restClient.get()
.uri("https://example.com/orders/{id}", id)
// ...
----
======
@@ -133,12 +133,12 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
String result = restClient.get() <1>
.uri("https://example.com") <2>
.retrieve() <3>
.body(String.class); <4>
System.out.println(result); <5>
String result = restClient.get() <1>
.uri("https://example.com") <2>
.retrieve() <3>
.body(String.class); <4>
System.out.println(result); <5>
----
<1> Set up a GET request
<2> Specify the URL to connect to
@@ -150,12 +150,12 @@ Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val result= restClient.get() <1>
.uri("https://example.com") <2>
.retrieve() <3>
.body<String>() <4>
println(result) <5>
val result= restClient.get() <1>
.uri("https://example.com") <2>
.retrieve() <3>
.body<String>() <4>
println(result) <5>
----
<1> Set up a GET request
<2> Specify the URL to connect to
@@ -172,14 +172,14 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
ResponseEntity<String> result = restClient.get() <1>
.uri("https://example.com") <1>
.retrieve()
.toEntity(String.class); <2>
System.out.println("Response status: " + result.getStatusCode()); <3>
System.out.println("Response headers: " + result.getHeaders()); <3>
System.out.println("Contents: " + result.getBody()); <3>
ResponseEntity<String> result = restClient.get() <1>
.uri("https://example.com") <1>
.retrieve()
.toEntity(String.class); <2>
System.out.println("Response status: " + result.getStatusCode()); <3>
System.out.println("Response headers: " + result.getHeaders()); <3>
System.out.println("Contents: " + result.getBody()); <3>
----
<1> Set up a GET request for the specified URL
<2> Convert the response into a `ResponseEntity`
@@ -189,14 +189,14 @@ Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val result = restClient.get() <1>
.uri("https://example.com") <1>
.retrieve()
.toEntity<String>() <2>
println("Response status: " + result.statusCode) <3>
println("Response headers: " + result.headers) <3>
println("Contents: " + result.body) <3>
val result = restClient.get() <1>
.uri("https://example.com") <1>
.retrieve()
.toEntity<String>() <2>
println("Response status: " + result.statusCode) <3>
println("Response headers: " + result.headers) <3>
println("Contents: " + result.body) <3>
----
<1> Set up a GET request for the specified URL
<2> Convert the response into a `ResponseEntity`
@@ -212,12 +212,12 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
int id = ...;
Pet pet = restClient.get()
.uri("https://petclinic.example.com/pets/{id}", id) <1>
.accept(APPLICATION_JSON) <2>
.retrieve()
.body(Pet.class); <3>
int id = ...;
Pet pet = restClient.get()
.uri("https://petclinic.example.com/pets/{id}", id) <1>
.accept(APPLICATION_JSON) <2>
.retrieve()
.body(Pet.class); <3>
----
<1> Using URI variables
<2> Set the `Accept` header to `application/json`
@@ -227,12 +227,12 @@ Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val id = ...
val pet = restClient.get()
.uri("https://petclinic.example.com/pets/{id}", id) <1>
.accept(APPLICATION_JSON) <2>
.retrieve()
.body<Pet>() <3>
val id = ...
val pet = restClient.get()
.uri("https://petclinic.example.com/pets/{id}", id) <1>
.accept(APPLICATION_JSON) <2>
.retrieve()
.body<Pet>() <3>
----
<1> Using URI variables
<2> Set the `Accept` header to `application/json`
@@ -247,13 +247,13 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
Pet pet = ... <1>
ResponseEntity<Void> response = restClient.post() <2>
.uri("https://petclinic.example.com/pets/new") <2>
.contentType(APPLICATION_JSON) <3>
.body(pet) <4>
.retrieve()
.toBodilessEntity(); <5>
Pet pet = ... <1>
ResponseEntity<Void> response = restClient.post() <2>
.uri("https://petclinic.example.com/pets/new") <2>
.contentType(APPLICATION_JSON) <3>
.body(pet) <4>
.retrieve()
.toBodilessEntity(); <5>
----
<1> Create a `Pet` domain object
<2> Set up a POST request, and the URL to connect to
@@ -265,13 +265,13 @@ Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val pet: Pet = ... <1>
val response = restClient.post() <2>
.uri("https://petclinic.example.com/pets/new") <2>
.contentType(APPLICATION_JSON) <3>
.body(pet) <4>
.retrieve()
.toBodilessEntity() <5>
val pet: Pet = ... <1>
val response = restClient.post() <2>
.uri("https://petclinic.example.com/pets/new") <2>
.contentType(APPLICATION_JSON) <3>
.body(pet) <4>
.retrieve()
.toBodilessEntity() <5>
----
<1> Create a `Pet` domain object
<2> Set up a POST request, and the URL to connect to
@@ -291,13 +291,13 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
String result = restClient.get() <1>
.uri("https://example.com/this-url-does-not-exist") <1>
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError, (request, response) -> { <2>
throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()); <3>
})
.body(String.class);
String result = restClient.get() <1>
.uri("https://example.com/this-url-does-not-exist") <1>
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError, (request, response) -> { <2>
throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()); <3>
})
.body(String.class);
----
<1> Create a GET request for a URL that returns a 404 status code
<2> Set up a status handler for all 4xx status codes
@@ -307,12 +307,12 @@ Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val result = restClient.get() <1>
.uri("https://example.com/this-url-does-not-exist") <1>
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError) { _, response -> <2>
throw MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()) } <3>
.body<String>()
val result = restClient.get() <1>
.uri("https://example.com/this-url-does-not-exist") <1>
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError) { _, response -> <2>
throw MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()) } <3>
.body<String>()
----
<1> Create a GET request for a URL that returns a 404 status code
<2> Set up a status handler for all 4xx status codes
@@ -330,18 +330,18 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
Pet result = restClient.get()
.uri("https://petclinic.example.com/pets/{id}", id)
.accept(APPLICATION_JSON)
.exchange((request, response) -> { <1>
if (response.getStatusCode().is4xxClientError()) { <2>
throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()); <2>
}
else {
Pet pet = convertResponse(response); <3>
return pet;
}
});
Pet result = restClient.get()
.uri("https://petclinic.example.com/pets/{id}", id)
.accept(APPLICATION_JSON)
.exchange((request, response) -> { <1>
if (response.getStatusCode().is4xxClientError()) { <2>
throw new MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()); <2>
}
else {
Pet pet = convertResponse(response); <3>
return pet;
}
});
----
<1> `exchange` provides the request and response
<2> Throw an exception when the response has a 4xx status code
@@ -351,17 +351,17 @@ Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val result = restClient.get()
.uri("https://petclinic.example.com/pets/{id}", id)
.accept(MediaType.APPLICATION_JSON)
.exchange { request, response -> <1>
if (response.getStatusCode().is4xxClientError()) { <2>
throw MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()) <2>
} else {
val pet: Pet = convertResponse(response) <3>
pet
}
}
val result = restClient.get()
.uri("https://petclinic.example.com/pets/{id}", id)
.accept(MediaType.APPLICATION_JSON)
.exchange { request, response -> <1>
if (response.getStatusCode().is4xxClientError()) { <2>
throw MyCustomRuntimeException(response.getStatusCode(), response.getHeaders()) <2>
} else {
val pet: Pet = convertResponse(response) <3>
pet
}
}
----
<1> `exchange` provides the request and response
<2> Throw an exception when the response has a 4xx status code
@@ -380,15 +380,14 @@ To serialize only a subset of the object properties, you can specify a {baeldung
[source,java,indent=0,subs="verbatim"]
----
MappingJacksonValue value = new MappingJacksonValue(new User("eric", "7!jd#h23"));
value.setSerializationView(User.WithoutPasswordView.class);
ResponseEntity<Void> response = restClient.post() // or RestTemplate.postForEntity
.contentType(APPLICATION_JSON)
.body(value)
.retrieve()
.toBodilessEntity();
MappingJacksonValue value = new MappingJacksonValue(new User("eric", "7!jd#h23"));
value.setSerializationView(User.WithoutPasswordView.class);
ResponseEntity<Void> response = restClient.post() // or RestTemplate.postForEntity
.contentType(APPLICATION_JSON)
.body(value)
.retrieve()
.toBodilessEntity();
----
==== Multipart
@@ -398,24 +397,24 @@ For example:
[source,java,indent=0,subs="verbatim"]
----
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
parts.add("fieldPart", "fieldValue");
parts.add("filePart", new FileSystemResource("...logo.png"));
parts.add("jsonPart", new Person("Jason"));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
parts.add("xmlPart", new HttpEntity<>(myBean, headers));
// send using RestClient.post or RestTemplate.postForEntity
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
parts.add("fieldPart", "fieldValue");
parts.add("filePart", new FileSystemResource("...logo.png"));
parts.add("jsonPart", new Person("Jason"));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
parts.add("xmlPart", new HttpEntity<>(myBean, headers));
// send using RestClient.post or RestTemplate.postForEntity
----
In most cases, you do not have to specify the `Content-Type` for each part.
The content type is determined automatically based on the `HttpMessageConverter` chosen to serialize it or, in the case of a `Resource`, based on the file extension.
If necessary, you can explicitly provide the `MediaType` with an `HttpEntity` wrapper.
Once the `MultiValueMap` is ready, you can use it as the body of a `POST` request, using `RestClient.post().body(parts)` (or `RestTemplate.postForObject`).
Once the `MultiValueMap` is ready, you can use it as the body of a `POST` request, using `RestClient.post().body(parts)` (or `RestTemplate.postForObject`).
If the `MultiValueMap` contains at least one non-`String` value, the `Content-Type` is set to `multipart/form-data` by the `FormHttpMessageConverter`.
If the `MultiValueMap` has `String` values, the `Content-Type` defaults to `application/x-www-form-urlencoded`.
@@ -1137,11 +1136,11 @@ performed through the client:
[source,java,indent=0,subs="verbatim,quotes"]
----
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(myErrorHandler);
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(myErrorHandler);
RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate);
HttpServiceProxyFactory factory = HttpServiceProxyFactory.builderFor(adapter).build();
----
For more details and options, see the Javadoc of `setErrorHandler` in `RestTemplate` and

View File

@@ -215,45 +215,43 @@ For suspending functions, a `TransactionalOperator.executeAndAwait` extension is
[source,kotlin,indent=0]
----
import org.springframework.transaction.reactive.executeAndAwait
import org.springframework.transaction.reactive.executeAndAwait
class PersonRepository(private val operator: TransactionalOperator) {
class PersonRepository(private val operator: TransactionalOperator) {
suspend fun initDatabase() = operator.executeAndAwait {
insertPerson1()
insertPerson2()
}
suspend fun initDatabase() = operator.executeAndAwait {
insertPerson1()
insertPerson2()
}
private suspend fun insertPerson1() {
// INSERT SQL statement
}
private suspend fun insertPerson1() {
// INSERT SQL statement
}
private suspend fun insertPerson2() {
// INSERT SQL statement
}
}
private suspend fun insertPerson2() {
// INSERT SQL statement
}
}
----
For Kotlin `Flow`, a `Flow<T>.transactional` extension is provided.
[source,kotlin,indent=0]
----
import org.springframework.transaction.reactive.transactional
import org.springframework.transaction.reactive.transactional
class PersonRepository(private val operator: TransactionalOperator) {
class PersonRepository(private val operator: TransactionalOperator) {
fun updatePeople() = findPeople().map(::updatePerson).transactional(operator)
fun updatePeople() = findPeople().map(::updatePerson).transactional(operator)
private fun findPeople(): Flow<Person> {
// SELECT SQL statement
}
private fun findPeople(): Flow<Person> {
// SELECT SQL statement
}
private suspend fun updatePerson(person: Person): Person {
// UPDATE SQL statement
}
}
private suspend fun updatePerson(person: Person): Person {
// UPDATE SQL statement
}
}
----

View File

@@ -296,17 +296,17 @@ for example when writing a `org.springframework.core.convert.converter.Converter
[source,kotlin,indent=0]
----
class ListOfFooConverter : Converter<List<Foo>, CustomJavaList<out Foo>> {
// ...
}
class ListOfFooConverter : Converter<List<Foo>, CustomJavaList<out Foo>> {
// ...
}
----
When converting any kind of objects, star projection with `*` can be used instead of `out Any`.
[source,kotlin,indent=0]
----
class ListOfAnyConverter : Converter<List<*>, CustomJavaList<*>> {
// ...
}
class ListOfAnyConverter : Converter<List<*>, CustomJavaList<*>> {
// ...
}
----
NOTE: Spring Framework does not leverage yet declaration-site variance type information for injecting beans,
@@ -340,13 +340,14 @@ file with a `spring.test.constructor.autowire.mode = all` property.
[source,kotlin,indent=0]
----
@SpringJUnitConfig(TestConfig::class)
@TestConstructor(autowireMode = AutowireMode.ALL)
class OrderServiceIntegrationTests(val orderService: OrderService,
val customerService: CustomerService) {
// tests that use the injected OrderService and CustomerService
}
@SpringJUnitConfig(TestConfig::class)
@TestConstructor(autowireMode = AutowireMode.ALL)
class OrderServiceIntegrationTests(
val orderService: OrderService,
val customerService: CustomerService) {
// tests that use the injected OrderService and CustomerService
}
----
@@ -368,29 +369,29 @@ The following example demonstrates `@BeforeAll` and `@AfterAll` annotations on n
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class IntegrationTests {
val application = Application(8181)
val client = WebClient.create("http://localhost:8181")
val application = Application(8181)
val client = WebClient.create("http://localhost:8181")
@BeforeAll
fun beforeAll() {
application.start()
}
@BeforeAll
fun beforeAll() {
application.start()
}
@Test
fun `Find all users on HTML page`() {
client.get().uri("/users")
.accept(TEXT_HTML)
.retrieve()
.bodyToMono<String>()
.test()
.expectNextMatches { it.contains("Foo") }
.verifyComplete()
}
@Test
fun `Find all users on HTML page`() {
client.get().uri("/users")
.accept(TEXT_HTML)
.retrieve()
.bodyToMono<String>()
.test()
.expectNextMatches { it.contains("Foo") }
.verifyComplete()
}
@AfterAll
fun afterAll() {
application.stop()
}
@AfterAll
fun afterAll() {
application.stop()
}
}
----
@@ -403,26 +404,27 @@ The following example shows how to do so:
[source,kotlin,indent=0]
----
class SpecificationLikeTests {
class SpecificationLikeTests {
@Nested
@DisplayName("a calculator")
inner class Calculator {
@Nested
@DisplayName("a calculator")
inner class Calculator {
val calculator = SampleCalculator()
@Test
fun `should return the result of adding the first number to the second number`() {
val sum = calculator.sum(2, 4)
assertEquals(6, sum)
}
@Test
fun `should return the result of subtracting the second number from the first number`() {
val subtract = calculator.subtract(4, 2)
assertEquals(2, subtract)
}
}
}
val calculator = SampleCalculator()
@Test
fun `should return the result of adding the first number to the second number`() {
val sum = calculator.sum(2, 4)
assertEquals(6, sum)
}
@Test
fun `should return the result of subtracting the second number from the first number`() {
val subtract = calculator.subtract(4, 2)
assertEquals(2, subtract)
}
}
}
----

View File

@@ -1,8 +1,6 @@
[[kotlin-web]]
= Web
[[router-dsl]]
== Router DSL
@@ -16,27 +14,27 @@ These DSL let you write clean and idiomatic Kotlin code to build a `RouterFuncti
[source,kotlin,indent=0]
----
@Configuration
class RouterRouterConfiguration {
@Bean
fun mainRouter(userHandler: UserHandler) = router {
accept(TEXT_HTML).nest {
GET("/") { ok().render("index") }
GET("/sse") { ok().render("sse") }
GET("/users", userHandler::findAllView)
}
"/api".nest {
accept(APPLICATION_JSON).nest {
GET("/users", userHandler::findAll)
@Configuration
class RouterRouterConfiguration {
@Bean
fun mainRouter(userHandler: UserHandler) = router {
accept(TEXT_HTML).nest {
GET("/") { ok().render("index") }
GET("/sse") { ok().render("sse") }
GET("/users", userHandler::findAllView)
}
accept(TEXT_EVENT_STREAM).nest {
GET("/users", userHandler::stream)
"/api".nest {
accept(APPLICATION_JSON).nest {
GET("/users", userHandler::findAll)
}
accept(TEXT_EVENT_STREAM).nest {
GET("/users", userHandler::stream)
}
}
resources("/**", ClassPathResource("static/"))
}
resources("/**", ClassPathResource("static/"))
}
}
----
NOTE: This DSL is programmatic, meaning that it allows custom registration logic of beans
@@ -55,22 +53,22 @@ idiomatic Kotlin API and to allow better discoverability (no usage of static met
[source,kotlin,indent=0]
----
val mockMvc: MockMvc = ...
mockMvc.get("/person/{name}", "Lee") {
secure = true
accept = APPLICATION_JSON
headers {
contentLanguage = Locale.FRANCE
val mockMvc: MockMvc = ...
mockMvc.get("/person/{name}", "Lee") {
secure = true
accept = APPLICATION_JSON
headers {
contentLanguage = Locale.FRANCE
}
principal = Principal { "foo" }
}.andExpect {
status { isOk }
content { contentType(APPLICATION_JSON) }
jsonPath("$.name") { value("Lee") }
content { json("""{"someBoolean": false}""", false) }
}.andDo {
print()
}
principal = Principal { "foo" }
}.andExpect {
status { isOk }
content { contentType(APPLICATION_JSON) }
jsonPath("$.name") { value("Lee") }
content { json("""{"someBoolean": false}""", false) }
}.andDo {
print()
}
----

View File

@@ -26,16 +26,16 @@ Java::
@Test
void test() throws Exception {
MvcResult mvcResult = this.mockMvc.perform(get("/path"))
.andExpect(status().isOk()) <1>
.andExpect(request().asyncStarted()) <2>
.andExpect(request().asyncResult("body")) <3>
.andReturn();
MvcResult mvcResult = this.mockMvc.perform(get("/path"))
.andExpect(status().isOk()) <1>
.andExpect(request().asyncStarted()) <2>
.andExpect(request().asyncResult("body")) <3>
.andReturn();
this.mockMvc.perform(asyncDispatch(mvcResult)) <4>
.andExpect(status().isOk()) <5>
.andExpect(content().string("body"));
}
this.mockMvc.perform(asyncDispatch(mvcResult)) <4>
.andExpect(status().isOk()) <5>
.andExpect(content().string("body"));
}
----
<1> Check response status is still unchanged
<2> Async processing must have started

View File

@@ -1,5 +1,5 @@
[[testcontext-context-customizers]]
= Configuration Configuration with Context Customizers
= Context Configuration with Context Customizers
A `ContextCustomizer` is responsible for customizing the supplied
`ConfigurableApplicationContext` after bean definitions have been loaded into the context

View File

@@ -396,7 +396,7 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
import org.springframework.test.web.reactive.server.expectBody
import org.springframework.test.web.reactive.server.expectBody
client.get().uri("/persons/1")
.exchange()

View File

@@ -306,34 +306,34 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
Resource resource = ...
Mono<String> result = webClient
.post()
.uri("https://example.com")
.body(Flux.concat(
FormPartEvent.create("field", "field value"),
FilePartEvent.create("file", resource)
), PartEvent.class)
.retrieve()
.bodyToMono(String.class);
Resource resource = ...
Mono<String> result = webClient
.post()
.uri("https://example.com")
.body(Flux.concat(
FormPartEvent.create("field", "field value"),
FilePartEvent.create("file", resource)
), PartEvent.class)
.retrieve()
.bodyToMono(String.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
var resource: Resource = ...
var result: Mono<String> = webClient
.post()
.uri("https://example.com")
.body(
Flux.concat(
FormPartEvent.create("field", "field value"),
FilePartEvent.create("file", resource)
var resource: Resource = ...
var result: Mono<String> = webClient
.post()
.uri("https://example.com")
.body(
Flux.concat(
FormPartEvent.create("field", "field value"),
FilePartEvent.create("file", resource)
)
)
)
.retrieve()
.bodyToMono()
.retrieve()
.bodyToMono()
----
======

View File

@@ -390,29 +390,29 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
HttpClient httpClient = HttpClient.newBuilder()
.followRedirects(Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
.build();
HttpClient httpClient = HttpClient.newBuilder()
.followRedirects(Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
.build();
ClientHttpConnector connector =
new JdkClientHttpConnector(httpClient, new DefaultDataBufferFactory());
ClientHttpConnector connector =
new JdkClientHttpConnector(httpClient, new DefaultDataBufferFactory());
WebClient webClient = WebClient.builder().clientConnector(connector).build();
WebClient webClient = WebClient.builder().clientConnector(connector).build();
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val httpClient = HttpClient.newBuilder()
.followRedirects(Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
.build()
val httpClient = HttpClient.newBuilder()
.followRedirects(Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
.build()
val connector = JdkClientHttpConnector(httpClient, DefaultDataBufferFactory())
val connector = JdkClientHttpConnector(httpClient, DefaultDataBufferFactory())
val webClient = WebClient.builder().clientConnector(connector).build()
val webClient = WebClient.builder().clientConnector(connector).build()
----
======

View File

@@ -158,65 +158,65 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
public class MultipartExchangeFilterFunction implements ExchangeFilterFunction {
@Override
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
if (MediaType.MULTIPART_FORM_DATA.includes(request.headers().getContentType())
&& (request.method() == HttpMethod.PUT || request.method() == HttpMethod.POST)) {
return next.exchange(ClientRequest.from(request).body((outputMessage, context) ->
request.body().insert(new BufferingDecorator(outputMessage), context)).build()
);
} else {
return next.exchange(request);
}
}
private static final class BufferingDecorator extends ClientHttpRequestDecorator {
private BufferingDecorator(ClientHttpRequest delegate) {
super(delegate);
}
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
return DataBufferUtils.join(body).flatMap(buffer -> {
getHeaders().setContentLength(buffer.readableByteCount());
return super.writeWith(Mono.just(buffer));
});
}
}
}
public class MultipartExchangeFilterFunction implements ExchangeFilterFunction {
@Override
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
if (MediaType.MULTIPART_FORM_DATA.includes(request.headers().getContentType())
&& (request.method() == HttpMethod.PUT || request.method() == HttpMethod.POST)) {
return next.exchange(ClientRequest.from(request).body((outputMessage, context) ->
request.body().insert(new BufferingDecorator(outputMessage), context)).build()
);
} else {
return next.exchange(request);
}
}
private static final class BufferingDecorator extends ClientHttpRequestDecorator {
private BufferingDecorator(ClientHttpRequest delegate) {
super(delegate);
}
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
return DataBufferUtils.join(body).flatMap(buffer -> {
getHeaders().setContentLength(buffer.readableByteCount());
return super.writeWith(Mono.just(buffer));
});
}
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
class MultipartExchangeFilterFunction : ExchangeFilterFunction {
override fun filter(request: ClientRequest, next: ExchangeFunction): Mono<ClientResponse> {
return if (MediaType.MULTIPART_FORM_DATA.includes(request.headers().getContentType())
&& (request.method() == HttpMethod.PUT || request.method() == HttpMethod.POST)) {
next.exchange(ClientRequest.from(request)
.body { message, context -> request.body().insert(BufferingDecorator(message), context) }
.build())
}
else {
next.exchange(request)
}
}
private class BufferingDecorator(delegate: ClientHttpRequest) : ClientHttpRequestDecorator(delegate) {
override fun writeWith(body: Publisher<out DataBuffer>): Mono<Void> {
return DataBufferUtils.join(body)
.flatMap {
headers.contentLength = it.readableByteCount().toLong()
super.writeWith(Mono.just(it))
}
}
}
}
class MultipartExchangeFilterFunction : ExchangeFilterFunction {
override fun filter(request: ClientRequest, next: ExchangeFunction): Mono<ClientResponse> {
return if (MediaType.MULTIPART_FORM_DATA.includes(request.headers().getContentType())
&& (request.method() == HttpMethod.PUT || request.method() == HttpMethod.POST)) {
next.exchange(ClientRequest.from(request)
.body { message, context -> request.body().insert(BufferingDecorator(message), context) }
.build())
}
else {
next.exchange(request)
}
}
private class BufferingDecorator(delegate: ClientHttpRequest) : ClientHttpRequestDecorator(delegate) {
override fun writeWith(body: Publisher<out DataBuffer>): Mono<Void> {
return DataBufferUtils.join(body)
.flatMap {
headers.contentLength = it.readableByteCount().toLong()
super.writeWith(Mono.just(it))
}
}
}
}
----
======
======

View File

@@ -207,14 +207,14 @@ Kotlin::
class ExampleHandler : WebSocketHandler {
override fun handle(session: WebSocketSession): Mono<Void> {
return session.receive() // <1>
return session.receive() // <1>
.doOnNext {
// ... // <2>
}
.concatMap {
// ... // <3>
}
.then() // <4>
.then() // <4>
}
}
----
@@ -268,16 +268,16 @@ Kotlin::
override fun handle(session: WebSocketSession): Mono<Void> {
val output = session.receive() // <1>
val output = session.receive() // <1>
.doOnNext {
// ...
}
.concatMap {
// ...
}
.map { session.textMessage("Echo $it") } // <2>
.map { session.textMessage("Echo $it") } // <2>
return session.send(output) // <3>
return session.send(output) // <3>
}
}
----

View File

@@ -149,7 +149,7 @@ Java::
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
}
}
}
----

View File

@@ -62,7 +62,7 @@ Java::
----
class Account {
private final String firstName;
private final String firstName;
public Account(@BindParam("first-name") String firstName) {
this.firstName = firstName;

View File

@@ -93,8 +93,8 @@ Java::
----
@ModelAttribute
public void addAccount(@RequestParam String number) {
Mono<Account> accountMono = accountRepository.findAccount(number);
model.addAttribute("account", accountMono);
Mono<Account> accountMono = accountRepository.findAccount(number);
model.addAttribute("account", accountMono);
}
@PostMapping("/accounts")

View File

@@ -104,21 +104,21 @@ Kotlin::
override fun requestHeader(requestHeader: RequestHeader, result: ParameterValidationResult) {
// ...
}
}
override fun requestParam(requestParam: RequestParam?, result: ParameterValidationResult) {
// ...
}
}
override fun modelAttribute(modelAttribute: ModelAttribute?, errors: ParameterErrors) {
// ...
}
}
// ...
override fun other(result: ParameterValidationResult) {
// ...
}
}
})
----
======

View File

@@ -782,8 +782,8 @@ Java::
----
WebClient webClient = WebClient.builder()
.codecs(configurer -> {
CustomDecoder decoder = new CustomDecoder();
configurer.customCodecs().registerWithDefaultConfig(decoder);
CustomDecoder decoder = new CustomDecoder();
configurer.customCodecs().registerWithDefaultConfig(decoder);
})
.build();
----
@@ -794,8 +794,8 @@ Kotlin::
----
val webClient = WebClient.builder()
.codecs({ configurer ->
val decoder = CustomDecoder()
configurer.customCodecs().registerWithDefaultConfig(decoder)
val decoder = CustomDecoder()
configurer.customCodecs().registerWithDefaultConfig(decoder)
})
.build()
----

View File

@@ -781,7 +781,7 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
ClassPathResource index = new ClassPathResource("static/index.html");
ClassPathResource index = new ClassPathResource("static/index.html");
List<String> extensions = List.of("js", "css", "ico", "png", "jpg", "gif");
RequestPredicate spaPredicate = path("/api/**").or(path("/error")).negate();
RouterFunction<ServerResponse> redirectToIndex = route()
@@ -793,7 +793,7 @@ Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val redirectToIndex = router {
val redirectToIndex = router {
val index = ClassPathResource("static/index.html")
val spaPredicate = !(path("/api/**") or path("/error"))
resource(spaPredicate, index)
@@ -812,16 +812,16 @@ Java::
+
[source,java,indent=0,subs="verbatim,quotes"]
----
Resource location = new FileUrlResource("public-resources/");
RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
Resource location = new FileUrlResource("public-resources/");
RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes"]
----
val location = FileUrlResource("public-resources/")
val resources = router { resources("/resources/**", location) }
val location = FileUrlResource("public-resources/")
val resources = router { resources("/resources/**", location) }
----
======

View File

@@ -97,7 +97,7 @@ Java::
----
class Account {
private final String firstName;
private final String firstName;
public Account(@BindParam("first-name") String firstName) {
this.firstName = firstName;

View File

@@ -73,12 +73,12 @@ Java::
@Override
public void requestHeader(RequestHeader requestHeader, ParameterValidationResult result) {
// ...
// ...
}
@Override
public void requestParam(@Nullable RequestParam requestParam, ParameterValidationResult result) {
// ...
// ...
}
@Override
@@ -88,7 +88,7 @@ Java::
@Override
public void other(ParameterValidationResult result) {
// ...
// ...
}
});
----
@@ -103,22 +103,22 @@ Kotlin::
ex.visitResults(object : HandlerMethodValidationException.Visitor {
override fun requestHeader(requestHeader: RequestHeader, result: ParameterValidationResult) {
// ...
}
// ...
}
override fun requestParam(requestParam: RequestParam?, result: ParameterValidationResult) {
// ...
}
// ...
}
override fun modelAttribute(modelAttribute: ModelAttribute?, errors: ParameterErrors) {
// ...
}
// ...
}
// ...
override fun other(result: ParameterValidationResult) {
// ...
}
// ...
}
})
----
======

View File

@@ -22,11 +22,11 @@ The following example code is based on it:
[source,javascript,indent=0,subs="verbatim,quotes"]
----
const stompClient = new StompJs.Client({
brokerURL: 'ws://domain.com/portfolio',
onConnect: () => {
// ...
}
});
brokerURL: 'ws://domain.com/portfolio',
onConnect: () => {
// ...
}
});
----
Alternatively, if you connect through SockJS, you can enable the
@@ -47,5 +47,3 @@ interactive web application] -- a getting started guide.
* https://github.com/rstoyanchev/spring-websocket-portfolio[Stock Portfolio] -- a sample
application.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -87,7 +87,7 @@ public class MethodOverrides {
/**
* Return the override for the given method, if any.
* @param method method to check for overrides for
* @param method the method to check for overrides for
* @return the method override, or {@code null} if none
*/
public @Nullable MethodOverride getOverride(Method method) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,7 +35,7 @@ public interface MethodReplacer {
* @param obj the instance we're reimplementing the method for
* @param method the method to reimplement
* @param args arguments to the method
* @return return value for the method
* @return the return value for the method
*/
Object reimplement(Object obj, Method method, Object[] args) throws Throwable;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -404,10 +404,10 @@ public class PropertiesBeanDefinitionReader extends AbstractBeanDefinitionReader
/**
* Get all property values, given a prefix (which will be stripped)
* and add the bean they define to the factory with the given name.
* @param beanName name of the bean to define
* @param beanName the name of the bean to define
* @param map a Map containing string pairs
* @param prefix prefix of each entry, which will be stripped
* @param resourceDescription description of the resource that the
* @param prefix the prefix of each entry, which will be stripped
* @param resourceDescription the description of the resource that the
* Map came from (for logging purposes)
* @throws BeansException if the bean definition could not be parsed or registered
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -81,11 +81,11 @@ public final class ResourceFiles implements Iterable<ResourceFile> {
/**
* Return a new {@link ResourceFiles} instance that merges files from
* another {@link ResourceFiles} instance.
* @param ResourceFiles the instance to merge
* @param resourceFiles the instance to merge
* @return a new {@link ResourceFiles} instance containing merged content
*/
public ResourceFiles and(ResourceFiles ResourceFiles) {
return new ResourceFiles(this.files.and(ResourceFiles.files));
public ResourceFiles and(ResourceFiles resourceFiles) {
return new ResourceFiles(this.files.and(resourceFiles.files));
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -294,7 +294,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
}
@Override
protected Mono<Void> doCommit(TransactionSynchronizationManager TransactionSynchronizationManager,
protected Mono<Void> doCommit(TransactionSynchronizationManager synchronizationManager,
GenericReactiveTransaction status) {
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) status.getTransaction();
@@ -306,7 +306,7 @@ public class R2dbcTransactionManager extends AbstractReactiveTransactionManager
}
@Override
protected Mono<Void> doRollback(TransactionSynchronizationManager TransactionSynchronizationManager,
protected Mono<Void> doRollback(TransactionSynchronizationManager synchronizationManager,
GenericReactiveTransaction status) {
ConnectionFactoryTransactionObject txObject = (ConnectionFactoryTransactionObject) status.getTransaction();

View File

@@ -126,7 +126,7 @@ class MockitoBeanOverrideHandlerTests {
/**
* Since the "field name as fallback qualifier" is not available for an annotated class,
* what would seem to be "equivalent" handlers are actually not considered "equal" when
* the the lookup is "by type".
* the lookup is "by type".
*/
@Test // gh-33925
void isNotEqualToWithSameByTypeLookupMetadataFromFieldAndClassLevel() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -89,7 +89,7 @@ public class ContextLoaderListener extends ContextLoader implements ServletConte
* <li>{@code ServletContext} and {@code ServletConfig} objects will be delegated to
* the application context</li>
* <li>{@link #customizeContext} will be called</li>
* <li>Any {@link org.springframework.context.ApplicationContextInitializer ApplicationContextInitializer org.springframework.context.ApplicationContextInitializer ApplicationContextInitializers}
* <li>Any {@link org.springframework.context.ApplicationContextInitializer ApplicationContextInitializers}
* specified through the "contextInitializerClasses" init-param will be applied.</li>
* <li>{@link org.springframework.context.ConfigurableApplicationContext#refresh refresh()} will be called</li>
* </ul>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -996,8 +996,8 @@ class PathPatternTests {
private void checkNoMatch(String uriTemplate, String path) {
PathPatternParser p = new PathPatternParser();
PathPattern pattern = p.parse(uriTemplate);
PathContainer PathContainer = toPathContainer(path);
assertThat(pattern.matches(PathContainer)).isFalse();
PathContainer pathContainer = toPathContainer(path);
assertThat(pattern.matches(pathContainer)).isFalse();
}
private PathPattern.PathMatchInfo checkCapture(String uriTemplate, String path, String... keyValues) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -153,7 +153,7 @@ public abstract class RouterFunctions {
* Resource resource = new ClassPathResource("static/index.html")
* RouterFunction&lt;ServerResponse&gt; resources = RouterFunctions.resource(path("/api/**").negate(), resource);
* </pre>
* @param predicate predicate to match
* @param predicate the predicate to match
* @param resource the resources to serve
* @return a router function that routes to a resource
* @since 6.1.4
@@ -169,7 +169,7 @@ public abstract class RouterFunctions {
* Resource resource = new ClassPathResource("static/index.html")
* RouterFunction&lt;ServerResponse&gt; resources = RouterFunctions.resource(path("/api/**").negate(), resource);
* </pre>
* @param predicate predicate to match
* @param predicate the predicate to match
* @param resource the resources to serve
* @param headersConsumer provides access to the HTTP headers for served resources
* @return a router function that routes to a resource
@@ -384,7 +384,7 @@ public abstract class RouterFunctions {
/**
* Adds a route to the given handler function that handles all HTTP {@code GET} requests
* that match the given predicate.
* @param predicate predicate to match
* @param predicate the predicate to match
* @param handlerFunction the handler function to handle all {@code GET} requests that
* match {@code predicate}
* @return this builder
@@ -436,7 +436,7 @@ public abstract class RouterFunctions {
/**
* Adds a route to the given handler function that handles all HTTP {@code HEAD} requests
* that match the given predicate.
* @param predicate predicate to match
* @param predicate the predicate to match
* @param handlerFunction the handler function to handle all {@code HEAD} requests that
* match {@code predicate}
* @return this builder
@@ -479,7 +479,7 @@ public abstract class RouterFunctions {
/**
* Adds a route to the given handler function that handles all HTTP {@code POST} requests
* that match the given predicate.
* @param predicate predicate to match
* @param predicate the predicate to match
* @param handlerFunction the handler function to handle all {@code POST} requests that
* match {@code predicate}
* @return this builder
@@ -530,7 +530,7 @@ public abstract class RouterFunctions {
/**
* Adds a route to the given handler function that handles all HTTP {@code PUT} requests
* that match the given predicate.
* @param predicate predicate to match
* @param predicate the predicate to match
* @param handlerFunction the handler function to handle all {@code PUT} requests that
* match {@code predicate}
* @return this builder
@@ -581,7 +581,7 @@ public abstract class RouterFunctions {
/**
* Adds a route to the given handler function that handles all HTTP {@code PATCH} requests
* that match the given predicate.
* @param predicate predicate to match
* @param predicate the predicate to match
* @param handlerFunction the handler function to handle all {@code PATCH} requests that
* match {@code predicate}
* @return this builder
@@ -632,7 +632,7 @@ public abstract class RouterFunctions {
/**
* Adds a route to the given handler function that handles all HTTP {@code DELETE} requests
* that match the given predicate.
* @param predicate predicate to match
* @param predicate the predicate to match
* @param handlerFunction the handler function to handle all {@code DELETE} requests that
* match {@code predicate}
* @return this builder
@@ -675,7 +675,7 @@ public abstract class RouterFunctions {
/**
* Adds a route to the given handler function that handles all HTTP {@code OPTIONS} requests
* that match the given predicate.
* @param predicate predicate to match
* @param predicate the predicate to match
* @param handlerFunction the handler function to handle all {@code OPTIONS} requests that
* match {@code predicate}
* @return this builder
@@ -735,7 +735,7 @@ public abstract class RouterFunctions {
* Resource resource = new ClassPathResource("static/index.html")
* RouterFunction&lt;ServerResponse&gt; resources = RouterFunctions.resource(path("/api/**").negate(), resource);
* </pre>
* @param predicate predicate to match
* @param predicate the predicate to match
* @param resource the resources to serve
* @return a router function that routes to a resource
* @since 6.1.4
@@ -749,7 +749,7 @@ public abstract class RouterFunctions {
* Resource resource = new ClassPathResource("static/index.html")
* RouterFunction&lt;ServerResponse&gt; resources = RouterFunctions.resource(path("/api/**").negate(), resource);
* </pre>
* @param predicate predicate to match
* @param predicate the predicate to match
* @param resource the resources to serve
* @param headersConsumer provides access to the HTTP headers for served resources
* @return a router function that routes to a resource

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -136,7 +136,7 @@ public abstract class RouterFunctions {
* Resource resource = new ClassPathResource("static/index.html")
* RouterFunction&lt;ServerResponse&gt; resources = RouterFunctions.resource(path("/api/**").negate(), resource);
* </pre>
* @param predicate predicate to match
* @param predicate the predicate to match
* @param resource the resources to serve
* @return a router function that routes to a resource
* @since 6.1.4
@@ -152,7 +152,7 @@ public abstract class RouterFunctions {
* Resource resource = new ClassPathResource("static/index.html")
* RouterFunction&lt;ServerResponse&gt; resources = RouterFunctions.resource(path("/api/**").negate(), resource);
* </pre>
* @param predicate predicate to match
* @param predicate the predicate to match
* @param resource the resources to serve
* @param headersConsumer provides access to the HTTP headers for served resources
* @return a router function that routes to a resource
@@ -298,7 +298,7 @@ public abstract class RouterFunctions {
/**
* Adds a route to the given handler function that handles all HTTP {@code GET} requests
* that match the given predicate.
* @param predicate predicate to match
* @param predicate the predicate to match
* @param handlerFunction the handler function to handle all {@code GET} requests that
* match {@code predicate}
* @return this builder
@@ -350,7 +350,7 @@ public abstract class RouterFunctions {
/**
* Adds a route to the given handler function that handles all HTTP {@code HEAD} requests
* that match the given predicate.
* @param predicate predicate to match
* @param predicate the predicate to match
* @param handlerFunction the handler function to handle all {@code HEAD} requests that
* match {@code predicate}
* @return this builder
@@ -393,7 +393,7 @@ public abstract class RouterFunctions {
/**
* Adds a route to the given handler function that handles all HTTP {@code POST} requests
* that match the given predicate.
* @param predicate predicate to match
* @param predicate the predicate to match
* @param handlerFunction the handler function to handle all {@code POST} requests that
* match {@code predicate}
* @return this builder
@@ -444,7 +444,7 @@ public abstract class RouterFunctions {
/**
* Adds a route to the given handler function that handles all HTTP {@code PUT} requests
* that match the given predicate.
* @param predicate predicate to match
* @param predicate the predicate to match
* @param handlerFunction the handler function to handle all {@code PUT} requests that
* match {@code predicate}
* @return this builder
@@ -495,7 +495,7 @@ public abstract class RouterFunctions {
/**
* Adds a route to the given handler function that handles all HTTP {@code PATCH} requests
* that match the given predicate.
* @param predicate predicate to match
* @param predicate the predicate to match
* @param handlerFunction the handler function to handle all {@code PATCH} requests that
* match {@code predicate}
* @return this builder
@@ -546,7 +546,7 @@ public abstract class RouterFunctions {
/**
* Adds a route to the given handler function that handles all HTTP {@code DELETE} requests
* that match the given predicate.
* @param predicate predicate to match
* @param predicate the predicate to match
* @param handlerFunction the handler function to handle all {@code DELETE} requests that
* match {@code predicate}
* @return this builder
@@ -589,7 +589,7 @@ public abstract class RouterFunctions {
/**
* Adds a route to the given handler function that handles all HTTP {@code OPTIONS} requests
* that match the given predicate.
* @param predicate predicate to match
* @param predicate the predicate to match
* @param handlerFunction the handler function to handle all {@code OPTIONS} requests that
* match {@code predicate}
* @return this builder
@@ -648,7 +648,7 @@ public abstract class RouterFunctions {
* Resource resource = new ClassPathResource("static/index.html")
* RouterFunction&lt;ServerResponse&gt; resources = RouterFunctions.resource(path("/api/**").negate(), resource);
* </pre>
* @param predicate predicate to match
* @param predicate the predicate to match
* @param resource the resources to serve
* @return a router function that routes to a resource
* @since 6.1.4
@@ -662,7 +662,7 @@ public abstract class RouterFunctions {
* Resource resource = new ClassPathResource("static/index.html")
* RouterFunction&lt;ServerResponse&gt; resources = RouterFunctions.resource(path("/api/**").negate(), resource);
* </pre>
* @param predicate predicate to match
* @param predicate the predicate to match
* @param resource the resources to serve
* @param headersConsumer provides access to the HTTP headers for served resources
* @return a router function that routes to a resource

View File

@@ -281,7 +281,7 @@ public interface ServerResponse {
* .send("Hello World!"));
* }
* </pre>
* @param consumer consumer that will be provided with an event builder
* @param consumer the consumer that will be provided with an event builder
* @return the server-side event response
* @since 5.3.2
* @see <a href="https://html.spec.whatwg.org/multipage/server-sent-events.html">Server-Sent Events</a>
@@ -310,8 +310,8 @@ public interface ServerResponse {
* .send("Hello World!"));
* }
* </pre>
* @param consumer consumer that will be provided with an event builder
* @param timeout maximum time period to wait before timing out
* @param consumer the consumer that will be provided with an event builder
* @param timeout maximum time period to wait before timing out
* @return the server-side event response
* @since 5.3.2
* @see <a href="https://html.spec.whatwg.org/multipage/server-sent-events.html">Server-Sent Events</a>
@@ -329,7 +329,7 @@ public interface ServerResponse {
/**
* Add the given header value(s) under the given name.
* @param headerName the header name
* @param headerName the header name
* @param headerValues the header value(s)
* @return this builder
* @see HttpHeaders#add(String, String)

View File

@@ -135,7 +135,7 @@ public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodRetur
* @param executor for blocking I/O writes of items emitted from reactive types
* @param manager for detecting streaming media types
* @param viewResolvers resolvers for fragment stream rendering
* @param localeResolver localeResolver for fragment stream rendering
* @param localeResolver the {@link LocaleResolver} for fragment stream rendering
* @since 6.2
*/
public ResponseBodyEmitterReturnValueHandler(