Поток через методы, чтобы найти информацию о сопоставлении отдыха - PullRequest
1 голос
/ 23 апреля 2020

У меня есть простой, но невероятно уродливый метод. У меня проблема в том, что я чувствую, что это можно сделать в миллион раз элегантнее. Кроме того, я также хотел бы просканировать метод на наличие более чем одной аннотации, а не только объявлений конечной точки Rest.

Я чувствую, что это можно сделать через поток Annotations[] (method.getDeclaredAnnotations()) и отфильтровать по List<Annotation> restEndpointAnnotationsAndOtherAnnotations, но я не могу заставить его работать.

Любая помощь будет принята с благодарностью. Я думаю, что это, наверное, довольно забавный вызов для некоторых людей. Основная проблема, которую я получаю (я думаю) - это попытка конвертировать Class<? extends Annotation> в Annotation, но, возможно, я упускаю отметку.

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);
    }

Где RestEndpoint - это простой POJO

@Value
public class RestEndpoint {

    @NonNull String endpoint;
    boolean isPublic;
}

Я на самом деле могу найти, где он соответствует сопоставлению Rest, используя потоки, но я не могу затем применить к нему метод .value() (так как он не знает, что это за аннотация, и будет столь же утомительным, чтобы потом приводить на несколько типов аннотаций)

РЕДАКТИРОВАТЬ: Это очень удобный способ получения информации о методах, если кому-то интересно.

ApplicationContext context = ((ContextRefreshedEvent) event).getApplicationContext();  
context.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();

1 Ответ

1 голос
/ 23 апреля 2020

Проблема в getAnnotation, так как ему нужен конкретный класс аннотаций, чтобы знать, что он имеет что-то вроде value(). Вы можете создать вспомогательный метод, который попытается вызвать value() для данного объекта и выполнить другой анализ.

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];
}

Затем использовать его следующим образом:

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);
...