Annotation Processing中は対象のクラスはプロセッサー側のClassLoaderに読み込まれていないので、この方法でClassを取得することはできません
# ElementからClassを取得する
- Type Element(クラスのElement)ならそのElementのClass
- Variable Element(フィールド/enum定数等の変数)ならその変数の型のClass
を取得します。
他にも3種類ほどElementがありますが、未検証&そこからClassを取得する必要が無さそうなので書いていません。
仕組みなんてどうでもいい、とりあえず動けばいい!って人はこちらのコードをどうぞ。
適当なところにコピペして使ってください。
fun Element.getDeclaredClass(): Class<*> = ((asType() as DeclaredType).asElement() as TypeElement).qualifiedName.let { name -> ClassLoader.getSystemClassLoader().loadClass(name.toString())}
Elementの拡張関数なので、roundEnv.getElementsAnnotatedWith()
あたりから取ってきたElementからそのままgetDeclaredClass()を呼び出して使います。
## ElementからClassを取得するためのプロセス
1. Element#asType()
を呼び出して型のTypeMirrorを取得する。
2. 取得した値をDeclaredTypeにキャストする。
3. DeclaredType#asElement()
を呼び出して型のElementを取得する。
4. 取得した値をTypeElementにキャストする
5. TypeElementからクラスのバイナリ名(完全修飾名)を取得する
6. ClassLoaderからバイナリ名を用いてClassを取得する
結局Elementから直接Classに変換出来ないんですよね。
ClassLoaderを通してClassを取得することになります。
Element#asType
について。JavaDocには
> この要素で定義された型を返します。
と書いてあります。
これは、Variable Elementならその変数の型、Type ElementならそのElement自身が表す型を返します。
ちなみに3で取得したElementは最初のElementと同一のものなので、Type Elementの場合は1~4をすっ飛ばして5,6だけで十分でしょう。
1~4がVariable Elementから型のType Elementを取得する方法
5~6がType ElementからClassを取得する方法
になりますね。
コードにしてみる
実際に書いたコードがこちら
fun Element.getDeclaredClass(): Class<*> {
return ((asType() as DeclaredType).asElement() as TypeElement).qualifiedName.let { name ->
ClassLoader.getSystemClassLoader().loadClass(name.toString())
}
}
Javaで書くならこうでしょうか。
public Class<?> getDEclaredClass(Element element) {
String name = ((TypeElement)((DeclaredType)element.asType()).asElement()).getQualifiedName().toString()
return ClassLoader.getSystemClassLoader().loadClass(name)
}