Improve Kotlin documentation
This commit is contained in:
parent
80ad60e91b
commit
cd0b517abf
|
@ -77,6 +77,9 @@ dokka {
|
||||||
externalDocumentationLink {
|
externalDocumentationLink {
|
||||||
url = new URL("https://www.reactive-streams.org/reactive-streams-1.0.1-javadoc/")
|
url = new URL("https://www.reactive-streams.org/reactive-streams-1.0.1-javadoc/")
|
||||||
}
|
}
|
||||||
|
externalDocumentationLink {
|
||||||
|
url = new URL("https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
|
|
|
@ -27,16 +27,38 @@ import org.springframework.web.reactive.function.server.RouterFunctions.nest
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Coroutines variant of [router].
|
* Allow to create easily a WebFlux.fn [RouterFunction] with a [Coroutines router Kotlin DSL][CoRouterFunctionDsl].
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* @Configuration
|
||||||
|
* class RouterConfiguration {
|
||||||
|
*
|
||||||
|
* @Bean
|
||||||
|
* fun mainRouter(userHandler: UserHandler) = coRouter {
|
||||||
|
* accept(TEXT_HTML).nest {
|
||||||
|
* (GET("/user/") or GET("/users/")).invoke(userHandler::findAllView)
|
||||||
|
* GET("/users/{login}", userHandler::findViewById)
|
||||||
|
* }
|
||||||
|
* accept(APPLICATION_JSON).nest {
|
||||||
|
* (GET("/api/user/") or GET("/api/users/")).invoke(userHandler::findAll)
|
||||||
|
* POST("/api/users/", userHandler::create)
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
*
|
*
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
|
* @see router
|
||||||
* @since 5.2
|
* @since 5.2
|
||||||
*/
|
*/
|
||||||
fun coRouter(routes: (CoRouterFunctionDsl.() -> Unit)) =
|
fun coRouter(routes: (CoRouterFunctionDsl.() -> Unit)) =
|
||||||
CoRouterFunctionDsl(routes).build()
|
CoRouterFunctionDsl(routes).build()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Coroutines variant of [RouterFunctionDsl].
|
* Provide a WebFlux.fn [RouterFunction] Coroutines Kotlin DSL created by [`coRouter { }`][coRouter] in order to be able to write idiomatic Kotlin code.
|
||||||
*
|
*
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @since 5.2
|
* @since 5.2
|
||||||
|
|
|
@ -26,18 +26,16 @@ import java.net.URI
|
||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow to create easily a WebFlux.fn `RouterFunction<ServerResponse>` from a Kotlin
|
* Allow to create easily a WebFlux.fn [RouterFunction] with a [Reactive router Kotlin DSL][RouterFunctionDsl].
|
||||||
* router DSL leveraging WebFlux.fn Java API ([RouterFunction], [RequestPredicate],
|
|
||||||
* [HandlerFunction]).
|
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* @Configuration
|
* @Configuration
|
||||||
* class ApplicationRoutes(val userHandler: UserHandler) {
|
* class RouterConfiguration {
|
||||||
*
|
*
|
||||||
* @Bean
|
* @Bean
|
||||||
* fun mainRouter() = router {
|
* fun mainRouter(userHandler: UserHandler) = router {
|
||||||
* accept(TEXT_HTML).nest {
|
* accept(TEXT_HTML).nest {
|
||||||
* (GET("/user/") or GET("/users/")).invoke(userHandler::findAllView)
|
* (GET("/user/") or GET("/users/")).invoke(userHandler::findAllView)
|
||||||
* GET("/users/{login}", userHandler::findViewById)
|
* GET("/users/{login}", userHandler::findViewById)
|
||||||
|
@ -51,14 +49,13 @@ import java.util.function.Supplier
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @see RouterFunctionDsl
|
* @see coRouter
|
||||||
* @see RouterFunctions.Builder
|
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
*/
|
*/
|
||||||
fun router(routes: RouterFunctionDsl.() -> Unit) = RouterFunctionDsl(routes).build()
|
fun router(routes: RouterFunctionDsl.() -> Unit) = RouterFunctionDsl(routes).build()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide a [RouterFunction] Kotlin DSL in order to be able to write idiomatic Kotlin code.
|
* Provide a WebFlux.fn [RouterFunction] Reactive Kotlin DSL created by [`router { }`][router] in order to be able to write idiomatic Kotlin code.
|
||||||
*
|
*
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @author Yevhenii Melnyk
|
* @author Yevhenii Melnyk
|
||||||
|
|
|
@ -25,18 +25,16 @@ import java.util.*
|
||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow to create easily a WebMvc.fn `RouterFunction<ServerResponse>` from a Kotlin router
|
* Allow to create easily a WebMvc.fn [RouterFunction] with a [Reactive router Kotlin DSL][RouterFunctionDsl].
|
||||||
* DSL leveraging WebMvc.fn the Java API ([RouterFunction], [RequestPredicate],
|
|
||||||
* [HandlerFunction]).
|
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* @Configuration
|
* @Configuration
|
||||||
* class ApplicationRoutes(val userHandler: UserHandler) {
|
* class RouterConfiguration {
|
||||||
*
|
*
|
||||||
* @Bean
|
* @Bean
|
||||||
* fun mainRouter() = router {
|
* fun mainRouter(userHandler: UserHandler) = router {
|
||||||
* accept(TEXT_HTML).nest {
|
* accept(TEXT_HTML).nest {
|
||||||
* (GET("/user/") or GET("/users/")).invoke(userHandler::findAllView)
|
* (GET("/user/") or GET("/users/")).invoke(userHandler::findAllView)
|
||||||
* GET("/users/{login}", userHandler::findViewById)
|
* GET("/users/{login}", userHandler::findViewById)
|
||||||
|
@ -50,14 +48,12 @@ import java.util.function.Supplier
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @see RouterFunctionDsl
|
|
||||||
* @see RouterFunctions.Builder
|
|
||||||
* @since 5.2
|
* @since 5.2
|
||||||
*/
|
*/
|
||||||
fun router(routes: (RouterFunctionDsl.() -> Unit)) = RouterFunctionDsl(routes).build()
|
fun router(routes: (RouterFunctionDsl.() -> Unit)) = RouterFunctionDsl(routes).build()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide a WebMvc.fn [RouterFunction] Kotlin DSL in order to be able to write idiomatic Kotlin code.
|
* Provide a WebMvc.fn [RouterFunction] Reactive Kotlin DSL created by [`router { }`][router] in order to be able to write idiomatic Kotlin code.
|
||||||
*
|
*
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @since 5.2
|
* @since 5.2
|
||||||
|
|
|
@ -229,10 +229,11 @@ which lets you deal with profiles and `Environment` for customizing
|
||||||
how beans are registered.
|
how beans are registered.
|
||||||
|
|
||||||
In the following example notice that:
|
In the following example notice that:
|
||||||
- Type inference usually allows to avoid specifying the type for bean references like `ref("bazBean")`
|
|
||||||
- It is possible to use Kotlin top level functions to declare beans using callable references like `bean(::myRouter)` in this example
|
* Type inference usually allows to avoid specifying the type for bean references like `ref("bazBean")`
|
||||||
- When specifying `bean<Bar>()` or `bean(::myRouter)`, parameters are autowired by type
|
* It is possible to use Kotlin top level functions to declare beans using callable references like `bean(::myRouter)` in this example
|
||||||
- The `FooBar` bean will be registered only if the `foobar` profile is active
|
* When specifying `bean<Bar>()` or `bean(::myRouter)`, parameters are autowired by type
|
||||||
|
* The `FooBar` bean will be registered only if the `foobar` profile is active
|
||||||
|
|
||||||
[source,kotlin,indent=0]
|
[source,kotlin,indent=0]
|
||||||
----
|
----
|
||||||
|
@ -290,20 +291,23 @@ for more details and up-to-date information.
|
||||||
== Web
|
== Web
|
||||||
|
|
||||||
|
|
||||||
|
=== Router DSL
|
||||||
|
|
||||||
=== WebFlux Router DSL
|
Spring Framework comes with a Kotlin router DSL available in 3 flavors:
|
||||||
|
|
||||||
Spring Framework comes with a Kotlin router DSL available in two flavors:
|
* WebMvc.fn {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.servlet.function/router.html[router { }]
|
||||||
|
* WebFlux.fn <<web-reactive#webflux-fn, Reactive>> {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/router.html[router { }]
|
||||||
|
* WebFlux.fn <<Coroutines>> {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/co-router.html[coRouter { }]
|
||||||
|
|
||||||
- Reactive with {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/-router-function-dsl/[router { }]
|
These DSL let you write clean and idiomatic Kotlin code to build a `RouterFunction` instance as the following example shows:
|
||||||
- <<Coroutines>>
|
|
||||||
|
|
||||||
These DSL let you use the <<web-reactive#webflux-fn, WebFlux functional API>> to write clean
|
|
||||||
and idiomatic Kotlin code to build a `RouterFunction` instance as the following example shows:
|
|
||||||
|
|
||||||
[source,kotlin,indent=0]
|
[source,kotlin,indent=0]
|
||||||
----
|
----
|
||||||
val myRouter: RouterFunction<ServerResponse> = router {
|
@Configuration
|
||||||
|
class RouterRouterConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun mainRouter(userHandler: UserHandler) = router {
|
||||||
accept(TEXT_HTML).nest {
|
accept(TEXT_HTML).nest {
|
||||||
GET("/") { ok().render("index") }
|
GET("/") { ok().render("index") }
|
||||||
GET("/sse") { ok().render("sse") }
|
GET("/sse") { ok().render("sse") }
|
||||||
|
@ -319,46 +323,56 @@ and idiomatic Kotlin code to build a `RouterFunction` instance as the following
|
||||||
}
|
}
|
||||||
resources("/**", ClassPathResource("static/"))
|
resources("/**", ClassPathResource("static/"))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
NOTE: This DSL is programmatic, meaning that it allows custom registration logic of beans
|
NOTE: This DSL is programmatic, meaning that it allows custom registration logic of beans
|
||||||
through an `if` expression, a `for` loop, or any other Kotlin constructs. That can be useful
|
through an `if` expression, a `for` loop, or any other Kotlin constructs. That can be useful
|
||||||
when you need to register routes depending on dynamic data (for example, from a database).
|
when you need to register routes depending on dynamic data (for example, from a database).
|
||||||
|
|
||||||
See https://github.com/mixitconf/mixit/tree/dafd5ccc92dfab6d9c306fcb60b28921a1ccbf79/src/main/kotlin/mixit/web/routes[MiXiT project routes]
|
See https://github.com/mixitconf/mixit/[MiXiT project] for a concrete example.
|
||||||
for a concrete example.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
=== Coroutines
|
=== Coroutines
|
||||||
|
|
||||||
As of Spring Framework 5.2, https://kotlinlang.org/docs/reference/coroutines-overview.html[Coroutines] support
|
As of Spring Framework 5.2, https://kotlinlang.org/docs/reference/coroutines-overview.html[Coroutines] support
|
||||||
is provided via extensions for WebFlux client and server functional API. A dedicated
|
is provided via:
|
||||||
{doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/-co-router-function-dsl/[`coRouter { }`]
|
|
||||||
router DSL is also available.
|
* https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/index.html[Deferred] and https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/index.html[Flow] return value support in Spring WebFlux annotated `@Controller`
|
||||||
|
* Suspending function support in Spring WebFlux annotated `@Controller`
|
||||||
|
* Extensions for WebFlux {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.client/index.html[client] and {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/index.html[server] functional API.
|
||||||
|
* WebFlux.fn {doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/co-router.html[coRouter { }]
|
||||||
|
|
||||||
Coroutines extensions use `await` prefix or `AndAwait` suffix, and most are using similar
|
Coroutines extensions use `await` prefix or `AndAwait` suffix, and most are using similar
|
||||||
names to their reactive counterparts, except `exchange` in `WebClient.RequestHeadersSpec`
|
names to their reactive counterparts.
|
||||||
which translates to `awaitResponse`.
|
|
||||||
|
|
||||||
[source,kotlin,indent=0]
|
[source,kotlin,indent=0]
|
||||||
----
|
----
|
||||||
fun routes(userHandler: UserHandler): RouterFunction<ServerResponse> = coRouter {
|
@Configuration
|
||||||
GET("/", userHandler::listView)
|
class RouterConfiguration {
|
||||||
GET("/api/user", userHandler::listApi)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun mainRouter(userHandler: UserHandler) = coRouter {
|
||||||
|
GET("/", userHandler::listView)
|
||||||
|
GET("/api/user", userHandler::listApi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
[source,kotlin,indent=0]
|
||||||
|
----
|
||||||
class UserHandler(builder: WebClient.Builder) {
|
class UserHandler(builder: WebClient.Builder) {
|
||||||
|
|
||||||
private val client = builder.baseUrl("...").build()
|
private val client = builder.baseUrl("...").build()
|
||||||
|
|
||||||
suspend fun listView(request: ServerRequest): ServerResponse =
|
suspend fun listView(request: ServerRequest): ServerResponse =
|
||||||
ServerResponse.ok().renderAndAwait("users", mapOf("users" to
|
ServerResponse.ok().renderAndAwait("users", mapOf("users" to
|
||||||
client.get().uri("...").awaitResponse().awaitBody<User>()))
|
client.get().uri("...").awaitExchange().awaitBody<User>()))
|
||||||
|
|
||||||
suspend fun listApi(request: ServerRequest): ServerResponse =
|
suspend fun listApi(request: ServerRequest): ServerResponse =
|
||||||
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8).bodyAndAwait(
|
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8).bodyAndAwait(
|
||||||
client.get().uri("...").awaitResponse().awaitBody<User>())
|
client.get().uri("...").awaitExchange().awaitBody<User>())
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue