From 9e47346314cdb832ff9bee9ebb8d489f89ace209 Mon Sep 17 00:00:00 2001 From: Jon Brisbin Date: Tue, 5 Mar 2013 08:59:13 -0600 Subject: [PATCH] Fix for DATAREST-69. Now inject an `EntityLinks` into the controller and provide the `RepositoryEntityLinks` as a bean in the `RepositoryRestMvcConfiguration`. --- .../support/RepositoryEntityLinks.java | 7 +- .../AbstractRepositoryRestController.java | 414 ++++---- .../rest/webmvc/RepositoryController.java | 77 +- .../webmvc/RepositoryEntityController.java | 10 +- ...toryEntityLinksMethodArgumentResolver.java | 42 - ...RepositoryPropertyReferenceController.java | 902 +++++++++--------- .../webmvc/RepositorySearchController.java | 374 ++++---- .../RepositoryRestMvcConfiguration.java | 30 +- 8 files changed, 924 insertions(+), 932 deletions(-) delete mode 100644 spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityLinksMethodArgumentResolver.java diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/support/RepositoryEntityLinks.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/support/RepositoryEntityLinks.java index c6b56d982..cd6d1a6b6 100644 --- a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/support/RepositoryEntityLinks.java +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/support/RepositoryEntityLinks.java @@ -22,14 +22,11 @@ import org.springframework.web.util.UriComponentsBuilder; */ public class RepositoryEntityLinks extends AbstractEntityLinks { - private final URI baseUri; private final Repositories repositories; private final RepositoryRestConfiguration config; - public RepositoryEntityLinks(URI baseUri, - Repositories repositories, + public RepositoryEntityLinks(Repositories repositories, RepositoryRestConfiguration config) { - this.baseUri = baseUri; this.repositories = repositories; this.config = config; } @@ -48,7 +45,7 @@ public class RepositoryEntityLinks extends AbstractEntityLinks { if(null == persistentEntity) { throw new IllegalArgumentException(type + " is not managed by any repository."); } - return new PersistentEntityLinkBuilder(baseUri, repoInfo, persistentEntity); + return new PersistentEntityLinkBuilder(config.getBaseUri(), repoInfo, persistentEntity); } @Override public LinkBuilder linkFor(Class type, Object... parameters) { diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java index a8a59620d..b59704ad2 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/AbstractRepositoryRestController.java @@ -34,6 +34,7 @@ import org.springframework.data.rest.webmvc.support.ConstraintViolationException import org.springframework.data.rest.webmvc.support.ExceptionMessage; import org.springframework.data.rest.webmvc.support.JsonpResponse; import org.springframework.data.rest.webmvc.support.RepositoryConstraintViolationExceptionMessage; +import org.springframework.hateoas.EntityLinks; import org.springframework.hateoas.Link; import org.springframework.hateoas.LinkBuilder; import org.springframework.hateoas.Resource; @@ -52,236 +53,239 @@ import org.springframework.web.bind.annotation.ResponseBody; */ public class AbstractRepositoryRestController implements ApplicationContextAware { - static final Resource EMPTY_RESOURCE = new Resource(Collections.emptyList()); - static final Resources> EMPTY_RESOURCES = new Resources>(Collections.>emptyList()); - static final Iterable> EMPTY_RESOURCE_LIST = Collections.emptyList(); - static final TypeDescriptor STRING_TYPE = TypeDescriptor.valueOf(String.class); - protected final Logger LOG = LoggerFactory.getLogger(getClass()); - protected final Repositories repositories; - protected final RepositoryRestConfiguration config; - protected final DomainClassConverter domainClassConverter; - protected final ConversionService conversionService; - protected final MethodParameterConversionService methodParameterConversionService; - protected ApplicationContext applicationContext; + static final Resource EMPTY_RESOURCE = new Resource(Collections.emptyList()); + static final Resources> EMPTY_RESOURCES = new Resources>(Collections.>emptyList()); + static final Iterable> EMPTY_RESOURCE_LIST = Collections.emptyList(); + static final TypeDescriptor STRING_TYPE = TypeDescriptor.valueOf(String.class); + protected final Logger LOG = LoggerFactory.getLogger(getClass()); + protected final Repositories repositories; + protected final RepositoryRestConfiguration config; + protected final DomainClassConverter domainClassConverter; + protected final ConversionService conversionService; + protected final MethodParameterConversionService methodParameterConversionService; + protected final EntityLinks entityLinks; + protected ApplicationContext applicationContext; - @Autowired - public AbstractRepositoryRestController(Repositories repositories, - RepositoryRestConfiguration config, - DomainClassConverter domainClassConverter, - ConversionService conversionService) { - this.repositories = repositories; - this.config = config; - this.domainClassConverter = domainClassConverter; - this.conversionService = conversionService; - this.methodParameterConversionService = new MethodParameterConversionService(conversionService); - } + @Autowired + public AbstractRepositoryRestController(Repositories repositories, + RepositoryRestConfiguration config, + DomainClassConverter domainClassConverter, + ConversionService conversionService, + EntityLinks entityLinks) { + this.repositories = repositories; + this.config = config; + this.domainClassConverter = domainClassConverter; + this.conversionService = conversionService; + this.entityLinks = entityLinks; + this.methodParameterConversionService = new MethodParameterConversionService(conversionService); + } - @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } + @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } - @ExceptionHandler({ - NullPointerException.class - }) - @ResponseBody - public ResponseEntity handleNPE(NullPointerException npe) { - return errorResponse(npe, HttpStatus.INTERNAL_SERVER_ERROR); - } + @ExceptionHandler({ + NullPointerException.class + }) + @ResponseBody + public ResponseEntity handleNPE(NullPointerException npe) { + return errorResponse(npe, HttpStatus.INTERNAL_SERVER_ERROR); + } - @ExceptionHandler({ - ResourceNotFoundException.class - }) - @ResponseBody - public ResponseEntity handleNotFound() { - return notFound(); - } + @ExceptionHandler({ + ResourceNotFoundException.class + }) + @ResponseBody + public ResponseEntity handleNotFound() { + return notFound(); + } - @ExceptionHandler({ - NoSuchMethodError.class, - HttpRequestMethodNotSupportedException.class - }) - @ResponseBody - public ResponseEntity handleNoSuchMethod() { - return errorResponse(null, HttpStatus.METHOD_NOT_ALLOWED); - } + @ExceptionHandler({ + NoSuchMethodError.class, + HttpRequestMethodNotSupportedException.class + }) + @ResponseBody + public ResponseEntity handleNoSuchMethod() { + return errorResponse(null, HttpStatus.METHOD_NOT_ALLOWED); + } - @ExceptionHandler({ - HttpMessageNotReadableException.class, - HttpMessageNotWritableException.class - }) - @ResponseBody - public ResponseEntity handleNotReadable(HttpMessageNotReadableException e) { - return badRequest(e); - } + @ExceptionHandler({ + HttpMessageNotReadableException.class, + HttpMessageNotWritableException.class + }) + @ResponseBody + public ResponseEntity handleNotReadable(HttpMessageNotReadableException e) { + return badRequest(e); + } - /** - * Handle failures commonly thrown from code tries to read incoming data and convert or cast it to the right type. - * - * @param t - * - * @return - * - * @throws java.io.IOException - */ - @ExceptionHandler({ - InvocationTargetException.class, - IllegalArgumentException.class, - ClassCastException.class, - ConversionFailedException.class - }) - @ResponseBody - public ResponseEntity handleMiscFailures(Throwable t) { - return badRequest(t); - } + /** + * Handle failures commonly thrown from code tries to read incoming data and convert or cast it to the right type. + * + * @param t + * + * @return + * + * @throws java.io.IOException + */ + @ExceptionHandler({ + InvocationTargetException.class, + IllegalArgumentException.class, + ClassCastException.class, + ConversionFailedException.class + }) + @ResponseBody + public ResponseEntity handleMiscFailures(Throwable t) { + return badRequest(t); + } - @ExceptionHandler({ - ConstraintViolationException.class - }) - @ResponseBody - public ResponseEntity handleConstraintViolationException(ConstraintViolationException cve) { - return response(null, - new ConstraintViolationExceptionMessage(cve, applicationContext), - HttpStatus.CONFLICT); - } + @ExceptionHandler({ + ConstraintViolationException.class + }) + @ResponseBody + public ResponseEntity handleConstraintViolationException(ConstraintViolationException cve) { + return response(null, + new ConstraintViolationExceptionMessage(cve, applicationContext), + HttpStatus.CONFLICT); + } - @ExceptionHandler({ - RepositoryConstraintViolationException.class - }) - @ResponseBody - public ResponseEntity handleRepositoryConstraintViolationException(RepositoryConstraintViolationException rcve) { - return response(null, - new RepositoryConstraintViolationExceptionMessage(rcve, applicationContext), - HttpStatus.CONFLICT); - } + @ExceptionHandler({ + RepositoryConstraintViolationException.class + }) + @ResponseBody + public ResponseEntity handleRepositoryConstraintViolationException(RepositoryConstraintViolationException rcve) { + return response(null, + new RepositoryConstraintViolationExceptionMessage(rcve, applicationContext), + HttpStatus.CONFLICT); + } - /** - * Send a 409 Conflict in case of concurrent modification. - * - * @param ex - * - * @return - */ - @SuppressWarnings({"unchecked"}) - @ExceptionHandler({ - OptimisticLockingFailureException.class, - DataIntegrityViolationException.class - }) - @ResponseBody - public ResponseEntity handleConflict(Exception ex) { - return errorResponse(null, ex, HttpStatus.CONFLICT); - } + /** + * Send a 409 Conflict in case of concurrent modification. + * + * @param ex + * + * @return + */ + @SuppressWarnings({"unchecked"}) + @ExceptionHandler({ + OptimisticLockingFailureException.class, + DataIntegrityViolationException.class + }) + @ResponseBody + public ResponseEntity handleConflict(Exception ex) { + return errorResponse(null, ex, HttpStatus.CONFLICT); + } - protected ResponseEntity notFound() { - return notFound(null, null); - } + protected ResponseEntity notFound() { + return notFound(null, null); + } - protected ResponseEntity notFound(HttpHeaders headers, T body) { - return response(headers, body, HttpStatus.NOT_FOUND); - } + protected ResponseEntity notFound(HttpHeaders headers, T body) { + return response(headers, body, HttpStatus.NOT_FOUND); + } - protected ResponseEntity badRequest(T throwable) { - return badRequest(null, throwable); - } + protected ResponseEntity badRequest(T throwable) { + return badRequest(null, throwable); + } - protected ResponseEntity badRequest(HttpHeaders headers, T throwable) { - return errorResponse(headers, throwable, HttpStatus.BAD_REQUEST); - } + protected ResponseEntity badRequest(HttpHeaders headers, T throwable) { + return errorResponse(headers, throwable, HttpStatus.BAD_REQUEST); + } - public ResponseEntity internalServerError(T throwable) { - return internalServerError(null, throwable); - } + public ResponseEntity internalServerError(T throwable) { + return internalServerError(null, throwable); + } - public ResponseEntity internalServerError(HttpHeaders headers, T throwable) { - return errorResponse(headers, throwable, HttpStatus.INTERNAL_SERVER_ERROR); - } + public ResponseEntity internalServerError(HttpHeaders headers, T throwable) { + return errorResponse(headers, throwable, HttpStatus.INTERNAL_SERVER_ERROR); + } - public ResponseEntity errorResponse(T throwable, - HttpStatus status) { - return errorResponse(null, throwable, status); - } + public ResponseEntity errorResponse(T throwable, + HttpStatus status) { + return errorResponse(null, throwable, status); + } - public ResponseEntity errorResponse(HttpHeaders headers, - T throwable, - HttpStatus status) { - LOG.error(throwable.getMessage(), throwable); - return response(headers, new ExceptionMessage(throwable), status); - } + public ResponseEntity errorResponse(HttpHeaders headers, + T throwable, + HttpStatus status) { + LOG.error(throwable.getMessage(), throwable); + return response(headers, new ExceptionMessage(throwable), status); + } - public ResponseEntity response(HttpHeaders headers, T body, HttpStatus status) { - HttpHeaders hdrs = new HttpHeaders(); - if(null != headers) { - hdrs.putAll(headers); - } - return new ResponseEntity(body, hdrs, status); - } + public ResponseEntity response(HttpHeaders headers, T body, HttpStatus status) { + HttpHeaders hdrs = new HttpHeaders(); + if(null != headers) { + hdrs.putAll(headers); + } + return new ResponseEntity(body, hdrs, status); + } - public > ResponseEntity> resourceResponse(HttpHeaders headers, - R resource, - HttpStatus status) { - HttpHeaders hdrs = new HttpHeaders(); - if(null != headers) { - hdrs.putAll(headers); - } - return new ResponseEntity>(resource, hdrs, status); - } + public > ResponseEntity> resourceResponse(HttpHeaders headers, + R resource, + HttpStatus status) { + HttpHeaders hdrs = new HttpHeaders(); + if(null != headers) { + hdrs.putAll(headers); + } + return new ResponseEntity>(resource, hdrs, status); + } - protected JsonpResponse jsonpWrapResponse(RepositoryRestRequest repoRequest, - T response, - HttpStatus status) { - return jsonpWrapResponse(repoRequest, response, null, status); - } + protected JsonpResponse jsonpWrapResponse(RepositoryRestRequest repoRequest, + T response, + HttpStatus status) { + return jsonpWrapResponse(repoRequest, response, null, status); + } - protected JsonpResponse jsonpWrapResponse(RepositoryRestRequest repoRequest, - ResponseEntity response) { - return jsonpWrapResponse(repoRequest, - response.getBody(), - response.getHeaders(), - response.getStatusCode()); - } + protected JsonpResponse jsonpWrapResponse(RepositoryRestRequest repoRequest, + ResponseEntity response) { + return jsonpWrapResponse(repoRequest, + response.getBody(), + response.getHeaders(), + response.getStatusCode()); + } - protected JsonpResponse jsonpWrapResponse(RepositoryRestRequest repoRequest, - T response, - HttpHeaders headers, - HttpStatus status) { - String callback = repoRequest.getRequest().getParameter(config.getJsonpParamName()); - String errback = (null != config.getJsonpOnErrParamName() - ? repoRequest.getRequest().getParameter(config.getJsonpOnErrParamName()) - : null); - ResponseEntity newResponse; - if(null != headers) { - newResponse = new ResponseEntity(response, headers, status); - } else { - newResponse = new ResponseEntity(response, status); - } - return new JsonpResponse(newResponse, - (null != callback ? callback : config.getJsonpParamName()), - (null != errback ? errback : config.getJsonpOnErrParamName())); - } + protected JsonpResponse jsonpWrapResponse(RepositoryRestRequest repoRequest, + T response, + HttpHeaders headers, + HttpStatus status) { + String callback = repoRequest.getRequest().getParameter(config.getJsonpParamName()); + String errback = (null != config.getJsonpOnErrParamName() + ? repoRequest.getRequest().getParameter(config.getJsonpOnErrParamName()) + : null); + ResponseEntity newResponse; + if(null != headers) { + newResponse = new ResponseEntity(response, headers, status); + } else { + newResponse = new ResponseEntity(response, status); + } + return new JsonpResponse(newResponse, + (null != callback ? callback : config.getJsonpParamName()), + (null != errback ? errback : config.getJsonpOnErrParamName())); + } - protected List queryMethodLinks(URI baseUri, Class domainType) { - List links = new ArrayList(); - RepositoryInformation repoInfo = repositories.getRepositoryInformationFor(domainType); - ResourceMapping repoMapping = ResourceMappingUtils.merge( - repoInfo.getRepositoryInterface(), - config.getResourceMappingForRepository(repoInfo.getRepositoryInterface()) - ); - for(Method method : repoInfo.getQueryMethods()) { - LinkBuilder linkBuilder = BaseUriLinkBuilder.create(buildUri(baseUri, repoMapping.getPath(), "search")); - ResourceMapping methodMapping = ResourceMappingUtils.merge(method, - repoMapping.getResourceMappingFor(method.getName())); - links.add(linkBuilder.slash(methodMapping.getPath()) - .withRel(repoMapping.getRel() + "." + methodMapping.getRel())); - } - return links; - } + protected List queryMethodLinks(URI baseUri, Class domainType) { + List links = new ArrayList(); + RepositoryInformation repoInfo = repositories.getRepositoryInformationFor(domainType); + ResourceMapping repoMapping = ResourceMappingUtils.merge( + repoInfo.getRepositoryInterface(), + config.getResourceMappingForRepository(repoInfo.getRepositoryInterface()) + ); + for(Method method : repoInfo.getQueryMethods()) { + LinkBuilder linkBuilder = BaseUriLinkBuilder.create(buildUri(baseUri, repoMapping.getPath(), "search")); + ResourceMapping methodMapping = ResourceMappingUtils.merge(method, + repoMapping.getResourceMappingFor(method.getName())); + links.add(linkBuilder.slash(methodMapping.getPath()) + .withRel(repoMapping.getRel() + "." + methodMapping.getRel())); + } + return links; + } - protected Link resourceLink(RepositoryRestRequest repoRequest, Resource resource) { - ResourceMapping repoMapping = repoRequest.getRepositoryResourceMapping(); - ResourceMapping entityMapping = repoRequest.getPersistentEntityResourceMapping(); + protected Link resourceLink(RepositoryRestRequest repoRequest, Resource resource) { + ResourceMapping repoMapping = repoRequest.getRepositoryResourceMapping(); + ResourceMapping entityMapping = repoRequest.getPersistentEntityResourceMapping(); - Link selfLink = resource.getLink("self"); - String rel = repoMapping.getRel() + "." + entityMapping.getRel(); - return new Link(selfLink.getHref(), rel); - } + Link selfLink = resource.getLink("self"); + String rel = repoMapping.getRel() + "." + entityMapping.getRel(); + return new Link(selfLink.getHref(), rel); + } } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryController.java index 94970c17b..caae871fb 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryController.java @@ -2,11 +2,11 @@ package org.springframework.data.rest.webmvc; import static java.util.Collections.*; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.convert.ConversionService; import org.springframework.data.repository.support.DomainClassConverter; import org.springframework.data.repository.support.Repositories; import org.springframework.data.rest.config.RepositoryRestConfiguration; -import org.springframework.data.rest.repository.support.RepositoryEntityLinks; import org.springframework.data.rest.webmvc.support.JsonpResponse; import org.springframework.hateoas.EntityLinks; import org.springframework.hateoas.Resource; @@ -23,43 +23,46 @@ import org.springframework.web.bind.annotation.ResponseBody; @RequestMapping("/") public class RepositoryController extends AbstractRepositoryRestController { - public RepositoryController(Repositories repositories, - RepositoryRestConfiguration config, - DomainClassConverter domainClassConverter, - ConversionService conversionService) { - super(repositories, config, domainClassConverter, conversionService); - } + @Autowired + public RepositoryController(Repositories repositories, + RepositoryRestConfiguration config, + DomainClassConverter domainClassConverter, + ConversionService conversionService, + EntityLinks entityLinks) { + super(repositories, + config, + domainClassConverter, + conversionService, + entityLinks); + } - @RequestMapping( - method = RequestMethod.GET, - produces = { - "application/json", - "application/x-spring-data-compact+json" - } - ) - @ResponseBody - public Resource listRepositories(RepositoryRestRequest repoRequest) - throws ResourceNotFoundException { - EntityLinks linkBuilder = new RepositoryEntityLinks(repoRequest.getBaseUri(), - repositories, - config); - Resource links = new Resource(emptyList()); - for(Class domainType : repositories) { - links.add(linkBuilder.linkToCollectionResource(domainType)); - } - return links; - } + @RequestMapping( + method = RequestMethod.GET, + produces = { + "application/json", + "application/x-spring-data-compact+json" + } + ) + @ResponseBody + public Resource listRepositories() + throws ResourceNotFoundException { + Resource links = new Resource(emptyList()); + for(Class domainType : repositories) { + links.add(entityLinks.linkToCollectionResource(domainType)); + } + return links; + } - @RequestMapping( - method = RequestMethod.GET, - produces = { - "application/javascript" - } - ) - @ResponseBody - public JsonpResponse> jsonpListRepositories(RepositoryRestRequest repoRequest) - throws ResourceNotFoundException { - return jsonpWrapResponse(repoRequest, listRepositories(repoRequest), HttpStatus.OK); - } + @RequestMapping( + method = RequestMethod.GET, + produces = { + "application/javascript" + } + ) + @ResponseBody + public JsonpResponse> jsonpListRepositories(RepositoryRestRequest repoRequest) + throws ResourceNotFoundException { + return jsonpWrapResponse(repoRequest, listRepositories(), HttpStatus.OK); + } } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java index 8e7e9bce9..cff5abe48 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java @@ -27,6 +27,7 @@ import org.springframework.data.rest.repository.json.JsonSchema; import org.springframework.data.rest.repository.json.PersistentEntityToJsonSchemaConverter; import org.springframework.data.rest.repository.support.DomainObjectMerger; import org.springframework.data.rest.webmvc.support.JsonpResponse; +import org.springframework.hateoas.EntityLinks; import org.springframework.hateoas.Link; import org.springframework.hateoas.Resource; import org.springframework.hateoas.Resources; @@ -54,8 +55,13 @@ public class RepositoryEntityController extends AbstractRepositoryRestController public RepositoryEntityController(Repositories repositories, RepositoryRestConfiguration config, DomainClassConverter domainClassConverter, - ConversionService conversionService) { - super(repositories, config, domainClassConverter, conversionService); + ConversionService conversionService, + EntityLinks entityLinks) { + super(repositories, + config, + domainClassConverter, + conversionService, + entityLinks); } @RequestMapping( diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityLinksMethodArgumentResolver.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityLinksMethodArgumentResolver.java deleted file mode 100644 index 8bf58e318..000000000 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityLinksMethodArgumentResolver.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.springframework.data.rest.webmvc; - -import java.net.URI; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.MethodParameter; -import org.springframework.data.rest.repository.support.RepositoryEntityLinks; -import org.springframework.data.rest.repository.support.RepositoryInformationSupport; -import org.springframework.hateoas.EntityLinks; -import org.springframework.web.bind.support.WebDataBinderFactory; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.method.support.ModelAndViewContainer; - -/** - * @author Jon Brisbin - */ -public class RepositoryEntityLinksMethodArgumentResolver - extends RepositoryInformationSupport - implements HandlerMethodArgumentResolver { - - @Autowired - private BaseUriMethodArgumentResolver baseUriResolver; - - @Override public boolean supportsParameter(MethodParameter parameter) { - return EntityLinks.class.isAssignableFrom(parameter.getParameterType()); - } - - @Override - public Object resolveArgument(MethodParameter parameter, - ModelAndViewContainer mavContainer, - NativeWebRequest webRequest, - WebDataBinderFactory binderFactory) - throws Exception { - URI baseUri = (URI)baseUriResolver.resolveArgument(parameter, - mavContainer, - webRequest, - binderFactory); - return new RepositoryEntityLinks(baseUri, repositories, config); - } - -} diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java index 0b7eee5a4..4ed270447 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java @@ -28,6 +28,7 @@ import org.springframework.data.rest.repository.context.BeforeLinkDeleteEvent; import org.springframework.data.rest.repository.context.BeforeLinkSaveEvent; import org.springframework.data.rest.repository.invoke.RepositoryMethodInvoker; import org.springframework.data.rest.webmvc.support.JsonpResponse; +import org.springframework.hateoas.EntityLinks; import org.springframework.hateoas.Link; import org.springframework.hateoas.Resource; import org.springframework.http.HttpHeaders; @@ -47,485 +48,490 @@ import org.springframework.web.bind.annotation.ResponseBody; @RequestMapping("/{repository}/{id}/{property}") public class RepositoryPropertyReferenceController extends AbstractRepositoryRestController { - public RepositoryPropertyReferenceController(Repositories repositories, - RepositoryRestConfiguration config, - DomainClassConverter domainClassConverter, - ConversionService conversionService) { - super(repositories, config, domainClassConverter, conversionService); - } + public RepositoryPropertyReferenceController(Repositories repositories, + RepositoryRestConfiguration config, + DomainClassConverter domainClassConverter, + ConversionService conversionService, + EntityLinks entityLinks) { + super(repositories, + config, + domainClassConverter, + conversionService, + entityLinks); + } - @SuppressWarnings({"unchecked"}) - @RequestMapping( - method = RequestMethod.GET, - produces = { - "application/json", - "application/x-spring-data-verbose+json" - } - ) - @ResponseBody - public ResponseEntity> followPropertyReference(final RepositoryRestRequest repoRequest, - @PathVariable String id, - @PathVariable String property) - throws ResourceNotFoundException, NoSuchMethodException { - final HttpHeaders headers = new HttpHeaders(); - Function> handler = new Function>() { - @Override public Resource apply(ReferencedProperty prop) { - if(prop.property.isCollectionLike()) { - List> resources = new ArrayList>(); - PersistentEntity entity = repositories.getPersistentEntity(prop.propertyType); - for(Object obj : ((Iterable)prop.propertyValue)) { - PersistentEntityResource per = PersistentEntityResource.wrap(entity, obj, repoRequest.getBaseUri()); - Link selfLink = repoRequest.buildEntitySelfLink(obj, conversionService); - per.add(selfLink); - resources.add(per); - } + @SuppressWarnings({"unchecked"}) + @RequestMapping( + method = RequestMethod.GET, + produces = { + "application/json", + "application/x-spring-data-verbose+json" + } + ) + @ResponseBody + public ResponseEntity> followPropertyReference(final RepositoryRestRequest repoRequest, + @PathVariable String id, + @PathVariable String property) + throws ResourceNotFoundException, NoSuchMethodException { + final HttpHeaders headers = new HttpHeaders(); + Function> handler = new Function>() { + @Override public Resource apply(ReferencedProperty prop) { + if(prop.property.isCollectionLike()) { + List> resources = new ArrayList>(); + PersistentEntity entity = repositories.getPersistentEntity(prop.propertyType); + for(Object obj : ((Iterable)prop.propertyValue)) { + PersistentEntityResource per = PersistentEntityResource.wrap(entity, obj, repoRequest.getBaseUri()); + Link selfLink = repoRequest.buildEntitySelfLink(obj, conversionService); + per.add(selfLink); + resources.add(per); + } - return new Resource(resources); - } else if(prop.property.isMap()) { - Map> resources = new HashMap>(); - PersistentEntity entity = repositories.getPersistentEntity(prop.propertyType); - for(Map.Entry entry : ((Map)prop.propertyValue).entrySet()) { - PersistentEntityResource per = PersistentEntityResource.wrap(entity, - entry.getValue(), - repoRequest.getBaseUri()); - Link selfLink = repoRequest.buildEntitySelfLink(entry.getValue(), conversionService); - per.add(selfLink); - resources.put(entry.getKey(), per); - } + return new Resource(resources); + } else if(prop.property.isMap()) { + Map> resources = new HashMap>(); + PersistentEntity entity = repositories.getPersistentEntity(prop.propertyType); + for(Map.Entry entry : ((Map)prop.propertyValue).entrySet()) { + PersistentEntityResource per = PersistentEntityResource.wrap(entity, + entry.getValue(), + repoRequest.getBaseUri()); + Link selfLink = repoRequest.buildEntitySelfLink(entry.getValue(), conversionService); + per.add(selfLink); + resources.put(entry.getKey(), per); + } - return new Resource(resources); - } else { - PersistentEntityResource per = PersistentEntityResource.wrap(repositories.getPersistentEntity(prop.propertyType), - prop.propertyValue, - repoRequest.getBaseUri()); - Link selfLink = repoRequest.buildEntitySelfLink(prop.propertyValue, conversionService); - per.add(selfLink); + return new Resource(resources); + } else { + PersistentEntityResource per = PersistentEntityResource.wrap(repositories.getPersistentEntity(prop.propertyType), + prop.propertyValue, + repoRequest.getBaseUri()); + Link selfLink = repoRequest.buildEntitySelfLink(prop.propertyValue, conversionService); + per.add(selfLink); - headers.set("Content-Location", selfLink.getHref()); + headers.set("Content-Location", selfLink.getHref()); - return new Resource(per); - } - } - }; - Resource responseResource = doWithReferencedProperty(repoRequest, - id, - property, - handler); - return resourceResponse(headers, responseResource, HttpStatus.OK); - } + return new Resource(per); + } + } + }; + Resource responseResource = doWithReferencedProperty(repoRequest, + id, + property, + handler); + return resourceResponse(headers, responseResource, HttpStatus.OK); + } - @SuppressWarnings({"unchecked"}) - @RequestMapping( - value = "/{propertyId}", - method = RequestMethod.GET, - produces = { - "application/json", - "application/x-spring-data-verbose+json", - "application/x-spring-data-compact+json", - "text/uri-list" - } - ) - @ResponseBody - public ResponseEntity> followPropertyReference(final RepositoryRestRequest repoRequest, - @PathVariable String id, - @PathVariable String property, - final @PathVariable String propertyId) - throws ResourceNotFoundException, NoSuchMethodException { - final HttpHeaders headers = new HttpHeaders(); - Function> handler = new Function>() { - @Override public Resource apply(ReferencedProperty prop) { - if(prop.property.isCollectionLike()) { - PersistentEntity entity = repositories.getPersistentEntity(prop.propertyType); - for(Object obj : ((Iterable)prop.propertyValue)) { - BeanWrapper propValWrapper = BeanWrapper.create(obj, conversionService); - String sId = propValWrapper.getProperty(prop.entity.getIdProperty()).toString(); - if(propertyId.equals(sId)) { - PersistentEntityResource per = PersistentEntityResource.wrap(entity, obj, repoRequest.getBaseUri()); - Link selfLink = repoRequest.buildEntitySelfLink(obj, conversionService); - per.add(selfLink); - headers.set("Content-Location", selfLink.getHref()); - return per; - } - } - } else if(prop.property.isMap()) { - PersistentEntity entity = repositories.getPersistentEntity(prop.propertyType); - for(Map.Entry entry : ((Map)prop.propertyValue).entrySet()) { - BeanWrapper propValWrapper = BeanWrapper.create(entry.getValue(), conversionService); - String sId = propValWrapper.getProperty(prop.entity.getIdProperty()).toString(); - if(propertyId.equals(sId)) { - PersistentEntityResource per = PersistentEntityResource.wrap(entity, - entry.getValue(), - repoRequest.getBaseUri()); - Link selfLink = repoRequest.buildEntitySelfLink(entry.getValue(), conversionService); - per.add(selfLink); - headers.set("Content-Location", selfLink.getHref()); - return per; - } - } - } else { - return new Resource(prop.propertyValue); - } - throw new IllegalArgumentException(new ResourceNotFoundException()); - } - }; - Resource responseResource = doWithReferencedProperty(repoRequest, - id, - property, - handler); - return resourceResponse(headers, responseResource, HttpStatus.OK); - } + @SuppressWarnings({"unchecked"}) + @RequestMapping( + value = "/{propertyId}", + method = RequestMethod.GET, + produces = { + "application/json", + "application/x-spring-data-verbose+json", + "application/x-spring-data-compact+json", + "text/uri-list" + } + ) + @ResponseBody + public ResponseEntity> followPropertyReference(final RepositoryRestRequest repoRequest, + @PathVariable String id, + @PathVariable String property, + final @PathVariable String propertyId) + throws ResourceNotFoundException, NoSuchMethodException { + final HttpHeaders headers = new HttpHeaders(); + Function> handler = new Function>() { + @Override public Resource apply(ReferencedProperty prop) { + if(prop.property.isCollectionLike()) { + PersistentEntity entity = repositories.getPersistentEntity(prop.propertyType); + for(Object obj : ((Iterable)prop.propertyValue)) { + BeanWrapper propValWrapper = BeanWrapper.create(obj, conversionService); + String sId = propValWrapper.getProperty(prop.entity.getIdProperty()).toString(); + if(propertyId.equals(sId)) { + PersistentEntityResource per = PersistentEntityResource.wrap(entity, obj, repoRequest.getBaseUri()); + Link selfLink = repoRequest.buildEntitySelfLink(obj, conversionService); + per.add(selfLink); + headers.set("Content-Location", selfLink.getHref()); + return per; + } + } + } else if(prop.property.isMap()) { + PersistentEntity entity = repositories.getPersistentEntity(prop.propertyType); + for(Map.Entry entry : ((Map)prop.propertyValue).entrySet()) { + BeanWrapper propValWrapper = BeanWrapper.create(entry.getValue(), conversionService); + String sId = propValWrapper.getProperty(prop.entity.getIdProperty()).toString(); + if(propertyId.equals(sId)) { + PersistentEntityResource per = PersistentEntityResource.wrap(entity, + entry.getValue(), + repoRequest.getBaseUri()); + Link selfLink = repoRequest.buildEntitySelfLink(entry.getValue(), conversionService); + per.add(selfLink); + headers.set("Content-Location", selfLink.getHref()); + return per; + } + } + } else { + return new Resource(prop.propertyValue); + } + throw new IllegalArgumentException(new ResourceNotFoundException()); + } + }; + Resource responseResource = doWithReferencedProperty(repoRequest, + id, + property, + handler); + return resourceResponse(headers, responseResource, HttpStatus.OK); + } - @SuppressWarnings({"unchecked"}) - @RequestMapping( - method = RequestMethod.GET, - produces = { - "application/x-spring-data-compact+json", - "text/uri-list" - } - ) - @ResponseBody - public ResponseEntity> followPropertyReferenceCompact(RepositoryRestRequest repoRequest, - @PathVariable String id, - @PathVariable String property) - throws ResourceNotFoundException, NoSuchMethodException { - ResponseEntity> response = followPropertyReference(repoRequest, id, property); - if(response.getStatusCode() != HttpStatus.OK) { - return response; - } + @SuppressWarnings({"unchecked"}) + @RequestMapping( + method = RequestMethod.GET, + produces = { + "application/x-spring-data-compact+json", + "text/uri-list" + } + ) + @ResponseBody + public ResponseEntity> followPropertyReferenceCompact(RepositoryRestRequest repoRequest, + @PathVariable String id, + @PathVariable String property) + throws ResourceNotFoundException, NoSuchMethodException { + ResponseEntity> response = followPropertyReference(repoRequest, id, property); + if(response.getStatusCode() != HttpStatus.OK) { + return response; + } - ResourceMapping repoMapping = repoRequest.getRepositoryResourceMapping(); - ResourceMapping entityMapping = repoRequest.getPersistentEntityResourceMapping(); - String propName = entityMapping.getNameForPath(property); - ResourceMapping propMapping = entityMapping.getResourceMappingFor(entityMapping.getNameForPath(property)); - PersistentProperty persistentProp = repoRequest.getPersistentEntity().getPersistentProperty(propName); - Class propType = (persistentProp.isCollectionLike() || persistentProp.isMap() - ? persistentProp.getComponentType() - : persistentProp.getType()); - ResourceMapping propRepoMapping = getResourceMapping(config, repositories.getRepositoryInformationFor(propType)); - String propRel = String.format("%s.%s.%s.%s", - repoMapping.getRel(), - entityMapping.getRel(), - (null != propMapping ? propMapping.getRel() : property), - propRepoMapping.getRel()); + ResourceMapping repoMapping = repoRequest.getRepositoryResourceMapping(); + ResourceMapping entityMapping = repoRequest.getPersistentEntityResourceMapping(); + String propName = entityMapping.getNameForPath(property); + ResourceMapping propMapping = entityMapping.getResourceMappingFor(entityMapping.getNameForPath(property)); + PersistentProperty persistentProp = repoRequest.getPersistentEntity().getPersistentProperty(propName); + Class propType = (persistentProp.isCollectionLike() || persistentProp.isMap() + ? persistentProp.getComponentType() + : persistentProp.getType()); + ResourceMapping propRepoMapping = getResourceMapping(config, repositories.getRepositoryInformationFor(propType)); + String propRel = String.format("%s.%s.%s.%s", + repoMapping.getRel(), + entityMapping.getRel(), + (null != propMapping ? propMapping.getRel() : property), + propRepoMapping.getRel()); - Resource resource = response.getBody(); + Resource resource = response.getBody(); - List links = new ArrayList(); + List links = new ArrayList(); - URI entityBaseUri = buildUri(repoRequest.getBaseUri(), - repoMapping.getPath(), - id, - property); + URI entityBaseUri = buildUri(repoRequest.getBaseUri(), + repoMapping.getPath(), + id, + property); - if(resource.getContent() instanceof Iterable) { - for(Resource res : (Iterable>)resource.getContent()) { - Link propLink = propertyReferenceLink(res, entityBaseUri, propRel); - links.add(propLink); - } - } else if(resource.getContent() instanceof Map) { - for(Map.Entry> entry : ((Map>)resource.getContent()).entrySet()) { - Link l = new Link(entry.getValue().getLink("self").getHref(), conversionService.convert(entry.getKey(), - String.class)); - links.add(l); - } - } else { - links.add(new Link(entityBaseUri.toString(), propRel)); - } + if(resource.getContent() instanceof Iterable) { + for(Resource res : (Iterable>)resource.getContent()) { + Link propLink = propertyReferenceLink(res, entityBaseUri, propRel); + links.add(propLink); + } + } else if(resource.getContent() instanceof Map) { + for(Map.Entry> entry : ((Map>)resource.getContent()).entrySet()) { + Link l = new Link(entry.getValue().getLink("self").getHref(), conversionService.convert(entry.getKey(), + String.class)); + links.add(l); + } + } else { + links.add(new Link(entityBaseUri.toString(), propRel)); + } - return resourceResponse(null, new Resource(EMPTY_RESOURCE_LIST, links), HttpStatus.OK); - } + return resourceResponse(null, new Resource(EMPTY_RESOURCE_LIST, links), HttpStatus.OK); + } - @SuppressWarnings({"unchecked"}) - @RequestMapping( - method = RequestMethod.GET, - produces = { - "application/javascript" - } - ) - @ResponseBody - public JsonpResponse jsonpFollowPropertyReference(RepositoryRestRequest repoRequest, - @PathVariable String id, - @PathVariable String property) - throws ResourceNotFoundException, NoSuchMethodException { - return jsonpWrapResponse(repoRequest, - followPropertyReference(repoRequest, - id, - property), - HttpStatus.OK); - } + @SuppressWarnings({"unchecked"}) + @RequestMapping( + method = RequestMethod.GET, + produces = { + "application/javascript" + } + ) + @ResponseBody + public JsonpResponse jsonpFollowPropertyReference(RepositoryRestRequest repoRequest, + @PathVariable String id, + @PathVariable String property) + throws ResourceNotFoundException, NoSuchMethodException { + return jsonpWrapResponse(repoRequest, + followPropertyReference(repoRequest, + id, + property), + HttpStatus.OK); + } - @SuppressWarnings({"unchecked"}) - @RequestMapping( - value = "/{propertyId}", - method = RequestMethod.GET, - produces = { - "application/javascript" - } - ) - @ResponseBody - public JsonpResponse jsonpFollowPropertyReference(RepositoryRestRequest repoRequest, - @PathVariable String id, - @PathVariable String property, - @PathVariable String propertyId) - throws ResourceNotFoundException, NoSuchMethodException { - return jsonpWrapResponse(repoRequest, - followPropertyReference(repoRequest, - id, - property, - propertyId), - HttpStatus.OK); - } + @SuppressWarnings({"unchecked"}) + @RequestMapping( + value = "/{propertyId}", + method = RequestMethod.GET, + produces = { + "application/javascript" + } + ) + @ResponseBody + public JsonpResponse jsonpFollowPropertyReference(RepositoryRestRequest repoRequest, + @PathVariable String id, + @PathVariable String property, + @PathVariable String propertyId) + throws ResourceNotFoundException, NoSuchMethodException { + return jsonpWrapResponse(repoRequest, + followPropertyReference(repoRequest, + id, + property, + propertyId), + HttpStatus.OK); + } - @SuppressWarnings({"unchecked"}) - @RequestMapping( - method = { - RequestMethod.POST, - RequestMethod.PUT - }, - consumes = { - "application/json", - "application/x-spring-data-compact+json", - "text/uri-list" - } - ) - @ResponseBody - public ResponseEntity> createPropertyReference(final RepositoryRestRequest repoRequest, - final @RequestBody Resource incoming, - @PathVariable String id, - @PathVariable String property) - throws ResourceNotFoundException, NoSuchMethodException { - final RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker(); - if(!repoMethodInvoker.hasSaveOne()) { - throw new NoSuchMethodException(); - } - Function> handler = new Function>() { - @Override public Resource apply(ReferencedProperty prop) { - if(prop.property.isCollectionLike()) { - Collection coll = new ArrayList(); - if("POST".equals(repoRequest.getRequest().getMethod())) { - coll.addAll((Collection)prop.propertyValue); - } - for(Link l : incoming.getLinks()) { - Object propVal = loadPropertyValue(prop.propertyType, l.getHref()); - coll.add(propVal); - } - prop.wrapper.setProperty(prop.property, coll); - } else if(prop.property.isMap()) { - Map m = new HashMap(); - if("POST".equals(repoRequest.getRequest().getMethod())) { - m.putAll((Map)prop.propertyValue); - } - for(Link l : incoming.getLinks()) { - Object propVal = loadPropertyValue(prop.propertyType, l.getHref()); - m.put(l.getRel(), propVal); - } - prop.wrapper.setProperty(prop.property, m); - } else { - if("POST".equals(repoRequest.getRequest().getMethod())) { - throw new IllegalStateException( - "Cannot POST a reference to this singular property since the property type is not a List or a Map."); - } - if(incoming.getLinks().size() != 1) { - throw new IllegalArgumentException( - "Must send only 1 link to update a property reference that isn't a List or a Map."); - } - Object propVal = loadPropertyValue(prop.propertyType, incoming.getLinks().get(0).getHref()); - prop.wrapper.setProperty(prop.property, propVal); - } + @SuppressWarnings({"unchecked"}) + @RequestMapping( + method = { + RequestMethod.POST, + RequestMethod.PUT + }, + consumes = { + "application/json", + "application/x-spring-data-compact+json", + "text/uri-list" + } + ) + @ResponseBody + public ResponseEntity> createPropertyReference(final RepositoryRestRequest repoRequest, + final @RequestBody Resource incoming, + @PathVariable String id, + @PathVariable String property) + throws ResourceNotFoundException, NoSuchMethodException { + final RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker(); + if(!repoMethodInvoker.hasSaveOne()) { + throw new NoSuchMethodException(); + } + Function> handler = new Function>() { + @Override public Resource apply(ReferencedProperty prop) { + if(prop.property.isCollectionLike()) { + Collection coll = new ArrayList(); + if("POST".equals(repoRequest.getRequest().getMethod())) { + coll.addAll((Collection)prop.propertyValue); + } + for(Link l : incoming.getLinks()) { + Object propVal = loadPropertyValue(prop.propertyType, l.getHref()); + coll.add(propVal); + } + prop.wrapper.setProperty(prop.property, coll); + } else if(prop.property.isMap()) { + Map m = new HashMap(); + if("POST".equals(repoRequest.getRequest().getMethod())) { + m.putAll((Map)prop.propertyValue); + } + for(Link l : incoming.getLinks()) { + Object propVal = loadPropertyValue(prop.propertyType, l.getHref()); + m.put(l.getRel(), propVal); + } + prop.wrapper.setProperty(prop.property, m); + } else { + if("POST".equals(repoRequest.getRequest().getMethod())) { + throw new IllegalStateException( + "Cannot POST a reference to this singular property since the property type is not a List or a Map."); + } + if(incoming.getLinks().size() != 1) { + throw new IllegalArgumentException( + "Must send only 1 link to update a property reference that isn't a List or a Map."); + } + Object propVal = loadPropertyValue(prop.propertyType, incoming.getLinks().get(0).getHref()); + prop.wrapper.setProperty(prop.property, propVal); + } - applicationContext.publishEvent(new BeforeLinkSaveEvent(prop.wrapper.getBean(), prop.propertyValue)); - Object result = repoMethodInvoker.save(prop.wrapper.getBean()); - applicationContext.publishEvent(new AfterLinkSaveEvent(result, prop.propertyValue)); - return null; - } - }; - doWithReferencedProperty(repoRequest, - id, - property, - handler); - return resourceResponse(null, EMPTY_RESOURCE, HttpStatus.CREATED); - } + applicationContext.publishEvent(new BeforeLinkSaveEvent(prop.wrapper.getBean(), prop.propertyValue)); + Object result = repoMethodInvoker.save(prop.wrapper.getBean()); + applicationContext.publishEvent(new AfterLinkSaveEvent(result, prop.propertyValue)); + return null; + } + }; + doWithReferencedProperty(repoRequest, + id, + property, + handler); + return resourceResponse(null, EMPTY_RESOURCE, HttpStatus.CREATED); + } - @SuppressWarnings({"unchecked"}) - @RequestMapping( - method = { - RequestMethod.POST, - RequestMethod.PUT - }, - consumes = { - "application/javascript" - } - ) - @ResponseBody - public JsonpResponse jsonpCreatePropertyReference(final RepositoryRestRequest repoRequest, - final @RequestBody Resource incoming, - @PathVariable String id, - @PathVariable String property) - throws ResourceNotFoundException, NoSuchMethodException { - return jsonpWrapResponse(repoRequest, createPropertyReference(repoRequest, - incoming, - id, - property)); - } + @SuppressWarnings({"unchecked"}) + @RequestMapping( + method = { + RequestMethod.POST, + RequestMethod.PUT + }, + consumes = { + "application/javascript" + } + ) + @ResponseBody + public JsonpResponse jsonpCreatePropertyReference(final RepositoryRestRequest repoRequest, + final @RequestBody Resource incoming, + @PathVariable String id, + @PathVariable String property) + throws ResourceNotFoundException, NoSuchMethodException { + return jsonpWrapResponse(repoRequest, createPropertyReference(repoRequest, + incoming, + id, + property)); + } - @SuppressWarnings({"unchecked"}) - @RequestMapping( - value = "/{propertyId}", - method = RequestMethod.DELETE - ) - @ResponseBody - public ResponseEntity> deletePropertyReference(final RepositoryRestRequest repoRequest, - @PathVariable String id, - @PathVariable String property, - final @PathVariable String propertyId) - throws ResourceNotFoundException, NoSuchMethodException { - final RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker(); - if(!repoMethodInvoker.hasDeleteOne()) { - throw new NoSuchMethodException(); - } + @SuppressWarnings({"unchecked"}) + @RequestMapping( + value = "/{propertyId}", + method = RequestMethod.DELETE + ) + @ResponseBody + public ResponseEntity> deletePropertyReference(final RepositoryRestRequest repoRequest, + @PathVariable String id, + @PathVariable String property, + final @PathVariable String propertyId) + throws ResourceNotFoundException, NoSuchMethodException { + final RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker(); + if(!repoMethodInvoker.hasDeleteOne()) { + throw new NoSuchMethodException(); + } - Function> handler = new Function>() { - @Override public Resource apply(ReferencedProperty prop) { - if(null == prop.propertyValue) { - return null; - } - if(prop.property.isCollectionLike()) { - Collection coll = new ArrayList(); - for(Object obj : (Collection)prop.propertyValue) { - BeanWrapper propValWrapper = BeanWrapper.create(obj, conversionService); - String s = (String)propValWrapper.getProperty(prop.entity.getIdProperty(), String.class, false); - if(!propertyId.equals(s)) { - coll.add(obj); - } - } - prop.wrapper.setProperty(prop.property, coll); - } else if(prop.property.isMap()) { - Map m = new HashMap(); - for(Map.Entry entry : ((Map)prop.propertyValue).entrySet()) { - BeanWrapper propValWrapper = BeanWrapper.create(entry.getValue(), conversionService); - String s = (String)propValWrapper.getProperty(prop.entity.getIdProperty(), String.class, false); - if(!propertyId.equals(s)) { - m.put(entry.getKey(), entry.getValue()); - } - } - prop.wrapper.setProperty(prop.property, m); - } else { - prop.wrapper.setProperty(prop.property, null); - } + Function> handler = new Function>() { + @Override public Resource apply(ReferencedProperty prop) { + if(null == prop.propertyValue) { + return null; + } + if(prop.property.isCollectionLike()) { + Collection coll = new ArrayList(); + for(Object obj : (Collection)prop.propertyValue) { + BeanWrapper propValWrapper = BeanWrapper.create(obj, conversionService); + String s = (String)propValWrapper.getProperty(prop.entity.getIdProperty(), String.class, false); + if(!propertyId.equals(s)) { + coll.add(obj); + } + } + prop.wrapper.setProperty(prop.property, coll); + } else if(prop.property.isMap()) { + Map m = new HashMap(); + for(Map.Entry entry : ((Map)prop.propertyValue).entrySet()) { + BeanWrapper propValWrapper = BeanWrapper.create(entry.getValue(), conversionService); + String s = (String)propValWrapper.getProperty(prop.entity.getIdProperty(), String.class, false); + if(!propertyId.equals(s)) { + m.put(entry.getKey(), entry.getValue()); + } + } + prop.wrapper.setProperty(prop.property, m); + } else { + prop.wrapper.setProperty(prop.property, null); + } - applicationContext.publishEvent(new BeforeLinkDeleteEvent(prop.wrapper.getBean(), prop.propertyValue)); - Object result = repoMethodInvoker.save(prop.wrapper.getBean()); - applicationContext.publishEvent(new AfterLinkDeleteEvent(result, prop.propertyValue)); - return null; - } - }; - doWithReferencedProperty(repoRequest, - id, - property, - handler); + applicationContext.publishEvent(new BeforeLinkDeleteEvent(prop.wrapper.getBean(), prop.propertyValue)); + Object result = repoMethodInvoker.save(prop.wrapper.getBean()); + applicationContext.publishEvent(new AfterLinkDeleteEvent(result, prop.propertyValue)); + return null; + } + }; + doWithReferencedProperty(repoRequest, + id, + property, + handler); - return resourceResponse(null, EMPTY_RESOURCE, HttpStatus.NO_CONTENT); - } + return resourceResponse(null, EMPTY_RESOURCE, HttpStatus.NO_CONTENT); + } - @SuppressWarnings({"unchecked"}) - @RequestMapping( - value = "/{propertyId}", - method = RequestMethod.DELETE, - produces = { - "application/javascript" - } - ) - @ResponseBody - public JsonpResponse jsonpDeletePropertyReference(final RepositoryRestRequest repoRequest, - @PathVariable String id, - @PathVariable String property, - final @PathVariable String propertyId) - throws ResourceNotFoundException, NoSuchMethodException { - return jsonpWrapResponse(repoRequest, deletePropertyReference(repoRequest, - id, - property, - propertyId)); - } + @SuppressWarnings({"unchecked"}) + @RequestMapping( + value = "/{propertyId}", + method = RequestMethod.DELETE, + produces = { + "application/javascript" + } + ) + @ResponseBody + public JsonpResponse jsonpDeletePropertyReference(final RepositoryRestRequest repoRequest, + @PathVariable String id, + @PathVariable String property, + final @PathVariable String propertyId) + throws ResourceNotFoundException, NoSuchMethodException { + return jsonpWrapResponse(repoRequest, deletePropertyReference(repoRequest, + id, + property, + propertyId)); + } - private Link propertyReferenceLink(Resource resource, - URI baseUri, - String rel) { - Link selfLink = resource.getLink("self"); - String objId = selfLink.getHref().substring(selfLink.getHref().lastIndexOf('/') + 1); - return new Link(buildUri(baseUri, objId).toString(), rel); - } + private Link propertyReferenceLink(Resource resource, + URI baseUri, + String rel) { + Link selfLink = resource.getLink("self"); + String objId = selfLink.getHref().substring(selfLink.getHref().lastIndexOf('/') + 1); + return new Link(buildUri(baseUri, objId).toString(), rel); + } - private Object loadPropertyValue(Class type, String href) { - String id = href.substring(href.lastIndexOf('/') + 1); - return domainClassConverter.convert(id, - STRING_TYPE, - TypeDescriptor.valueOf(type)); - } + private Object loadPropertyValue(Class type, String href) { + String id = href.substring(href.lastIndexOf('/') + 1); + return domainClassConverter.convert(id, + STRING_TYPE, + TypeDescriptor.valueOf(type)); + } - @SuppressWarnings({"unchecked"}) - private Resource doWithReferencedProperty(RepositoryRestRequest repoRequest, - String id, - String propertyPath, - Function> handler) - throws ResourceNotFoundException, NoSuchMethodException { - RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker(); - if(!repoMethodInvoker.hasFindOne()) { - throw new NoSuchMethodException(); - } + @SuppressWarnings({"unchecked"}) + private Resource doWithReferencedProperty(RepositoryRestRequest repoRequest, + String id, + String propertyPath, + Function> handler) + throws ResourceNotFoundException, NoSuchMethodException { + RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker(); + if(!repoMethodInvoker.hasFindOne()) { + throw new NoSuchMethodException(); + } - Object domainObj = domainClassConverter.convert(id, - STRING_TYPE, - TypeDescriptor.valueOf(repoRequest.getPersistentEntity() - .getType())); - if(null == domainObj) { - throw new ResourceNotFoundException(); - } + Object domainObj = domainClassConverter.convert(id, + STRING_TYPE, + TypeDescriptor.valueOf(repoRequest.getPersistentEntity() + .getType())); + if(null == domainObj) { + throw new ResourceNotFoundException(); + } - String propertyName = repoRequest.getPersistentEntityResourceMapping().getNameForPath(propertyPath); - PersistentProperty prop = repoRequest.getPersistentEntity().getPersistentProperty(propertyName); - if(null == prop) { - throw new ResourceNotFoundException(); - } + String propertyName = repoRequest.getPersistentEntityResourceMapping().getNameForPath(propertyPath); + PersistentProperty prop = repoRequest.getPersistentEntity().getPersistentProperty(propertyName); + if(null == prop) { + throw new ResourceNotFoundException(); + } - BeanWrapper wrapper = BeanWrapper.create(domainObj, conversionService); - Object propVal = wrapper.getProperty(prop); - if(null == propVal) { - throw new ResourceNotFoundException(); - } + BeanWrapper wrapper = BeanWrapper.create(domainObj, conversionService); + Object propVal = wrapper.getProperty(prop); + if(null == propVal) { + throw new ResourceNotFoundException(); + } - return handler.apply(new ReferencedProperty(prop, - propVal, - wrapper)); - } + return handler.apply(new ReferencedProperty(prop, + propVal, + wrapper)); + } - private class ReferencedProperty { - final PersistentEntity entity; - final PersistentProperty property; - final Class propertyType; - final Object propertyValue; - final BeanWrapper wrapper; - final RepositoryInformation propertyRepoInfo; - final Object propertyRepo; - final RepositoryMethodInvoker repoMethodInvoker; + private class ReferencedProperty { + final PersistentEntity entity; + final PersistentProperty property; + final Class propertyType; + final Object propertyValue; + final BeanWrapper wrapper; + final RepositoryInformation propertyRepoInfo; + final Object propertyRepo; + final RepositoryMethodInvoker repoMethodInvoker; - private ReferencedProperty(PersistentProperty property, - Object propertyValue, - BeanWrapper wrapper) { - this.property = property; - this.propertyValue = propertyValue; - this.wrapper = wrapper; - if(property.isCollectionLike()) { - this.propertyType = property.getComponentType(); - } else if(property.isMap()) { - this.propertyType = property.getMapValueType(); - } else { - this.propertyType = property.getType(); - } - this.propertyRepoInfo = repositories.getRepositoryInformationFor(propertyType); - this.entity = repositories.getPersistentEntity(propertyType); - this.propertyRepo = repositories.getRepositoryFor(entity.getType()); - this.repoMethodInvoker = new RepositoryMethodInvoker(propertyRepo, propertyRepoInfo, entity); - } - } + private ReferencedProperty(PersistentProperty property, + Object propertyValue, + BeanWrapper wrapper) { + this.property = property; + this.propertyValue = propertyValue; + this.wrapper = wrapper; + if(property.isCollectionLike()) { + this.propertyType = property.getComponentType(); + } else if(property.isMap()) { + this.propertyType = property.getMapValueType(); + } else { + this.propertyType = property.getType(); + } + this.propertyRepoInfo = repositories.getRepositoryInformationFor(propertyType); + this.entity = repositories.getPersistentEntity(propertyType); + this.propertyRepo = repositories.getRepositoryFor(entity.getType()); + this.repoMethodInvoker = new RepositoryMethodInvoker(propertyRepo, propertyRepoInfo, entity); + } + } } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySearchController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySearchController.java index ddde8ce23..62e9148f3 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySearchController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySearchController.java @@ -22,6 +22,7 @@ import org.springframework.data.rest.repository.PersistentEntityResource; import org.springframework.data.rest.repository.invoke.RepositoryMethod; import org.springframework.data.rest.repository.invoke.RepositoryMethodInvoker; import org.springframework.data.rest.webmvc.support.JsonpResponse; +import org.springframework.hateoas.EntityLinks; import org.springframework.hateoas.Link; import org.springframework.hateoas.Resource; import org.springframework.http.HttpStatus; @@ -38,204 +39,209 @@ import org.springframework.web.bind.annotation.ResponseBody; @RequestMapping("/{repository}/search") public class RepositorySearchController extends AbstractRepositoryRestController { - public RepositorySearchController(Repositories repositories, - RepositoryRestConfiguration config, - DomainClassConverter domainClassConverter, - ConversionService conversionService) { - super(repositories, config, domainClassConverter, conversionService); - } + public RepositorySearchController(Repositories repositories, + RepositoryRestConfiguration config, + DomainClassConverter domainClassConverter, + ConversionService conversionService, + EntityLinks entityLinks) { + super(repositories, + config, + domainClassConverter, + conversionService, + entityLinks); + } - @RequestMapping( - method = RequestMethod.GET, - produces = { - "application/json", - "application/x-spring-data-compact+json" - } - ) - @ResponseBody - public Resource list(RepositoryRestRequest repoRequest) { - List links = new ArrayList(); - links.addAll(queryMethodLinks(repoRequest.getBaseUri(), - repoRequest.getPersistentEntity().getType())); - return new Resource(Collections.emptyList(), links); - } + @RequestMapping( + method = RequestMethod.GET, + produces = { + "application/json", + "application/x-spring-data-compact+json" + } + ) + @ResponseBody + public Resource list(RepositoryRestRequest repoRequest) { + List links = new ArrayList(); + links.addAll(queryMethodLinks(repoRequest.getBaseUri(), + repoRequest.getPersistentEntity().getType())); + return new Resource(Collections.emptyList(), links); + } - @RequestMapping( - method = RequestMethod.GET, - produces = { - "application/javascript" - } - ) - @ResponseBody - public JsonpResponse jsonpList(RepositoryRestRequest repoRequest) { - return jsonpWrapResponse(repoRequest, list(repoRequest), HttpStatus.OK); - } + @RequestMapping( + method = RequestMethod.GET, + produces = { + "application/javascript" + } + ) + @ResponseBody + public JsonpResponse jsonpList(RepositoryRestRequest repoRequest) { + return jsonpWrapResponse(repoRequest, list(repoRequest), HttpStatus.OK); + } - @SuppressWarnings({"unchecked"}) - @RequestMapping( - value = "/{method}", - method = RequestMethod.GET, - produces = { - "application/json", - "application/x-spring-data-verbose+json" - } - ) - @ResponseBody - public Resource query(RepositoryRestRequest repoRequest, - @PathVariable String method) - throws ResourceNotFoundException { - RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker(); - if(repoMethodInvoker.getQueryMethods().isEmpty()) { - throw new ResourceNotFoundException(); - } + @SuppressWarnings({"unchecked"}) + @RequestMapping( + value = "/{method}", + method = RequestMethod.GET, + produces = { + "application/json", + "application/x-spring-data-verbose+json" + } + ) + @ResponseBody + public Resource query(RepositoryRestRequest repoRequest, + @PathVariable String method) + throws ResourceNotFoundException { + RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker(); + if(repoMethodInvoker.getQueryMethods().isEmpty()) { + throw new ResourceNotFoundException(); + } - ResourceMapping repoMapping = repoRequest.getRepositoryResourceMapping(); - String methodName = repoMapping.getNameForPath(method); - RepositoryMethod repoMethod = repoMethodInvoker.getQueryMethods().get(methodName); - if(null == repoMethod) { - for(RepositoryMethod queryMethod : repoMethodInvoker.getQueryMethods().values()) { - String path = findPath(queryMethod.getMethod()); - if(path.equals(method)) { - repoMethod = queryMethod; - break; - } - } - if(null == repoMethod) { - throw new ResourceNotFoundException(); - } - } + ResourceMapping repoMapping = repoRequest.getRepositoryResourceMapping(); + String methodName = repoMapping.getNameForPath(method); + RepositoryMethod repoMethod = repoMethodInvoker.getQueryMethods().get(methodName); + if(null == repoMethod) { + for(RepositoryMethod queryMethod : repoMethodInvoker.getQueryMethods().values()) { + String path = findPath(queryMethod.getMethod()); + if(path.equals(method)) { + repoMethod = queryMethod; + break; + } + } + if(null == repoMethod) { + throw new ResourceNotFoundException(); + } + } - List methodParams = repoMethod.getParameters(); - Object[] paramValues = new Object[methodParams.size()]; - if(!methodParams.isEmpty()) { - for(int i = 0; i < paramValues.length; i++) { - MethodParameter param = methodParams.get(i); - if(Pageable.class.isAssignableFrom(param.getParameterType())) { - paramValues[i] = new PageRequest(repoRequest.getPagingAndSorting().getPageNumber(), - repoRequest.getPagingAndSorting().getPageSize(), - repoRequest.getPagingAndSorting().getSort()); - } else if(Sort.class.isAssignableFrom(param.getParameterType())) { - paramValues[i] = repoRequest.getPagingAndSorting().getSort(); - } else { - String paramName = repoMethod.getParameterNames().get(i); - String[] queryParamVals = repoRequest.getRequest().getParameterValues(paramName); - if(null == queryParamVals) { - if(paramName.startsWith("arg")) { - throw new IllegalArgumentException("No @Param annotation found on query method " - + repoMethod.getMethod().getName() - + " for parameter " + param.getParameterName()); - } else { - throw new IllegalArgumentException("No query parameter specified for " - + repoMethod.getMethod().getName() + " param '" - + paramName + "'"); - } - } - paramValues[i] = methodParameterConversionService.convert(queryParamVals, param); - } - } - } + List methodParams = repoMethod.getParameters(); + Object[] paramValues = new Object[methodParams.size()]; + if(!methodParams.isEmpty()) { + for(int i = 0; i < paramValues.length; i++) { + MethodParameter param = methodParams.get(i); + if(Pageable.class.isAssignableFrom(param.getParameterType())) { + paramValues[i] = new PageRequest(repoRequest.getPagingAndSorting().getPageNumber(), + repoRequest.getPagingAndSorting().getPageSize(), + repoRequest.getPagingAndSorting().getSort()); + } else if(Sort.class.isAssignableFrom(param.getParameterType())) { + paramValues[i] = repoRequest.getPagingAndSorting().getSort(); + } else { + String paramName = repoMethod.getParameterNames().get(i); + String[] queryParamVals = repoRequest.getRequest().getParameterValues(paramName); + if(null == queryParamVals) { + if(paramName.startsWith("arg")) { + throw new IllegalArgumentException("No @Param annotation found on query method " + + repoMethod.getMethod().getName() + + " for parameter " + param.getParameterName()); + } else { + throw new IllegalArgumentException("No query parameter specified for " + + repoMethod.getMethod().getName() + " param '" + + paramName + "'"); + } + } + paramValues[i] = methodParameterConversionService.convert(queryParamVals, param); + } + } + } - BaseUriAwareResource resources; - List links = new ArrayList(); - Object result = repoMethodInvoker.invokeQueryMethod(repoMethod, paramValues); - if(result instanceof Page) { - Page page = (Page)result; - if(page.hasPreviousPage()) { - repoRequest.addPrevLink(page, links); - } - if(page.hasNextPage()) { - repoRequest.addNextLink(page, links); - } - if(page.hasContent()) { - resources = entitiesToResource(repoRequest, page.getContent()); - } else { - resources = new BaseUriAwareResource(EMPTY_RESOURCE_LIST); - } - } else if(result instanceof Iterable) { - resources = entitiesToResource(repoRequest, (Iterable)result); - } else if(null == result) { - resources = new BaseUriAwareResource(EMPTY_RESOURCE_LIST); - } else { - PersistentEntityResource per = PersistentEntityResource.wrap(repoRequest.getPersistentEntity(), - result, - repoRequest.getBaseUri()); - per.add(repoRequest.buildEntitySelfLink(result, conversionService)); - resources = per; - } - resources.setBaseUri(repoRequest.getBaseUri()) - .add(links); + BaseUriAwareResource resources; + List links = new ArrayList(); + Object result = repoMethodInvoker.invokeQueryMethod(repoMethod, paramValues); + if(result instanceof Page) { + Page page = (Page)result; + if(page.hasPreviousPage()) { + repoRequest.addPrevLink(page, links); + } + if(page.hasNextPage()) { + repoRequest.addNextLink(page, links); + } + if(page.hasContent()) { + resources = entitiesToResource(repoRequest, page.getContent()); + } else { + resources = new BaseUriAwareResource(EMPTY_RESOURCE_LIST); + } + } else if(result instanceof Iterable) { + resources = entitiesToResource(repoRequest, (Iterable)result); + } else if(null == result) { + resources = new BaseUriAwareResource(EMPTY_RESOURCE_LIST); + } else { + PersistentEntityResource per = PersistentEntityResource.wrap(repoRequest.getPersistentEntity(), + result, + repoRequest.getBaseUri()); + per.add(repoRequest.buildEntitySelfLink(result, conversionService)); + resources = per; + } + resources.setBaseUri(repoRequest.getBaseUri()) + .add(links); - return resources; - } + return resources; + } - @RequestMapping( - value = "/{method}", - method = RequestMethod.GET, - produces = { - "application/x-spring-data-compact+json" - } - ) - @ResponseBody - public Resource queryCompact(RepositoryRestRequest repoRequest, - @PathVariable String method) - throws ResourceNotFoundException { - List links = new ArrayList(); + @RequestMapping( + value = "/{method}", + method = RequestMethod.GET, + produces = { + "application/x-spring-data-compact+json" + } + ) + @ResponseBody + public Resource queryCompact(RepositoryRestRequest repoRequest, + @PathVariable String method) + throws ResourceNotFoundException { + List links = new ArrayList(); - Resource resource = query(repoRequest, method); - links.addAll(resource.getLinks()); + Resource resource = query(repoRequest, method); + links.addAll(resource.getLinks()); - if(resource.getContent() instanceof Iterable) { - Iterable iter = (Iterable)resource.getContent(); - for(Object obj : iter) { - if(null != obj && obj instanceof Resource) { - Resource res = (Resource)obj; - links.add(resourceLink(repoRequest, res)); - } - } - } else if(resource.getContent() instanceof Resource) { - Resource res = (Resource)resource.getContent(); - links.add(resourceLink(repoRequest, res)); - } + if(resource.getContent() instanceof Iterable) { + Iterable iter = (Iterable)resource.getContent(); + for(Object obj : iter) { + if(null != obj && obj instanceof Resource) { + Resource res = (Resource)obj; + links.add(resourceLink(repoRequest, res)); + } + } + } else if(resource.getContent() instanceof Resource) { + Resource res = (Resource)resource.getContent(); + links.add(resourceLink(repoRequest, res)); + } - return new Resource(EMPTY_RESOURCE_LIST, links); - } + return new Resource(EMPTY_RESOURCE_LIST, links); + } - @RequestMapping( - value = "/{method}", - method = RequestMethod.GET, - produces = { - "application/javascript" - } - ) - @ResponseBody - public JsonpResponse> jsonpQuery(RepositoryRestRequest repoRequest, - @PathVariable String method) - throws ResourceNotFoundException { - return jsonpWrapResponse(repoRequest, query(repoRequest, method), HttpStatus.OK); - } + @RequestMapping( + value = "/{method}", + method = RequestMethod.GET, + produces = { + "application/javascript" + } + ) + @ResponseBody + public JsonpResponse> jsonpQuery(RepositoryRestRequest repoRequest, + @PathVariable String method) + throws ResourceNotFoundException { + return jsonpWrapResponse(repoRequest, query(repoRequest, method), HttpStatus.OK); + } - @SuppressWarnings({"unchecked"}) - private BaseUriAwareResource entitiesToResource(RepositoryRestRequest repoRequest, Iterable entities) { - List> resources = new ArrayList>(); - for(Object obj : entities) { - if(null == obj) { - resources.add(null); - break; - } + @SuppressWarnings({"unchecked"}) + private BaseUriAwareResource entitiesToResource(RepositoryRestRequest repoRequest, Iterable entities) { + List> resources = new ArrayList>(); + for(Object obj : entities) { + if(null == obj) { + resources.add(null); + break; + } - PersistentEntity persistentEntity = repositories.getPersistentEntity(obj.getClass()); - if(null == persistentEntity) { - resources.add(new BaseUriAwareResource(obj) - .setBaseUri(repoRequest.getBaseUri())); - continue; - } + PersistentEntity persistentEntity = repositories.getPersistentEntity(obj.getClass()); + if(null == persistentEntity) { + resources.add(new BaseUriAwareResource(obj) + .setBaseUri(repoRequest.getBaseUri())); + continue; + } - PersistentEntityResource per = PersistentEntityResource.wrap(persistentEntity, obj, repoRequest.getBaseUri()); - per.add(repoRequest.buildEntitySelfLink(obj, conversionService)); - resources.add(per); - } - return new BaseUriAwareResource(resources) - .setBaseUri(repoRequest.getBaseUri()); - } + PersistentEntityResource per = PersistentEntityResource.wrap(persistentEntity, obj, repoRequest.getBaseUri()); + per.add(repoRequest.buildEntitySelfLink(obj, conversionService)); + resources.add(per); + } + return new BaseUriAwareResource(resources) + .setBaseUri(repoRequest.getBaseUri()); + } } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java index 1c6f3fc2a..01c2f99a9 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java @@ -23,12 +23,12 @@ import org.springframework.data.rest.repository.json.Jackson2DatatypeHelper; import org.springframework.data.rest.repository.json.PersistentEntityJackson2Module; import org.springframework.data.rest.repository.json.PersistentEntityToJsonSchemaConverter; import org.springframework.data.rest.repository.support.DomainObjectMerger; +import org.springframework.data.rest.repository.support.RepositoryEntityLinks; import org.springframework.data.rest.webmvc.BaseUriMethodArgumentResolver; import org.springframework.data.rest.webmvc.PagingAndSortingMethodArgumentResolver; import org.springframework.data.rest.webmvc.PersistentEntityResourceHandlerMethodArgumentResolver; import org.springframework.data.rest.webmvc.RepositoryController; import org.springframework.data.rest.webmvc.RepositoryEntityController; -import org.springframework.data.rest.webmvc.RepositoryEntityLinksMethodArgumentResolver; import org.springframework.data.rest.webmvc.RepositoryInformationHandlerMethodArgumentResolver; import org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController; import org.springframework.data.rest.webmvc.RepositoryRestHandlerAdapter; @@ -39,6 +39,7 @@ import org.springframework.data.rest.webmvc.ServerHttpRequestMethodArgumentResol import org.springframework.data.rest.webmvc.convert.JsonpResponseHttpMessageConverter; import org.springframework.data.rest.webmvc.convert.UriListHttpMessageConverter; import org.springframework.format.support.DefaultFormattingConversionService; +import org.springframework.hateoas.EntityLinks; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; @@ -145,7 +146,8 @@ public class RepositoryRestMvcConfiguration { repositories().getObject(), config(), domainClassConverter(), - defaultConversionService() + defaultConversionService(), + entityLinks() ); } @@ -161,7 +163,8 @@ public class RepositoryRestMvcConfiguration { repositories().getObject(), config(), domainClassConverter(), - defaultConversionService() + defaultConversionService(), + entityLinks() ); } @@ -177,7 +180,8 @@ public class RepositoryRestMvcConfiguration { repositories().getObject(), config(), domainClassConverter(), - defaultConversionService() + defaultConversionService(), + entityLinks() ); } @@ -193,7 +197,8 @@ public class RepositoryRestMvcConfiguration { repositories().getObject(), config(), domainClassConverter(), - defaultConversionService() + defaultConversionService(), + entityLinks() ); } @@ -242,8 +247,16 @@ public class RepositoryRestMvcConfiguration { return new RepositoryRestRequestHandlerMethodArgumentResolver(); } - @Bean public RepositoryEntityLinksMethodArgumentResolver entityLinksMethodArgumentResolver() { - return new RepositoryEntityLinksMethodArgumentResolver(); + /** + * A special {@link org.springframework.hateoas.EntityLinks} implementation that takes repository and current + * configuration into account when generating links. + * + * @return + * + * @throws Exception + */ + @Bean public EntityLinks entityLinks() throws Exception { + return new RepositoryEntityLinks(repositories().getObject(), config()); } /** @@ -387,8 +400,7 @@ public class RepositoryRestMvcConfiguration { serverHttpRequestMethodArgumentResolver(), repoInfoMethodArgumentResolver(), repoRequestArgumentResolver(), - persistentEntityArgumentResolver(), - entityLinksMethodArgumentResolver()); + persistentEntityArgumentResolver()); } /**