通过方法流式查找 Rest 映射信息

Stream through methods to find Rest mapping information

我有一个简单但非常难看的方法。 我遇到的问题是我觉得这可以优雅地完成一百万倍。此外,我还想为多个注释扫描一个方法,而不仅仅是 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();

问题出在 getAnnotation,因为它需要具体注释 class 才能知道它有类似 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);