Skip to content

Commit 29f2477

Browse files
authored
Add spring boot example for mill configuration compatible with spring initializr for a maven kotlin project (#6014)
## Motivation Related to #6006 Getting a "learning path" on how to setup spring boot projects in increasing complexity. The aim of the documentation is to follow the spring boot learning path and map it to mill. ## In this PR This is the first small step of getting a kotlin project as downloaded from spring boot's [initializr](https://start.spring.io/) project to work with mill . While spring boot examples exist in mill, this differentiates by - Project structure is the same as initializr - Dependencies are up to date (and thus resulting in Junit5 failing without the platform version override) - I can also do these updates in the existing examples if you'd like - Added an extra mill command to demonstrate how to build a jar and run the spring boot server - Documentation scaffolding (see below) ### Documentation Scaffolding This PR adds a special section for spring boot in both Java and Kotlin. The aim is to add more examples in increasing complexity as they appear [here](https://spring.io/projects/spring-boot) <img width="1409" height="982" alt="image" src="https://github.com/user-attachments/assets/05ede119-a999-4e1c-8c2f-49014a1496f4" /> The examples an in a separate example/springboot so it will be easier to the reader and to the tester (e.g. for directory grouping without affecting other javalib/kotlinlib examples, port isolation) ## Manual Tests ### Running the assembly jar <img width="1762" height="409" alt="image" src="https://github.com/user-attachments/assets/1f896198-066b-4b9d-9af7-34686b885a41" /> <img width="277" height="124" alt="image" src="https://github.com/user-attachments/assets/8a65915a-25ac-4cdd-8638-f1358694cdd7" /> ## Follow up PRs (plan) - More examples - More docs
1 parent 44f492a commit 29f2477

File tree

13 files changed

+202
-0
lines changed

13 files changed

+202
-0
lines changed

.github/workflows/run-tests.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ jobs:
150150
- java-version: 21
151151
millargs: "example.javalib.__.local.daemon"
152152

153+
- java-version: 21
154+
millargs: "example.springboot.__.local.daemon"
155+
153156
- java-version: 17
154157
millargs: "'example.androidlib.__.local.daemon'"
155158
setup-android: true

example/package.mill

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ object `package` extends Module {
4646
object script extends Cross[ExampleCrossModuleKotlin](build.listCross)
4747
object web extends Cross[ExampleCrossModuleKotlin](build.listCross)
4848
}
49+
object springboot extends Module {
50+
object java extends Cross[ExampleCrossModule](build.listCross)
51+
object kotlin extends Cross[ExampleCrossModule](build.listCross)
52+
}
4953
object scalalib extends Module {
5054
object basic extends Cross[ExampleCrossModule](build.listCross)
5155
object module extends Cross[ExampleCrossModule](build.listCross)
@@ -135,6 +139,7 @@ object `package` extends Module {
135139
trait ExampleCrossModuleAndroid extends ExampleCrossModule {
136140
def testExclusive = true
137141
}
142+
138143
trait ExampleCrossModuleJava extends ExampleCrossModule {
139144

140145
def upstreamCross(s: String) = s match {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package build
2+
3+
import mill.*
4+
import mill.javalib.*
5+
6+
object `package` extends MavenModule {
7+
8+
def mvnDeps = Seq(mvn"org.springframework.boot:spring-boot-starter-web:3.5.6")
9+
10+
object test extends MavenTests, TestModule.Junit5 {
11+
12+
override def junitPlatformVersion: T[String] = "6.0.0"
13+
14+
def mvnDeps =
15+
Seq(mvn"org.springframework.boot:spring-boot-starter-test:3.5.6")
16+
}
17+
}
18+
19+
// This example demonstrates how to configure mill for a simple initializr project,
20+
// using https://start.spring.io/[https://start.spring.io/] by choosing:
21+
//
22+
//* Project: maven
23+
//* Language: Java
24+
//* Dependencies: Spring Web,
25+
//
26+
// The structure of this project follows the MavenModule structure (i.e. the same structure
27+
// as generated from the initialzr tool).
28+
//
29+
// For more information visit https://spring.io/quickstart[https://spring.io/quickstart]
30+
31+
/** Usage
32+
33+
> ./mill test
34+
...Test com.example.demo.DemoApplicationTests#contextLoads() finished...
35+
36+
> ./mill runBackground
37+
38+
> curl http://localhost:8096/hello
39+
...Hello, World!...
40+
41+
> curl http://localhost:8096/hello?name=Mill
42+
...Hello, Mill!...
43+
44+
> ./mill clean runBackground
45+
46+
> ./mill show assembly
47+
.../out/assembly.dest/out.jar...
48+
49+
*/
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.example.demo;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.web.bind.annotation.GetMapping;
6+
import org.springframework.web.bind.annotation.RequestParam;
7+
import org.springframework.web.bind.annotation.RestController;
8+
9+
@SpringBootApplication
10+
@RestController
11+
public class DemoApplication {
12+
13+
public static void main(String[] args) {
14+
SpringApplication.run(DemoApplication.class, args);
15+
}
16+
17+
@GetMapping("/hello")
18+
public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
19+
return String.format("Hello, %s!", name);
20+
}
21+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
spring.application.name=demo
2+
server.port=8096
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.example.demo;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.springframework.boot.test.context.SpringBootTest;
5+
6+
@SpringBootTest
7+
class DemoApplicationTests {
8+
9+
@Test
10+
void contextLoads() {}
11+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package build
2+
3+
import mill.*
4+
import mill.javalib.*
5+
import mill.kotlinlib.KotlinMavenModule
6+
7+
object `package` extends KotlinMavenModule {
8+
9+
def kotlinVersion = "1.9.25"
10+
11+
override def kotlincOptions: T[Seq[String]] = super.kotlincOptions() ++ Seq("-jvm-target", "17")
12+
13+
def mvnDeps = Seq(
14+
mvn"com.fasterxml.jackson.module:jackson-module-kotlin:2.19.2",
15+
mvn"org.jetbrains.kotlin:kotlin-reflect:1.9.25",
16+
mvn"org.jetbrains.kotlin:kotlin-stdlib:1.9.25",
17+
mvn"org.springframework.boot:spring-boot-starter-web:3.5.6"
18+
)
19+
20+
object test extends KotlinMavenTests, TestModule.Junit5 {
21+
22+
override def junitPlatformVersion: T[String] = "6.0.0"
23+
24+
def mvnDeps = Seq(
25+
mvn"org.jetbrains.kotlin:kotlin-test-junit5:1.9.25",
26+
mvn"org.springframework.boot:spring-boot-starter-test:3.5.6"
27+
)
28+
29+
}
30+
}
31+
32+
// This example demonstrates how to configure mill for a simple initializr project,
33+
// using https://start.spring.io/[https://start.spring.io/] by choosing:
34+
//
35+
//* Project: maven
36+
//* Language: Kotlin
37+
//* Dependencies: Spring Web,
38+
//
39+
// The structure of this project follows the MavenModule structure (i.e. the same structure
40+
// as generated from the initialzr tool).
41+
//
42+
// For more information visit https://spring.io/quickstart[quickstart]
43+
// and https://spring.io/guides/tutorials/spring-boot-kotlin[spring-boot-kotlin]
44+
45+
/** Usage
46+
47+
> ./mill test
48+
...Test com.example.demokotlin.DemoKotlinApplicationTests#contextLoads() finished...
49+
50+
> ./mill runBackground
51+
52+
> curl http://localhost:9096/hello
53+
...Hello, World!...
54+
55+
> curl http://localhost:9096/hello?name=Mill
56+
...Hello, Mill!...
57+
58+
> ./mill clean runBackground
59+
60+
> ./mill show assembly
61+
.../out/assembly.dest/out.jar...
62+
63+
*/
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.example.demokotlin
2+
3+
import org.springframework.boot.autoconfigure.SpringBootApplication
4+
import org.springframework.boot.runApplication
5+
import org.springframework.web.bind.annotation.GetMapping
6+
import org.springframework.web.bind.annotation.RequestParam
7+
import org.springframework.web.bind.annotation.RestController
8+
9+
@SpringBootApplication
10+
@RestController
11+
class DemoKotlinApplication {
12+
@GetMapping("/hello")
13+
fun hello(@RequestParam(value = "name", defaultValue = "World") name: String?): String? = String.format("Hello, %s!", name)
14+
}
15+
16+
fun main(args: Array<String>) {
17+
runApplication<DemoKotlinApplication>(*args)
18+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
spring.application.name=demo-kotlin
2+
server.port=9096
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.example.demokotlin
2+
3+
import org.junit.jupiter.api.Test
4+
import org.springframework.boot.test.context.SpringBootTest
5+
6+
@SpringBootTest
7+
class DemoKotlinApplicationTests {
8+
9+
@Test
10+
fun contextLoads() {
11+
}
12+
}

0 commit comments

Comments
 (0)