Even though my question origins from annotation processing, my question is more Java annotation related.
I was writing some code until I realised I didn't know a good way to implement something.
The program uses annotation-processing, I'm trying to get the value of multiple JAX-RS annotations, let's take @PathParam
and @QueryParam
as example. Both annotations have the abstract method called value()
The following piece of code is an example of how I do not want to write it. I'd have to do this for each JAX-RS annotation.
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for(Element element : roundEnv.getElementsAnnotatedWith(PathParam.class)) {
PathParam parameter = element.getAnnotation(PathParam.class);
String value = parameter.value();
// Process data & more program code.
}
for(Element element : roundEnv.getElementsAnnotatedWith(QueryParam.class)) {
QueryParam parameter = element.getAnnotation(QueryParam.class);
String value = parameter.value();
// Process data & more program code.
}
// Etc... do the same for other JAX-RS annotations.
return true;
}
I know with abstract classes you can do the following:
abstract class Animal {
abstract String name();
}
class Dog extends Animal {
public String name() {
return "Dog";
}
}
class Cat extends Animal {
public String name() {
return "Cat";
}
}
Animal animal = new Cat();
System.out.println(animal.name()); // Prints 'Cat'
animal = new Dog();
System.out.println(animal.name()); // Prints 'Dog'
But I'm not sure how to accomplish a similar thing using annotation since there is no superclass which it can be cast to. I'm imagining it should be something along the lines of this:
ArrayList<Class<? extends Annotation>> annotationsToCheck =
new ArrayList<>(Arrays.asList(PathParam.class, QueryParam.class));
for(Class<? extends Annotation> annotationToCheck : annotationsToCheck) {
for(Element element : roundEnv.getElementsAnnotatedWith(annotationToCheck)) {
// Somehow cast it to something so that the value() method can be accessed
// Process data & more program code.
}
}
I feel like I'm close but I just can't quite put my finger on it. Is there a good way to solve my problem?
In Java 9+, no casting is needed:
for (Element element : roundEnv.getElementsAnnotatedWithAny(Set.of(PathParam.class,
QueryParam.class))) {
PathParam pathParam = element.getAnnotation(PathParam.class);
if (pathParam != null) {
String value = pathParam.value();
// Process @PathParam value
}
QueryParam queryParam = element.getAnnotation(QueryParam.class);
if (queryParam != null) {
String value = queryParam.value();
// Process @QueryParam value
}
}
Or, if you only expect one of them:
for (Element element : roundEnv.getElementsAnnotatedWithAny(Set.of(PathParam.class,
QueryParam.class))) {
String value = null;
PathParam pathParam = null;
QueryParam queryParam = null;
if ((pathParam = element.getAnnotation(PathParam.class)) != null) {
value = pathParam.value();
} else if ((queryParam = element.getAnnotation(QueryParam.class)) != null) {
value = queryParam.value();
}
// Process value. Exactly one of pathParam and queryParam will be non-null
}