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 6c2c72e4b..936975691 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 @@ -165,26 +165,26 @@ public class AbstractRepositoryRestController implements ApplicationContextAware return badRequest(t); } - @ExceptionHandler({ - RuntimeException.class - }) - @ResponseBody - public ResponseEntity maybeHandleValidationException(Locale locale, - RuntimeException ex) { - if(ResourceNotFoundException.class.isAssignableFrom(ex.getClass())) { - return handleNotFound(); - } - - if(null != handler) { - return handler.handleValidationException(ex, - applicationContext, - locale); - } else { - return response(null, - ex, - HttpStatus.BAD_REQUEST); - } - } + // @ExceptionHandler({ + // RuntimeException.class + // }) + // @ResponseBody + // public ResponseEntity maybeHandleValidationException(Locale locale, + // RuntimeException ex) { + // if(ResourceNotFoundException.class.isAssignableFrom(ex.getClass())) { + // return handleNotFound(); + // } + // + // if(null != handler) { + // return handler.handleValidationException(ex, + // applicationContext, + // locale); + // } else { + // return response(null, + // ex, + // HttpStatus.BAD_REQUEST); + // } + // } @ExceptionHandler({ RepositoryConstraintViolationException.class @@ -230,14 +230,6 @@ public class AbstractRepositoryRestController implements ApplicationContextAware return errorResponse(headers, throwable, HttpStatus.BAD_REQUEST); } - 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 errorResponse(T throwable, HttpStatus status) { return errorResponse(null, throwable, status); @@ -246,8 +238,12 @@ public class AbstractRepositoryRestController implements ApplicationContextAware public ResponseEntity errorResponse(HttpHeaders headers, T throwable, HttpStatus status) { - LOG.error(throwable.getMessage(), throwable); - return response(headers, new ExceptionMessage(throwable), status); + if(null != throwable && null != throwable.getMessage()) { + LOG.error(throwable.getMessage(), throwable); + return response(headers, new ExceptionMessage(throwable), status); + } else { + return response(headers, null, status); + } } public ResponseEntity response(HttpHeaders headers, T body, HttpStatus status) { 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 41e9f1e15..19245ffd0 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 @@ -41,6 +41,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -315,11 +316,15 @@ public class RepositoryEntityController extends AbstractRepositoryRestController @ResponseBody public ResponseEntity deleteEntity(final RepositoryRestRequest repoRequest, @PathVariable final String id) - throws ResourceNotFoundException { + throws ResourceNotFoundException, HttpRequestMethodNotSupportedException { final RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker(); if(null == repoMethodInvoker || (!repoMethodInvoker.hasFindOne() && !(repoMethodInvoker.hasDeleteOne() || repoMethodInvoker.hasDeleteOneById()))) { - throw new NoSuchMethodError(); + throw new HttpRequestMethodNotSupportedException("DELETE"); + } + ResourceMapping methodMapping = repoRequest.getRepositoryResourceMapping().getResourceMappingFor("delete"); + if(null != methodMapping && !methodMapping.isExported()) { + throw new HttpRequestMethodNotSupportedException("DELETE"); } final Object domainObj = domainClassConverter.convert(id, 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 9f43ab645..75c2b5938 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 @@ -34,6 +34,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -75,6 +76,9 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes final HttpHeaders headers = new HttpHeaders(); Function> handler = new Function>() { @Override public Resource apply(ReferencedProperty prop) { + if(null == prop.propertyValue) { + throw new ResourceNotFoundException(); + } if(prop.property.isCollectionLike()) { List> resources = new ArrayList>(); PersistentEntity entity = repositories.getPersistentEntity(prop.propertyType); @@ -127,6 +131,53 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes return resourceResponse(headers, responseResource, HttpStatus.OK); } + @SuppressWarnings({"unchecked"}) + @RequestMapping( + method = RequestMethod.DELETE + ) + @ResponseBody + public ResponseEntity> deletePropertyReference(final RepositoryRestRequest repoRequest, + @PathVariable String id, + @PathVariable String property) + throws ResourceNotFoundException, NoSuchMethodException, HttpRequestMethodNotSupportedException { + 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()) { + throw new IllegalArgumentException(new HttpRequestMethodNotSupportedException("DELETE")); + } else if(prop.property.isMap()) { + throw new IllegalArgumentException(new HttpRequestMethodNotSupportedException("DELETE")); + } 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; + } + }; + try { + doWithReferencedProperty(repoRequest, + id, + property, + handler); + } catch(IllegalArgumentException iae) { + if(iae.getCause() instanceof HttpRequestMethodNotSupportedException) { + throw (HttpRequestMethodNotSupportedException)iae.getCause(); + } + } + + return resourceResponse(null, EMPTY_RESOURCE, HttpStatus.NO_CONTENT); + } + @SuppressWarnings({"unchecked"}) @RequestMapping( value = "/{propertyId}", @@ -147,6 +198,9 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes final HttpHeaders headers = new HttpHeaders(); Function> handler = new Function>() { @Override public Resource apply(ReferencedProperty prop) { + if(null == prop.propertyValue) { + throw new ResourceNotFoundException(); + } if(prop.property.isCollectionLike()) { PersistentEntity entity = repositories.getPersistentEntity(prop.propertyType); for(Object obj : ((Iterable)prop.propertyValue)) { @@ -324,10 +378,10 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes method = RequestMethod.DELETE ) @ResponseBody - public ResponseEntity> deletePropertyReference(final RepositoryRestRequest repoRequest, - @PathVariable String id, - @PathVariable String property, - final @PathVariable String propertyId) + public ResponseEntity> deletePropertyReferenceId(final RepositoryRestRequest repoRequest, + @PathVariable String id, + @PathVariable String property, + final @PathVariable String propertyId) throws ResourceNotFoundException, NoSuchMethodException { final RepositoryMethodInvoker repoMethodInvoker = repoRequest.getRepositoryMethodInvoker(); if(!repoMethodInvoker.hasDeleteOne()) { @@ -419,9 +473,6 @@ public class RepositoryPropertyReferenceController extends AbstractRepositoryRes BeanWrapper wrapper = BeanWrapper.create(domainObj, conversionService); Object propVal = wrapper.getProperty(prop); - if(null == propVal) { - throw new ResourceNotFoundException(); - } return handler.apply(new ReferencedProperty(prop, propVal, diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java index 8eef4ef53..f1ec0b14d 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java @@ -70,14 +70,6 @@ public class RepositoryRestHandlerMapping extends RequestMappingHandlerMapping { HttpServletRequest request = new DefaultAcceptTypeHttpServletRequest(origRequest, acceptType); - if(acceptType.contains("javascript")) { - if(null != request.getParameter(config.getJsonpParamName()) - || null != request.getParameter(config.getJsonpOnErrParamName())) { - return super.lookupHandlerMethod(lookupPath, request); - } else { - return null; - } - } String requestUri = lookupPath; if(requestUri.startsWith("/")) { requestUri = requestUri.substring(1); diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/ResourceNotFoundException.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/ResourceNotFoundException.java index 42d92cdd1..26a9f364c 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/ResourceNotFoundException.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/ResourceNotFoundException.java @@ -5,7 +5,7 @@ package org.springframework.data.rest.webmvc; * * @author Jon Brisbin */ -public class ResourceNotFoundException extends Exception { +public class ResourceNotFoundException extends RuntimeException { public ResourceNotFoundException() { super("Resource not found"); }