From 28db79ef426ec46280f50eb6a37214a5982e0da6 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 5 Dec 2014 10:21:16 +0100 Subject: [PATCH] DATAREST-421 - Polishing of new exception handling infrastructure. Removed leftovers from AbstractRepositoryRestController. Renamed GlobalExceptionHandler to RepositoryRestExceptionHandler and minimized visibility of exception handler methods. Restricted application of the exception handler to controllers in the Spring Data REST base package. Relatted pull request: #155. --- .../AbstractRepositoryRestController.java | 16 +- .../rest/webmvc/GlobalExceptionHandler.java | 160 -------------- .../RepositoryRestExceptionHandler.java | 195 ++++++++++++++++++ .../RepositoryRestMvcConfiguration.java | 20 +- .../rest/webmvc/support/ExceptionMessage.java | 14 +- ...ryConstraintViolationExceptionMessage.java | 28 ++- .../support/ControllerAdviceConfig.java | 32 --- .../support/ControllerAdviceWebTests.java | 29 --- ...HandlingCustomizationIntegrationTests.java | 84 ++++++++ 9 files changed, 317 insertions(+), 261 deletions(-) delete mode 100644 spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/GlobalExceptionHandler.java create mode 100644 spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestExceptionHandler.java delete mode 100644 spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ControllerAdviceConfig.java delete mode 100644 spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ControllerAdviceWebTests.java create mode 100644 spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ExceptionHandlingCustomizationIntegrationTests.java 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 e58d4a2c1..438705ffc 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 @@ -15,8 +15,12 @@ */ package org.springframework.data.rest.webmvc; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static org.springframework.data.rest.webmvc.ControllerUtils.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import org.springframework.data.domain.Page; import org.springframework.data.rest.core.mapping.ResourceMetadata; import org.springframework.data.web.PagedResourcesAssembler; @@ -25,12 +29,6 @@ import org.springframework.hateoas.Resource; import org.springframework.hateoas.Resources; import org.springframework.util.Assert; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import static org.springframework.data.rest.webmvc.ControllerUtils.EMPTY_RESOURCE_LIST; - /** * @author Jon Brisbin * @author Oliver Gierke @@ -39,8 +37,6 @@ import static org.springframework.data.rest.webmvc.ControllerUtils.EMPTY_RESOURC @SuppressWarnings({ "rawtypes" }) class AbstractRepositoryRestController { - private static final Logger LOG = LoggerFactory.getLogger(AbstractRepositoryRestController.class); - private final PagedResourcesAssembler pagedResourcesAssembler; /** diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/GlobalExceptionHandler.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/GlobalExceptionHandler.java deleted file mode 100644 index 20ccaf17d..000000000 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/GlobalExceptionHandler.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.springframework.data.rest.webmvc; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.MessageSource; -import org.springframework.context.MessageSourceAware; -import org.springframework.context.support.MessageSourceAccessor; -import org.springframework.core.convert.ConversionFailedException; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.dao.OptimisticLockingFailureException; -import org.springframework.data.rest.core.RepositoryConstraintViolationException; -import org.springframework.data.rest.webmvc.support.ETagDoesntMatchException; -import org.springframework.data.rest.webmvc.support.ExceptionMessage; -import org.springframework.data.rest.webmvc.support.RepositoryConstraintViolationExceptionMessage; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.http.converter.HttpMessageNotReadableException; -import org.springframework.web.HttpRequestMethodNotSupportedException; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; - -import java.lang.reflect.InvocationTargetException; -import java.util.Locale; - -/** - * @author Thibaud Lepretre - */ -@ControllerAdvice -public class GlobalExceptionHandler implements MessageSourceAware { - - private static final Logger LOG = LoggerFactory.getLogger(GlobalExceptionHandler.class); - - - private MessageSourceAccessor messageSourceAccessor; - - /* - * (non-Javadoc) - * @see org.springframework.context.MessageSourceAware#setMessageSource(org.springframework.context.MessageSource) - */ - @Override - public void setMessageSource(MessageSource messageSource) { - this.messageSourceAccessor = new MessageSourceAccessor(messageSource); - } - - @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({ HttpMessageNotReadableException.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 - */ - @ExceptionHandler({ InvocationTargetException.class, IllegalArgumentException.class, ClassCastException.class, - ConversionFailedException.class }) - @ResponseBody - public ResponseEntity handleMiscFailures(Throwable t) { - if (null != t.getCause() && t.getCause() instanceof ResourceNotFoundException) { - return notFound(); - } - return badRequest(t); - } - - @ExceptionHandler({ RepositoryConstraintViolationException.class }) - @ResponseBody - public ResponseEntity handleRepositoryConstraintViolationException(Locale locale, - RepositoryConstraintViolationException rcve) { - - return response(null, new RepositoryConstraintViolationExceptionMessage(rcve, messageSourceAccessor), - HttpStatus.BAD_REQUEST); - } - - /** - * Send a 409 Conflict in case of concurrent modification. - * - * @param ex - * @return HTTP Status 409 ResponseEntity - */ - @ExceptionHandler({ OptimisticLockingFailureException.class, DataIntegrityViolationException.class }) - public ResponseEntity handleConflict(Exception ex) { - return errorResponse(null, ex, HttpStatus.CONFLICT); - } - - /** - * Send {@code 405 Method Not Allowed} and include the supported {@link org.springframework.http.HttpMethod}s in the {@code Allow} header. - * - * @param o_O - * @return HTTP Status 405 ResponseEntity - */ - @ExceptionHandler - public ResponseEntity handle(HttpRequestMethodNotSupportedException o_O) { - - HttpHeaders headers = new HttpHeaders(); - headers.setAllow(o_O.getSupportedHttpMethods()); - - return new ResponseEntity(headers, HttpStatus.METHOD_NOT_ALLOWED); - } - - @ExceptionHandler - public ResponseEntity handle(ETagDoesntMatchException o_O) { - - HttpHeaders headers = o_O.getExpectedETag().addTo(new HttpHeaders()); - return new ResponseEntity(headers, HttpStatus.PRECONDITION_FAILED); - } - - protected ResponseEntity notFound() { - return notFound(null, null); - } - - 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(HttpHeaders headers, T throwable) { - return errorResponse(headers, throwable, HttpStatus.BAD_REQUEST); - } - - public ResponseEntity errorResponse(T throwable, HttpStatus status) { - return errorResponse(null, throwable, status); - } - - public ResponseEntity errorResponse(HttpHeaders headers, T throwable, - HttpStatus 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) { - HttpHeaders hdrs = new HttpHeaders(); - if (null != headers) { - hdrs.putAll(headers); - } - return new ResponseEntity(body, hdrs, status); - } -} diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestExceptionHandler.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestExceptionHandler.java new file mode 100644 index 000000000..1d7ce7206 --- /dev/null +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestExceptionHandler.java @@ -0,0 +1,195 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.rest.webmvc; + +import java.lang.reflect.InvocationTargetException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.MessageSource; +import org.springframework.context.support.MessageSourceAccessor; +import org.springframework.core.convert.ConversionFailedException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.OptimisticLockingFailureException; +import org.springframework.data.rest.core.RepositoryConstraintViolationException; +import org.springframework.data.rest.webmvc.support.ETagDoesntMatchException; +import org.springframework.data.rest.webmvc.support.ExceptionMessage; +import org.springframework.data.rest.webmvc.support.RepositoryConstraintViolationExceptionMessage; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.util.Assert; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +/** + * Exception handler for Spring Data REST controllers. + * + * @author Thibaud Lepretre + * @author Oliver Gierke + */ +@ControllerAdvice(basePackageClasses = RepositoryRestExceptionHandler.class) +public class RepositoryRestExceptionHandler { + + private static final Logger LOG = LoggerFactory.getLogger(RepositoryRestExceptionHandler.class); + + private final MessageSourceAccessor messageSourceAccessor; + + /** + * Creates a new {@link RepositoryRestExceptionHandler} using the given {@link MessageSource}. + * + * @param messageSource must not be {@literal null}. + */ + public RepositoryRestExceptionHandler(MessageSource messageSource) { + + Assert.notNull(messageSource, "MessageSource must not be null!"); + this.messageSourceAccessor = new MessageSourceAccessor(messageSource); + } + + /** + * Handles {@link ResourceNotFoundException} by returning {@code 404 Not Found}. + * + * @param o_O the exception to handle. + * @return + */ + @ExceptionHandler + ResponseEntity handleNotFound(ResourceNotFoundException o_O) { + return notFound(); + } + + /** + * Handles {@link HttpMessageNotReadableException} by returning {@code 400 Bad Request}. + * + * @param o_O the exception to handle. + * @return + */ + @ExceptionHandler + ResponseEntity handleNotReadable(HttpMessageNotReadableException o_O) { + return badRequest(o_O); + } + + /** + * Handle failures commonly thrown from code tries to read incoming data and convert or cast it to the right type by + * returning {@code 500 Internal Server Error} and the thrown exception marshalled into JSON. + * + * @param o_O the exception to handle. + * @return + */ + @ExceptionHandler({ InvocationTargetException.class, IllegalArgumentException.class, ClassCastException.class, + ConversionFailedException.class, NullPointerException.class }) + ResponseEntity handleMiscFailures(Exception o_O) { + return errorResponse(null, HttpStatus.INTERNAL_SERVER_ERROR); + } + + /** + * Handles {@link RepositoryConstraintViolationException}s by returning {@code 400 Bad Request}. + * + * @param o_O the exception to handle. + * @return + */ + @ExceptionHandler + ResponseEntity handleRepositoryConstraintViolationException( + RepositoryConstraintViolationException o_O) { + + return response(new HttpHeaders(), new RepositoryConstraintViolationExceptionMessage(o_O, messageSourceAccessor), + HttpStatus.BAD_REQUEST); + } + + /** + * Send a {@code 409 Conflict} in case of concurrent modification. + * + * @param o_O the exception to handle. + * @return + */ + @ExceptionHandler({ OptimisticLockingFailureException.class, DataIntegrityViolationException.class }) + ResponseEntity handleConflict(Exception o_O) { + return errorResponse(null, o_O, HttpStatus.CONFLICT); + } + + /** + * Send {@code 405 Method Not Allowed} and include the supported {@link org.springframework.http.HttpMethod}s in the + * {@code Allow} header. + * + * @param o_O the exception to handle. + * @return + */ + @ExceptionHandler + ResponseEntity handle(HttpRequestMethodNotSupportedException o_O) { + + HttpHeaders headers = new HttpHeaders(); + headers.setAllow(o_O.getSupportedHttpMethods()); + + return new ResponseEntity(headers, HttpStatus.METHOD_NOT_ALLOWED); + } + + /** + * Handles {@link ETagDoesntMatchException} by returning {@code 412 Precondition Failed}. + * + * @param o_O the exception to handle. + * @return + */ + @ExceptionHandler + ResponseEntity handle(ETagDoesntMatchException o_O) { + + HttpHeaders headers = o_O.getExpectedETag().addTo(new HttpHeaders()); + return new ResponseEntity(headers, HttpStatus.PRECONDITION_FAILED); + } + + private ResponseEntity notFound() { + return notFound(new HttpHeaders(), null); + } + + private ResponseEntity notFound(HttpHeaders headers, T body) { + return response(headers, body, HttpStatus.NOT_FOUND); + } + + private ResponseEntity badRequest(T throwable) { + return badRequest(null, throwable); + } + + private ResponseEntity badRequest(HttpHeaders headers, T throwable) { + return errorResponse(headers, throwable, HttpStatus.BAD_REQUEST); + } + + private ResponseEntity errorResponse(T throwable, HttpStatus status) { + return errorResponse(new HttpHeaders(), throwable, status); + } + + private ResponseEntity errorResponse(HttpHeaders headers, + Exception exception, HttpStatus status) { + + if (null != exception && null != exception.getMessage()) { + + LOG.error(exception.getMessage(), exception); + + return response(headers, new ExceptionMessage(exception), status); + + } else { + + return response(headers, null, status); + } + } + + public ResponseEntity response(HttpHeaders headers, T body, HttpStatus status) { + + Assert.notNull(headers, "Headers must not be null!"); + Assert.notNull(status, "HttpStatus must not be null!"); + + return new ResponseEntity(body, headers, status); + } +} 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 7f084de69..63cac206b 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 @@ -25,7 +25,6 @@ import java.util.Set; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanFactoryUtils; -import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -68,8 +67,8 @@ import org.springframework.data.rest.core.support.RepositoryRelProvider; import org.springframework.data.rest.webmvc.BaseUri; import org.springframework.data.rest.webmvc.BaseUriAwareController; import org.springframework.data.rest.webmvc.BaseUriAwareHandlerMapping; -import org.springframework.data.rest.webmvc.GlobalExceptionHandler; import org.springframework.data.rest.webmvc.RepositoryRestController; +import org.springframework.data.rest.webmvc.RepositoryRestExceptionHandler; import org.springframework.data.rest.webmvc.RepositoryRestHandlerAdapter; import org.springframework.data.rest.webmvc.RepositoryRestHandlerMapping; import org.springframework.data.rest.webmvc.RestMediaTypes; @@ -146,7 +145,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon private static final boolean IS_JPA_AVAILABLE = ClassUtils.isPresent("javax.persistence.EntityManager", RepositoryRestMvcConfiguration.class.getClassLoader()); - @Autowired ListableBeanFactory beanFactory; + @Autowired ApplicationContext applicationContext; @Autowired(required = false) List idConverters = Collections.emptyList(); @@ -155,7 +154,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon @Bean public Repositories repositories() { - return new Repositories(beanFactory); + return new Repositories(applicationContext); } @Bean @@ -168,7 +167,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon List> arrayList = new ArrayList>(); - for (MappingContext context : BeanFactoryUtils.beansOfTypeIncludingAncestors(beanFactory, + for (MappingContext context : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MappingContext.class).values()) { arrayList.add(context); } @@ -474,7 +473,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon List> messageConverters = defaultMessageConverters(); configureHttpMessageConverters(messageConverters); - Collection beans = beanFactory.getBeansOfType(ResourceProcessor.class, false, false).values(); + Collection beans = applicationContext.getBeansOfType(ResourceProcessor.class, false, false) + .values(); List> processors = new ArrayList>(beans.size()); for (ResourceProcessor bean : beans) { @@ -549,8 +549,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon } @Bean - public GlobalExceptionHandler globalExceptionHandler() { - return new GlobalExceptionHandler(); + public RepositoryRestExceptionHandler repositoryRestExceptionHandler() { + return new RepositoryRestExceptionHandler(applicationContext); } @Bean @@ -628,8 +628,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon private List defaultMethodArgumentResolvers() { PersistentEntityResourceAssemblerArgumentResolver peraResolver = new PersistentEntityResourceAssemblerArgumentResolver( - repositories(), entityLinks(), config().projectionConfiguration(), new ProxyProjectionFactory(beanFactory), - resourceMappings()); + repositories(), entityLinks(), config().projectionConfiguration(), new ProxyProjectionFactory( + applicationContext), resourceMappings()); HateoasPageableHandlerMethodArgumentResolver pageableResolver = pageableResolver(); HandlerMethodArgumentResolver defaultedPageableResolver = new DefaultedPageableHandlerMethodArgumentResolver( diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/ExceptionMessage.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/ExceptionMessage.java index e358e555d..210c76782 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/ExceptionMessage.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/ExceptionMessage.java @@ -9,23 +9,19 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ public class ExceptionMessage { - private final Throwable exception; + private final Throwable throwable; - public ExceptionMessage(Throwable exception) { - this.exception = exception; + public ExceptionMessage(Throwable throwable) { + this.throwable = throwable; } @JsonProperty("message") public String getMessage() { - return exception.getMessage(); + return throwable.getMessage(); } @JsonProperty("cause") public ExceptionMessage getCause() { - if (null != exception.getCause()) { - return new ExceptionMessage(exception.getCause()); - } - return null; + return throwable.getCause() != null ? new ExceptionMessage(throwable.getCause()) : null; } - } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryConstraintViolationExceptionMessage.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryConstraintViolationExceptionMessage.java index 932e94f82..521517f86 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryConstraintViolationExceptionMessage.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/support/RepositoryConstraintViolationExceptionMessage.java @@ -1,3 +1,18 @@ +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.data.rest.webmvc.support; import java.util.ArrayList; @@ -11,6 +26,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; /** * @author Jon Brisbin + * @author Oliver Gierke */ public class RepositoryConstraintViolationExceptionMessage { @@ -21,17 +37,8 @@ public class RepositoryConstraintViolationExceptionMessage { for (FieldError fieldError : violationException.getErrors().getFieldErrors()) { - List args = new ArrayList(); - args.add(fieldError.getObjectName()); - args.add(fieldError.getField()); - args.add(fieldError.getRejectedValue()); - if (null != fieldError.getArguments()) { - for (Object o : fieldError.getArguments()) { - args.add(o); - } - } + String message = accessor.getMessage(fieldError); - String message = accessor.getMessage(fieldError.getCode(), args.toArray(), fieldError.getDefaultMessage()); this.errors.add(new ValidationError(fieldError.getObjectName(), message, String.format("%s", fieldError.getRejectedValue()), fieldError.getField())); } @@ -72,5 +79,4 @@ public class RepositoryConstraintViolationExceptionMessage { return property; } } - } diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ControllerAdviceConfig.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ControllerAdviceConfig.java deleted file mode 100644 index 710545fd8..000000000 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ControllerAdviceConfig.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.springframework.data.rest.webmvc.support; - -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.HttpRequestMethodNotSupportedException; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; - -/** - * @author Thibaud Lepretre - */ -@Configuration -@Import(JpaRepositoryConfig.class) -public class ControllerAdviceConfig { - @Order(Ordered.HIGHEST_PRECEDENCE) - @ControllerAdvice - public static class CustomGlobalConfiguration { - @ExceptionHandler - public ResponseEntity handle(HttpRequestMethodNotSupportedException o_O) { - HttpHeaders headers = new HttpHeaders(); - headers.setAllow(o_O.getSupportedHttpMethods()); - - return new ResponseEntity(headers, HttpStatus.INTERNAL_SERVER_ERROR); - } - } -} diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ControllerAdviceWebTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ControllerAdviceWebTests.java deleted file mode 100644 index edd78cca2..000000000 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ControllerAdviceWebTests.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.springframework.data.rest.webmvc.support; - -import org.junit.Test; -import org.springframework.data.rest.webmvc.AbstractWebIntegrationTests; -import org.springframework.hateoas.Link; -import org.springframework.test.context.ContextConfiguration; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * @author Thibaud Lepretre - */ -@ContextConfiguration(classes = ControllerAdviceConfig.class) -public class ControllerAdviceWebTests extends AbstractWebIntegrationTests { - @Test - public void httpRequestMethodNotSupportedExceptionShouldNowReturnHttpStatus500Over405() throws Exception { - - Link link = client.discoverUnique("addresses"); - - mvc.perform(get(link.getHref())).// - andExpect(status().isInternalServerError()); - } - - @Override - protected Iterable expectedRootLinkRels() { - return null; - } -} diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ExceptionHandlingCustomizationIntegrationTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ExceptionHandlingCustomizationIntegrationTests.java new file mode 100644 index 000000000..a15e2b35a --- /dev/null +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/ExceptionHandlingCustomizationIntegrationTests.java @@ -0,0 +1,84 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.rest.webmvc.support; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import java.util.Collections; + +import org.junit.Test; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.data.rest.webmvc.AbstractWebIntegrationTests; +import org.springframework.data.rest.webmvc.jpa.JpaRepositoryConfig; +import org.springframework.hateoas.Link; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +/** + * Integration tests for customization of Spring Data REST's exception handling. + * + * @author Thibaud Lepretre + * @author Oliver Gierke + */ +@ContextConfiguration +public class ExceptionHandlingCustomizationIntegrationTests extends AbstractWebIntegrationTests { + + @Configuration + @Import(JpaRepositoryConfig.class) + static class ControllerAdviceConfig { + + @ControllerAdvice + @Order(Ordered.HIGHEST_PRECEDENCE) + static class CustomGlobalConfiguration { + + @ExceptionHandler + ResponseEntity handle(HttpRequestMethodNotSupportedException o_O) { + + HttpHeaders headers = new HttpHeaders(); + headers.setAllow(o_O.getSupportedHttpMethods()); + + return new ResponseEntity(headers, HttpStatus.INTERNAL_SERVER_ERROR); + } + } + } + + @Test + public void httpRequestMethodNotSupportedExceptionShouldNowReturnHttpStatus500Over405() throws Exception { + + Link link = client.discoverUnique("addresses"); + + mvc.perform(get(link.getHref())).// + andExpect(status().isInternalServerError()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.rest.webmvc.AbstractWebIntegrationTests#expectedRootLinkRels() + */ + @Override + protected Iterable expectedRootLinkRels() { + return Collections.emptySet(); + } +}