Java(JavaEE)をやりだして半年ぐらいたつんですが、個人的に鬼門だとおもっていたのが下記内容です。
- MVCではないコンポーネントの考え方
- クラスを使ったジェネリクスの使い方(型パラメータなど)
- リフレクション
- スコープアノテーション
- アノテーション
あとは単純にglassfishが遅いことですかね(汗)これは解決できそうにありませんが・・
ようやく少しずつ慣れてきたんですが5がいまだにわかっておらず、頭にもやもやとしたものがたまっていました。
以前にも一応記事は書いていたんですけどね・・・ようわかってなかったんで(汗)
今回、アノテーションを何とか使うことができ、少し理解がすすんだのでメモしておきます。
Contents
アノテーションとは
定義はいまだによくわかっていません(汗)
メソッドやフィールドにコメント的につけることで属性を付加させる仕組みかな?
こんな説明を読んでも全く分からないですね(汗)
私もいままでたくさんの説明をいろいろと呼んだんですが、ようわかりませんでした。
おそらくサンプルや実際のソースを大量にみて覚えるのが一番だと思います。
わかりやすい具体例としてはオーバーライドするメソッドには@Overrideなど書くことが一般的です。
あとは非推奨のメソッドのところに@Deprecatedなど書いたりとか。
すでにJavaに標準で用意されているアノテーションはいっぱいあるのですが、独自にアノテーションをつくることもできます。
作るケースとしては画面からの入力のエラーチェックが一番わかりやすいですかね。
name,age,emailみたいなフィールドがあって必須やエラーチェックを行いたい場合、@NotNullとか作って設定しておけばnullだった場合にエラーメッセージを吐く、こんなことができます。
上記のものはBeanValidationとしてすでにありますが・・・
今回私がやろうとしたのは
- CSVをMapでとりこむ(1行目が日本語のヘッダ、それ以降がデータ)
- Mapをクラスに格納する
っていう単純な処理なんです。
具体例を挙げますと、
CSVで
番号 名前 年齢
1 松本 35
とか書いてあるやつをMapにそのまま
“番号”=>”1”
“名前”=>”松本”
“年齢”=>35
と保存しておき、これを
public class Person{
private String id;
private String name;
private String age;
みたいなクラスに格納するってことです。
このMapからクラスへの変換の際にアノテーションを使ってみました。普通にヘッダーで変数名のList渡せば一発なんですけどね・・・まあ勉強もかねて。
要は日本語と変数名(英名)の対応ですね。あと必須項目フラグもいれたかったので。
ソース
ソースは主に3か所です。
- アノテーション自体の定義
- アノテーションを付加させる
- アノテーションで実際に処理を行う
です。
まずアノテーション自体の定義を下記のように行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Documented //ドキュメント化させたい場合に付与 @Target(ElementType.FIELD)//アノテーションを付ける対象を記述できます。フィールド、メソッド、関数の3種類 @Retention(RetentionPolicy.RUNTIME)//アノテーションの有効範囲です。コンパイル時なのか実行時なのかなど public @interface Mapping{ /** * CSVヘッダーの和名 * * @return 和名 */ String csvField() default ""; /** * 必須フラグ * * @return true(必須)/false(不必要) */ boolean isRequired() default false; } |
アノテーションを付加
Mapから変換させたいクラスに下記の用につけます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import lombok.Getter; import lombok.Setter; public class Person { @Getter @Setter @Mapping(csvField = "番号" ,isRequired = true) private String id; @Getter @Setter @Mapping(csvField = "名前") private String name; @Getter @Setter @Mapping(csvField = "年齢") private String age; public Person(){ } } |
実際にMapからクラスにデータをコンバートする部分です。csvMapというのが<String,String>型のMapでここにすでにデータが入っているものとします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
Person person = new Person(); Field[] fields = Person.class.getDeclaredFields(); List<Field> fieldList = Arrays.asList(fields); csvData.entrySet().stream().forEach((csvEntry) -> { String csvFieldName = csvEntry.getKey(); String csvValue = csvEntry.getValue(); try { for (Field field : fieldList) { //フィールドに付加されているアノテーションを取り出しキャスト Mapping map = (Mapping) field.getAnnotation(Mapping.class); //格納されている値を取り出せる String propDispName = map.csvField(); //Mapの和名と一緒かどうかの判定 if (propDispName.equals(csvFieldName)) { //必須チェック if (Person.isRequired() && StringUtils.isBlank(csvValue)) { throw new IllegalArgumentException("必要なパラメーターがありません フィールド名: " + csvFieldName); } //オブジェクトに格納 PropertyUtils.setProperty(Person, field.getName(), csvValue); } } } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException | IllegalArgumentException ex) { Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex); } }); |
現物はもっと複雑なデータで、ブログアップの際に手直ししているんで動かなかったらすいません(笑)
ポイントとしては
- フィールドを取り出す
- そのフィールドに付加されているアノテーションをキャスト
- プロパティの取り出し
になります。
今回は非常に簡単な例でしたが、活用するともっといろいろところで使えそうですね。