I am trying to setup versioned services with Spring MVC, using inheritance to extend older controllers to avoid rewriting unchanged controller methods. I've based my solution on a previous question about versioning services, however I've run into a problem with ambiguous mappings.
@Controller
@RequestMapping({"/rest/v1/bookmark"})
public class BookmarkJsonController {
@ResponseBody
@RequestMapping(value = "/write", produces = "application/json", method = RequestMethod.POST)
public Map<String, String> writeBookmark(@RequestParam String parameter) {
// Perform some operations and return String
}
}
@Controller
@RequestMapping({"/rest/v2/bookmark"})
public class BookmarkJsonControllerV2 extends BookmarkJsonController {
@ResponseBody
@RequestMapping(value = "/write", produces = "application/json", method = RequestMethod.POST)
public BookmarkJsonModel writeBookmark(@RequestBody @Valid BookmarkJsonModel bookmark) {
// Perform some operations and return BookmarkJsonModel
}
}
With this setup I get IllegalStateException: Ambiguous mapping found
. My thought regarding this is that because I have two methods with different return/argument types I have two methods in BookmarkJsonControllerV2
with the same mapping. As a workaround I attempted to override writeBookmark
in BookmarkJsonControllerV2
without any request mapping:
@Override
public Map<String, String> writeBookmark(@RequestParam String parameter) {
return null; // Shouldn't actually be used
}
However, when I compiled and ran this code I still got the exception for an ambiguous mapping. However, when I hit the URL /rest/v2/bookmark/write
I got back an empty/null response. Upon changing return null
to:
return new HashMap<String, String>() {{
put("This is called from /rest/v2/bookmark/write", "?!");
}};
I would receive JSON with that map, indicating that despite not having any request mapping annotation, it is apparently "inheriting" the annotation from the super class. At this point, my only "solution" to future-proofing the extension of the controllers is to make every controller return Object
and only have the HttpServletRequest
and HttpServletResponse
objects as arguments. This seems like a total hack and I would rather never do this.
So is there a better approach to achieve URL versioning using Spring MVC that allows me to only override updated methods in subsequent versions or is my only real option to completely rewrite each controller?