package org.magnum.mobilecloud.video.json; import java.io.IOException; import org.springframework.hateoas.Resources; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.module.SimpleModule; /** * Begin long explanation of why this class was created... * * * By default, Spring Data Rest uses a format called HATEOAS (http://en.wikipedia.org/wiki/HATEOAS) * to output the data returned from a Repository. The results from findAll(), findByName(), etc. are * wrapped in an Object called Resources. When this Resources object is converted to JSON, it adds * additional fields to the JSON so that we don't just get back a list of Video objects. * * For our VideoRepository, the default output would like something like this for the /video : * * { "_links": { "search": { "href": "http://localhost:8080/video/search" } }, "_embedded": { "videos": [ { "name": "Foo", "url": null, "duration": 100, "_links": { "self": { "href": "http://localhost:8080/video/1" } } } ] } } * You can comment out the Application.halObjectMapper() and rerun the application if you would * like to see what the default format looks like with full HATEOAS. * * For this simple example, the extra HATEOAS "_embedded" and "_links" formatting for the top-level * JSON adds extra complexity. Because of the format, we can't just directly unmarshall this response * into a list of Video objects. * * To simplify this example and make it possible to directly unmarshall the responses as a list of * Video objects, this ObjectMapper overrides the default JSON marshalling of Spring Data Rest so * that it outputs this instead: * * [ { "name": "Foo", "url": null, "duration": 100, "_links": { "self": { "href": "http://localhost:8080/video/1" } } } ] * * This alternate format allows us to directly unmarshall the HTTP response bodies from the VideoRepository * into a list of Video objects. * * @author jules * */ public class ResourcesMapper extends ObjectMapper { // This anonymous inner class will handle conversion of the Spring Data Rest // Resources objects into JSON. Resources are objects that Spring Data Rest // creates with the Videos it obtains from your VideoRepository @SuppressWarnings("rawtypes") private JsonSerializer<Resources> serializer = new JsonSerializer<Resources>() { // We are going to register this class to handle all instances of type // Resources @Override public Class<Resources> handledType() { return Resources.class; } @Override public void serialize(Resources value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { // Extracted the actual data inside of the Resources object // that we care about (e.g., the list of Video objects) Object content = value.getContent(); // Instead of all of the Resources member variables, etc. // Just mashall the actual content (Videos) into the JSON JsonSerializer<Object> s = provider.findValueSerializer( content.getClass(), null); s.serialize(content, jgen, provider); } }; // Create an ObjectMapper and tell it to use our customer serializer // to convert Resources objects into JSON public ResourcesMapper() { SimpleModule module = new SimpleModule(); module.addSerializer(serializer); registerModule(module); } }