6

I'm going to implement a RESTful webservice using Spring. Let it be an ordinary PUT method, something like this:

@RequestMapping(method=RequestMethod.PUT, value="/foo")
public @ResponseBody void updateFoo(@RequestBody Foo foo) {
    fooService.update(foo);
}

In such a case input JSON format (if it corresponds to Foo class) will be successfully converted to Foo instance with no extra efforts, or error will be issued in case of wrong format. But I'd like to make the service able to consume two different types of formats using same method (e.g. PUT) and same URL (e.g. /foo).

So that it possibly looked like:

//PUT method #1
@RequestMapping(method=RequestMethod.PUT, value="/foo")
public @ResponseBody void updateFoo(@RequestBody Foo foo) {
    fooService.update(foo);
}

//PUT method #2
@RequestMapping(method=RequestMethod.PUT, value="/foo")
public @ResponseBody void updateFoo(@RequestBody FooExtra fooExtra) {
    fooService.update(fooExtra);
}

and Spring converter tried to convert input JSON not only in Foo but in FooExtra as well and invoked corresponding PUT method depending on input format.

In fact, I tried to implement it exactly as it described above but without success. Is it even possible? Maybe, I need some kind of "trick"? What is the best (and the most proper) way to achieve such behavior? Of course, I could always make two different URLs but I'd like to know whether it is possible with the same one.

1
  • If you know what RESTful is then you also know about media types. That's the way to go. Commented Nov 17, 2014 at 14:53

2 Answers 2

7

Your attempt didn't work simply because Spring tried to match your methods against the request, by looking at url and method type, which are in both cases the same. It does not work like overloading in Java; argument types do not differentiate your methods.
But there are good news. SpringMVC can also examine request headers and request parameters when trying to match your handler methods. Since what you want to pass is actually pure metadata -an alternative format type of the same information- it makes perfect sense to use a custom request header. It's very easy to add custom headers when using a rest api. See the following link for JAX-RS: Adding a custom header.

Now in your server side you should configure the handler methods as:

//PUT method #1
@RequestMapping(method=RequestMethod.PUT, value="/foo", headers="returnType=Foo")
public @ResponseBody Foo updateFoo(@RequestBody Foo foo) {
    fooService.update(foo);
}

//PUT method #2
@RequestMapping(method=RequestMethod.PUT, value="/foo", headers="returnType=FooExtra")
public @ResponseBody FooExtra updateFoo(@RequestBody FooExtra fooExtra) {
    fooService.update(fooExtra);
}

Note also that if you want to access a return value with @ResponseBody you have to return your object, otherwise make the methods void

Sign up to request clarification or add additional context in comments.

2 Comments

Although this approach works, it become tedious for clients if PUT /foo supports a lot of return types. I am facing similar issue, still looking for a more optimized solution with Spring-boot 1.5.6
If you are going to modify the client to add headers, why not just change the endpoint then? I don't see how this is a good solution.
0

For understanding it we should think how Spring works, it uses Dispatcher Servlet. I don't think that spring does "combine" work for different types of input.

So my answer will be: "trick" with two different urls ;)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.