From 28f4936d97faf8bb992586904e4ff75977650461 Mon Sep 17 00:00:00 2001 From: Jon Brisbin Date: Thu, 27 Sep 2012 15:53:32 -0500 Subject: [PATCH] Added JsonSchemaController for generating JSON schema for managed entities. --- .../webmvc/RepositoryRestHandlerAdapter.java | 4 +- .../webmvc/RepositoryRestHandlerMapping.java | 4 +- .../RepositoryRestMvcConfiguration.java | 5 ++ .../webmvc/json/JsonSchemaController.java | 65 +++++++++++++++++++ 4 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/JsonSchemaController.java diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerAdapter.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerAdapter.java index 9f135b2a3..bb1602b4e 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerAdapter.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerAdapter.java @@ -3,6 +3,7 @@ package org.springframework.data.rest.webmvc; import java.util.Arrays; import org.springframework.core.Ordered; +import org.springframework.data.rest.webmvc.json.JsonSchemaController; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; @@ -29,7 +30,8 @@ public class RepositoryRestHandlerAdapter extends ResourceProcessorInvokingHandl @Override protected boolean supportsInternal(HandlerMethod handlerMethod) { return super.supportsInternal(handlerMethod) - && RepositoryRestController.class.isAssignableFrom(handlerMethod.getBeanType()); + && (RepositoryRestController.class.isAssignableFrom(handlerMethod.getBeanType()) + || JsonSchemaController.class.isAssignableFrom(handlerMethod.getBeanType())); } } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java index 1ba28d8cd..21795d0f1 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java @@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.Ordered; import org.springframework.data.rest.repository.RepositoryExporter; +import org.springframework.data.rest.webmvc.json.JsonSchemaController; import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; @@ -57,7 +58,8 @@ public class RepositoryRestHandlerMapping extends RequestMappingHandlerMapping { } @Override protected boolean isHandler(Class beanType) { - return RepositoryRestController.class.isAssignableFrom(beanType); + return (RepositoryRestController.class.isAssignableFrom(beanType) + || JsonSchemaController.class.isAssignableFrom(beanType)); } @Override protected void extendInterceptors(List interceptors) { diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestMvcConfiguration.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestMvcConfiguration.java index e3cf3f229..9f08c548a 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestMvcConfiguration.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestMvcConfiguration.java @@ -9,6 +9,7 @@ import org.springframework.context.annotation.ImportResource; import org.springframework.data.rest.repository.UriToDomainObjectUriResolver; import org.springframework.data.rest.repository.context.ValidatingRepositoryEventListener; import org.springframework.data.rest.repository.jpa.JpaRepositoryExporter; +import org.springframework.data.rest.webmvc.json.JsonSchemaController; import org.springframework.data.rest.webmvc.json.RepositoryAwareJacksonModule; import org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor; import org.springframework.web.method.support.HandlerMethodArgumentResolver; @@ -120,6 +121,10 @@ public class RepositoryRestMvcConfiguration { return new RepositoryRestController(); } + @Bean public JsonSchemaController jsonSchemaController() { + return new JsonSchemaController(); + } + /** * Special {@link org.springframework.web.servlet.HandlerAdapter} that only recognizes handler methods defined in the * {@link RepositoryRestController} class. diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/JsonSchemaController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/JsonSchemaController.java new file mode 100644 index 000000000..c1e38e157 --- /dev/null +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/json/JsonSchemaController.java @@ -0,0 +1,65 @@ +package org.springframework.data.rest.webmvc.json; + +import java.io.IOException; +import java.net.URI; + +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.SerializationConfig; +import org.codehaus.jackson.schema.JsonSchema; +import org.springframework.data.rest.repository.RepositoryExporterSupport; +import org.springframework.data.rest.repository.RepositoryMetadata; +import org.springframework.data.rest.webmvc.RepositoryRestController; +import org.springframework.hateoas.Link; +import org.springframework.hateoas.Resource; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.server.ServletServerHttpRequest; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.util.UriComponentsBuilder; + +/** + * A controller to output JSON schema based on Jackson's schema generator. + * + * @author Jon Brisbin + */ +public class JsonSchemaController extends RepositoryExporterSupport { + + private ObjectMapper mapper = new ObjectMapper(); + + { + mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); + } + + @RequestMapping( + value = "/{repository}/schema", + method = RequestMethod.GET, + produces = "application/json" + ) + @ResponseBody + public ResponseEntity schemaForRepository(ServletServerHttpRequest request, + UriComponentsBuilder uriBuilder, + @PathVariable String repository) throws IOException { + URI baseUri = uriBuilder.build().toUri(); + RepositoryRestController.BASE_URI.set(baseUri); + + RepositoryMetadata repoMeta = repositoryMetadataFor(repository); + if(null == repoMeta) { + throw new IllegalArgumentException("Resource /" + repository + "/schema not found."); + } + + JsonSchema schema = mapper.generateJsonSchema(repoMeta.domainType()); + + URI requestUri = UriComponentsBuilder.fromUri(baseUri).path(repository).build().toUri(); + Resource resource = new Resource(schema, + new Link(request.getURI().toString(), "self"), + new Link(requestUri.toString(), repoMeta.rel())); + + String output = mapper.writeValueAsString(resource); + + return new ResponseEntity(output, HttpStatus.OK); + } + +}