Spring Bootってキワードよく聞くし、触ってみたくなったのでKotlinつかってちょっとだけ書いてみた。
やったこと
「Hello World!」と表示するhtmlを返すだけ。Viewは「thymeleaf」を使っています。
一応テストコード的なものも書いてみました。
プロダクション側のコード
多分Javaで書いてもあんまり変わらない感じだと思います。
package siosio.application import org.springframework.boot.SpringApplication import org.springframework.context.annotation.ComponentScan import org.springframework.boot.autoconfigure.EnableAutoConfiguration import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component import org.springframework.web.bind.annotation.ResponseBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.stereotype.Controller import kotlin.properties.Delegates import org.springframework.ui.Model fun main(args: Array<String>) { SpringApplication.run(array(javaClass<Application>()), args) } [EnableAutoConfiguration] [ComponentScan] [Controller] open class Application { private [Autowired] val hello: HelloService? = null [RequestMapping(array("/"))] fun home(model: Model): String { model.addAttribute("message", hello!!.getMessage()) return "home/hello" } } [Component] class HelloService { fun getMessage(): String = "Hello World!" }
テスト側のコード
Modelにつめた値とViewの名称などをアサートしてみている。
xpathつかったアサートもできるっぽいけど確認できていないです。
package siosio import org.junit.runner.RunWith import org.springframework.test.context.junit4.SpringJUnit4ClassRunner import org.springframework.test.context.web.WebAppConfiguration import org.springframework.test.context.ContextConfiguration import siosio.application.Application import org.junit.Test import org.springframework.test.web.servlet.MockMvc import org.junit.Before import org.mockito.MockitoAnnotations import org.springframework.test.web.servlet.setup.MockMvcBuilders import kotlin.properties.Delegates import org.springframework.beans.factory.annotation.Autowired import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.* import org.springframework.test.web.servlet.result.MockMvcResultMatchers.* import org.springframework.test.web.servlet.result.MockMvcResultHandlers.* import org.springframework.http.MediaType [RunWith(javaClass<SpringJUnit4ClassRunner>())] [ContextConfiguration(classes = array(javaClass<Application>()))] [WebAppConfiguration] public class ApplicationTest { private var mockMvc: MockMvc by Delegates.notNull() Autowired val controller: Application? = null Before public fun setup() { MockitoAnnotations.initMocks(this); mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); } Test fun testHelloWorld() { mockMvc.perform(get("/")) .andExpect(status().isOk()) .andExpect(view().name("home/hello")) .andExpect(model().attribute("message", "Hello World!")) } }
Kotlinでやった場合面倒だった点
アノテーションの補完ができない
これSpring全く関係ないけど、アノテーション多用するSpringで補完できないのはつらみしかない。
一応この問題チケット登録されているので、そのうち対応されると思われます→https://youtrack.jetbrains.com/issue/KT-5992
Autowiredなプロパティの定義
必ずオートワイヤされるプロパティは、nullになることはないからnull不許可な型で宣言したいんだけど、下のコードみたいに初期化しないといけなくってnullで初期化することでnull許可の型になってしまうのが残念な感じがありますね。
private [Autowired] val hello: HelloService? = null
これを使う箇所では、下のコードのように「!!」でnullだったら例外ぶん投げてくれるような実装にしたりする必要があってかなりあれ。
model.addAttribute("message", hello!!.getMessage())
プログラム内で参照するフィールドをnull不可な型にするには、下のコードのようにオートワイヤされるnull許可フィールドとは別にプログラム内で参照されるnull不可なフィールドを定義する必要があります。このコードでは、プログラム内で参照されるフィールドのアクセッサーで、nullの場合にはAssertionErrorをぶん投げるようにして、null不可な型を実現しています。
こんな面倒くさいコードをオートワイヤされるフィールドに対して毎回書くとかアホらしいので、これだったらnull許可型で「!!」書いたほうが楽な感じありますね。
private [Autowired] val _hello: HelloService? = null private val hello: HelloService get() = _hello ?: throw AssertionError() [RequestMapping(array("/"))] fun home(model: Model): String { model.addAttribute("message", hello.getMessage()) return "home/hello" }
ソースコード全量
siosio/SpringBoot-Kotlin · GitHubにおいてあります。
追記・・・
以下のアドバイスを受けてオートワイヤをフィールドではなくコンストラクタで行うようにしてみました。
これだと、上に書いたnull許容型にしたりなどがなくなるのでいい感じですね。修正したコードが、githubにあげてあります。
@_siosio_ Autowireするのはコンストラクタインジェクションが良いのでは?
— Toshiaki Maki (@making) 2014, 12月 3
はじめてのSpring Boot―「Spring Framework」で簡単Java (I/O BOOKS)
- 作者: 槙俊明
- 出版社/メーカー: 工学社
- 発売日: 2014/11
- メディア: 単行本
- この商品を含むブログ (1件) を見る
- 作者: Greg L. Turnquist
- 出版社/メーカー: Packt Publishing
- 発売日: 2014/11/27
- メディア: ペーパーバック
- この商品を含むブログを見る