Java:パッケージに実行時取得可能情報を付加する
実行時にパッケージの情報を得たいと思う。そのパッケージが格納しているクラスが一口に言って、どのような内容であるかを実行時に得たい。
これを得ることによって、巨大なプログラムのデバッグが楽になる。ロギングを行っている場合に、注目すべきパッケージについてだけトレースをONにすることで、そのトレース情報を出力させるのだが、この場合に各パッケージが何をするものかを「実行時にその場で」把握できれば楽だろう。
※もちろん、javadocを作成し、それを見ながらということも可能は可能だが、パッケージの数が多い巨大なプロジェクトの場合にはやっていられない。
これを簡単に行う方法があったのである。これまで知らなかったのだが、パッケージにはアノテーションをつけることができ、そのアノテーションを実行時に取得することができるのだ。これは以下のように行う。
パッケージにのみつけられるアノテーションの定義
package packageTest;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PACKAGE)
public @interface PackageDesc {
public String summary();
public String desc() default "";
}
上記アノテーションをつけたpackage-info.java
/**
* これはテスト用パッケージ
*/
@PackageDesc(summary="test", desc="パッケージテスト")
package packageTest;
パッケージのアノテーションを読み出すプログラム
package packageTest;
public class Main {
void get(String packagename) {
// 指定されたパッケージの"package-info"につけられたPackageDescアノテーションがある場合に
// その内容を取得する
getPackageInfoClass(packageName)
.flatMap(this::getPackageDesc)
.ifPresent(pd-> {
// PackageDescを得られたので、その内容を処理する
});
}
/**
* "package-info"クラスの{@link PackageDesc}アノテーションを取得する
* @param packageInfoClass "package-info"クラス
* @return {@link PackageDesc}アノテーション、あるいは空
*/
Optional<PackageDesc>getPackageDesc(Class<?>packageInfoClass) {
Package pkg = packageInfoClass.getClassLoader()
.getDefinedPackage(packageInfoClass.getPackageName());
return Optional.ofNullable((PackageDesc)pkg.getAnnotation(PackageDesc.class));
}
/**
* 指定されたパッケージ名称のpackage-infoクラスを取得する。
* <p>
* 例えば"foo.bar"パッケージが指定されたら、"foo.bar.package-info"クラスを取得する
* </p>
* @param packageName パッケージ名称
* @return "package-info"クラス、あるいは空
*/
Optional<Class<?>>getPackageInfoClass(String packageName) {
try {
return Optional.of( Class.forName(packageName+".package-info"));
} catch (ClassNotFoundException ex) {
return Optional.empty();
}
}
}