Spring MVC Annotated Controller Interface with @PathVariable
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.
Recently I had the same problem. Following has worked for me:
public class GoalServiceImpl implements GoalService {
...
public void removeGoal(@PathVariableString id) {
}
}
It works in newer version of Spring.
import org.springframework.web.bind.annotation.RequestMapping;
public interface TestApi {
@RequestMapping("/test")
public String test();
}
Implement the interface in the Controller
@RestController
@Slf4j
public class TestApiController implements TestApi {
@Override
public String test() {
log.info("In Test");
return "Value";
}
}
It can be used as: Rest client
The feature of defining all bindings on interface actually got implement recently in Spring 5.1.5.
Please see this issue: https://github.com/spring-projects/spring-framework/issues/15682 - it was a struggle :)
Now you can actually do:
@RequestMapping("/random")
public interface RandomDataController {
@RequestMapping(value = "/{type}", method = RequestMethod.GET)
@ResponseBody
RandomData getRandomData(
@PathVariable(value = "type") RandomDataType type, @RequestParam(value = "size", required = false, defaultValue = "10") int size);
}
@Controller
public class RandomDataImpl implements RandomDataController {
@Autowired
private RandomGenerator randomGenerator;
@Override
public RandomData getPathParamRandomData(RandomDataType type, int size) {
return randomGenerator.generateRandomData(type, size);
}
}
You can even use this library: https://github.com/ggeorgovassilis/spring-rest-invoker
To get a client-proxy based on that interface, similarly to how RestEasys client framework works in the JAX-RS land.