Is there any reason not to map Controllers as interfaces?
In all the examples and questions I see surrounding controllers, all are concrete classes. Is there a reason for this? I would like to separate the request mappings from the implementation. I hit a wall though when I tried to get a @PathVariable
as a parameter in my concrete class.
My Controller interface looks like this:
@Controller @RequestMapping("/services/goal/") public interface GoalService { @RequestMapping("options/") @ResponseBody Map<String, Long> getGoals(); @RequestMapping(value = "{id}/", method = RequestMethod.DELETE) @ResponseBody void removeGoal(@PathVariable String id); }
And the implementing class:
@Component public class GoalServiceImpl implements GoalService { /* init code */ public Map<String, Long> getGoals() { /* method code */ return map; } public void removeGoal(String id) { Goal goal = goalDao.findByPrimaryKey(Long.parseLong(id)); goalDao.remove(goal); } }
The getGoals()
method works great; the removeGoal(String id)
throws an exception
ExceptionHandlerExceptionResolver - Resolving exception from handler [public void todo.webapp.controllers.services.GoalServiceImpl.removeGoal(java.lang.String)]: org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'id' is not present
If I add the @PathVariable
annotation to the concrete class everything works as expected, but why should i have to re-declare this in the concrete class? Shouldn't it be handled by whatever has the @Controller
annotation?
@PathVariable is a Spring annotation which indicates that a method parameter should be bound to a URI template variable. If the method parameter is Map<String, String> then the map is populated with all path variable names and values. It has the following optional elements: name - name of the path variable to bind to.
The @PathVariable annotation is used for data passed in the URI (e.g. RESTful web services) while @RequestParam is used to extract the data found in query parameters. These annotations can be mixed together inside the same controller. @PathParam is a JAX-RS annotation that is equivalent to @PathVariable in Spring.
The @PathVariable annotation is used to extract the value of the template variables and assign their value to a method variable. A Spring controller method to process above example is shown below; @RequestMapping("/users/{userid}", method=RequestMethod.
The @PathVariable annotation is used to extract the value from the URI. It is most suitable for the RESTful web service where the URL contains some value. Spring MVC allows us to use multiple @PathVariable annotations in the same method. A path variable is a critical part of creating rest resources.
Apparently, when a request pattern is mapped to a method via the @RequestMapping
annotation, it is mapped to to the concrete method implementation. So a request that matches the declaration will invoke GoalServiceImpl.removeGoal()
directly rather than the method that originally declared the @RequestMapping
ie GoalService.removeGoal()
.
Since an annotation on an interface, interface method, or interface method parameter does not carry over to the implementation there is no way for Spring MVC to recognize this as a @PathVariable
unless the implementing class declares it explicitly. Without it, any AOP advice that targets @PathVariable
parameters will not be executed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With