5

I'm creating a REST service using annotated controllers and the content negotiation (@ResponceBody). I have two different controller methods returning instance of {{Foo}} that serves different use cases and I want the JSON representation of the {{Foo}} to be different for those methods.

For example:

@ResponseBody
public Foo method1() {... return new Foo(123); } // should produce '123'
@ResponseBody
public Foo method2() {... return new Foo(123); } // should produce '{name:"Foo", number:123}'

Of course I could use DTO pattern and return different DTOs in different methods (e.g. {{FooDTO1}} and {{FooDTO2}} respectively) and simply register different JSON serializers for those DTOs. But I wonder if there is a better way, as to me it just feels wrong to define two additional DTO classes and create disposable instances of those classes only in order to apply proper JSON serializers. Can't I just somehow hint to Spring or Jackson which Serializer should be used for which case?

Alex Vayda
  • 6,154
  • 5
  • 34
  • 50
  • You could return a String and serialize it manually using the preferred JSON utility. – CodeChimp Jun 10 '13 at 20:23
  • `should produce '123'` - the output `123` is not JSON. If you want it to be the _String_ `123` then changing the return type to String and implementing toString() to just return the `123` value might work – andyb Jun 12 '13 at 07:39
  • @CodeChimp, the controller method must return object in order to allow for the content negotiation. JSON is just an example here. There could be also a pair of say XML representations between which I would need to distinguish somehow as well. What I'm looking for is a way to associate Spring's http message converter with a particular controller method or a set of methods, or method annotated with some metadata, etc. – Alex Vayda Jun 12 '13 at 09:53
  • 2
    You can use the HttpServletResponse to set the content type. People do that all the time. Since you are requesting a non-standard way of returning JSON (using two serialization frameworks), you need a slightly not-so-standard approach. If you simply return an Object, Spring will use Jackson, if it's available. If you want to use some other framework to marshal it, then you will have to set the content type and return a String representing the marshaled object. I would also suggest toning down your response to @andyb. You catch more flies with honey. – CodeChimp Jun 12 '13 at 14:07
  • 1
    You might be able to do this with `@JsonView`s - see http://stackoverflow.com/questions/5772304/using-jsonview-with-spring-mvc/, and thanks for the support @CodeChimp :) – andyb Jun 12 '13 at 14:20
  • I like the idea of differentiating them by setting different response content types. It sounds logical, I don't know why I didn't think about it. @CodeChimp, if you add an answer I will accept it. – Alex Vayda Jun 13 '13 at 21:31

2 Answers2

1

As suggested by @CodeChimp, the different request content types can be used to switch between different representations of the same resource. It corresponds the REST philosophy and is directly supported by Spring as it relies on the content type to pick a serializer. So, all I need to do is to register two serializers for class Foo each bound to a different content type. E.g. application/json-vnd.myCompany.com+type1 representation would be produced by Serializer1 and application/json-vnd.myCompany.com+type2 by Serializer2 accordingly. It will be up to the client then which representation to choose.

Alex Vayda
  • 6,154
  • 5
  • 34
  • 50
-1
want the JSON representation of the {{Foo}} to be different for those methods

Well you'll definitely need different serializers and foos. There is no getting away from the fact. And its preferable imho.

NimChimpsky
  • 46,453
  • 60
  • 198
  • 311
  • Sure, I do have those serializers. The question is how to make Spring (or Jackson) to use Serializer1 for the output of method1() and Serializer2 for the output of method2() even though the output is of the same type for both methods? – Alex Vayda Jun 12 '13 at 10:11
  • @wajda ok you'll need two different foo's is what I should have said aswell. – NimChimpsky Jun 12 '13 at 10:12