I am trying to use the Jersey client API to consume a third-party REST service. I plan to use the automatic POJO deserialisation to go from JSON responses to Java objects.
Unfortunately, the third party service returns the responses using the content type "text/javascript". My Jersey client fails to understand that this should be considered as a JSON object and fails to deserialise the object.
I wrote a simple Jersey server application to verify that by changing the content type from "text/javascript" to "application/json" that the deserialisation works.
Armed with this information, I set about to use a Jersey client filter to modify the response headers. The code comes from a comment by the author of this question. In fact, the question appears to be exactly the same as mine – however the answerer mis-answered the question and shows how to modify the request headers (rather than the response headers). The original author was able to use the answer to create his solution, but, it seems his stated solution fails to work.
The filter code is:
client.addFilter(new ClientFilter() {
@Override public ClientResponse handle(ClientRequest cr)
throws ClientHandlerException {
ClientResponse response = getNext().handle(cr);
response.getHeaders().putSingle(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
return response;
}
});
When executed however, an UnsupportedOperationException is raised:
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableCollection.clear(Collections.java:1035)
at com.sun.jersey.core.util.StringKeyIgnoreCaseMultivaluedMap.putSingle(StringKeyIgnoreCaseMultivaluedMap.java:78)
at com.sun.jersey.core.util.StringKeyIgnoreCaseMultivaluedMap.putSingle(StringKeyIgnoreCaseMultivaluedMap.java:56)
at App$1.handle(App.java:49)
at com.sun.jersey.api.client.Client.handle(Client.java:648)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:680)
at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:507)
at App.main(App.java:63)
The returned headers appear to be wrapped in an unmodifiable collection.
I then attempted to copy all of the headers to a new collection, but there is no way that I can see to set a map of headers back into the response.
Finally, I thought perhaps I can create a new ClientResponse containing my amended headers. However, the constructor for ClientResponse has this signature:
public ClientResponse(int status,
InBoundHeaders headers,
InputStream entity,
MessageBodyWorkers workers)
It is trivial to copy the status, headers and entity variables from the original. However, I can see no way of getting a reference to the workers field.
How can I use a Jersey client filter to modify the response header from "text/javascript" to "application/json" so that my POJO deserialisation will work?
I don’t have an answer to your real question, but I think I see how you can get that workers instance if you want to try to create a new response in your filter.
The “workers” object that you need appears to be a singleton. If you can get hold of your com.sun.jersey.api.client.Client instance, you can retrieve the workers object. In my case, the Jersey client code is in a unit test which subclassed JerseyTest. JerseyTest defines a method “client()” which returns the Client object. I added the following test code (well not exactly but close):
Then I set a breakpoint in the constructor of ClientResponse (this is the original ClientResponse returned by Jersey. I have not attempted to clone it because I don’t need to for my test). The workers passed to the constructor was the same instance. So, even though you can not get the workers object from the response object, you should be able to get it elsewhere.