Proper way for getting annotations of Java-Methods

2019-07-07 00:11发布

I try to write a custom Sonar-rule (Java) and struggle with the proper way for getting annotation of invoked Java methods. This rule should detect illegal access to methods and fields marked as @VisibleForTesting. Accesing such elements from production code is illegal, but access from the same class is legal. My first approach is to implement BaseTreeVisitor.visitMethodInvocation(MethodInvocationTree) and use the metadata of the belonging symbol:

  • get annotations: methodInvocationSymbol.metadata().annotations()
  • analyse the names of the symbols of each AnnotationInstance (annotations class) and its owner (annotations package)

This works great as long other classes invoke the method. When the call is made inside the same class - the annotations name and package are set to !unknownSymbol!.

I also tried an alternative approach: to analyse the IdentifierTree of the AnnotationTree (inside of BaseTreeVisitor.visitMethodInvocation(MethodInvocationTree)), but I could not find the way how to get the package name of the annotation.

I use sonar-java-plugin 3.7.1 and sonar-plugin-api 5.1.

The code is commited in this mvn / Eclipse project. The UnexpectedAccessCheckTest contains 2 use-cases. The "InvokedFromOtherClass" works well. The InvokedFromSameClass passes the test, but it happens only by accident - the annotation is not correctly detected. It produces this output:

[main] DEBUG d.t.s.p.vft.checks.IsAnAnnotation - Checking Annotation. 
    Expected [com.google.common.annotations.VisibleForTesting] 
    got [.!unknownSymbol!]

The correct running use-case produces this:

[main] DEBUG d.t.s.p.vft.checks.IsAnAnnotation - Checking Annotation. 
    Expected [com.google.common.annotations.VisibleForTesting] 
    got [com.google.common.annotations.VisibleForTesting]

Do you have any hint for me?

1条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-07-07 00:56

The first way is prefered and should work for every method call, even within the same class.

If it does not work it probably means that the method invoked is not resolved from semantic (which is why the symbol is set to unknown, the analyzer has some bugs regarding method calls when generics are involved). In order to point you out to the correct ticket, an example would be required.

Regarding your comment about the syntax tree : the identifier in the syntax tree won't contain information about the package (as its name gives it away, it concerns only syntax ;) ). However, you can use the following to find the type of the annotation from the source :

annotationTree.annotationType().symbolType().is("com.mypackage.MyAnnotation")

Make sure that the expected binary is in the Classpath while runnnig the scan (see sonar.java.binaries property, or usage of maven-dependency-plugin if you use Maven).

查看更多
登录 后发表回答