In Spring framework, there is a message converter for json but there isn't a converter for json-p.
I 've seen a few solutions on
here.
One of the solution in
here,
was extending
MappingJacksonJsonView class. But I didn't like the idea of checking every 'GET' request whether it has a
'callback' param or not.
And the other solution in
here,
was extending
MappingJackson2HttpMessageConverter class. I preferred this approach. But, I didn't like the
idea of implementing an interface (JsonObject) for every request. So, I decided to change it a bit.
I decided to get the callback parameter over the servlet request. So, I neither had to implement JsonObject interface nor
had to get the callback parameter with the
@RequestParam annotation. Here is my solution:
/**
* Converter class that we are going to use to create json-p messages.
*
* @author sinan.yumak
*
*/
public class MappingJackson2JsonpHttpMessageConverter extends MappingJackson2HttpMessageConverter {
private static final String DEFAULT_CALLBACK_PARAMETER = "callback";
private static final List SUPPORTED_MEDIA_TYPES = new ArrayList() {{
add( new MediaType("application", "x-javascript") );
add( new MediaType("application", "javascript") );
add( new MediaType("text", "javascript") );
}};
public MappingJackson2JsonpHttpMessageConverter() {
setSupportedMediaTypes(SUPPORTED_MEDIA_TYPES);
}
@Override
protected void writeInternal( Object object, HttpOutputMessage outputMessage )
throws IOException, HttpMessageNotWritableException {
JsonGenerator jsonGenerator = getJsonGenerator(outputMessage);
try {
String callbackParam = getRequestParam( DEFAULT_CALLBACK_PARAMETER );
if ( Strings.isNullOrEmpty(callbackParam) ) {
//if the callback parameter doesn't exists, use the default one...
callbackParam = DEFAULT_CALLBACK_PARAMETER;
}
jsonGenerator.writeRaw(callbackParam);
jsonGenerator.writeRaw(" (");
getObjectMapper().writeValue(jsonGenerator, object);
jsonGenerator.writeRaw(");");
jsonGenerator.flush();
} catch (JsonProcessingException ex) {
throw new HttpMessageNotWritableException("Could not write JSON:" + ex.getMessage(), ex);
}
}
private JsonGenerator getJsonGenerator( HttpOutputMessage outputMessage ) throws IOException {
JsonEncoding encoding = getJsonEncoding(outputMessage.getHeaders().getContentType());
return getObjectMapper().getFactory().createJsonGenerator(outputMessage.getBody(), encoding);
}
/**
* Returns given parameter from servlet request.
*
* @param paramName
* Name of the param
*/
private String getRequestParam( String paramName ) {
return getServletRequest().getParameter( paramName );
}
/**
* Returns current servlet request.
*/
private HttpServletRequest getServletRequest() {
return ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
}
}
And you can register your converter like that:
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
public void configureMessageConverters( List> converters ) {
converters.add( new MappingJackson2JsonpHttpMessageConverter() );
addDefaultHttpMessageConverters( converters );
}
}