Skip to content

Commit 2a0a002

Browse files
committed
Improve Kotlin documentation
Closes gh-22400
1 parent 514f7e3 commit 2a0a002

File tree

1 file changed

+77
-78
lines changed

1 file changed

+77
-78
lines changed

src/docs/asciidoc/languages/kotlin.adoc

Lines changed: 77 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -186,15 +186,28 @@ In Java, you can, for example, write the following:
186186
----
187187
====
188188

189-
In Kotlin, with reified type parameters and `GenericApplicationContext`
190-
Kotlin extensions, you can instead write the following:
189+
In Kotlin, with reified type parameters and `GenericApplicationContext` Kotlin extensions,
190+
you can instead write the following:
191191

192192
====
193193
[source,kotlin,indent=0]
194194
----
195195
val context = GenericApplicationContext().apply {
196196
registerBean<Foo>()
197-
registerBean { Bar(it.getBean<Foo>()) }
197+
registerBean { Bar(it.getBean()) }
198+
}
199+
----
200+
====
201+
202+
If the class `Bar` has a single constructor, you can even just specify the bean class,
203+
the constructor parameters will be autowired by type:
204+
205+
====
206+
[source,kotlin,indent=0]
207+
----
208+
val context = GenericApplicationContext().apply {
209+
registerBean<Foo>()
210+
registerBean<Bar>()
198211
}
199212
----
200213
====
@@ -208,39 +221,23 @@ how beans are registered. The following example creates a `Play` profile:
208221
====
209222
[source,kotlin,indent=0]
210223
----
211-
fun beans() = beans {
212-
bean<UserHandler>()
213-
bean<Routes>()
214-
bean<WebHandler>("webHandler") {
215-
RouterFunctions.toWebHandler(
216-
ref<Routes>().router(),
217-
HandlerStrategies.builder().viewResolver(ref()).build()
218-
)
219-
}
220-
bean("messageSource") {
221-
ReloadableResourceBundleMessageSource().apply {
222-
setBasename("messages")
223-
setDefaultEncoding("UTF-8")
224+
val myBeans = beans {
225+
bean<Foo>()
226+
bean<Bar>()
227+
bean("bazBean") {
228+
Baz().apply {
229+
message = "Hello world"
224230
}
225231
}
226-
bean {
227-
val prefix = "classpath:/templates/"
228-
val suffix = ".mustache"
229-
val loader = MustacheResourceTemplateLoader(prefix, suffix)
230-
MustacheViewResolver(Mustache.compiler().withLoader(loader)).apply {
231-
setPrefix(prefix)
232-
setSuffix(suffix)
233-
}
234-
}
235-
profile("play") {
236-
bean<Play>()
232+
profile("foobar") {
233+
bean { FooBar(ref("bazBean")) }
237234
}
238235
}
239236
----
240237
====
241238

242-
In the preceding example, `bean<Routes>()` uses autowiring by constructor, and `ref<Routes>()`
243-
is a shortcut for `applicationContext.getBean(Routes::class.java)`.
239+
NOTE: This DSL is programmatic, meaning it allows custom registration logic of beans
240+
through an `if` expression, a `for` loop, or any other Kotlin constructs.
244241

245242
You can then use this `beans()` function to register beans on the application context,
246243
as the following example shows:
@@ -249,19 +246,16 @@ as the following example shows:
249246
[source,kotlin,indent=0]
250247
----
251248
val context = GenericApplicationContext().apply {
252-
beans().initialize(this)
249+
myBeans.initialize(this)
253250
refresh()
254251
}
255252
----
256253
====
257254

258-
NOTE: This DSL is programmatic, meaning it allows custom registration logic of beans
259-
through an `if` expression, a `for` loop, or any other Kotlin constructs.
260255

261-
See https://github.com/sdeleuze/spring-kotlin-functional/blob/master/src/main/kotlin/functional/Beans.kt[spring-kotlin-functional beans declaration]
262-
for a concrete example.
256+
See https://github.com/sdeleuze/spring-kotlin-functional[spring-kotlin-functional beans declaration] for a concrete example.
263257

264-
NOTE: Spring Boot is based on Java configuration and
258+
NOTE: Spring Boot is based on JavaConfig and
265259
https://github.com/spring-projects/spring-boot/issues/8115[does not yet provide specific support for functional bean definition],
266260
but you can experimentally use functional bean definitions through Spring Boot's `ApplicationContextInitializer` support.
267261
See https://stackoverflow.com/questions/45935931/how-to-use-functional-bean-definition-kotlin-dsl-with-spring-boot-and-spring-w/46033685#46033685[this Stack Overflow answer]
@@ -278,8 +272,8 @@ for more details and up-to-date information.
278272

279273
Spring Framework now comes with a
280274
{doc-root}/spring-framework/docs/{spring-version}/kdoc-api/spring-framework/org.springframework.web.reactive.function.server/-router-function-dsl/[Kotlin routing DSL]
281-
that lets you use the <<web-reactive#webflux-fn,WebFlux functional
282-
API>> to write clean and idiomatic Kotlin code, as the following example shows:
275+
that lets you use the <<web-reactive#webflux-fn,WebFlux functional API>> to write clean and idiomatic Kotlin code,
276+
as the following example shows:
283277

284278
====
285279
[source,kotlin,indent=0]
@@ -307,7 +301,7 @@ NOTE: This DSL is programmatic, meaning that it allows custom registration logic
307301
through an `if` expression, a `for` loop, or any other Kotlin constructs. That can be useful when you need to register routes
308302
depending on dynamic data (for example, from a database).
309303

310-
See https://github.com/mixitconf/mixit/tree/bad6b92bce6193f9b3f696af9d416c276501dbf1/src/main/kotlin/mixit/web/routes[MiXiT project routes]
304+
See https://github.com/mixitconf/mixit/tree/dafd5ccc92dfab6d9c306fcb60b28921a1ccbf79/src/main/kotlin/mixit/web/routes[MiXiT project routes]
311305
for a concrete example.
312306

313307

@@ -583,8 +577,42 @@ all HTTP methods will be matched, not only the `GET` one.
583577

584578
=== Testing
585579

586-
This section address testing with the combination of Kotlin and the Spring Framework.
580+
This section addresses testing with the combination of Kotlin and Spring Framework. The recommended testing framework
581+
is https://junit.org/junit5/[JUnit 5], as well as https://mockk.io/[Mockk] for mocking.
582+
583+
584+
==== Constructor injection
585+
586+
As described in the <<testing#testcontext-junit-jupiter-di#spring-web-reactive,dedicated section>>, JUnit 5 allows
587+
constructor injection of beans which is pretty useful with Kotlin in order to use `val` instead of `lateinit var `.
588+
589+
590+
====
591+
[source]
592+
----
593+
@SpringJUnitConfig(TestConfig::class)
594+
class OrderServiceIntegrationTests(@Autowired val orderService: OrderService,
595+
@Autowired val customerService: CustomerService) {
596+
597+
// tests that use the injected OrderService and CustomerService
598+
}
599+
----
600+
====
601+
602+
You can also use `@Autowired` at constructor level to autowire all parameters.
603+
604+
====
605+
[source]
606+
----
607+
@SpringJUnitConfig(TestConfig::class)
608+
class OrderServiceIntegrationTests @Autowired constructor(
609+
val orderService: OrderService,
610+
val customerService: CustomerService) {
587611
612+
// tests that use the injected OrderService and CustomerService
613+
}
614+
----
615+
====
588616

589617

590618
==== `PER_CLASS` Lifecycle
@@ -681,32 +709,27 @@ See also the related https://jira.spring.io/browse/SPR-16057[SPR-16057] issue.
681709
[[kotlin-getting-started]]
682710
== Getting Started
683711

684-
This section describes the fastest way to get started with a project that combines
685-
Kotlin and the Spring Framework.
686-
712+
The easiest way to learn how to build a Spring application with Kotlin is to follow
713+
https://spring.io/guides/tutorials/spring-boot-kotlin/[the dedicated tutorial].
687714

688715

689-
=== Using `start.spring.io`
716+
=== `start.spring.io`
690717

691718
The easiest way to start a new Spring Framework 5 project in Kotlin is to create a new Spring
692719
Boot 2 project on https://start.spring.io/#!language=kotlin[start.spring.io].
693720

694-
You can also create a standalone WebFlux project, as described in
695-
https://spring.io/blog/2017/08/01/spring-framework-5-kotlin-apis-the-functional-way[this blog post].
696-
697-
698721

699722
=== Choosing the Web Flavor
700723

701724
Spring Framework now comes with two different web stacks: <<web#mvc,Spring MVC>> and
702725
<<web-reactive#spring-web-reactive,Spring WebFlux>>.
703726

704727
Spring WebFlux is recommended if you want to create applications that will deal with latency,
705-
long-lived connections, o streaming scenarios or if you want to use the web functional
728+
long-lived connections, streaming scenarios or if you want to use the web functional
706729
Kotlin DSL.
707730

708731
For other use cases, especially if you are using blocking technologies such as JPA, Spring
709-
MVC and its annotation-based programming model is a perfectly valid and fully supported choice.
732+
MVC and its annotation-based programming model is the recommended choice.
710733

711734

712735

@@ -724,27 +747,6 @@ Kotlin and the Spring Framework:
724747
* https://kotlin.link/[Awesome Kotlin]
725748

726749

727-
728-
=== Tutorials
729-
730-
We recommend the following tutorials:
731-
732-
* https://spring.io/guides/tutorials/spring-boot-kotlin/[Building web applications with Spring Boot and Kotlin]
733-
* https://kotlinlang.org/docs/tutorials/spring-boot-restful.html[Creating a RESTful Web Service with Spring Boot]
734-
735-
736-
737-
=== Blog posts
738-
739-
The following blog posts provide further details:
740-
741-
* https://spring.io/blog/2016/02/15/developing-spring-boot-applications-with-kotlin[Developing Spring Boot applications with Kotlin]
742-
* https://spring.io/blog/2016/03/20/a-geospatial-messenger-with-kotlin-spring-boot-and-postgresql[A Geospatial Messenger with Kotlin, Spring Boot and PostgreSQL]
743-
* https://spring.io/blog/2017/01/04/introducing-kotlin-support-in-spring-framework-5-0[Introducing Kotlin support in Spring Framework 5.0]
744-
* https://spring.io/blog/2017/08/01/spring-framework-5-kotlin-apis-the-functional-way[Spring Framework 5 Kotlin APIs, the functional way]
745-
746-
747-
748750
=== Examples
749751

750752
The following Github projects offer examples that you can learn from and possibly even extend:
@@ -764,22 +766,19 @@ The following Github projects offer examples that you can learn from and possibl
764766
The following list categorizes the pending issues related to Spring and Kotlin support:
765767

766768
* Spring Framework
767-
** https://jira.spring.io/browse/SPR-16057[Unable to use WebTestClient with mock server in Kotlin]
768-
** https://jira.spring.io/browse/SPR-15942[Support null-safety at generics, varargs and array elements level]
769-
** https://jira.spring.io/browse/SPR-15413[Add support for Kotlin coroutines]
769+
** https://github.com/spring-projects/spring-framework/issues/20606[Unable to use WebTestClient with mock server in Kotlin]
770+
** https://github.com/spring-projects/spring-framework/issues/20496[Support null-safety at generics, varargs and array elements level]
771+
** https://github.com/spring-projects/spring-framework/issues/19975[Add support for Kotlin coroutines]
770772
* Spring Boot
771773
** https://github.com/spring-projects/spring-boot/issues/8762[Allow `@ConfigurationProperties` binding for immutable POJOs]
772-
** https://github.com/spring-projects/spring-boot/issues/1254[Allow `@ConfigurationProperties` binding on interfaces]
773774
** https://github.com/spring-projects/spring-boot/issues/8115[Expose the functional bean registration API via `SpringApplication`]
774775
** https://github.com/spring-projects/spring-boot/issues/10712[Add null-safety annotations on Spring Boot APIs]
775776
** https://github.com/spring-projects/spring-boot/issues/9486[Use Kotlin's bom to provide dependency management for Kotlin]
776777
* Kotlin
777778
** https://youtrack.jetbrains.com/issue/KT-6380[Parent issue for Spring Framework support]
778779
** https://youtrack.jetbrains.com/issue/KT-5464[Kotlin requires type inference where Java doesn't]
779-
** https://github.com/Kotlin/KEEP/issues/79[Better generics null-safety support]
780780
** https://youtrack.jetbrains.com/issue/KT-20283[Smart cast regression with open classes]
781781
** https://youtrack.jetbrains.com/issue/KT-14984[Impossible to pass not all SAM argument as function]
782-
** https://youtrack.jetbrains.com/issue/KT-19592[Apply JSR 305 meta-annotations to generic type parameters]
783-
** https://youtrack.jetbrains.com/issue/KT-18398[Provide a way for libraries to avoid mixing Kotlin 1.0 and 1.1 dependencies]
784782
** https://youtrack.jetbrains.com/issue/KT-15125[Support JSR 223 bindings directly via script variables]
785-
** https://youtrack.jetbrains.com/issue/KT-15467[Support all-open and no-arg compiler plugins in Kotlin Eclipse plugin]
783+
** https://youtrack.jetbrains.com/issue/KT-6653[Kotlin properties do not override Java-style getters and setters]
784+

0 commit comments

Comments
 (0)