I have a simple, but incredibly ugly looking method. The issue I am having is that I feel this can be done a million times more elegantly. In addition, I would also like to scan a method for more than one annotation, and not just the Rest endpoint declarations.
I feel this can be done through a stream of Annotations[] (method.getDeclaredAnnotations())
and filtered by a List<Annotation> restEndpointAnnotationsAndOtherAnnotations
, but I cannot seem to get it to work.
Any help would be greatly appreciated. I think it's probably a fairly fun challenge for some people. The primary issue I am getting (I think) is trying to convert Class<? extends Annotation>
to Annotation
, but perhaps I am missing the mark.
public RestEndpoint mapToRestEndpoint(Method method) {
String url = null;
if (method.isAnnotationPresent(GetMapping.class)) {
url = method.getAnnotation(GetMapping.class).value()[0];
} else
if (method.isAnnotationPresent(PutMapping.class)) {
url = method.getAnnotation(PutMapping.class).value()[0];
} else
if (method.isAnnotationPresent(PostMapping.class)) {
url = method.getAnnotation(PostMapping.class).value()[0];
} else
if (method.isAnnotationPresent(PatchMapping.class)) {
url = method.getAnnotation(PatchMapping.class).value()[0];
} else
if (method.isAnnotationPresent(DeleteMapping.class)) {
url = method.getAnnotation(DeleteMapping.class).value()[0];
} else
if (method.isAnnotationPresent(RequestMapping.class)) {
url = method.getAnnotation(RequestMapping.class).value()[0];
} else return null;
return new RestEndpoint(url, true);
}
Where RestEndpoint is a simple POJO
@Value
public class RestEndpoint {
@NonNull String endpoint;
boolean isPublic;
}
I can actually find where it matches the Rest mapping using streams, but I cannot then apply the .value()
method to it (since it doesn't know what annotation it is, and would be just as tedious to then cast to multiple annotation types)
EDIT: This is a pretty handy way of getting the information on methods if anyone is interested.
ApplicationContext context = ((ContextRefreshedEvent) event).getApplicationContext();
context.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();
Problem is in getAnnotation
as it need concrete annotation class to know that it has somethings like value()
. You can create helper method that try to invoke value()
on given object and do other parsing.
private String getUrl(Method method, Class<? extends Annotation> annotationClass){
Annotation annotation = method.getAnnotation(annotationClass);
String[] value;
try {
value = (String[])annotationClass.getMethod("value").invoke(annotation);
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
return null;
}
return value[0];
}
Then use it like this:
String url = Stream.of(
GetMapping.class, PutMapping.class, PostMapping.class, PatchMapping.class, DeleteMapping.class, RequestMapping.class)
.filter(clazz -> method.isAnnotationPresent(clazz))
.map(clazz -> getUrl(method, clazz))
.findFirst().orElse(null);