Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
KotlinでSpring 完全理解ガイド #jsug
Search
Taro Nagasawa
January 27, 2020
Programming
3.7k
6
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
KotlinでSpring 完全理解ガイド #jsug
日本Springユーザグループの勉強会、登壇資料
https://jsug.doorkeeper.jp/events/102390
Java x Springユーザ向け資料です
Taro Nagasawa
January 27, 2020
More Decks by Taro Nagasawa
See All by Taro Nagasawa
Android開発者のための Kotlin Multiplatform入門
ntaro
0
1.8k
Kotlin 最新動向2022 #tfcon #techfeed
ntaro
1
2.4k
#Ubie 狂気の認知施策と選考設計
ntaro
14
14k
UbieにおけるサーバサイドKotlin活用事例
ntaro
1
1.2k
Kotlinでサーバサイドを始めよう!
ntaro
1
1.1k
Androidからサーバーサイドまで!プログラミング言語 Kotlinの魅力 #devboost
ntaro
5
3.1k
Kotlin Contracts #m3kt
ntaro
4
4.4k
How_to_Test_Server-side_Kotlin.pdf
ntaro
1
590
Kotlin Fest 2018 - Opening session
ntaro
0
4.4k
Other Decks in Programming
See All in Programming
UPDATE をやめる — EF Core でマスタをバージョン管理する
panda728
PRO
0
1k
SONY CISC-NEWS NWS-1750 + NWB-225 フレームバッファの NetBSD/news68k ドライバ実装 / OSC2026Hiroshima
tsutsui
0
160
ゲームコントローラやキーボードのファームウェアをSwiftで書く
kishikawakatsumi
1
270
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
660
Omarchy Tokyo やると聞いて UMPC 買ってセットアップしてきた
mtsmfm
0
200
AgentCore CLI で進化した AWS での AI エージェントの作り方 : 必要な機能を必要な時に
icoxfog417
PRO
4
410
パズルゲームの作り方 / how to make puzzle games
kaityo256
PRO
2
260
AGENTS.md Is Not Enough:Build Skills, Don't Download Them
lx_t
0
130
Webの地図
yosuke_furukawa
PRO
6
5k
Simple Storage Service(S3) is not simple
iwatsukayura
0
120
フロントエンドUIフレームワークのこれまでとこれから
ssssota
5
3.1k
Vue Fes Japan 2026 タイムテーブル徹底解説
448jp
1
590
Featured
See All Featured
Heart Work Chapter 1 - Part 1
lfama
PRO
10
36k
What's in a price? How to price your products and services
michaelherold
247
13k
GitHub's CSS Performance
jonrohan
1033
470k
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
960
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3.1k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
710
New Earth Scene 8
popppiees
4
2.6k
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
410
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
The Language of Interfaces
destraynor
162
27k
Transcript
2020-01-27 長澤 太郎 KotlinでSpring 完全理解ガイド
本発表のゴール チョットデキル 何もわからない 完全に理解した ここまで ガイドします!
より具体的には 「Kotlinでも普通にSpring使えるんだ!」 「Kotlinにはこういう事情があるんだ!」 が わかるようになる!
長澤 太郎
◦◦を使えば Kotlinで簡単に Spring開発を始められる
Spring Initializr - start.spring.io
Spring Initializr - start.spring.io
IntelliJ IDEA
すぐに開発を始められる!
◦◦を使えば Kotlinで簡単に Spring開発を始められる 答. Spring Initializr
おまけ ビルドツールにGradleを選択すると ビルド設定ファイルがbuild.gradle.kts として生成され、そのスクリプトが Kotlinで記述されている
Kotlinでも◦◦を使って bean登録やハンドラ定義
Hello World @Service class HelloWorldService { fun helloWorld(): String =
"Hello, world!" } @RestController class HelloWorldController(val helloWorldService: HelloWorldService) { @GetMapping("/hello-world") fun helloWorld(): String = helloWorldService.helloWorld() }
Hello World @Service class HelloWorldService { fun helloWorld(): String =
"Hello, world!" } @RestController class HelloWorldController(val helloWorldService: HelloWorldService) { @GetMapping("/hello-world") fun helloWorld(): String = helloWorldService.helloWorld() }
Kotlin事情: デフォルトで継承を許可しない • Kotlinのクラスはデフォルトで継承を許可しない • open修飾子を付けることで継承を許可する • @Serviceなどが付いたクラスはSpringによってサブクラス が生成される(継承を許可する必要がある) @Service
open class FooService { ... } @Service open class BarService { ... } 面倒だしダサい
大丈夫!基本的に意識する必要なし! • Kotlin公式 allopenプラグイン ◦ 自分で指定したアノテーションが付与されたクラスをすべてopenクラス として扱ってくれるプラグイン • kotlin-springプラグイン ◦
Spring用allopenプラグイン ◦ 予め@Serviceや@Configurationのようなアノテーションが allopen対象として登録されている Spring Initializrで生成したプロジェクトには 最初から設定されているので意識する必要はない
Kotlin事情: バリデーションに注意 class PostBody( @NotNull val value: Int ) @PostMapping
fun create( @Valid @RequestBody body: PostBody, bindingResult: BindingResult ) { ... }
Kotlin事情: バリデーションに注意 class PostBody( @NotNull val value: Int ) @PostMapping
fun create( @Valid @RequestBody body: PostBody, bindingResult: BindingResult ) { ... } こっちは問題なし
Kotlin事情: バリデーションに注意 class PostBody( @NotNull val value: Int ) @PostMapping
fun create( @Valid @RequestBody body: PostBody, bindingResult: BindingResult ) { ... } プロパティはJavaで言う フィールドとアクセサが組み合 わさったようなもの NotNull型 + Javaのプリミティ ブ型 = ...!?
Kotlin事情: バリデーションに注意 class PostBody( @NotNull val value: Int ) class
PostBody( @field:NotNull val value: Int? )
Kotlinでも◦◦を使って bean登録やハンドラ定義 答. アノテーション
おまけ もしフィールドインジェクションがしたいなら... @RestController class HelloWorldController { @Autowired lateinit var helloWorldService:
HelloWorldService @GetMapping("/hello-world") fun helloWorld(): String { ... } }
◦◦を使った比較的新しい bean登録やハンドラ定義
Bean Definition DSL fun main(args: Array<String>) { SpringApplicationBuilder() .sources(DemoApplication::class.java) .initializers(beans
{ bean<UserRepositoryImpl>() bean<UserService>() }) .run(*args) }
[NEW] Router DSL bean { val userService = ref<UserService>() router
{ "/api".nest { GET("/users") { val users = userService.findAll() ok().body(users) } } } }
[NEW] Router DSL val userHandler = ref<UserHandler>() router { "/api".nest
{ GET("/users", userHandler::findAll) } } class UserHandler(val userService: UserService) { fun findAll(req: ServerRequest): ServerResponse { val users = userService.findAll() return ServerResponse.ok().body(users) } }
◦◦を使った比較的新しい bean登録やハンドラ定義 答. Kotlin用 DSL
おまけ • ktlint - いわゆる Linter 兼 Formatter • Gradleプラグインがある
• IntelliJ IDEAのフォーマッタの自動設定あり $ ./gradlew ktlintCheck $ ./gradlew ktlintFormat
WebFluxでKotlinの ◦◦という機能が便利
Kotlinでも普通にWebFlux @RestController class DemoController(val demoService: DemoService) { @GetMapping("demo") fun handle():
Mono<String> = Mono.zip( demoService.getMonoA(), demoService.getMonoB() ) .flatMap { demoService.getMonoC(it.t1, it.t2) } .map { it.answer } }
Kotlinでも普通にWebFlux @RestController class DemoController(val demoService: DemoService) { @GetMapping("demo") fun handle():
Mono<String> = Mono.zip( demoService.getMonoA(), demoService.getMonoB() ) .flatMap { demoService.getMonoC(it.t1, it.t2) } .map { it.answer } } AとBを同時に取得して ペアとしてまとめる
Kotlinでも普通にWebFlux @RestController class DemoController(val demoService: DemoService) { @GetMapping("demo") fun handle():
Mono<String> = Mono.zip( demoService.getMonoA(), demoService.getMonoB() ) .flatMap { demoService.getMonoC(it.t1, it.t2) } .map { it.answer } } AとBを同時に取得して ペアとしてまとめる CをMonoとして取得 Monoの入れ子を解除
Kotlinでも普通にWebFlux @RestController class DemoController(val demoService: DemoService) { @GetMapping("demo") fun handle():
Mono<String> = Mono.zip( demoService.getMonoA(), demoService.getMonoB() ) .flatMap { demoService.getMonoC(it.t1, it.t2) } .map { it.answer } } AとBを同時に取得して ペアとしてまとめる CをMonoとして取得 Monoの入れ子を解除 Cの結果のプロパティで変換
Kotlinでも普通にWebFlux @RestController class DemoController(val demoService: DemoService) { @GetMapping("demo") fun handle():
Mono<String> = Mono.zip( demoService.getMonoA(), demoService.getMonoB() ) .flatMap { demoService.getMonoC(it.t1, it.t2) } .map { it.answer } } AとBを同時に取得して ペアとしてまとめる CをMonoとして取得 Monoの入れ子を解除 Cの結果のプロパティで変換
Kotlinにはコルーチンがある! • Reactor対応のライブラリが公式である ◦ コルーチンでMonoやFluxを表現できる • というかむしろSpring Framework 5.2から◦◦! •
詳しくは次の木原さんの発表で!
WebFluxでKotlinの ◦◦という機能が便利 答. コルーチン
おまけ • Ktor というKotlin用Webアプリフレームワークがいい 感じ • JetBrains公式 • 非常に薄く、余分な機能は3rdパーティ任せ ◦
ロギング、永続化、テンプレートエンジン、DI • DSL ◦ ラムダ(特に拡張関数としてのラムダ)を多様 ◦ 宣言的にプログラムを組み立てる • ノンブロッキング ◦ 複雑な非同期プログラミングをコルーチンで
Kotlinでも◦◦を使ったテスト
class FooTest { @Nested inner class fooMethod { @Test fun
`should throw exception`() { assertThrows<MyException>() { Foo().foo() } } } } JUnit5
class FooTest { @Nested inner class fooMethod { @Test fun
`should throw exception`() { assertThrows<MyException>() { Foo().foo() } } } } JUnit5 グルーピングしてテストの見通しを良く
class FooTest { @Nested inner class fooMethod { @Test fun
`should throw exception`() { assertThrows<MyException>() { Foo().foo() } } } } JUnit5
client.get() .uri("/hello-world") .exchange() .expectBody(HelloWorldResource::class.java) .isEqualTo<Nothing>(expectedResource) WebTestClientによるテスト Javaと同じ感覚で 書いてるとこうなりそう
client.get() .uri("/hello-world") .exchange() .expectBody(HelloWorldResource::class.java) .isEqualTo<Nothing>(expectedResource) WebTestClientによるテスト Javaと同じ感覚で 書いてるとこうなりそう ここで例外が発生する!!
client.get() .uri("/hello-world") .exchange() .expectBody<HelloWorldResource>() .isEqualTo(expectedResource) Kotlin用の拡張関数 expectBodyを使う
Kotlinでも◦◦を使ったテスト 答. JUnit
おまけ • アサーションライブラリは何がいいか • 弊社では AssertJを使っています • assertkが気になる ◦ Kotlinフレンドリ(nullまわりとか)
◦ ただし v0.21 で不安定か? assertThat(yourName).isEqualTo("Alice")
Kotlinでモックするなら ◦◦がイイ感じ
MockK val userRepo = mockk<UserRepository>() every { userRepo.findUser(1) } returns
user 通常のメソッドであれば このように挙動を変更できる interface UserRepository { suspend fun findUser(id: Long): User? }
MockK interface UserRepository { suspend fun findUser(id: Long): User? }
val userRepo = mockk<UserRepository>() every { userRepo.findUser(1) } returns user coEvery { userRepo.findUser(1) } returns user 今回はコルーチン(suspend関数)なので
モック生成を繰り返さないこと class DesignControllerTest { private lateinit var repo: DesignRepository private
lateinit var client: DesignClient private lateinit var controller: DesignController @BeforeEach fun init() { repo = mockk() client = mockk() controller = DesignController(repo, client) } } 高コスト 参考 https://www.youtube.com/watch?v=RX_g65J14H0
モック生成は一度、都度リセット class DesignControllerTest { private val repo: DesignRepository = mockk()
private val client: DesignClient = mockk() private val controller: DesignController(repo, client) @BeforeEach fun init() { clearMocks(repo, client) } } 参考 https://www.youtube.com/watch?v=RX_g65J14H0
そのほか基本的なことは一通りできる // キャプチャ val slot = slot<String>() // 戻り値がないメソッド every
{ myService.run(capture(slot)) } just runs // 検証 verify(exactly = 1) { myService.run(any()) }
Kotlinでモックするなら ◦◦がイイ感じ 答. Mockk
まとめ • Spring InitializrやIntelliJで簡単にSpring Kotlinを始めら れる! • 普通にアノテーションを使ってもいいし、DSLを使ってもbean 登録やルーティングができる ◦
Kotlin固有の問題はあまりないが、バリデーションに注意 • コルーチンというものが便利っぽいぞ • KotlinでもJUnitでSpringテストができる • モックライブラリはMockKがよさそう
「Spring Kotlin, 完全に理解した!」
よくある質問 「DBアクセスは どうしてる?」