Primarily formatting changes.

This commit is contained in:
Jon Brisbin
2013-04-25 15:04:13 -05:00
parent f60219480f
commit 467966ef63

View File

@@ -1,17 +1,5 @@
package org.springframework.data.rest.webmvc; package org.springframework.data.rest.webmvc;
import static org.springframework.data.rest.core.util.UriUtils.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
@@ -42,13 +30,7 @@ import org.springframework.data.rest.webmvc.support.BaseUriLinkBuilder;
import org.springframework.data.rest.webmvc.support.ExceptionMessage; import org.springframework.data.rest.webmvc.support.ExceptionMessage;
import org.springframework.data.rest.webmvc.support.RepositoryConstraintViolationExceptionMessage; import org.springframework.data.rest.webmvc.support.RepositoryConstraintViolationExceptionMessage;
import org.springframework.data.rest.webmvc.support.ValidationExceptionHandler; import org.springframework.data.rest.webmvc.support.ValidationExceptionHandler;
import org.springframework.hateoas.EntityLinks; import org.springframework.hateoas.*;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkBuilder;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@@ -61,11 +43,20 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.*;
import static org.springframework.data.rest.core.util.UriUtils.buildUri;
/** /**
* @author Jon Brisbin * @author Jon Brisbin
*/ */
@SuppressWarnings({"rawtypes"})
public class AbstractRepositoryRestController implements ApplicationContextAware, public class AbstractRepositoryRestController implements ApplicationContextAware,
InitializingBean { InitializingBean {
static final Resource<?> EMPTY_RESOURCE = new Resource<Object>(Collections.emptyList()); static final Resource<?> EMPTY_RESOURCE = new Resource<Object>(Collections.emptyList());
static final Resources<Resource<?>> EMPTY_RESOURCES = new Resources<Resource<?>>(Collections.<Resource<?>>emptyList()); static final Resources<Resource<?>> EMPTY_RESOURCES = new Resources<Resource<?>>(Collections.<Resource<?>>emptyList());
@@ -87,10 +78,10 @@ public class AbstractRepositoryRestController implements ApplicationContextAware
@Autowired @Autowired
public AbstractRepositoryRestController(Repositories repositories, public AbstractRepositoryRestController(Repositories repositories,
RepositoryRestConfiguration config, RepositoryRestConfiguration config,
DomainClassConverter domainClassConverter, DomainClassConverter domainClassConverter,
ConversionService conversionService, ConversionService conversionService,
EntityLinks entityLinks) { EntityLinks entityLinks) {
this.repositories = repositories; this.repositories = repositories;
this.config = config; this.config = config;
this.domainClassConverter = domainClassConverter; this.domainClassConverter = domainClassConverter;
@@ -99,46 +90,48 @@ public class AbstractRepositoryRestController implements ApplicationContextAware
this.methodParameterConversionService = new MethodParameterConversionService(conversionService); this.methodParameterConversionService = new MethodParameterConversionService(conversionService);
} }
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
} }
@Override public void afterPropertiesSet() throws Exception { @Override
if(null != txMgr) { public void afterPropertiesSet() throws Exception {
if (null != txMgr) {
txTmpl = new TransactionTemplate(txMgr); txTmpl = new TransactionTemplate(txMgr);
txTmpl.afterPropertiesSet(); txTmpl.afterPropertiesSet();
} }
} }
@ExceptionHandler({ @ExceptionHandler({
NullPointerException.class NullPointerException.class
}) })
@ResponseBody @ResponseBody
public ResponseEntity<?> handleNPE(NullPointerException npe) { public ResponseEntity<?> handleNPE(NullPointerException npe) {
return errorResponse(npe, HttpStatus.INTERNAL_SERVER_ERROR); return errorResponse(npe, HttpStatus.INTERNAL_SERVER_ERROR);
} }
@ExceptionHandler({ @ExceptionHandler({
ResourceNotFoundException.class ResourceNotFoundException.class
}) })
@ResponseBody @ResponseBody
public ResponseEntity<?> handleNotFound() { public ResponseEntity<?> handleNotFound() {
return notFound(); return notFound();
} }
@ExceptionHandler({ @ExceptionHandler({
NoSuchMethodError.class, NoSuchMethodError.class,
HttpRequestMethodNotSupportedException.class HttpRequestMethodNotSupportedException.class
}) })
@ResponseBody @ResponseBody
public ResponseEntity<?> handleNoSuchMethod() { public ResponseEntity<?> handleNoSuchMethod() {
return errorResponse(null, HttpStatus.METHOD_NOT_ALLOWED); return errorResponse(null, HttpStatus.METHOD_NOT_ALLOWED);
} }
@ExceptionHandler({ @ExceptionHandler({
HttpMessageNotReadableException.class, HttpMessageNotReadableException.class,
HttpMessageNotWritableException.class HttpMessageNotWritableException.class
}) })
@ResponseBody @ResponseBody
public ResponseEntity<ExceptionMessage> handleNotReadable(HttpMessageNotReadableException e) { public ResponseEntity<ExceptionMessage> handleNotReadable(HttpMessageNotReadableException e) {
return badRequest(e); return badRequest(e);
@@ -148,18 +141,17 @@ public class AbstractRepositoryRestController implements ApplicationContextAware
* Handle failures commonly thrown from code tries to read incoming data and convert or cast it to the right type. * Handle failures commonly thrown from code tries to read incoming data and convert or cast it to the right type.
* *
* @param t * @param t
*
* @return * @return
*/ */
@ExceptionHandler({ @ExceptionHandler({
InvocationTargetException.class, InvocationTargetException.class,
IllegalArgumentException.class, IllegalArgumentException.class,
ClassCastException.class, ClassCastException.class,
ConversionFailedException.class ConversionFailedException.class
}) })
@ResponseBody @ResponseBody
public ResponseEntity handleMiscFailures(Throwable t) { public ResponseEntity handleMiscFailures(Throwable t) {
if(null != t.getCause() && t.getCause() instanceof ResourceNotFoundException) { if (null != t.getCause() && t.getCause() instanceof ResourceNotFoundException) {
return notFound(); return notFound();
} }
return badRequest(t); return badRequest(t);
@@ -187,28 +179,27 @@ public class AbstractRepositoryRestController implements ApplicationContextAware
// } // }
@ExceptionHandler({ @ExceptionHandler({
RepositoryConstraintViolationException.class RepositoryConstraintViolationException.class
}) })
@ResponseBody @ResponseBody
public ResponseEntity handleRepositoryConstraintViolationException(Locale locale, public ResponseEntity handleRepositoryConstraintViolationException(Locale locale,
RepositoryConstraintViolationException rcve) { RepositoryConstraintViolationException rcve) {
return response(null, return response(null,
new RepositoryConstraintViolationExceptionMessage(rcve, applicationContext, locale), new RepositoryConstraintViolationExceptionMessage(rcve, applicationContext, locale),
HttpStatus.BAD_REQUEST); HttpStatus.BAD_REQUEST);
} }
/** /**
* Send a 409 Conflict in case of concurrent modification. * Send a 409 Conflict in case of concurrent modification.
* *
* @param ex * @param ex
*
* @return * @return
*/ */
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
@ExceptionHandler({ @ExceptionHandler({
OptimisticLockingFailureException.class, OptimisticLockingFailureException.class,
DataIntegrityViolationException.class DataIntegrityViolationException.class
}) })
@ResponseBody @ResponseBody
public ResponseEntity handleConflict(Exception ex) { public ResponseEntity handleConflict(Exception ex) {
return errorResponse(null, ex, HttpStatus.CONFLICT); return errorResponse(null, ex, HttpStatus.CONFLICT);
@@ -231,14 +222,14 @@ public class AbstractRepositoryRestController implements ApplicationContextAware
} }
public <T extends Throwable> ResponseEntity<ExceptionMessage> errorResponse(T throwable, public <T extends Throwable> ResponseEntity<ExceptionMessage> errorResponse(T throwable,
HttpStatus status) { HttpStatus status) {
return errorResponse(null, throwable, status); return errorResponse(null, throwable, status);
} }
public <T extends Throwable> ResponseEntity<ExceptionMessage> errorResponse(HttpHeaders headers, public <T extends Throwable> ResponseEntity<ExceptionMessage> errorResponse(HttpHeaders headers,
T throwable, T throwable,
HttpStatus status) { HttpStatus status) {
if(null != throwable && null != throwable.getMessage()) { if (null != throwable && null != throwable.getMessage()) {
LOG.error(throwable.getMessage(), throwable); LOG.error(throwable.getMessage(), throwable);
return response(headers, new ExceptionMessage(throwable), status); return response(headers, new ExceptionMessage(throwable), status);
} else { } else {
@@ -248,28 +239,28 @@ public class AbstractRepositoryRestController implements ApplicationContextAware
public <T> ResponseEntity<T> response(HttpHeaders headers, T body, HttpStatus status) { public <T> ResponseEntity<T> response(HttpHeaders headers, T body, HttpStatus status) {
HttpHeaders hdrs = new HttpHeaders(); HttpHeaders hdrs = new HttpHeaders();
if(null != headers) { if (null != headers) {
hdrs.putAll(headers); hdrs.putAll(headers);
} }
return new ResponseEntity<T>(body, hdrs, status); return new ResponseEntity<T>(body, hdrs, status);
} }
public <R extends Resource<?>> ResponseEntity<Resource<?>> resourceResponse(HttpHeaders headers, public <R extends Resource<?>> ResponseEntity<Resource<?>> resourceResponse(HttpHeaders headers,
R resource, R resource,
HttpStatus status) { HttpStatus status) {
HttpHeaders hdrs = new HttpHeaders(); HttpHeaders hdrs = new HttpHeaders();
if(null != headers) { if (null != headers) {
hdrs.putAll(headers); hdrs.putAll(headers);
} }
return new ResponseEntity<Resource<?>>(resource, hdrs, status); return new ResponseEntity<Resource<?>>(resource, hdrs, status);
} }
protected void addQueryParameters(HttpServletRequest request, protected void addQueryParameters(HttpServletRequest request,
UriComponentsBuilder builder) { UriComponentsBuilder builder) {
for(Enumeration<String> names = request.getParameterNames(); names.hasMoreElements(); ) { for (Enumeration<String> names = request.getParameterNames(); names.hasMoreElements(); ) {
String name = names.nextElement(); String name = names.nextElement();
String value = request.getParameter(name); String value = request.getParameter(name);
if(name.equals(config.getPageParamName()) || name.equals(config.getLimitParamName())) { if (name.equals(config.getPageParamName()) || name.equals(config.getLimitParamName())) {
continue; continue;
} }
@@ -278,18 +269,18 @@ public class AbstractRepositoryRestController implements ApplicationContextAware
} }
protected Link searchLink(RepositoryRestRequest repoRequest, protected Link searchLink(RepositoryRestRequest repoRequest,
int pageIncrement, int pageIncrement,
String method, String method,
String rel) { String rel) {
PagingAndSorting pageSort = repoRequest.getPagingAndSorting(); PagingAndSorting pageSort = repoRequest.getPagingAndSorting();
UriComponentsBuilder ucb = UriComponentsBuilder.fromUri( UriComponentsBuilder ucb = UriComponentsBuilder.fromUri(
entityLinks.linkFor(repoRequest.getPersistentEntity().getType()) entityLinks.linkFor(repoRequest.getPersistentEntity().getType())
.slash("search") .slash("search")
.slash(method) .slash(method)
.toUri() .toUri()
); );
ucb.queryParam(config.getPageParamName(), Math.max(pageSort.getPageNumber() + pageIncrement, 1)) ucb.queryParam(config.getPageParamName(), Math.max(pageSort.getPageNumber() + pageIncrement, 1))
.queryParam(config.getLimitParamName(), pageSort.getPageSize()); .queryParam(config.getLimitParamName(), pageSort.getPageSize());
addQueryParameters(repoRequest.getRequest(), ucb); addQueryParameters(repoRequest.getRequest(), ucb);
@@ -297,16 +288,16 @@ public class AbstractRepositoryRestController implements ApplicationContextAware
} }
protected Link entitiesPageLink(RepositoryRestRequest repoRequest, protected Link entitiesPageLink(RepositoryRestRequest repoRequest,
int pageIncrement, int pageIncrement,
String rel) { String rel) {
PagingAndSorting pageSort = repoRequest.getPagingAndSorting(); PagingAndSorting pageSort = repoRequest.getPagingAndSorting();
UriComponentsBuilder ucb = UriComponentsBuilder.fromUri( UriComponentsBuilder ucb = UriComponentsBuilder.fromUri(
entityLinks.linkFor(repoRequest.getPersistentEntity().getType()) entityLinks.linkFor(repoRequest.getPersistentEntity().getType())
.toUri() .toUri()
); );
if(null != repoRequest.getRequest().getParameter(config.getPageParamName())) { if (null != repoRequest.getRequest().getParameter(config.getPageParamName())) {
ucb.queryParam(config.getPageParamName(), Math.max(pageSort.getPageNumber() + pageIncrement, 1)) ucb.queryParam(config.getPageParamName(), Math.max(pageSort.getPageNumber() + pageIncrement, 1))
.queryParam(config.getLimitParamName(), pageSort.getPageSize()); .queryParam(config.getLimitParamName(), pageSort.getPageSize());
} }
addQueryParameters(repoRequest.getRequest(), ucb); addQueryParameters(repoRequest.getRequest(), ucb);
@@ -321,15 +312,15 @@ public class AbstractRepositoryRestController implements ApplicationContextAware
repoInfo.getRepositoryInterface(), repoInfo.getRepositoryInterface(),
config.getResourceMappingForRepository(repoInfo.getRepositoryInterface()) config.getResourceMappingForRepository(repoInfo.getRepositoryInterface())
); );
for(Method method : repoInfo.getQueryMethods()) { for (Method method : repoInfo.getQueryMethods()) {
LinkBuilder linkBuilder = BaseUriLinkBuilder.create(buildUri(baseUri, repoMapping.getPath(), "search")); LinkBuilder linkBuilder = BaseUriLinkBuilder.create(buildUri(baseUri, repoMapping.getPath(), "search"));
ResourceMapping methodMapping = ResourceMappingUtils.merge(method, ResourceMapping methodMapping = ResourceMappingUtils.merge(method,
repoMapping.getResourceMappingFor(method.getName())); repoMapping.getResourceMappingFor(method.getName()));
if(!methodMapping.isExported()) { if (!methodMapping.isExported()) {
continue; continue;
} }
links.add(linkBuilder.slash(methodMapping.getPath()) links.add(linkBuilder.slash(methodMapping.getPath())
.withRel(repoMapping.getRel() + "." + methodMapping.getRel())); .withRel(repoMapping.getRel() + "." + methodMapping.getRel()));
} }
return links; return links;
} }
@@ -344,79 +335,79 @@ public class AbstractRepositoryRestController implements ApplicationContextAware
} }
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
protected ResourceSupport resultToResourceSupport(RepositoryRestRequest repoRequest, protected Resources resultToResources(RepositoryRestRequest repoRequest,
Object result, Object result,
List<Link> links, List<Link> links,
Link prevLink, Link prevLink,
Link nextLink) { Link nextLink) {
ResourceSupport resources; if (result instanceof Page) {
if(result instanceof Page) { Page page = (Page) result;
Page page = (Page)result;
PagedResources.PageMetadata pageMeta = pageMetadata(page); PagedResources.PageMetadata pageMeta = pageMetadata(page);
if(page.hasPreviousPage() && null != prevLink) { if (page.hasPreviousPage() && null != prevLink) {
links.add(prevLink); links.add(prevLink);
} }
if(page.hasNextPage() && null != nextLink) { if (page.hasNextPage() && null != nextLink) {
links.add(nextLink); links.add(nextLink);
} }
if(page.hasContent()) { if (page.hasContent()) {
resources = entitiesToResource(repoRequest, page); return entitiesToResources(repoRequest, links, page);
} else { } else {
resources = new PagedResources(Collections.emptyList(), pageMeta); return new PagedResources(Collections.emptyList(), pageMeta, links);
} }
} else if(result instanceof Iterable) { } else if (result instanceof Iterable) {
resources = entitiesToResource(repoRequest, (Iterable)result); return entitiesToResources(repoRequest, links, (Iterable) result);
} else if(null == result) { } else if (null == result) {
resources = new Resources(EMPTY_RESOURCE_LIST); return new Resources(EMPTY_RESOURCE_LIST);
} else { } else {
PersistentEntityResource per = PersistentEntityResource.wrap(repoRequest.getPersistentEntity(), PersistentEntityResource per = PersistentEntityResource.wrap(
result, repoRequest.getPersistentEntity(),
repoRequest.getBaseUri()); result,
repoRequest.getBaseUri()
);
BeanWrapper wrapper = BeanWrapper.create(result, conversionService); BeanWrapper wrapper = BeanWrapper.create(result, conversionService);
Link selfLink = entityLinks.linkForSingleResource(result.getClass(), Link selfLink = entityLinks.linkForSingleResource(
wrapper.getProperty(repoRequest.getPersistentEntity() result.getClass(),
.getIdProperty())) wrapper.getProperty(repoRequest.getPersistentEntity().getIdProperty())
.withSelfRel(); )
.withSelfRel();
per.add(selfLink); per.add(selfLink);
resources = per; return new Resources(Collections.singletonList(per), links);
} }
resources.add(links);
return resources;
} }
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
protected ResourceSupport entitiesToResource(RepositoryRestRequest repoRequest, Page page) { protected Resources entitiesToResources(RepositoryRestRequest repoRequest, List<Link> links, Page page) {
PagedResources.PageMetadata pageMeta = pageMetadata(page); PagedResources.PageMetadata pageMeta = pageMetadata(page);
Resources<Object> resource = (Resources<Object>)entitiesToResource(repoRequest, page.getContent()); Resources<Object> resource = (Resources<Object>) entitiesToResources(repoRequest, links, page.getContent());
return new PagedResources<Object>(resource.getContent(), pageMeta, resource.getLinks()); return new PagedResources<Object>(resource.getContent(), pageMeta, resource.getLinks());
} }
@SuppressWarnings({"unchecked"}) @SuppressWarnings({"unchecked"})
protected ResourceSupport entitiesToResource(RepositoryRestRequest repoRequest, Iterable entities) { protected Resources entitiesToResources(RepositoryRestRequest repoRequest, List<Link> links, Iterable entities) {
List<Resource<?>> resources = new ArrayList<Resource<?>>(); List<Resource<?>> resources = new ArrayList<Resource<?>>();
for(Object obj : entities) { for (Object obj : entities) {
if(null == obj) { if (null == obj) {
resources.add(null); resources.add(null);
continue; continue;
} }
PersistentEntity persistentEntity = repositories.getPersistentEntity(obj.getClass()); PersistentEntity persistentEntity = repositories.getPersistentEntity(obj.getClass());
if(null == persistentEntity) { if (null == persistentEntity) {
resources.add(new BaseUriAwareResource<Object>(obj) resources.add(new BaseUriAwareResource<Object>(obj)
.setBaseUri(repoRequest.getBaseUri())); .setBaseUri(repoRequest.getBaseUri()));
continue; continue;
} }
BeanWrapper wrapper = BeanWrapper.create(obj, conversionService); BeanWrapper wrapper = BeanWrapper.create(obj, conversionService);
PersistentEntityResource per = PersistentEntityResource.wrap(persistentEntity, obj, repoRequest.getBaseUri()); PersistentEntityResource per = PersistentEntityResource.wrap(persistentEntity, obj, repoRequest.getBaseUri());
Link selfLink = entityLinks.linkForSingleResource(persistentEntity.getType(), Link selfLink = entityLinks.linkForSingleResource(persistentEntity.getType(),
wrapper.getProperty(persistentEntity.getIdProperty())) wrapper.getProperty(persistentEntity.getIdProperty()))
.withSelfRel(); .withSelfRel();
per.add(selfLink); per.add(selfLink);
resources.add(per); resources.add(per);
} }
return new Resources(resources); return new Resources(resources, links);
} }
protected PagedResources.PageMetadata pageMetadata(Page page) { protected PagedResources.PageMetadata pageMetadata(Page page) {