In this post let us discuss how to write a simple custom annotation processor in J2SE 6. Let us begin with our annotation Requirement which is very simple and has an id and description as below.
package com.ts.customannot;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Requirement {
String id();
String desc();
}
package com.ts.annot.target;
import com.ts.customannot.Requirement;
@Requirement(id="12",desc="student maintenance")
public class StudentService {
public String getStudentName(String id){
return "Student's Name";
}
}
Now let us write a custom annotation processor which will look for the annotation requirement and print the value of id and desc.
package com.ts.annot.processor;
import com.ts.customannot.Requirement;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
/**
*
* @author karthikeyanc
*/
@SupportedSourceVersion(SourceVersion.RELEASE_6)
@SupportedAnnotationTypes("com.ts.customannot.Requirement")
public class CustomProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (!roundEnv.processingOver()) {
try {
Class reqClass = Class.forName("com.ts.customannot.Requirement");
for (Element element : roundEnv.getRootElements()) {
Requirement reqObj = (Requirement) element.getAnnotation(reqClass);
if (reqObj != null) {
System.out.println(reqObj.id() + " : " + reqObj.desc());
}
}
} catch (Exception ex) {
Logger.getLogger(CustomProcessor.class.getName()).log(Level.SEVERE, null, ex);
}
}
return false; // No annotations claimed
}
}
We need to invoke this CustomProcessor. So let us write a Main class which will act as the starting point. The argument to this Main class will be the root source folder containing Java files.
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Main {
/**
* @param args the command line arguments arg[0] is the root src folder.
*/
public static void main(String[] args) {
try {
File srcFolder = new File(args[0]);
processFile(srcFolder);
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
private static void processFile(File file) throws IOException {
if (file.isDirectory()) {
for (File child : file.listFiles()) {
processFile(child);
}
processForAnnotation(file);
}
}
private static void processForAnnotation(File file) throws IOException {
String str = "javac -cp .\\build\\classes -processor com.ts.annot.processor.CustomProcessor -proc:only " + file.getAbsolutePath() + File.separator + "*.java";
//Just obtain and print the console output.
Process proc=Runtime.getRuntime().exec(str);
InputStream is=proc.getInputStream();
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String line=null;
while( (line=br.readLine())!=null){
System.out.println(line);
}
br.close();
}
}
Below is the screenshot of running Main and the output obtained [In my example args[0] is E:\javacode\netbeanscode\CustomAnnotationProcessor\src] where CustomAnnotationProcessor is the project root folder.
