リフレクションユーティリティを作る③

# はじめに
今回はアノテーションを利用したリフレクションです。
フィールドにちょっとした属性を持たせたいけど、ビジネスロジックに書くのは嫌だなぁ、というときにフィールドアノテーションが便利です。

前回作ったやつ→[オブジェクトのフィールドを適当な値で埋めるユーティリティ](https://qiita.com/atmospheri/items/9a8d9b969745e6248094)

# 今回作ったもの
今回はEntityオブジェクトをヨコ(CSVの1レコード)に変換するUtilメソッドを作りました。

- Dataアノテーション
- AnnotationUtilクラス
- Userクラス
- Mainクラス

# AnnotationUtil
getHeaderメソッドでヘッダ行を出力します。
getDataメソッドでデータ行を出力します。

```java:AnnotationUtil.java
package test1;
import java.lang.reflect.Field;

public class AnnotationUtil {
	/** カンマ */
	private static final String DELIMITER = ",";
	/** ダブルクォーテーション */
	private static final String QUOTE = "\"";

	/**
	 * UserをCSV1行に変換する。<br>
	 * Userが持つ@Dataが付与されたフィールドを、CSV1行にして返す。<br>
	 * isHeader=trueの場合はtitleを指定されたCSV形式で返す。
	 */
	public static String getUser(User obj, boolean isHeader, String delimiter, String quote) {
		Field[] fieldList = obj.getClass().getDeclaredFields();
		StringBuilder sb = new StringBuilder();

		for (Field f : fieldList) {
			f.setAccessible(true);
			Data annotation = f.getAnnotation(Data.class);
			if (annotation == null) {
				continue;
			}
			String value;
			try {
				if (isHeader) {
					value = annotation.title(); // タイトル
				} else {
					value = String.valueOf(f.get(obj)); // 値
				}
			} catch (IllegalArgumentException | IllegalAccessException e) {
				// throws宣言が面倒なので全部実行時例外にする
				throw new RuntimeException(e);
			}

			// 囲み文字に指定がある場合
			if (quote != null)
				sb.append(quote);
			// 値 or 項目名
			sb.append(value);
			// 囲み文字に指定がある場合
			if (quote != null)
				sb.append(quote);

			// 区切り文字
			sb.append(delimiter);
		}
		// 最後の区切り文字を削除
		sb.deleteCharAt(sb.length() - 1);

		return sb.toString();
	}

	public static String getHeader(User user) {
		return getUser(user, true, DELIMITER, QUOTE);
	}

	public static String getData(User user) {
		return getUser(user, false, DELIMITER, QUOTE);
	}
}
```

# Data
このアノテーションをCSVデータとして出力するフィールドに付与します。
titleでヘッダ名を指定します。

```java:Data.java
package test1;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Target(FIELD)
@Retention(RUNTIME)
public @interface Data {
	String title();
}
```

# User
Entityクラス。出力したいフィールドにDataアノテーションを付与します。

```java:User.java
package test1;

public class User {
	@Data(title = "社員ID")
	public Integer id;
	@Data(title = "名前")
	public String name;
	public String insertDate;
	public String insertUser;
	public String updateDate;
	public String updateUser;
}

```

# Main
ユーティリティの動作確認用。

```java:Main.java
package test1;

public class Main {
	public static void main(String[] args) {
		System.out.println("### Start ###");
		User user = new User();
		user.id = 101;
		user.name = "アルバート";
		user.insertDate = "20190501";
		user.insertUser = "クリス";
		user.updateDate = "20190512";
		user.updateUser = "ジル";

		System.out.println(AnnotationUtil.getHeader(user));
		System.out.println(AnnotationUtil.getData(user));
		System.out.println("### End ###");
	}

}
```

# 実行結果

```csv:
### Start ###
"社員ID","名前"
"101","アルバート"
### End ###
```

タテからヨコに変換されてますね。
idとnameのみにDataをつけているのでちゃんとその2つだけ出力されていますね。

# あとがき
最初、久しぶりにIDEを使用せずに実装してみたらなぜかField#getAnnotation()の戻り値がすべてNULLになった。IDE使用したらちゃんと動いたがなぜだろう？？