没有类型参数的继承控制器方法不会与 RequestMapping 映射

Inherited controller method without type parameter does not get mapped with RequestMapping

我为我最新的 Web 应用程序项目创建了一个基础 Spring 控制器,我从它继承了我所有的基本 CRUD 控制器,称为 CrudController:

class CrudController<T, K extends Serializable>

T 是实体类型,K 是用于该类型的键(几乎是 Spring 的 CrudRepository 所需的参数)。我通过扩展它来创建一个休息控制器,如下所示:

@RestController
@RequestMapping(path = "/hats")
public class HatController extends CrudController<Hat, Integer> {
}

一切正常,除了获取项目列表的方法 /hats。使用这种方法,我得到一个 405 Method Not Allowed。当我查看启动期间完成的日志记录时,我可以看到 RequestMappingHandlerMapping 没有映射 {[/hats],methods=[GET]} 但它确实映射了控制器中的其他四个方法。这是未映射的方法的代码:

@RequestMapping(method = RequestMethod.GET)
public HttpEntity<?> getAll() {
    Iterable<T> result = controllerRepository.findAll();
    return new ResponseEntity<Object>(result, HttpStatus.OK);
}

经过多次试验,我发现如果我向 getAll 方法添加一个参数,该参数是 class 参数类型之一,该方法将被映射。检查这个非常相似的代码:

@RequestMapping(method = RequestMethod.GET)
public HttpEntity<?> getAll(K dontuse) {
    Iterable<T> result = controllerRepository.findAll();
    return new ResponseEntity<Object>(result, HttpStatus.OK);
}

通过那个小的代码更改,/find 调用可以正常工作。我可以把我的虚拟参数放在那里,一切都会正常工作,但它有味道。

有什么想法吗?可以在此处找到复制该问题的简化项目:

Simple Project

目前 Java 中存在一个错误,请参阅错误报告 here and here, where Class#getDeclaredMethods() returns 一个桥 Method 用于声明为 superclass 的每个继承方法包私有。根据 javadoc,它不应该那样做。

这混淆了 Spring MVC 对 @Controller 注释 classes 和处理程序方法的检查。在此答案中详细介绍不会很有用,但您可以查看处理它的代码 here.

最简单的解决方案是将您的 CrudRepository class 声明为 public

public class CrudController<T, K extends Serializable>