--- title: Spring Framework 5のKotlinサポート tags: ["Spring Framework", "Kotlin", "Java"] categories: ["Programming", "Java", "org", "springframework"] date: 2017-02-05T08:09:27Z updated: 2017-02-05T08:11:46Z --- Spring 5でフレームワークのコア部分で[Kotlin対応](https://spring.io/blog/2017/01/04/introducing-kotlin-support-in-spring-framework-5-0)が入る。 Kotlinサポートのポイントは[Extension Functions](https://kotlinlang.org/docs/reference/extensions.html#extension-functions)と[Reified type parameters](https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters)。 Spring 5での対応がどのようなものを見る前に、この二つのKotlinの言語仕様を知っておくと理解しやすい。 次のJavaコードを例に簡単に説明する。 ``` java package com.example; public class Foo { public T create(Class clazz) { try { return clazz.newInstance(); } catch (Exception e) { throw new IllegalStateException(e); } } } ``` この機能をJavaで使うと ``` java Foo foo = new Foo(); Bar bar = foo.create(Bar.class); ``` となる。Javaユーザーにとっては特に違和感のない、よくある使い方の一つだと思う。 ではこのコードをそのままKotlinで書くとどうなるか。 ``` kotlin val foo = Foo() val bar = foo.create(Bar::class.java) ``` `Bar::class`で得られるのは`KClass`(`kotlin.reflect.KClass`)であり、`Class`(`java.lang.Class`)に変換するのに`.java`をつける必要がある。 このままでも使えないわけではないが、Javaで書くより簡単になってる?感が出てくる。 Kotlin対応していないJavaライブラリ、フレームワークとはこのような付き合い方になる。 ### Extension Functions ``` kotlin val bar = foo.create(Bar::class) ``` って書きたい。でもJavaフレームワーク側で直接Kotlinのクラスを使いたくない。 そんな時にKotlinの[Extension Functions](https://kotlinlang.org/docs/reference/extensions.html#extension-functions)が使うと、あたかも`Foo`クラスにメソッドを追加したかのように見せられる。 `FooExtensions.kt`というファイルに ``` kotlin package com.example import kotlin.reflect.KClass fun Foo.create(kclass: KClass) = create(kclass.java) ``` を書くと`Foo`クラスのメソッドとして`create(KClass)`を追加し、中で`java.lang.Class`に変換して`create(java.lang.Class)`を呼び出すことができる。 これで ``` kotlin val foo = Foo() val bar = foo.create(Bar::class) ``` と素直にKotlinコードを書くことができるようになる。 ### Reified type parameters もう一歩進もう。Kotlinには[Reified type parameters](https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters)という仕組みがあり、Javaではコンパイル時に消えてしまうジェネリクスの型を、inline展開することでコード中で参照することができる。ということはJavaでは書けなかった`T`をごにょごにょ...ってのが可能になり、メソッド引数から`Class`を消すことができる。 これを使って`FooExtensions.kt`に次のメソッドを追加する。 ``` kotlin inline fun Foo.create() = create(T::class.java) ``` これで ``` kotlin val foo = Foo() val bar = foo.create() ``` こう書ける。 あるいは左辺の型推論を使って ``` kotlin val foo = Foo() val bar: Bar = foo.create() ``` こう書くこともできる。 このようなコードが"idiomatic Kotlin code"(Kotlinらしいコード)と呼ばれる。 ### Spring 5の"idiomatic Kotlin code" Springユーザーならすでに気づいているかもしれないが、Springの中には`Class clazz`を引数に取るメソッドが多くある。 それらに対して上記のような`**Extensions.kt`が用意されている。外部ライブラリではなくSpring Framework本体に含まれているのである。 例えば、今まで書いていた ``` java ApplicationContext context = ...; Bar bar = context.getBean(Bar.class); ``` が ``` kotlin val bar = context.getBean(Bar::class) ``` こう書けるし ``` kotlin val bar = context.getBean() ``` こう書けるし ``` kotlin val bar: Bar = context.getBean() ``` こう書くこともできる。 今まで書いていた ``` java Long count = jdbcTemplate.queryForObject("SELECT count(*) FROM foo", Long.class); ``` が ``` kotlin val count = jdbcTemplate.queryForObject("SELECT count(*) FROM foo", Long::class) ``` こう書けるし ``` kotlin val count = jdbcTemplate.queryForObject("SELECT count(*) FROM foo") ``` こう書けるし ``` kotlin val count: Long = jdbcTemplate.queryForObject("SELECT count(*) FROM foo") ``` こう書くこともできる。 特に恩恵を受けるのは`RestTemplate`だろう。 ``` java String foo = restTemplate.getForObject("http://example.com", String.class); ``` が ``` kotlin val foo: String = restTemplate.getForObject("http://example.com") ``` 書けるのはわかった。 けれども、 ``` java List foos = restTemplate.exchange("http://api.example.com/foos", HttpMethod.GET, null, new ParameterizedTypeReference>() { }).getBody(); ``` これが ``` kotlin val foos: List = restTemplate.getForObject("http://api.example.com/foos") ``` こう書けるようになるのは素晴らしくないか。 Spring 5ではこのようなKotlinによる改善が至るところで利用できるようになる。 --- その他 * Functional Router Functions * Functional Bean Registration といった、Spring 5自体の全く新しい機能にも初めからKotlinのExtensionsが用意されているし、 `org.springframework.ui.Model`にArray like setterが追加され、 ``` java model.addAttribute("foo", foo); ``` を ``` kotlin model["foo"] = foo ``` と書けるようになったりする。 この記事を読んだ後なら https://spring.io/blog/2017/01/04/introducing-kotlin-support-in-spring-framework-5-0 を読めるようになっていると思う。 ちなみにKotlinのメソッドがデフォルトで`final`になるので`open`を明示的につけなけらばいけなかった問題は[kotlin-spring](https://spring.io/blog/2017/01/04/introducing-kotlin-support-in-spring-framework-5-0#no-need-to-declare-your-bean-class-as-open-anymore)プラグインで解決されている。 このあたりは[SPRING INITIALIZR](https://start.spring.io)でLanguageにKotlinを選択することで初めから設定済みになっている。 ![image](https://qiita-image-store.s3.amazonaws.com/0/1852/020a5106-02a5-786e-45df-d6565de572e7.png) なのですぐにSpring + Kotlinなアプリケーションを始めることができる。 Spring ❤️ Kotlin Spring 5に備えてKotlinを学んでおきたければKotlinスタートブック -新しいAndroidプログラミングがとっつきやすい。この記事で説明した[Extension Functions](https://kotlinlang.org/docs/reference/extensions.html#extension-functions)や[Reified type parameters](https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters)にも触れられている。 Kotlinスタートブック -新しいAndroidプログラミング