Springの@ValueでString型のデフォルト値をnullにする方法

Spring Frameworkでは、プロパティ値(プロパティファイルやシステムプロパティの値)を取得する場合に`@org.springframework.beans.factory.annotation.Value`アノテーションを使うことができます。`@Value`はキーがない時のデフォルト値を指定することができますが、String型のデフォルト値を`null`にするにはちょっとした工夫が必要です。

# まずは、デフォルト値を指定してみる・・・

デフォルト値を指定する場合は、`@Value("${キー名:デフォルト値}")`という形式で指定します。

```java
package com.example;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
    @Component
    static class MyCommandLineRunner implements CommandLineRunner {
        @Value("${value:01}")
        String value;

        @Override
        public void run(String... args) throws Exception {
            System.out.println(value == null);
            System.out.println("value : " + value);
        }
    }
}
```

```text:コンソール
false
value : 01
```

# ちなみにキーだけ指定してみると・・・

```java
@Value("${value}")
String value;
```

```text:コンソール
...
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'value' in string value "${value}"
	at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174) ~[spring-core-4.3.0.RELEASE.jar:4.3.0.RELEASE]
```

キーがみつからないと、そんなプロパティないよ〜というエラーになります。

# じゃあ、デフォルト値を空にしてみると・・・

```java
@Value("${value:}")
String value;
```

```text:コンソール
false
value :
```

`null`ではなく空文字になります。

# それじゃ〜、デフォルト値に`null`を指定すると・・・

```java
@Value("${value:null}")
String value;
```

```text:コンソール
false
value : null
```

当たり前ですが・・・`null`という文字列が設定されます。

# で・・・結局どうすればいいのかというと・・・・

デフォルト値に、SpELを使って`null`値を指定すれば`null`値が設定できます。（他にやり方あるのかな〜）
SpELは、「`#{SpEL}`」という形式で指定します。

```java
@Value("${value:#{null}}")
String value;
```

```text:コンソール
true
value : null
```

# `java.util.Optional`も使えるよ :wink: 

キーがない場合(＝値が`null`の場合)に、状況によってデフォルト値を切り替えたりエラーにしたい場合は、Java SE 8から追加された`Optional`として扱うとよい気がします。

```java
@Value("${value:#{null}}")
Optional<String> value;

@Override
public void run(String... args) throws Exception {
    System.out.println("value : " + value.orElse("default1"));
    System.out.println("value : " + value.orElse("default2"));
    value.orElseThrow(() -> new IllegalStateException("value is required"));
}
```

```text:コンソール

value : default1
value : default2
2016-08-07 12:55:11.833 ERROR 48919 --- [           main] o.s.boot.SpringApplication               : Application startup failed

java.lang.IllegalStateException: Failed to execute CommandLineRunner
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:803) [spring-boot-1.3.7.RELEASE.jar:1.3.7.RELEASE]
...
Caused by: java.lang.IllegalStateException: value is required
	at com.example.DemoApplication$MyCommandLineRunner.lambda$run$0(DemoApplication.java:27) ~[classes/:na]
```

# 文字列以外は・・・

文字列以外であれば、SpELを使わなくてもデフォルト値を空にしておけば、`null`値になります。ただし・・・`int`などのプリミティブ型の場合は型変換エラーになるので悪しからず・・・

```java
@Value("${value:}")
Integer value;
```

# まとめ

特にまとめることはありませんが、ちょっとした豆知識の共有でした。
なお、Spring Bootユーザーは、`@Value`ではなく「[Type-safe Configuration Properties](http://docs.spring.io/spring-boot/docs/1.4.0.RELEASE/reference/htmlsingle/#boot-features-external-config-typesafe-configuration-properties)」を使いましょう！！ キーがなければBeanのプロパティに指定した値がデフォルト値として扱われるので、本投稿で紹介したような豆知識も不要です :smile: