How to check if a Java annotation has a specific property using CodeQL?

325 Views Asked by At

Let's say we have the following piece of code:

public class Demo {
    @ABC(name = "abc")
    private String field1;

    @ABC
    private String field2;
}

@interface ABC {
    String name() default "";
}

How can I write a query that selects all the fields annotated with @ABC that does not have the name property?

There's getValue(string) method in Annotation object, but getValue("name") returns empty string for the annotation on field2 because it's the default value. But I am wondering how can I check if that property is even there, mentioned by the author.

1

There are 1 best solutions below

0
On

Unfortunately CodeQL does not provide any predicates for this out of the box (see also this related issue). However, you can exploit the fact that default value Expr does not seem to have a location in source (i.e. its getLocation() has a .class file location as result).

You could then have a utility predicate, such as the following, to detect whether an annotation has a default value for an element:

predicate hasDefaultValue(Annotation annotation, string elementName) {
  // If value file location is not the same as annotation file location, then most likely it
  // is the default value (unless there is a bug with the CodeQL extractor)
  annotation.getValue(elementName).getLocation().getFile() != annotation.getLocation().getFile()
}

But keep in mind that this behavior is not explicitly defined, and could change in the future, or bugs with the CodeQL extractor could cause false positives here. Additionally this does not work for annotations which occur in dependencies or the JDK, since the annotation itself is then not present in source either.