---
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> T create(Class<T> 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<Bar>`(`kotlin.reflect.KClass`)であり、`Class<Bar>`(`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 <T : Any> Foo.create(kclass: KClass<T>) = create(kclass.java)
```

を書くと`Foo`クラスのメソッドとして`create(KClass<T>)`を追加し、中で`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 <reified T : Any> Foo.create() = create(T::class.java)
```

これで

``` kotlin
val foo = Foo()
val bar = foo.create<Bar>()
```

こう書ける。

あるいは左辺の型推論を使って

``` kotlin
val foo = Foo()
val bar: Bar = foo.create()
```

こう書くこともできる。

このようなコードが"idiomatic Kotlin code"(Kotlinらしいコード)と呼ばれる。

### Spring 5の"idiomatic Kotlin code"

Springユーザーならすでに気づいているかもしれないが、Springの中には`Class<T> 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<Bean>()
```

こう書けるし

``` 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<Long>("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<Foo> foos = restTemplate.exchange("http://api.example.com/foos", HttpMethod.GET, null, new ParameterizedTypeReference<List<Foo>>() { }).getBody();
```

これが

``` kotlin
val foos: List<Foo> = 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を学んでおきたければ<a href="http://www.amazon.co.jp/exec/obidos/ASIN/4865940391/ikam-22/ref=nosim/" name="amazletlink" target="_blank">Kotlinスタートブック -新しいAndroidプログラミング</a>がとっつきやすい。この記事で説明した[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)にも触れられている。

<a href="http://www.amazon.co.jp/exec/obidos/ASIN/4865940391/ikam-22/ref=nosim/" name="amazletlink" target="_blank"><img src="https://images-fe.ssl-images-amazon.com/images/I/51HzwN0d1iL._SL160_.jpg" alt="Kotlinスタートブック -新しいAndroidプログラミング" style="border: none;" /></a>
