Javassistで対象クラスのアノテーション情報を取得
Javassitはいわゆるバイトコード操作ライブラリですが、クラスの解析も出来るんじゃないかなと思いました。
ということで、やってみた記事になります。
解析対象クラス
このクラスのメソッドに付与されているアノテーションを取得してみます。
雑いテストクラスで正直すまんこってす。
package oreore.tool.detector.target; public class Target { Date date; LocalDate localDate; @Deprecated public Date getDate() { return date; } @Transient public void setDate(Date date) { this.date = date; } @Addressing public LocalDate getLocalDate() { return localDate; } public void setLocalDate(LocalDate localDate) { this.localDate = localDate; } }
アノテーションを解析するクラス
ちょっとOOPっぽい形にしてみました。
まず親がこれ。
public abstract class Detector { CtClass loadClass(final String fqcn) { ClassPool classPool = ClassPool.getDefault(); CtClass ctClass = null; try { ctClass = classPool.get(fqcn); } catch (NotFoundException e) { e.printStackTrace(); } return ctClass; } protected abstract DetectorResult analyze(final CtClass ctClass, final DetectorResult detectorResult); public DetectorResult invoke(final String fqcn) { final CtClass ctClass = loadClass(fqcn); final DetectorResult detectorResult = new DetectorResult(); analyze(ctClass, detectorResult); return detectorResult; } public static class DetectorResult { private Map<String, Object> information = new HashMap<>(); public Map<String, Object> getInformation() { return information; } public void addInformation(final String key, final List list) { this.information.put(key, list); } } }
そして、アノテーション解析するクラスです。
こいつの中にpsmvを定義しているのはご愛嬌。(面倒くさかっただけともいう)
public class AnnotationDetector extends Detector { @Override protected DetectorResult analyze(CtClass ctClass, DetectorResult detectorResult) { final Stream<CtMethod> ctMethodStream = Arrays.stream(ctClass.getMethods()); ctMethodStream.forEach(method -> { try { final List<Object> annotations = Arrays.asList(method.getAnnotations()); detectorResult.addInformation(method.getName(), annotations); } catch (ClassNotFoundException e) { e.printStackTrace(); } }); return detectorResult; } public static void main(String[] args) { final Detector annotationDetector = new AnnotationDetector(); final DetectorResult result = annotationDetector.invoke("oreore.tool.detector.target.Target"); for (Map.Entry<String, Object> entry: result.getInformation().entrySet()) { System.out.println(entry.getKey() + " : " + entry.getValue()); } } }
実行結果
ふむ。
getClass : [] wait : [] notifyAll : [] notify : [] getLocalDate : [@javax.xml.ws.soap.Addressing] setLocalDate : [] hashCode : [] equals : [] clone : [] setDate : [@java.beans.Transient] finalize : [] toString : [] getDate : [@java.lang.Deprecated]
まとめ
JavaのReflection APIでも同様の事が出来るらしいので、わざわざJavassistを使う必要はないと思います。 解析結果に基づいて元クラスにごにょごにょするようなユースケースがあればJavassistの出番ではないでしょうか。