diff --git a/doc/changing_json.md b/doc/changing_json.md new file mode 100644 index 000000000..944dcaeaf --- /dev/null +++ b/doc/changing_json.md @@ -0,0 +1,45 @@ +# Customizing the JSON output + +Sometimes in your application you need to provide links to other resources from a particular entity. For example, a +`Customer` response might be enriched with links to a current shopping cart, or links to manage resources related to +that entity. Spring Data REST provides integration with [Spring HATEOAS](https://github.com/SpringSource/spring-hateoas) +and provides an extension hook for users to alter the representation of resources going out to the client. + +### The ResourceProcessor interface + +Spring HATEOAS defines a `ResourceProcessor` interface for processing entities. All beans of type +`ResourceProcessor>` will be automatically picked up by the Spring Data REST exporter and triggered when +serializing an entity of type `T`. For example, to define a processor for a `Person` entity, add a `@Bean` to your +ApplicationContext like the following (which is taken from the Spring Data REST tests): + + @Bean public ResourceProcessor> personProcessor() { + return new ResourceProcessor>() { + @Override public Resource process(Resource resource) { + resource.add(new Link("http://localhost:8080/people", "added-link")); + return resource; + } + }; + } + + +### Adding Links + +It's possible to add links to the default representation of an entity by simply calling `resource.add(Link)` like the +example above. Any links you add to the `Resource` will be added to the final output. + +### Customizing the representation + +The Spring Data REST exporter executes any discovered `ResourceProcessor`s before it creates the output representation. +It does this by registering a `Converter` instance with an internal `ConversionService`. This is the +component responsible for creating the links to referenced entities (e.g. those objects under the "links" property in +the object's JSON representation). It takes an `@Entity` and iterates over its properties, creating links for those +properties that are managed by a `Repository` and copying across any embedded or simple properties. + +If your project needs to have output in a different format, however, it's possible to completely replace the default +outgoing JSON representation with your own. If you register your own `ConversionService` in the ApplicationContext and +register your own `Converter`, then you can return a `Resource` implementation of your choosing. + +For example, to rename the "links" property to "_links", create your own `Resource` subclass that renames the +property using Jackson's `@JsonProperty` annotation: + + public class MyResource extends Resource \ No newline at end of file diff --git a/doc/handling_events.md b/doc/handling_events.md index e18691326..04d52b556 100644 --- a/doc/handling_events.md +++ b/doc/handling_events.md @@ -1,6 +1,6 @@ # Handling ApplicationEvents in the REST Exporter -There are eight different events that the REST exporter emits throughout the process of working with an entity. Those are: +There are six different events that the REST exporter emits throughout the process of working with an entity. Those are: * BeforeSaveEvent * AfterSaveEvent @@ -8,8 +8,6 @@ There are eight different events that the REST exporter emits throughout the pro * AfterLinkSaveEvent * BeforeDeleteEvent * AfterDeleteEvent -* BeforeRenderResourcesEvent -* BeforeRenderResourceEvent ### ApplicationListener @@ -110,28 +108,3 @@ You can pass the base package of the packages you want searched for handlers in - -### Handling Render events - -It's possible to alter the representation of the resource that gets sent back to the client. There are two possible reponses: a `org.springframework.data.rest.core.Resources` bean, which has a `content` and `links` property. The `content` property is a list of `org.springframework.data.rest.core.Resource` objects. In the case of JPA @Entities, these will actually be the `org.springframework.data.rest.core.MapResource` subclass of `Resource`. These helpers are what are run through the JSON mapper and used to produce the output sent to the client. - -If, for example, you want to add links to the representation for a `Person`, you could define a POJO class and annotate it with `@RepositoryEventHandler(Person.class)` just like in the above example. Then you could define a couple of methods for altering the representations of the `Resources` and `Resource` objects that are sent to the client. - -The `org.springframework.data.rest.core.Resources` bean is sent to the client whenever lists or results are required. If you call a query method or ask for a list of entities, then the `Resources` response is the one you'll get. If you ask for a specific entity's representation, however, you'll want to alter the plain `org.springframework.data.rest.core.Resource` bean. - -An example handler class for these would look something like this: - - @RepositoryEventHandler(Person.class) - public class PersonRenderHandler { - - @HandleBeforeRenderResources - public void handleBeforeRenderResources(ServerHttpRequest request, RepositoryMetadata repoMeta, Resources resources) { - resources.addLink(new SimpleLink("linkAddedByHandler", new URI("http://localhost:8080/linkAddedByHandler")); - } - - @HandleBeforeRenderResource - public void handleBeforeRenderResource(ServerHttpRequest request, RepositoryMetadata repoMeta, Resource resource) { - resource.addLink(new SimpleLink("linkAddedByHandler", new URI("http://localhost:8080/linkAddedByHandler")); - } - - } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestController.java index ea975de86..90ab3898e 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestController.java @@ -641,7 +641,7 @@ public class RepositoryRestController new Resources(Collections.emptyList())); } - Set links = new HashSet(); + List links = new ArrayList(); PagedResources.PageMetadata pageMetadata = null; Iterator entities = Collections.emptyList().iterator(); @@ -717,8 +717,8 @@ public class RepositoryRestController HttpStatus.OK, new HttpHeaders(), (null != pageMetadata - ? new PagedResources(results, pageMetadata) - : new Resources(results))); + ? new PagedResources(results, pageMetadata, links) + : new Resources(results, links))); } /**