Skip to content

Commit b7e99fb

Browse files
committed
Additional documentation notes on Java/Kotlin parameter name retention
See gh-29563
1 parent a27f2e9 commit b7e99fb

File tree

4 files changed

+95
-8
lines changed

4 files changed

+95
-8
lines changed

framework-docs/src/docs/asciidoc/languages/kotlin.adoc

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ Feel free to join the #spring channel of https://slack.kotlinlang.org/[Kotlin Sl
2020
or ask a question with `spring` and `kotlin` as tags on
2121
https://stackoverflow.com/questions/tagged/spring+kotlin[Stackoverflow] if you need support.
2222

23+
24+
25+
2326
[[kotlin-requirements]]
2427
== Requirements
2528

@@ -37,6 +40,9 @@ for serializing or deserializing JSON data for Kotlin classes with Jackson, so m
3740
`com.fasterxml.jackson.module:jackson-module-kotlin` dependency to your project if you have such need.
3841
It is automatically registered when found in the classpath.
3942

43+
44+
45+
4046
[[kotlin-extensions]]
4147
== Extensions
4248

@@ -80,6 +86,9 @@ With Kotlin and the Spring Framework extensions, you can instead write the follo
8086
As in Java, `users` in Kotlin is strongly typed, but Kotlin's clever type inference allows
8187
for shorter syntax.
8288

89+
90+
91+
8392
[[kotlin-null-safety]]
8493
== Null-safety
8594

@@ -115,6 +124,9 @@ NOTE: Generic type arguments, varargs, and array elements nullability are not su
115124
but should be in an upcoming release. See https://github.com/Kotlin/KEEP/issues/79[this discussion]
116125
for up-to-date information.
117126

127+
128+
129+
118130
[[kotlin-classes-interfaces]]
119131
== Classes and Interfaces
120132

@@ -124,12 +136,16 @@ with default values.
124136

125137
Kotlin parameter names are recognized through a dedicated `KotlinReflectionParameterNameDiscoverer`,
126138
which allows finding interface method parameter names without requiring the Java 8 `-parameters`
127-
compiler flag to be enabled during compilation.
139+
compiler flag to be enabled during compilation. (For completeness, we nevertheless recommend
140+
running the Kotlin compiler with its `-java-parameters` flag for standard Java parameter exposure.)
128141

129142
You can declare configuration classes as
130143
https://kotlinlang.org/docs/reference/nested-classes.html[top level or nested but not inner],
131144
since the later requires a reference to the outer class.
132145

146+
147+
148+
133149
[[kotlin-annotations]]
134150
== Annotations
135151

@@ -156,6 +172,9 @@ https://kotlinlang.org/docs/reference/annotations.html#annotation-use-site-targe
156172
such as `@field:NotNull` or `@get:Size(min=5, max=15)`, as described in
157173
https://stackoverflow.com/a/35853200/1092077[this Stack Overflow response].
158174

175+
176+
177+
159178
[[kotlin-bean-definition-dsl]]
160179
== Bean Definition DSL
161180

@@ -263,16 +282,20 @@ as the following example shows:
263282
}
264283
----
265284

266-
267285
NOTE: Spring Boot is based on JavaConfig and
268286
https://github.com/spring-projects/spring-boot/issues/8115[does not yet provide specific support for functional bean definition],
269287
but you can experimentally use functional bean definitions through Spring Boot's `ApplicationContextInitializer` support.
270288
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]
271289
for more details and up-to-date information. See also the experimental Kofu DSL developed in https://github.com/spring-projects/spring-fu[Spring Fu incubator].
272290

291+
292+
293+
273294
[[kotlin-web]]
274295
== Web
275296

297+
298+
276299
=== Router DSL
277300

278301
Spring Framework comes with a Kotlin router DSL available in 3 flavors:
@@ -314,6 +337,8 @@ when you need to register routes depending on dynamic data (for example, from a
314337

315338
See https://github.com/mixitconf/mixit/[MiXiT project] for a concrete example.
316339

340+
341+
317342
=== MockMvc DSL
318343

319344
A Kotlin DSL is provided via `MockMvc` Kotlin extensions in order to provide a more
@@ -339,6 +364,8 @@ mockMvc.get("/person/{name}", "Lee") {
339364
}
340365
----
341366

367+
368+
342369
=== Kotlin Script Templates
343370

344371
Spring Framework provides a
@@ -357,9 +384,7 @@ dependencies {
357384
}
358385
----
359386

360-
Configuration is usually done with `ScriptTemplateConfigurer` and `ScriptTemplateViewResolver`
361-
beans.
362-
387+
Configuration is usually done with `ScriptTemplateConfigurer` and `ScriptTemplateViewResolver` beans.
363388

364389
`KotlinScriptConfiguration.kt`
365390
[source,kotlin,indent=0]
@@ -386,6 +411,8 @@ class KotlinScriptConfiguration {
386411
See the https://github.com/sdeleuze/kotlin-script-templating[kotlin-script-templating] example
387412
project for more details.
388413

414+
415+
389416
=== Kotlin multiplatform serialization
390417

391418
As of Spring Framework 5.3, https://github.com/Kotlin/kotlinx.serialization[Kotlin multiplatform serialization] is
@@ -397,6 +424,9 @@ Kotlin serialization is designed to serialize only Kotlin classes annotated with
397424
With Spring Messaging (RSocket), make sure that neither Jackson, GSON or JSONB are in the classpath if you want automatic configuration,
398425
if Jackson is needed configure `KotlinSerializationJsonMessageConverter` manually.
399426

427+
428+
429+
400430
== Coroutines
401431

402432
Kotlin https://kotlinlang.org/docs/reference/coroutines-overview.html[Coroutines] are Kotlin
@@ -415,6 +445,8 @@ Spring Framework provides support for Coroutines on the following scope:
415445
* Suspending function and `Flow` support in RSocket `@MessageMapping` annotated methods
416446
* Extensions for {docs-spring-framework}/kdoc-api/spring-messaging/org.springframework.messaging.rsocket/index.html[`RSocketRequester`]
417447

448+
449+
418450
=== Dependencies
419451

420452
Coroutines support is enabled when `kotlinx-coroutines-core` and `kotlinx-coroutines-reactor`
@@ -432,6 +464,8 @@ dependencies {
432464

433465
Version `1.4.0` and above are supported.
434466

467+
468+
435469
=== How Reactive translates to Coroutines?
436470

437471
For return values, the translation from Reactive to Coroutines APIs is the following:
@@ -458,6 +492,8 @@ https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coro
458492
Read this blog post about https://spring.io/blog/2019/04/12/going-reactive-with-spring-coroutines-and-kotlin-flow[Going Reactive with Spring, Coroutines and Kotlin Flow]
459493
for more details, including how to run code concurrently with Coroutines.
460494

495+
496+
461497
=== Controllers
462498

463499
Here is an example of a Coroutines `@RestController`.
@@ -554,6 +590,8 @@ class CoroutinesViewController(banner: Banner) {
554590
}
555591
----
556592

593+
594+
557595
=== WebFlux.fn
558596

559597
Here is an example of Coroutines router defined via the {docs-spring-framework}/kdoc-api/spring-webflux/org.springframework.web.reactive.function.server/co-router.html[coRouter { }] DSL and related handlers.
@@ -587,6 +625,8 @@ class UserHandler(builder: WebClient.Builder) {
587625
}
588626
----
589627

628+
629+
590630
=== Transactions
591631

592632
Transactions on Coroutines are supported via the programmatic variant of the Reactive
@@ -636,6 +676,8 @@ For Kotlin `Flow`, a `Flow<T>.transactional` extension is provided.
636676
----
637677

638678

679+
680+
639681
[[kotlin-spring-projects-in-kotlin]]
640682
== Spring Projects in Kotlin
641683

@@ -683,6 +725,8 @@ NOTE: The Kotlin code samples in Spring Framework documentation do not explicitl
683725
`open` on the classes and their member functions. The samples are written for projects
684726
using the `kotlin-allopen` plugin, since this is the most commonly used setup.
685727

728+
729+
686730
=== Using Immutable Class Instances for Persistence
687731

688732
In Kotlin, it is convenient and considered to be a best practice to declare read-only properties
@@ -726,6 +770,8 @@ NOTE: As of the Kay release train, Spring Data supports Kotlin immutable class i
726770
does not require the `kotlin-noarg` plugin if the module uses Spring Data object mappings
727771
(such as MongoDB, Redis, Cassandra, and others).
728772

773+
774+
729775
=== Injecting Dependencies
730776

731777
Our recommendation is to try to favor constructor injection with `val` read-only (and
@@ -761,6 +807,8 @@ as the following example shows:
761807
}
762808
----
763809

810+
811+
764812
=== Injecting Configuration Properties
765813

766814
In Java, you can inject configuration properties by using annotations (such as pass:q[`@Value("${property}")`)].
@@ -801,6 +849,7 @@ that uses the `${...}` syntax, with configuration beans, as the following exampl
801849
----
802850

803851

852+
804853
=== Checked Exceptions
805854

806855
Java and https://kotlinlang.org/docs/reference/exceptions.html[Kotlin exception handling]
@@ -813,6 +862,8 @@ To get the original exception thrown like in Java, methods should be annotated w
813862
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-throws/index.html[`@Throws`]
814863
to specify explicitly the checked exceptions thrown (for example `@Throws(IOException::class)`).
815864

865+
866+
816867
=== Annotation Array Attributes
817868

818869
Kotlin annotations are mostly similar to Java annotations, but array attributes (which are
@@ -857,6 +908,8 @@ use a shortcut annotation, such as `@GetMapping`, `@PostMapping`, and others.
857908
NOTE: If the `@RequestMapping` `method` attribute is not specified, all HTTP methods will
858909
be matched, not only the `GET` method.
859910

911+
912+
860913
=== Testing
861914

862915
This section addresses testing with the combination of Kotlin and Spring Framework.
@@ -866,6 +919,7 @@ https://mockk.io/[Mockk] for mocking.
866919
NOTE: If you are using Spring Boot, see
867920
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-kotlin-testing[this related documentation].
868921

922+
869923
==== Constructor injection
870924

871925
As described in the <<testing#testcontext-junit-jupiter-di, dedicated section>>,
@@ -887,6 +941,7 @@ class OrderServiceIntegrationTests(val orderService: OrderService,
887941
----
888942
====
889943

944+
890945
==== `PER_CLASS` Lifecycle
891946

892947
Kotlin lets you specify meaningful test function names between backticks (```).
@@ -930,6 +985,7 @@ class IntegrationTests {
930985
}
931986
----
932987

988+
933989
==== Specification-like Tests
934990

935991
You can create specification-like tests with JUnit 5 and Kotlin.
@@ -959,6 +1015,7 @@ class SpecificationLikeTests {
9591015
}
9601016
----
9611017

1018+
9621019
[[kotlin-webtestclient-issue]]
9631020
==== `WebTestClient` Type Inference Issue in Kotlin
9641021

@@ -968,17 +1025,24 @@ since it provides a workaround for the Kotlin issue with the Java API.
9681025

9691026
See also the related https://jira.spring.io/browse/SPR-16057[SPR-16057] issue.
9701027

1028+
1029+
1030+
9711031
[[kotlin-getting-started]]
9721032
== Getting Started
9731033

9741034
The easiest way to learn how to build a Spring application with Kotlin is to follow
9751035
https://spring.io/guides/tutorials/spring-boot-kotlin/[the dedicated tutorial].
9761036

1037+
1038+
9771039
=== `start.spring.io`
9781040

9791041
The easiest way to start a new Spring Framework project in Kotlin is to create a new Spring
9801042
Boot 2 project on https://start.spring.io/#!language=kotlin&type=gradle-project[start.spring.io].
9811043

1044+
1045+
9821046
=== Choosing the Web Flavor
9831047

9841048
Spring Framework now comes with two different web stacks: <<web#mvc, Spring MVC>> and
@@ -991,6 +1055,9 @@ Kotlin DSL.
9911055
For other use cases, especially if you are using blocking technologies such as JPA, Spring
9921056
MVC and its annotation-based programming model is the recommended choice.
9931057

1058+
1059+
1060+
9941061
[[kotlin-resources]]
9951062
== Resources
9961063

@@ -1004,6 +1071,8 @@ Kotlin and the Spring Framework:
10041071
* https://blog.jetbrains.com/kotlin/[Kotlin blog]
10051072
* https://kotlin.link/[Awesome Kotlin]
10061073

1074+
1075+
10071076
=== Examples
10081077

10091078
The following Github projects offer examples that you can learn from and possibly even extend:
@@ -1016,6 +1085,8 @@ The following Github projects offer examples that you can learn from and possibl
10161085
* https://github.com/sdeleuze/spring-kotlin-deepdive[spring-kotlin-deepdive]: A step-by-step migration guide for Boot 1.0 and Java to Boot 2.0 and Kotlin
10171086
* https://github.com/spring-cloud/spring-cloud-gcp/tree/master/spring-cloud-gcp-kotlin-samples/spring-cloud-gcp-kotlin-app-sample[spring-cloud-gcp-kotlin-app-sample]: Spring Boot with Google Cloud Platform Integrations
10181087

1088+
1089+
10191090
=== Issues
10201091

10211092
The following list categorizes the pending issues related to Spring and Kotlin support:

spring-core/src/main/java/org/springframework/core/KotlinReflectionParameterNameDiscoverer.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,11 +30,13 @@
3030
* {@link ParameterNameDiscoverer} implementation which uses Kotlin's reflection facilities
3131
* for introspecting parameter names.
3232
*
33-
* Compared to {@link StandardReflectionParameterNameDiscoverer}, it allows in addition to
33+
* <p>Compared to {@link StandardReflectionParameterNameDiscoverer}, it allows in addition to
3434
* determine interface parameter names without requiring Java 8 -parameters compiler flag.
3535
*
3636
* @author Sebastien Deleuze
3737
* @since 5.0
38+
* @see StandardReflectionParameterNameDiscoverer
39+
* @see DefaultParameterNameDiscoverer
3840
*/
3941
public class KotlinReflectionParameterNameDiscoverer implements ParameterNameDiscoverer {
4042

spring-core/src/main/java/org/springframework/core/LocalVariableTableParameterNameDiscoverer.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,21 @@
4747
* caches the ASM discovered information for each introspected Class, in a thread-safe
4848
* manner. It is recommended to reuse ParameterNameDiscoverer instances as far as possible.
4949
*
50+
* <p>This class is deprecated in the 6.0 generation and scheduled for removal in 6.1
51+
* since it is effectively superseded by {@link StandardReflectionParameterNameDiscoverer}.
52+
* For the time being, this discoverer logs a warning every time it actually inspects a
53+
* class file which is particularly useful for identifying remaining gaps in usage of
54+
* the standard "-parameters" compiler flag, and also unintended over-inspection of
55+
* e.g. JDK core library classes (which are not compiled with the "-parameters" flag).
56+
*
5057
* @author Adrian Colyer
5158
* @author Costin Leau
5259
* @author Juergen Hoeller
5360
* @author Chris Beams
5461
* @author Sam Brannen
5562
* @since 2.0
63+
* @see StandardReflectionParameterNameDiscoverer
64+
* @see DefaultParameterNameDiscoverer
5665
* @deprecated as of 6.0.1, in favor of {@link StandardReflectionParameterNameDiscoverer}
5766
* (with the "-parameters" compiler flag)
5867
*/

spring-core/src/main/java/org/springframework/core/StandardReflectionParameterNameDiscoverer.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,10 +26,15 @@
2626
* {@link ParameterNameDiscoverer} implementation which uses JDK 8's reflection facilities
2727
* for introspecting parameter names (based on the "-parameters" compiler flag).
2828
*
29+
* <p>This is a key element of {@link DefaultParameterNameDiscoverer} where it is being
30+
* combined with {@link KotlinReflectionParameterNameDiscoverer} if Kotlin is present.
31+
*
2932
* @author Juergen Hoeller
3033
* @since 4.0
3134
* @see java.lang.reflect.Method#getParameters()
3235
* @see java.lang.reflect.Parameter#getName()
36+
* @see KotlinReflectionParameterNameDiscoverer
37+
* @see DefaultParameterNameDiscoverer
3338
*/
3439
public class StandardReflectionParameterNameDiscoverer implements ParameterNameDiscoverer {
3540

0 commit comments

Comments
 (0)