
上一篇先說明了這個系列想做什麼,這篇會先把後面相關的 Kotlin 專案建起來
原本寫 Kotlin JVM 專案,我通常會直接用 Gradle Kotlin DSL,但這個系列的重點不是建置腳本,而是一個小而乾淨、能 build、run、test 的練習專案,既然前面已經整理過 Kotlin Toolchain 這套工具,這次就改用 Kotlin Toolchain CLI 建專案
這樣做的好處很直接,少掉 build.gradle.kts、settings.gradle.kts 和一堆版本設定,先把注意力留給 Relix 本身
本文使用的 Kotlin Toolchain 仍在 Alpha 階段,指令與 module.yaml 格式可能調整,實際跟做時,請以你安裝版本的 kotlin --help 與官方文件為準,本文則固定使用同一套設定,避免系列中途切換建置方式
這篇只做幾件事
./kotlin build 和 ./kotlin run 可以正常執行HttpServer 環境測試,確定下一篇會用到的 JDK 類別存在為什麼一開始就要確認測試 ? 因為這個系列會用測試帶著實作往前走,後面每一篇都會先寫測試,再補框架功能,如果測試入口不穩,後面會一直被環境問題干擾
先確認本機的 kotlin 指令可用
kotlin --version
我實測時的版本是
Kotlin Toolchain version 0.11.0 (35ef359, 2026-05-20)
kotlin init 可以互動式選 template,也可以直接指定 template 名稱。這個系列用最單純的 jvm-cli
mkdir relix
kotlin init jvm-cli --target-dir=relix
cd relix
我實測時,--target-dir 指向的目錄要先存在,所以前面先用 mkdir 建好
成功後會看到類似這樣的訊息
Extracting template jvm-cli to relix…
Project successfully generated
Now you may build your project with ./kotlin build or open this folder in an IDE with the Kotlin Toolchain plugin
注意最後建議的是 ./kotlin build,不是全域的 kotlin build。這個 ./kotlin 是專案內的 wrapper script,概念跟 Gradle Wrapper 很像,專案自己帶著固定入口,新成員 clone 下來後不用先手動裝同一版 CLI
jvm-cli template 產出的檔案很少
relix/
├── kotlin
├── kotlin.bat
├── module.yaml
├── src/
│ ├── main.kt
│ └── World.kt
└── test/
└── WorldTest.kt
跟 Gradle 專案相比,這裡沒有 build.gradle.kts 和 settings.gradle.kts,主要設定都放在 module.yaml
product: jvm/app
這一行表示它是一個 JVM application。對這個系列來說已經夠用,後面要加自己的 Kotlin 檔案和測試,都可以直接放進這個專案
src/main.kt 預設長這樣
fun main() {
println("Hello, ${World.get()}!")
}
src/World.kt 則是一個簡單的 object
object World {
fun get(): String {
return "World";
}
}
這些都是 template 附的範例,後面可以刪掉,也可以先留著。這篇先不急著整理檔案,重點是確認專案可以正常建置和測試
先跑 build
./kotlin build
我實測的結果是
Build successful
再跑程式
./kotlin run
會印出
Hello, World!
00:00.741 INFO :relix:runJvm Process exited with exit code 0
第一行是程式輸出,第二行是 Kotlin Toolchain 的執行資訊。exit code 0 表示程式正常結束
jvm-cli template 會在 test/WorldTest.kt 放兩個測試,其中一個是故意失敗的 shouldFail()
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class WorldTest {
@Test
fun doTest() {
assertEquals("World", World.get())
}
@Test
fun shouldFail() {
assertTrue(false)
}
}
所以你直接跑
./kotlin test
會看到 shouldFail() 失敗。這不是環境壞掉,是 template 故意讓你看到測試失敗時的輸出
這個系列不需要保留它,把 shouldFail() 和沒用到的 assertTrue import 刪掉即可
import kotlin.test.Test
import kotlin.test.assertEquals
class WorldTest {
@Test
fun doTest() {
assertEquals("World", World.get())
}
}
下一篇會用 JDK 內建的 HttpServer 跑起第一個 HTTP Server,這個類別在標準 JDK 裡就有,不需要另外加相依套件
不過既然這個系列是 TDD 節奏,我們可以先寫一個小測試,確認目前 JDK 真的載得到它
在 test/EnvironmentTest.kt 加上
import kotlin.test.Test
import kotlin.test.assertTrue
class EnvironmentTest {
@Test
fun `JDK HttpServer class is available`() {
val clazz = Class.forName("com.sun.net.httpserver.HttpServer")
assertTrue(clazz.methods.isNotEmpty())
}
}
這個測試不是為了測 JDK,而是為了讓開發環境的前提明確。如果你用的是標準 JDK,通常不會有問題。如果用了某些精簡版 runtime,這裡會先失敗,總比下一篇寫 server 時才發現好
移除 shouldFail() 並補上 EnvironmentTest 後,再跑一次
./kotlin test
我實測會看到兩個測試通過
Started WorldTest
Started doTest()
Passed doTest()
Completed WorldTest
Started EnvironmentTest
Started JDK HttpServer class is available()
Passed JDK HttpServer class is available()
Completed EnvironmentTest
[ 2 tests found ]
[ 2 tests successful ]
[ 0 tests failed ]
到這裡,我們已經有一個可以 build、run、test 的 Kotlin JVM 專案,也確認下一篇要用的 HttpServer 存在
如果你要跟著系列一路做,建議一開始就初始化 git
git init
.gitignore 建議至少包含這些
gitignore
.kotlin/
.idea/
*.iml
out/
.DS_Store
Thumbs.db
local.properties
build/
Kotlin Toolchain 會透過 wrapper 和本機快取處理工具版本,專案裡真正重要的是 module.yaml、src/、test/、kotlin 和 kotlin.bat
--target-dir 指向的目錄不存在
--target-dir 指向的目錄要先存在,先跑 mkdir relix 再執行 kotlin init
建立成功後,建議用 ./kotlin build、./kotlin run、./kotlin test。這樣每個人都走專案自己的入口,不會因為全域 CLI 版本不同產生奇怪差異
shouldFail() 失敗
這是 template 內建的示範失敗測試,不是環境壞掉,刪掉 shouldFail() 和沒用到的 assertTrue import,再跑一次測試
HttpServer 測試失敗
HttpServer 在標準 JDK 裡可用,如果這個測試失敗,先確認你使用的是標準 JDK,而不是只包含部分模組的 runtime
這篇把 Relix 的專案骨架準備好了,用 Kotlin Toolchain CLI 建立 JVM project,確認 build、run、test 都能跑,也補上 HttpServer 可用的環境測試
下一篇會正式用 JDK 的 HttpServer 跑起第一個能回應 "Hello, Relix!" 的伺服器,建立 RelixApplication 類別,並用整合測試確認行為
同步刊登於 Blog
圖片來源:AI 產生