HandleableProcessor.javaクラスを変更して次のコードを追加します。変更を保存します。
package proc;
import ann.Handleable;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
@SupportedAnnotationTypes("ann.Handleable")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class HandleableProcessor extends AbstractProcessor {
/** public for ServiceLoader */
public HandleableProcessor() {
}
public boolean process(Set annotations,
RoundEnvironment roundEnv) {
for (Element e : roundEnv.getElementsAnnotatedWith(Handleable.class)) {
if (e.getKind() != ElementKind.FIELD) {
processingEnv.getMessager().printMessage(
Diagnostic.Kind.WARNING,
"Not a field", e);
continue;
}
String name = capitalize(e.getSimpleName().toString());
TypeElement clazz = (TypeElement) e.getEnclosingElement();
try {
JavaFileObject f = processingEnv.getFiler().
createSourceFile(clazz.getQualifiedName() + "Extras");
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
"Creating " + f.toUri());
Writer w = f.openWriter();
try {
PrintWriter pw = new PrintWriter(w);
pw.println("package "
+ clazz.getEnclosingElement().getSimpleName() + ";");
pw.println("public abstract class "
+ clazz.getSimpleName() + "Extras {");
pw.println(" protected " + clazz.getSimpleName()
+ "Extras() {}");
TypeMirror type = e.asType();
pw.println(" /** Handle something. */");
pw.println(" protected final void handle" + name
+ "(" + type + " value) {");
pw.println(" System.out.println(value);");
pw.println(" }");
pw.println("}");
pw.flush();
} finally {
w.close();
}
} catch (IOException x) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
x.toString());
}
}
return true;
}
private static String capitalize(String name) {
char[] c = name.toCharArray();
c[0] = Character.toUpperCase(c[0]);
return new String(c);
}
}
ここで、注釈プロセッサのコードを構成する主要な部分について少し詳しく見てみます(便宜上、コードの一部しか示されていないことに注意してください)。
最初に、注釈プロセッサでサポートされている注釈型(@SupportedAnnotationTypesを使用)と、サポートされているソース・ファイルのバージョン(@SupportedSourceVersionを使用。この場合のバージョンはJDK 6)を指定します。
@SupportedAnnotationTypes("ann.Handleable")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
次に、javax.annotation.processingパッケージのAbstractProcessorクラスを拡張する、このプロセッサのための公開クラスを宣言します。AbstractProcessorは、注釈を処理するために必要なメソッドを含む、具象注釈プロセッサの標準スーパー・クラスです。
public class HandleableProcessor extends AbstractProcessor {
...
}
ここで、このクラスのpublicコンストラクタを指定する必要があります。
public class HandleableProcessor extends AbstractProcessor {
public HandleableProcessor() {
}
...
}
次に、親AbstractProcessorクラスのprocess()メソッドをコールします。このメソッドを通して、処理対象の注釈が提供されます。また、このメソッドには、処理のラウンドについての情報も含まれています。
public class HandleableProcessor extends AbstractProcessor {
...
public boolean process(Set annotations,
RoundEnvironment roundEnv) {
...
}
}
注釈プロセッサのロジックは、AbstractProcessorクラスのprocess()メソッド内に含まれています。AbstractProcessorを通してProcessingEnvironmentのインタフェースにもアクセスすることにより、注釈プロセッサはFiler(注釈プロセッサが新しいファイルを作成できるようになるファイラ・ハンドラ)やMessager(注釈プロセッサがエラーを報告する手段)のような複数の便利な機能を使用できるようになります。
public class HandleableProcessor extends AbstractProcessor {
...
public boolean process(Set annotations,
RoundEnvironment roundEnv) {
//For each element annotated with the Handleable annotation
for (Element e : roundEnv.getElementsAnnotatedWith(Handleable.class)) {
//Check if the type of the annotated element is not a field. If yes, return a warning.
if (e.getKind() != ElementKind.FIELD) {
processingEnv.getMessager().printMessage(
Diagnostic.Kind.WARNING,
"Not a field", e);
continue;
}
//Define the following variables: name and clazz.
String name = capitalize(e.getSimpleName().toString());
TypeElement clazz = (TypeElement) e.getEnclosingElement();
//Generate a source file with a specified class name.
try {
JavaFileObject f = processingEnv.getFiler().
createSourceFile(clazz.getQualifiedName() + "Extras");
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
"Creating " + f.toUri());
Writer w = f.openWriter();
//Add the content to the newly generated file.
try {
PrintWriter pw = new PrintWriter(w);
pw.println("package "
+ clazz.getEnclosingElement().getSimpleName() + ";");
pw.println("public abstract class "
+ clazz.getSimpleName() + "Extras {");
pw.println(" protected " + clazz.getSimpleName()
+ "Extras() {}");
TypeMirror type = e.asType();
pw.println(" /** Handle something. */");
pw.println(" protected final void handle" + name
+ "(" + type + " value) {");
pw.println(" System.out.println(value);");
pw.println(" }");
pw.println("}");
pw.flush();
} finally {
w.close();
}
} catch (IOException x) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
x.toString());
}
}
return true;
}
...
}
このコードの最後のブロックでは、注釈付き要素の名前を大文字にするために使用されるcapitalizeメソッドを宣言しています。
public class HandleableProcessor extends AbstractProcessor {
...
private static String capitalize(String name) {
char[] c = name.toCharArray();
c[0] = Character.toUpperCase(c[0]);
return new String(c);
}
}