Requirement
I am building a REST API. It has two REST calls. The call /format to output formatted JSON based on the parameters provided. The call /raw with same parameters should output JSON with raw values (without the formatting). The formatting here would be locale specific like date changes, displaying the correct currency, decimal formatting, time formatting etc for the values.
Tools
Java, Tomcat, Spring, Apache CXF, JAX-RS and Jackson.
Implementation
REST service is setup and works fine. No problems there. I have written seperate custom serializers in which I provide desired formatting using NumberFormat, DateFormat, DecimalFormat etc. I have extended the SimpleModule from Jackson to register all my custom serializers mentioned above. I am using two separate ObjectMapper (FomatOM and RawOM).FormatOM registers the custom Module for formatted JSON output, RawOM is for raw JSON output as per the requirement. These two objectmappers are registered to two different JacksonJsonProviders and declared as beans in my spring config xml. For /format I use FormatOM with custom serializers, and in /raw I use RawOM.
Problem
It doesn't work as I would have expected. I expected that when I make a request through /format call the FormatOM would be used and for /raw RawOM would be used. What is happening is whichever call I make first, subsequent calls are served using the same ObjectMapper. Thus, if the first call is /raw; subsequent calls to /format or /raw render raw JSON output. After a Tomcat restart, if the first call is to /format then subsequent calls to either API calls render formatted JSON output
Questions
1. How do you achieve my requirement for rendering formatted + raw JSON
output?
2. What's is wrong with my implementation?
3. Any ideas or suggestions or critiques?
4. Any other way to have request based mappers?
Thanks
One work-around is just to use a StreamingOutput, and bundle specific ObjectMapper in there, use it directly (ObjectMapper.writeValue(output, value);)
Thanks for your answer StaxMan. Since I am using Spring, I decided to inject the JacksonJsonProvider and do JacksonJsonProvider.setMapper(mapper) to set the mapper per request. If anyone has tried the above approach and ran into a problem do let me know. If I run into any sort of issue, I shall update this answer.
Related
I am using JAX-RS whereby I have an interface which contains annotated methods for my endpoints (Apache CXF). I am using Jackson as my serializer.
I have noticed that the first request is particularly slow. This is because the JSON serializer is building its internal metadata on how to serialize/deserialize a given type on the first request.
It is possible to get Jackson to do this upfront (before the first request) by registering the type with Jackson. Is it possible to do this in a generic way, such that I have an interface and using reflection it goes and finds all the inputs and outputs to the JAX-RS annotated methods and registers the types with Jackson?
I figured this must be an "already solved" problem and in the vein of DRY - is there something out there that will do this already without me having to write some nasty reflection code myself? (Or any helper methods in Spring etc that could help here?)
I have recently upgraded to Genson 1.3 and I am not 100% sure if this issue is new or not as previously I patched the 0.98 version to make it work.
Context
We are using our own implementation of the BeanMutatorAccessorResolver. This is so that we can dynamically decide whether a property should be serialized or not. Basically we have integrated Genson into our generic jersey REST API interface. Genson does all the serializing and deserializing. When doing a GET requests it is possible for a user to pass fields in the URL in order to filter those he specifically needs (especially for large objects this is necessary where you only need 3 fields or so for displaying a table overview). For example: ?fields=field1, field2, field3. We then know in our implementation of BeanMutatorAccessorResolver exactly which fields to serialize and which ones to ignore. This is mainly intended for speeding up requests and parsing as we are then working with less data.
Problem
Unfortunately it seems that once Genson has read in all the fields via reflection or whatever, it caches that. This would be no problem if we were always requesting the same fields. Unfortunately on some occasions we need more fields then before, but because Genson does not visit our BeanMutatorAccessorResolver a second time it only returns the few fields that it has already cached.
Is there anyway around this? Perhaps there is a better solution than turning cahing off completely - because that would most probably hurt performance, right?
Update
Is seems that I have found the location where this is happening. Basically Genson returns a cached converter in Genson.provideConverter(Type forType) (line: 154).
Converter<T> converter = (Converter<T>) converterCache.get(forType);
At the top of the method I have noticed that it looks for a __GENSON$DO_NOT_CACHE_CONVERTER.
if (Boolean.TRUE.equals(ThreadLocalHolder.get("__GENSON$DO_NOT_CACHE_CONVERTER", Boolean.class))) {
Should I perhaps set this value or is there a better solution?
The problem has been solved thanks to Eugen. The solution can be found here: https://groups.google.com/forum/#!topic/genson/Z1oFHJfA-5w.
Basically you need to extend 3 classes to get this working:
GensonBundle, which you can register with the GensonBuilder.
BaseBeanDescriptorProvider, which gets created in GensonBundle.
BeanDescriptor, which gets created in BaseBeanDescriptorProvider and
which contains the serialize method to adapt to your needs.
I want to format my REST interface as follows:
myurl.com/resources/{resourceId}
I optionally want people to be able to provide the following variations to specify return formats:
myurl.com/resources.json/{resourceId}
I am using Jersey to provide my REST services. What is the best way to handle these parameters?
Should a create a separate class with a different #PATH notation, or can I have a single class and parse out that parameter? Are there any built in annotations that might handle this, similar to #PathParam or #QueryParam?
There already is a mechanism for this (as #digitaljoel already stated) - HTTP Accept header.
Jersey doesn't have any direct support for your usecase, but there is something similar - media type mapping feature, see
http://jersey.java.net/nonav/apidocs/1.12/jersey/com/sun/jersey/api/core/ResourceConfig.html#PROPERTY_MEDIA_TYPE_MAPPINGS
and
http://jersey.java.net/nonav/apidocs/1.12/jersey/com/sun/jersey/api/core/ResourceConfig.html#getMediaTypeMappings%28%29
Unfortunately for you it handles only URLs which have this "param" at the end, but it should not be very hard to take UriConnegFilter sources (http://java.net/projects/jersey/sources/svn/content/trunk/jersey/jersey-server/src/main/java/com/sun/jersey/api/container/filter/UriConnegFilter.java?rev=5698) and modify it to suit your needs.
This must have been answered previously, but my Google powers are off today and I have been struggling with this for a bit. We are migrating from an old PHP base to a Jersey-based JVM stack, which will ultimately provide a JSON-based RESTful API that can be consumed from many applications. Things have been really good so far and we love the easy POJO-to-JSON conversion. However, we are dealing with difficulties in Cross-Domain JSON requests. We essentially have all of our responses returning JSON (using #Produces("application/json") and the com.sun.jersey.api.json.POJOMappingFeature set to true) but for JSONP support we need to change our methods to return an instance of JSONWithPadding. This of course also requires us to add a #QueryParam("callback") parameter to each method, which will essentially duplicate our efforts, causing two methods to be needed to respond with the same data depending on whether or not there is a callback parameter in the request. Obviously, this is not what we want.
So we essentially have tried a couple different options. Being relatively new to Jersey, I am sure this problem has been solved. I read from a few places that I could write a request filter or I could extend the JSON Provider. My ideal solution is to have no impact on our data or logic layers and instead have some code that says "if there is a call back parameter, surround the JSON with the callback, otherwise just return the JSON". A solution was found here:
http://jersey.576304.n2.nabble.com/JsonP-without-using-JSONWithPadding-td7015082.html
However, that solution extends the Jackson JSON object, not the default JSON provider.
What are the best practices? If I am on the right track, what is class for the default JSON filter that I can extend? Is there any additional configuration needed? Am I completely off track?
If all your resource methods return JSONWithPadding object, then Jersey automatically figures out if it should return JSON (i.e. just the object wrapped by it) or the callback as well based on the requested media type - i.e. if the media type requested by the client is any of application/javascript, application/x-javascript, text/ecmascript, application/ecmascript or text/jscript, then Jersey returns the object wrapped by the callback. If the requested media type is application/json, Jersey returns the JSON object (i.e. does not wrap it with the callback). So, one way to make this work is to make your resource method produce all the above media types (including application/json), always return JSONWithPadding and let Jersey figure out what to do.
If this does not work for you, let us know why it does not cover your use case (at users at jersey.java.net). Anyway, in that case you can use ContainerRequest/ResponseFilters. In the request filter you can modify the request headers any way you want (e.g. adjust the accept header) to ensure it matches the right resource method. Then in the response filter you can wrap the response entity using the JSONWithPadding depending on whether the callback query param is available and adjust the content type header.
So what I ultimately ended up doing (before Martin's great response came in) was creating a Filter and a ResponseWrapper that intercepted the output. The basis for the code is at http://docs.oracle.com/cd/B31017_01/web.1013/b28959/filters.htm
Essentially, the filter checks to see if the callback parameter exists. If it does, it prepends the callback to the outputted JSON and appends the ) at the end. This works great for us in our testing, although it has not been hardened yet. While I would have loved for Jersey to be able to handle it automatically, I could not get it to work with jQuery correctly (probably something on my side, not a problem with Jersey). We have pre-existing jQuery calls and we are changing the URLs to look at the new Jersey Server and we really didn't want to go into each $.ajax call to change any headers or content types in the calls if we didn't have to.
Aside from the small issue, Jersey has been great to work with!
for a REST PUT service, im trying to use xml as the payload. My question is can I have the whole payload as xml? or should I do something like Data=<mydata>......</mydada>?
basically
<mydata>......</mydada>
or
Data=<mydata>......</mydada>
Sure you can just set the mediaType to be application/xml just as you can for json or plain text. The first example is valid XML, second one is not. So the first one can be done.
I am not sure what framework you are using. For example if you plan to use Spring you can take a look at an example here.
The basic idea is that you define the media type to be application/xml . You can also specicfy a marshaller/unmarshaller (ie. using JAXB) if you want to marshal/unmarshal from a Java bean.