設定ファイル地獄という言葉がある。 設定中心のフレームワークが、設定だらけになって メンテナンスが地獄のように面倒になる現象だ。
ここで、アノテーションと呼ばれるものの登場である。
最初アノテーションと言う言葉を知ったときには、何につかうのか?と使い道が思いつかなかったのだが、どうやら、設定中心のフレームワークに応用すると、地獄から抜けられる。たとえば、Strutsに対するSAStrutsの登場である。
自分は、当初SAStrutsがあるんだから、それを使えばよいと思っていた。
しかしながら、SAStrutsは、独自の規約で作成しなくてはならないため、プロジェクトに応用できないということがわかってきた。
だったら、自分で道を切り開くのみである。
というわけで、以下アノテーションについてまとめてみた。
以下の方法を理解する。
最小限の学習ですむように説明するならば、 たとえば、 StringValueAnnotation というアノテーションを作りたいとすると下記のようになる。 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @interface StringValueAnnotation { String value() default "デフォルト値"; } その他は、固定値だと思って差しつかえない。
上記の例でTYPEとなっている箇所を FIELD に置き換えるだけでよい。
知りたいのは、実装するクラスの一覧であるが、どういうわけか Javaらしからず、そのような一覧取得のメソッドは用意されていない、 自分で道を切り開くのみである。
ソースフォルダを指定すると、クラス一覧を取得するメソッドを作製する。
package kuniwiki;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface ActionAnnotation {
String value1() default "";
String value2() default "";
String value3() default "";
}
package kuniwiki;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
public class AnnoMain {
public static void main(String[] args) throws IOException {
String basePath = "C:/bin/pleiades/workspace/prjAno/src";
FileSearch search = new FileSearch();
File[] files = search.listFiles(basePath, "*.java");
for(File f : files){
Class clazz = toClass(basePath, files[4]);
HashMap<String, HashMap<String, String>> ano = toAnoHash(clazz);
if (ano != null) {
System.out.println(ano.get("kuniwiki.ActionAnnotation").get("value1"));
System.out.println(ano.get("kuniwiki.ActionAnnotation").get("value2"));
System.out.println(ano.get("kuniwiki.ActionAnnotation").get("value3"));
}
}
}
private static HashMap toAnoHash(Class clazz) {
HashMap ret = new HashMap<String, HashMap<String, String>>();
Annotation[] as = clazz.getDeclaredAnnotations();
for (Annotation a : as) {
Class tp = a.annotationType();
// アノテーション名を登録;
HashMap<String, String> item = new HashMap<String, String>();
ret.put(a.annotationType().getName(), item);
// フィールドを追加
ActionAnnotation an = (ActionAnnotation)a;
//tp.getTypeParameters();
Method[] ms = an.getClass().getMethods();
//Annotation[][] ma = ms[0].getParameterAnnotations();
try {
Object[] param = {};
item.put(ms[4].getName(),ms[4].invoke(an, param).toString());
} catch (IllegalArgumentException e) {
// TODO
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO
e.printStackTrace();
}
// item.put("value1",Class.forName("kuniwiki.ActionAnnotation").cast(a).getClass().getFields()[0].toString());
}
return ret;
}
private static boolean hasActionAnnotation(Class clazz) {
Class ano = ActionAnnotation.class;
Annotation[] as = clazz.getDeclaredAnnotations();
for (Annotation a : as) {
if (a instanceof ActionAnnotation) {
return true;
}
}
return false;
}
private static Class toClass(String src, File fi) {
// ソースのパスを置換用に置き換える
String srcpath = src.replaceAll("/", "\\\\\\\\");
// ファイルの親パスからソースパスをさっぴいて、フォルダを意味する記号をドットに置き換え、ファイル名をクラス名として連結する。
String classname = fi.getParent().replaceFirst(srcpath, "")
.replaceAll("\\\\", ".").replaceFirst("\\.", "")
+ "." + fi.getName().replace(".java", "");
try {
System.out.println(classname);
return Class.forName(classname);
} catch (ClassNotFoundException e) {
return null;
}
}
}
http://sattontanabe.blog86.fc2.com/blog-entry-55.html
http://www.ne.jp/asahi/hishidama/home/tech/java/annotation.html