There is less information about where the version information (URI and title) resides, and how you arrange the code for different versions.
I doubt there is one standard approach. It only depends on how different the versions are.
Simple format change. Suppose, for example, that the difference is that you switched from XML in V1 to JSON in V2. In this case, you can use the exact same code, but just configure the application to output JSON globally. No need for different packages or controllers. (For example, you can use JAXB annotations to control both XML and the JSON-generated Jackson message.)
Changes to a modest scheme. Say that V2 introduces a small number of partition scheme changes. In this case, it would probably not make sense to create new packages on top of it. You may have simple conditional logic in your controller to handle / maintain the correct representation for the version.
The main changes to the scheme. If your circuit changes are deep and far-reaching, you may need more separate controllers. You might need a different domain model (objects / services). In this case, it may well make sense to have a parallel set of packages for controllers up to objects, repositories, and possibly even database tables.
Application of ideas
Approach 1. By applying these ideas to your @RequestMapping examples, you can do what you say there, but if the answer exactly matches the versions, then they should just delegate one common method:
@RequestMapping( value = "/orders/{id}", method = RequestMethod.GET, produces = "application/vnd.example-v1") @ResponseBody public Order getOrderV1(@PathVariable("id") Long id) { return getOrder(id); } @RequestMapping( value = "/orders/{id}", method = RequestMethod.GET, produces = "application/vnd.example-v2") @ResponseBody public Order getOrderV2(@PathVariable("id") Long id) { return getOrder(id); } private Order getOrder(Long id) { return orderRepo.findOne(id); }
Something like this will work. If orders differ between versions, you can implement the differences directly in the method.
Approach 2. Another thing you can try - and I have not tried it myself - each type of resource (for example, orders, products, customers, etc.) having its own controller base with method level annotations for the HTTP method (only value and method defined, but do not produces ). Then use extensions for the version expanding the base where the extension controllers have @RequestMapping(value = "/orders", produces = "application/vnd.example-v1") at the class level. Then only the delta between the version and the base is redefined. I'm not sure if this will work , but if it is, it will be a pretty clean way to organize controllers. Here is what I mean:
// The baseline public abstract class BaseOrderController { @RequestMapping(value = "/{id}", method = RequestMethod.GET) @ResponseBody public Order getOrder(@PathVariable("id") Long id) { ... } } // V1 controller @RequestMapping(value = "/orders", produces = "application/vnd.example-v1") public class OrderControllerV1 extends BaseOrderController { ... no difference from baseline, so nothing to implement ... } // V2 controller @RequestMapping(value = "/orders", produces = "application/vnd.example-v2") public class OrderControllerV2 extends BaseOrderController { @RequestMapping(value = "/{id}", method = RequestMethod.GET) @ResponseBody @Override public Order getOrder(@PathVariable("id") Long id) { return orderRepoV2.findOne(id); } }