EnumとキャストでInvokeしまくるソースよりは・・・
Strutsの様にその実装をXMLで隠蔽した方が数段マシ。
しかし、StrutsのXMLよりは・・・
SpringというかJAX-RSのアノテーションを使った方がマシ。
とは云うものの自分でアノテーションを書く機会がほとんどなく、すっかり忘れてしまったので
また調べてみた。
Java 独自のアノテーションを作成して値を取得するサンプル
がレイアウトが見やすく、サンプルで使い方を説明していて好感が持てた。
しかし、実際に使うにはサンプルのクラスの中が混ざりすぎ、更に調べてみると
Java Java リフレクションとアノテーションを組み合わせて使用する
の記事が、そのまま使えそう風のサンプル・ソースが付いていたが、特定のクラスしか調べられない。
なので更に調べてみた。
java パッケージ配下のクラス一覧を取得 外部ライブラリは使用しない
特定のパッケージのみだが、そこにあるクラスをザザっと調べるので、使えそう。
ここで、2番目の記事のソースのReflectionUtil.output(Object obj) { … } のパラメータを Class<?> cc に変えてみたバージョンを追加。
途中で後悔しそうになったけど、
Eclipseのエラった時のヘルプの誘導でクリアできた。
書き込んだアノテーションは全部列挙するようになっている(ハズ
でも、f.get(cc.newInstance()); の部分はどうにかならないかな?(と思っている。
途中で本当にドン詰まりになってしまってから・・・
「プロジェクトのJavaのランタイムがJDK5」のままだったことに気が付き、
JDK8に切り替えたので、そこまでの部分は無駄が多いかもしれない。
public static void output(Class<?> cc) { if (cc == null) { return; } System.out.println("クラス名:" + cc.getName() + "{"); Field[] fieldList = cc.getDeclaredFields(); for (Field f : fieldList) { f.setAccessible(true); String name = f.getName(); System.out.print(" プロパティ名:" + name + " "); try { /*Object fieldObj =*/ f.get(cc.newInstance()); } catch (IllegalArgumentException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } catch (IllegalAccessException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } catch (InstantiationException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } // RetentionPolicy.RUNTIME以外はここがnullになります。 if (f.getAnnotation(CustomAnnotation.class) != null) { Annotation[] anoLst = f.getAnnotations(); for (Annotation ano : anoLst) { Annotation element = f.getAnnotation(ano.annotationType()); System.out.print(" " + " アノテーションの設定値:" + f.getAnnotation(CustomAnnotation.class)); } } System.out.println(""); } System.out.println("}"); }
これを3番目の記事のソースからちょっこと呼び出してみる。
public static void main(String... args) throws Exception { String packageName = PK_NAME; List<Class<?>> classes = getClasses(packageName); for (Class<?> class1 : classes) { System.out.println(class1.getName()); //ここから Class<?> cc = Class.forName(class1.getName()); ReflectionUtil.output(cc); //ここまで } }
でも、配下のパッケージとかも対象にして欲しかったのでちょっと追記してみた。
// ディレクトリ配下のファイル数分ループ for (String path : dir.list()) { // ".class"で終わるファイルのみ返却用のリストに追加 if (path.endsWith(".class")) { classes.add(Class.forName(packageName + "." + path.substring(0, path.length() - 6))); // } /* ここから */ else { // サブ・パッケージ classes.addAll(getClasses(packageName + "." + path)); } // ここまで }
そして実行結果
※検索するパッケージのパスはSampleに変えてあります。
Sample.CustomAnnotation クラス名:Sample.CustomAnnotation{ } Sample.demo1.Hoge2 クラス名:Sample.demo1.Hoge2{ プロパティ名:name アノテーションの設定値:@Sample.CustomAnnotation(value=aaaa) プロパティ名:value アノテーションの設定値:@Sample.CustomAnnotation(value=bbbb) } Sample.GetClassList クラス名:Sample.GetClassList{ メソッド名:PK_NAME } Sample.Hoge クラス名:Sample.Hoge{ プロパティ名:name アノテーションの設定値:@Sample.CustomAnnotation(value=aaaa) プロパティ名:value アノテーションの設定値:@Sample.CustomAnnotation(value=bbbb) } Sample.ReflectionUtil クラス名:Sample.ReflectionUtil{ } Sample.TestMain クラス名:Sample.TestMain{ }
まだ、調査が甘いけど、アノテーションを使ったワークフレームの雰囲気をちょっとだけ触れた気がしてきた。
もっと理解が進めば、WEBアプリのワークフレームやJUnitモドキを作れるようになれるのかな?(大笑
しかし、一番気になるのはSpringとかアノテーションをたっぷり使ったワークフレームのサンプルだったら、実行やデバッグの準備に半日(かな漢変換すると「反日」がデフォな変な日本語IMEだな)かかったりするんだよね(大笑
やっぱり実装はEnumとキャストでInvokeしまくってるか?良くてもジネリックな<?>や<T>な?ソースだろうから、依存パッケージの微妙なバージョンの違いで、微妙な実行結果が出てしまうんだろうな・・・(トホホ
上のソースにも Class> cc) なんて書いてしまってるけど、これなんかはJDKのアップデートが来ただけで、動かなくなることは十分にあり得る。(と思う。
※ソース中の < や > が < や &rt; に化けていたので修正。
※ソース中の メソッド名を プロパティ名に 訂正。
メソッドとプロパティって内包するデータの構造がチョット違う程度なので、今でも同じに見えてしまう。
C言語のStructやClassがJavaではみんなClassな様に、だったらJavaのEnumやinterfaceもClassしても良さそうなものだが、実行時の事前分析がとてもメンドクサイことになり起動がもっともっさりしてしまうに違いない。