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

时间:2016-04-21 21:54:22

标签: java spring spring-mvc spring-annotations

I created a base Spring controller for my latest web app project that I inherit from for all my basic CRUD controllers, called CrudController:

class CrudController<T, K extends Serializable>

T is the Entity type, and K is the key used for that type (pretty much the parameters needed for Spring's CrudRepository). I create a rest controller by extending it, like so:

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

Everything works great, except for the method that gets the list of items, /hats. With this method, I get a 405 Method Not Allowed. When I look at the logging that was done during startup, I can see that RequestMappingHandlerMapping did not map {[/hats],methods=[GET]} but it did map the other four methods in the controller. Here is the code for the method that isn't being mapped:

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

After much experimentation, I have discovered that if I add a parameter to the getAll method that is one of the class parameter types, the method will get mapped. Check this very similar code out:

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

With that small code change, the /find call works fine. I can keep my dummy parameter in there and everything will work, but it smells.

Any ideas? A simplified project that replicates the issue can be found here:

Simple Project

1 个答案:

答案 0 :(得分:4)

目前Java中存在一个错误,请参阅错误报告herehere,其中Class#getDeclaredMethods()为声明为包的超类的每个继承方法返回一个桥Method - 私人的。基于javadoc,它不应该这样做。

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

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

public class CrudController<T, K extends Serializable>