title: Controller Inheritance and Ambiguous Mappings with URL Versioning in Spring MVC
body: <p>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 <a href="https://stackoverflow.com/questions/14080684/api-versioning-with-fall-through-in-spring-3-2-mvc">previous question</a> about versioning services, however I've run into a problem with ambiguous mappings.</p>
  
  <pre><code>@Controller
  @RequestMapping({"/rest/v1/bookmark"})
  public class BookmarkJsonController {
  
    @ResponseBody
    @RequestMapping(value = "/write", produces = "application/json", method = RequestMethod.POST)
    public Map&lt;String, String&gt; 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
    }
  }
  </code></pre>
  
  <p>With this setup I get <code>IllegalStateException: Ambiguous mapping found</code>. My thought regarding this is that because I have two methods with different return/argument types I have two methods in <code>BookmarkJsonControllerV2</code> with the same mapping. As a workaround I attempted to override <code>writeBookmark</code> in <code>BookmarkJsonControllerV2</code> without any request mapping:</p>
  
  <pre><code>@Override
  public Map&lt;String, String&gt; writeBookmark(@RequestParam String parameter) {
    return null; // Shouldn't actually be used
  }
  </code></pre>
  
  <p>However, when I compiled and ran this code I still got the exception for an ambiguous mapping. However, when I hit the URL <code>/rest/v2/bookmark/write</code> I got back an empty/null response. Upon changing <code>return null</code> to:</p>
  
  <pre><code>return new HashMap&lt;String, String&gt;() {{
    put("This is called from /rest/v2/bookmark/write", "?!");
  }};
  </code></pre>
  
  <p>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 <code>Object</code> and only have the <code>HttpServletRequest</code> and <code>HttpServletResponse</code> objects as arguments. This seems like a total hack and I would rather never do this.</p>
  
  <p>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?</p>