Add kotlin module: null safety, coroutines, allopen/noarg, JSpecify interop (post #42)
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
# kotlin
|
||||
|
||||
Companion project for the article **[Kotlin with Spring Boot 4.1: Null Safety, Coroutines, and What Java Developers Get Wrong](https://ankurm.com/)** on **[ankurm.com](https://ankurm.com)**.
|
||||
|
||||
Every console block quoted in the article came out of `docs/output/`. 03-08 are raw `curl` captures
|
||||
against a running instance; 01, 02 and 09 are real build/startup transcripts. `BookControllerTest.kt`
|
||||
turns the null-safety claims into assertions, so a change in Spring, Kotlin or JSpecify behaviour
|
||||
breaks the build, not just the prose.
|
||||
|
||||
There is deliberately **no `docs/NN-topic.md` chapter folder**: the deeper material lives in
|
||||
collapsible "going deeper" sections inside the article itself, next to the paragraph each one
|
||||
extends. `docs/output/` (captured transcripts) is the one thing that still lives under `docs/`.
|
||||
|
||||
## Versions
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| Spring Boot | 4.1.1 |
|
||||
| Spring Framework | 7.0.9 |
|
||||
| Kotlin | 2.3.21 (Spring Boot 4.1.1's own managed version; latest actual GA is 2.4.20 — see the article) |
|
||||
| kotlinx.coroutines | 1.10.2 |
|
||||
| jackson-module-kotlin | 2.22.3 (not BOM-managed; pin it explicitly) |
|
||||
| JSpecify | 1.0.0 |
|
||||
| JDK | 25 (GraalVM CE 25.4.4.1.1) |
|
||||
| Maven | 3.9 |
|
||||
|
||||
## Quickstart
|
||||
|
||||
```bash
|
||||
export JAVA_HOME=/path/to/jdk-25
|
||||
mvn test # runs BookControllerTest, re-verifying every null-safety claim
|
||||
mvn spring-boot:run # starts the app on :8090 with 3 seeded books
|
||||
```
|
||||
|
||||
## What's demonstrated
|
||||
|
||||
| Area | Where |
|
||||
|---|---|
|
||||
| allopen/noarg via the `spring`/`jpa` kotlin compiler plugins | `pom.xml`'s `kotlin-maven-plugin` config; `BookService.kt`, `Book.kt`, `Application.kt` |
|
||||
| Real build failure without the `spring` plugin (`@Configuration class may not be final`, then `@Bean method must not be private or final`) | `docs/output/01-build-failure-without-allopen.txt` |
|
||||
| Clean startup with both plugins restored | `docs/output/02-fixed-startup.txt` |
|
||||
| `suspend fun` / `Flow<T>` controller methods under plain `spring-boot-starter-webmvc` (Tomcat, not WebFlux) | `BookController.kt` (`/books`, `/books/flow`) |
|
||||
| Which thread actually resumes a suspended controller method | `/books/thread-check`, `docs/output/05-thread-check.txt` |
|
||||
| Kotlin platform types (`String!`) for un-annotated Java APIs | `legacy/LegacyJavaApi.java`, `/books/null-demo/legacy/{id}`, `docs/output/06-null-demo-legacy.txt` |
|
||||
| JSpecify `@NullMarked`/`@Nullable` interop, and that it is a static contract, not a runtime guarantee | `legacy/NullMarkedJavaApi.java`, `/books/null-demo/jspecify/{id}`, `/books/null-demo/jspecify-honest/{id}`, `docs/output/07-08` |
|
||||
| Mixed Kotlin+Java compilation in one Maven module | `pom.xml` (`kotlin-maven-plugin` compiles `src/main/kotlin` + `src/main/java`; `maven-compiler-plugin`'s `default-compile`/`default-testCompile` disabled, `java-compile` picks up the default `src/main/java`) |
|
||||
| `TestRestTemplate` no longer shipping in Spring Boot 4.1's `spring-boot-test` module | `docs/output/09-no-testresttemplate.txt`, `BookControllerTest.kt` (plain `java.net.http.HttpClient` instead) |
|
||||
|
||||
## Captured output
|
||||
|
||||
| File | What it shows |
|
||||
|---|---|
|
||||
| `01-build-failure-without-allopen.txt` | both real failures when the `spring` compiler plugin is removed |
|
||||
| `02-fixed-startup.txt` | clean startup once it's restored |
|
||||
| `03-books-endpoint.txt` | `GET /books`, a `suspend fun` controller method, real JSON |
|
||||
| `04-books-flow-endpoint.txt` | `GET /books/flow`, a `Flow<Book>` controller method |
|
||||
| `05-thread-check.txt` | three runs of `/books/thread-check`: before/after thread names across a real suspension point |
|
||||
| `06-null-demo-legacy.txt` | the platform-type NPE, with no compiler hint anywhere, plus its stack trace |
|
||||
| `07-null-demo-jspecify.txt` | the `@NullMarked` Java method that still NPEs, plus its stack trace |
|
||||
| `08-null-demo-jspecify-honest.txt` | the `@Nullable`-annotated method the Kotlin compiler forces a null check on — no NPE |
|
||||
| `09-no-testresttemplate.txt` | `TestRestTemplate` verified absent from `spring-boot-test-4.1.1.jar` |
|
||||
|
||||
Endpoints default to `http://localhost:8090`. H2 is in-memory (`jdbc:h2:mem:kotlindemo`), reseeded
|
||||
on every restart with three books, one of them with a `null` title.
|
||||
Reference in New Issue
Block a user