I am trying to write an annotation Procssor to detect the methods that are annotated with the @PrintMethod annotation. For example in the test Class below, i want to print the codes within the test Method. Is there a way to do it?
From the AnnotationProcessor class stated below, i am only able get the method name but not the details of the method.
Test Class
public class test {
public static void main(String[] args) {
System.out.println("Args");
}
@PrintMethod
private boolean testMethod(String input) {
if(input!=null) {
return true;
}
return false;
}
}
Annotation Processor Class
public class AnnotationProcessor extends AbstractProcessor {
//......
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
//retrieve test Anntoation
Set<? extends Element> ann =roundEnv.getElementsAnnotatedWith(PrintMethod.class);
//Print the Method Name
for(Element e: ann) {
String msg="Element ee :"+ee.getSimpleName().toString();
processingEnv.getMessager().printMessage( javax.tools.Diagnostic.Kind.ERROR, msg, e);
}
}
}
I was curious about this too so I decided to try and figure it out. Turns out to be easier than I expected. All you need to do is leverage the Trees
api out of the proprietary tools.jar library. I've made a quick annotation processor along these lines here: https://github.com/johncarl81/printMethod
Here's the meat of it:
@SupportedSourceVersion(SourceVersion.RELEASE_6)
@SupportedAnnotationTypes("org.printMethod.PrintMethod")
public class PrintMethodAnnotationProcessor extends AbstractProcessor {
private Trees trees;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
trees = Trees.instance(processingEnv); //initialize the Trees api.
}
@Override
public boolean process(Set<? extends TypeElement> typeElements, RoundEnvironment roundEnvironment) {
MethodPrintScanner visitor = new MethodPrintScanner();
for (Element e : roundEnvironment.getElementsAnnotatedWith(PrintMethod.class)) {
TreePath tp = trees.getPath(e);
// visit the annotated methods
visitor.scan(tp, trees);
}
return true;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
}
And the MethodPrintScanner
:
public class MethodPrintScanner extends TreePathScanner {
@Override
public Object visitMethod(MethodTree methodTree, Object o) {
System.out.println(methodTree);
return null;
}
}
You can see that we are able to visit the TreePath
associated with the given annotated Element. For each method, we simply println()
the methodTree
which gives us the contents of the method.
Using your example, here's the output of the program during compilation:
@PrintMethod()
private boolean testMethod(String input) {
if (input != null) {
return true;
}
return false;
}