diff --git a/pom.xml b/pom.xml
index f7050cb0..d96482be 100644
--- a/pom.xml
+++ b/pom.xml
@@ -68,6 +68,12 @@
jsr305
3.0.1
+
+ org.projectlombok
+ lombok
+ 1.16.10
+ provided
+
com.google.guava
guava
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/AdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/AdviceTrait.java
index ae2835ba..f5547985 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/AdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/AdviceTrait.java
@@ -1,5 +1,6 @@
package org.zalando.problem.spring.web.advice;
+import lombok.SneakyThrows;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@@ -21,12 +22,14 @@
import org.zalando.problem.spring.web.advice.validation.ValidationAdviceTrait;
import javax.ws.rs.core.Response.StatusType;
-import java.net.URI;
import java.util.List;
import java.util.Optional;
+import static com.google.common.base.MoreObjects.firstNonNull;
import static java.util.Arrays.asList;
import static javax.servlet.RequestDispatcher.ERROR_EXCEPTION;
+import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
+import static org.springframework.http.HttpStatus.NOT_ACCEPTABLE;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.context.request.RequestAttributes.SCOPE_REQUEST;
import static org.zalando.problem.spring.web.advice.Lists.lengthOfTrailingPartialSubList;
@@ -63,13 +66,12 @@
public interface AdviceTrait {
default ResponseEntity create(final StatusType status, final Throwable throwable,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
return create(status, throwable, request, new HttpHeaders());
}
default ResponseEntity create(final StatusType status, final Throwable throwable,
- final NativeWebRequest request, final HttpHeaders headers)
- throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request, final HttpHeaders headers) {
return create(throwable, toProblem(throwable, status), request, headers);
}
@@ -105,48 +107,47 @@ default boolean isCausalChainsEnabled() {
return false;
}
- default ResponseEntity create(final ThrowableProblem problem, final NativeWebRequest request)
- throws HttpMediaTypeNotAcceptableException {
+ default ResponseEntity create(final ThrowableProblem problem, final NativeWebRequest request) {
return create(problem, request, new HttpHeaders());
}
default ResponseEntity create(final ThrowableProblem problem, final NativeWebRequest request,
- final HttpHeaders headers) throws HttpMediaTypeNotAcceptableException {
+ final HttpHeaders headers) {
return create(problem, problem, request, headers);
}
default ResponseEntity create(final Throwable throwable, final Problem problem,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
return create(throwable, problem, request, new HttpHeaders());
}
default ResponseEntity create(final Throwable throwable, final Problem problem,
- final NativeWebRequest request, final HttpHeaders headers) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request, final HttpHeaders headers) {
+
+ final HttpStatus status = HttpStatus.valueOf(firstNonNull(
+ problem.getStatus(), INTERNAL_SERVER_ERROR).getStatusCode());
- // TODO magic! always?
- if (problem.getStatus().getStatusCode() == 500) {
+ if (status == HttpStatus.INTERNAL_SERVER_ERROR) {
request.setAttribute(ERROR_EXCEPTION, throwable, SCOPE_REQUEST);
}
- return process(negotiate(request).map(contentType -> {
- final int statusCode = problem.getStatus().getStatusCode();
- final HttpStatus status = HttpStatus.valueOf(statusCode);
-
- return ResponseEntity.status(status)
- .headers(headers)
- .contentType(contentType)
- .body(problem);
- }).orElseGet(() -> fallback(throwable, problem, request, headers)));
-
+ return process(negotiate(request).map(contentType ->
+ ResponseEntity.status(status)
+ .headers(headers)
+ .contentType(contentType)
+ .body(problem))
+ .orElseGet(() -> fallback(throwable, problem, request, headers)));
}
default ResponseEntity fallback(final Throwable throwable, final Problem problem,
final NativeWebRequest request, final HttpHeaders headers) {
- return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).body(null);
+ return ResponseEntity.status(NOT_ACCEPTABLE).body(null);
}
- default Optional negotiate(final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ @SneakyThrows(HttpMediaTypeNotAcceptableException.class)
+ default Optional negotiate(final NativeWebRequest request) {
final HeaderContentNegotiationStrategy negotiator = new HeaderContentNegotiationStrategy();
+
final List mediaTypes = negotiator.resolveMediaTypes(request);
if (mediaTypes.isEmpty()) {
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/HttpStatusAdapter.java b/src/main/java/org/zalando/problem/spring/web/advice/HttpStatusAdapter.java
index c2c23adf..cb7b6288 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/HttpStatusAdapter.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/HttpStatusAdapter.java
@@ -1,10 +1,10 @@
package org.zalando.problem.spring.web.advice;
-import java.util.Objects;
import org.springframework.http.HttpStatus;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status.Family;
+import java.util.Objects;
/**
* An implementation of {@link javax.ws.rs.core.Response.StatusType} to map {@link HttpStatus}.
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/SpringAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/SpringAdviceTrait.java
index 5b132374..dfdace25 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/SpringAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/SpringAdviceTrait.java
@@ -3,7 +3,6 @@
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.context.request.NativeWebRequest;
import org.zalando.problem.Problem;
import org.zalando.problem.ThrowableProblem;
@@ -19,13 +18,12 @@
public interface SpringAdviceTrait extends AdviceTrait {
default ResponseEntity create(final HttpStatus status, final Throwable throwable,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
return create(status, throwable, request, new HttpHeaders());
}
default ResponseEntity create(final HttpStatus status, final Throwable throwable,
- final NativeWebRequest request, final HttpHeaders headers)
- throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request, final HttpHeaders headers) {
return create(toStatus(status), throwable, request, headers);
}
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/general/ProblemAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/general/ProblemAdviceTrait.java
index 8213b631..452cab70 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/general/ProblemAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/general/ProblemAdviceTrait.java
@@ -1,7 +1,6 @@
package org.zalando.problem.spring.web.advice.general;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
import org.zalando.problem.Problem;
@@ -17,7 +16,7 @@ public interface ProblemAdviceTrait extends AdviceTrait {
@ExceptionHandler
default ResponseEntity handleProblem(
final ThrowableProblem problem,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
return create(problem, request);
}
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/general/ThrowableAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/general/ThrowableAdviceTrait.java
index 8f98ddb5..aea88251 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/general/ThrowableAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/general/ThrowableAdviceTrait.java
@@ -1,7 +1,6 @@
package org.zalando.problem.spring.web.advice.general;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
import org.zalando.problem.Problem;
@@ -19,7 +18,7 @@ public interface ThrowableAdviceTrait extends AdviceTrait {
@ExceptionHandler
default ResponseEntity handleThrowable(
final Throwable throwable,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
return create(Status.INTERNAL_SERVER_ERROR, throwable, request);
}
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/general/UnsupportedOperationAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/general/UnsupportedOperationAdviceTrait.java
index 3cc7164f..c51bcd78 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/general/UnsupportedOperationAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/general/UnsupportedOperationAdviceTrait.java
@@ -1,7 +1,6 @@
package org.zalando.problem.spring.web.advice.general;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
import org.zalando.problem.Problem;
@@ -18,7 +17,7 @@ public interface UnsupportedOperationAdviceTrait extends AdviceTrait {
@ExceptionHandler
default ResponseEntity handleUnsupportedOperation(
final UnsupportedOperationException exception,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
return create(Status.NOT_IMPLEMENTED, exception, request);
}
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/http/MethodNotAllowedAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/http/MethodNotAllowedAdviceTrait.java
index 225b066a..a2822daf 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/http/MethodNotAllowedAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/http/MethodNotAllowedAdviceTrait.java
@@ -4,7 +4,6 @@
import com.google.gag.annotation.remark.WTF;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
@@ -19,7 +18,7 @@ public interface MethodNotAllowedAdviceTrait extends AdviceTrait {
@ExceptionHandler
default ResponseEntity handleRequestMethodNotSupportedException(
final HttpRequestMethodNotSupportedException exception,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
@WTF
@Facepalm("Nullable arrays... great work from Spring :/")
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/http/NotAcceptableAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/http/NotAcceptableAdviceTrait.java
index c844e316..4ee554be 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/http/NotAcceptableAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/http/NotAcceptableAdviceTrait.java
@@ -18,7 +18,7 @@ public interface NotAcceptableAdviceTrait extends AdviceTrait {
@ExceptionHandler
default ResponseEntity handleMediaTypeNotAcceptable(
final HttpMediaTypeNotAcceptableException exception,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
return create(Status.NOT_ACCEPTABLE, exception, request);
}
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/http/UnsupportedMediaTypeAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/http/UnsupportedMediaTypeAdviceTrait.java
index 661320fd..536d307a 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/http/UnsupportedMediaTypeAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/http/UnsupportedMediaTypeAdviceTrait.java
@@ -2,7 +2,6 @@
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
@@ -20,7 +19,7 @@ public interface UnsupportedMediaTypeAdviceTrait extends AdviceTrait {
@ExceptionHandler
default ResponseEntity handleMediaTypeNotSupportedException(
final HttpMediaTypeNotSupportedException exception,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
final HttpHeaders headers = new HttpHeaders();
headers.setAccept(exception.getSupportedMediaTypes());
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/io/MessageNotReadableAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/io/MessageNotReadableAdviceTrait.java
index f2703993..fcfb5d4a 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/io/MessageNotReadableAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/io/MessageNotReadableAdviceTrait.java
@@ -2,7 +2,6 @@
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
import org.zalando.problem.Problem;
@@ -11,8 +10,6 @@
import javax.ws.rs.core.Response.Status;
/**
- * TODO support for different causes
- *
* @see HttpMessageNotReadableException
* @see Status#BAD_REQUEST
*/
@@ -21,7 +18,7 @@ public interface MessageNotReadableAdviceTrait extends AdviceTrait {
@ExceptionHandler
default ResponseEntity handleMessageNotReadableException(
final HttpMessageNotReadableException exception,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
return create(Status.BAD_REQUEST, exception, request);
}
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/io/MultipartAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/io/MultipartAdviceTrait.java
index 10d3e842..5454ea03 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/io/MultipartAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/io/MultipartAdviceTrait.java
@@ -1,7 +1,6 @@
package org.zalando.problem.spring.web.advice.io;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.multipart.MultipartException;
@@ -16,7 +15,7 @@ public interface MultipartAdviceTrait extends AdviceTrait {
@ExceptionHandler
default ResponseEntity handleMultipart(
final MultipartException exception,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
return create(Status.BAD_REQUEST, exception, request);
}
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/io/TypeMistmatchAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/io/TypeMistmatchAdviceTrait.java
index f807d62b..cee376f3 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/io/TypeMistmatchAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/io/TypeMistmatchAdviceTrait.java
@@ -2,7 +2,6 @@
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
import org.zalando.problem.Problem;
@@ -19,7 +18,7 @@ public interface TypeMistmatchAdviceTrait extends AdviceTrait {
@ExceptionHandler
default ResponseEntity handleTypeMismatch(
final TypeMismatchException exception,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
return create(Status.BAD_REQUEST, exception, request);
}
}
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/routing/MissingServletRequestParameterAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/routing/MissingServletRequestParameterAdviceTrait.java
index 111e250e..472b53cc 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/routing/MissingServletRequestParameterAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/routing/MissingServletRequestParameterAdviceTrait.java
@@ -1,7 +1,6 @@
package org.zalando.problem.spring.web.advice.routing;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
@@ -19,7 +18,7 @@ public interface MissingServletRequestParameterAdviceTrait extends AdviceTrait {
@ExceptionHandler
default ResponseEntity handleMissingServletRequestParameter(
final MissingServletRequestParameterException exception,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
return create(Status.BAD_REQUEST, exception, request);
}
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/routing/MissingServletRequestPartAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/routing/MissingServletRequestPartAdviceTrait.java
index 2d1c3828..b2d0f92c 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/routing/MissingServletRequestPartAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/routing/MissingServletRequestPartAdviceTrait.java
@@ -1,7 +1,6 @@
package org.zalando.problem.spring.web.advice.routing;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
@@ -19,7 +18,7 @@ public interface MissingServletRequestPartAdviceTrait extends AdviceTrait {
@ExceptionHandler
default ResponseEntity handleMissingServletRequestPart(
final MissingServletRequestPartException exception,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
return create(Status.BAD_REQUEST, exception, request);
}
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/routing/NoHandlerFoundAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/routing/NoHandlerFoundAdviceTrait.java
index 138456d1..b235453d 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/routing/NoHandlerFoundAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/routing/NoHandlerFoundAdviceTrait.java
@@ -1,7 +1,6 @@
package org.zalando.problem.spring.web.advice.routing;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.servlet.DispatcherServlet;
@@ -29,7 +28,7 @@ public interface NoHandlerFoundAdviceTrait extends AdviceTrait {
@ExceptionHandler
default ResponseEntity handleNoHandlerFound(
final NoHandlerFoundException exception,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
return create(Status.NOT_FOUND, exception, request);
}
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/routing/ServletRequestBindingAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/routing/ServletRequestBindingAdviceTrait.java
index 235eb90a..b824ea74 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/routing/ServletRequestBindingAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/routing/ServletRequestBindingAdviceTrait.java
@@ -1,7 +1,6 @@
package org.zalando.problem.spring.web.advice.routing;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
@@ -19,7 +18,7 @@ public interface ServletRequestBindingAdviceTrait extends AdviceTrait {
@ExceptionHandler
default ResponseEntity handleServletRequestBinding(
final ServletRequestBindingException exception,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
return create(Status.BAD_REQUEST, exception, request);
}
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/security/AuthenticationAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/security/AuthenticationAdviceTrait.java
index b211c082..21e11d52 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/security/AuthenticationAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/security/AuthenticationAdviceTrait.java
@@ -2,7 +2,6 @@
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.AuthenticationException;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
import org.zalando.problem.Problem;
@@ -14,7 +13,7 @@ public interface AuthenticationAdviceTrait extends AdviceTrait {
@ExceptionHandler
default ResponseEntity handleAuthentication(final AuthenticationException e,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
return create(Response.Status.FORBIDDEN, e, request);
}
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/validation/BaseValidationAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/validation/BaseValidationAdviceTrait.java
index 3b29962f..e2047de8 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/validation/BaseValidationAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/validation/BaseValidationAdviceTrait.java
@@ -1,7 +1,6 @@
package org.zalando.problem.spring.web.advice.validation;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.context.request.NativeWebRequest;
import org.zalando.problem.Problem;
import org.zalando.problem.spring.web.advice.AdviceTrait;
@@ -31,8 +30,7 @@ default String formatFieldName(final String fieldName) {
}
default ResponseEntity newConstraintViolationProblem(final Throwable throwable,
- final Collection stream, final NativeWebRequest request)
- throws HttpMediaTypeNotAcceptableException {
+ final Collection stream, final NativeWebRequest request) {
final StatusType status = defaultConstraintViolationStatus();
final List violations = stream.stream()
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/validation/ConstraintViolationAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/validation/ConstraintViolationAdviceTrait.java
index 6edb0201..10345ccf 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/validation/ConstraintViolationAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/validation/ConstraintViolationAdviceTrait.java
@@ -1,7 +1,6 @@
package org.zalando.problem.spring.web.advice.validation;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
import org.zalando.problem.MoreStatus;
@@ -29,7 +28,7 @@ default Violation createViolation(final ConstraintViolation violation) {
@ExceptionHandler
default ResponseEntity handleConstraintViolation(
final ConstraintViolationException exception,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
final List violations = exception.getConstraintViolations().stream()
.map(this::createViolation)
diff --git a/src/main/java/org/zalando/problem/spring/web/advice/validation/MethodArgumentNotValidAdviceTrait.java b/src/main/java/org/zalando/problem/spring/web/advice/validation/MethodArgumentNotValidAdviceTrait.java
index 2165a705..107484ae 100644
--- a/src/main/java/org/zalando/problem/spring/web/advice/validation/MethodArgumentNotValidAdviceTrait.java
+++ b/src/main/java/org/zalando/problem/spring/web/advice/validation/MethodArgumentNotValidAdviceTrait.java
@@ -3,7 +3,6 @@
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.NativeWebRequest;
@@ -37,7 +36,7 @@ default Violation createViolation(final ObjectError error) {
@ExceptionHandler
default ResponseEntity handleMethodArgumentNotValid(
final MethodArgumentNotValidException exception,
- final NativeWebRequest request) throws HttpMediaTypeNotAcceptableException {
+ final NativeWebRequest request) {
final List violations = Stream.concat(
exception.getBindingResult().getFieldErrors().stream().map(this::createViolation),
diff --git a/src/test/java/org/zalando/problem/spring/web/advice/AdviceTraitTest.java b/src/test/java/org/zalando/problem/spring/web/advice/AdviceTraitTest.java
index 72320b1d..955e0750 100644
--- a/src/test/java/org/zalando/problem/spring/web/advice/AdviceTraitTest.java
+++ b/src/test/java/org/zalando/problem/spring/web/advice/AdviceTraitTest.java
@@ -5,7 +5,6 @@
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.context.request.NativeWebRequest;
import org.zalando.problem.Problem;
import org.zalando.problem.ThrowableProblem;
@@ -13,7 +12,6 @@
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import java.util.List;
-import java.util.Optional;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toList;
@@ -38,7 +36,7 @@ public class AdviceTraitTest {
};
@Test
- public void buildsOnProblem() throws HttpMediaTypeNotAcceptableException {
+ public void buildsOnProblem() {
final ThrowableProblem problem = mock(ThrowableProblem.class);
when(problem.getStatus()).thenReturn(Status.RESET_CONTENT);
@@ -50,7 +48,7 @@ public void buildsOnProblem() throws HttpMediaTypeNotAcceptableException {
}
@Test
- public void buildsOnThrowable() throws HttpMediaTypeNotAcceptableException {
+ public void buildsOnThrowable() {
final ResponseEntity result = unit.create(Status.RESET_CONTENT,
new IllegalStateException("Message"), request());
@@ -61,7 +59,7 @@ public void buildsOnThrowable() throws HttpMediaTypeNotAcceptableException {
}
@Test
- public void buildsOnMessage() throws HttpMediaTypeNotAcceptableException {
+ public void buildsOnMessage() {
final ResponseEntity result = unit.create(Status.RESET_CONTENT,
new IllegalStateException("Message"), request());
@@ -72,7 +70,7 @@ public void buildsOnMessage() throws HttpMediaTypeNotAcceptableException {
}
@Test
- public void buildsIfIncludes() throws HttpMediaTypeNotAcceptableException {
+ public void buildsIfIncludes() {
final String message = "Message";
final ResponseEntity result = unit.create(Status.RESET_CONTENT,
@@ -86,7 +84,7 @@ public void buildsIfIncludes() throws HttpMediaTypeNotAcceptableException {
}
@Test
- public void buildsStacktrace() throws HttpMediaTypeNotAcceptableException {
+ public void buildsStacktrace() {
final Throwable throwable;
try {
@@ -163,7 +161,7 @@ private NullPointerException newNullPointer() {
}
@Test
- public void mapsStatus() throws HttpMediaTypeNotAcceptableException {
+ public void mapsStatus() {
final HttpStatus expected = HttpStatus.BAD_REQUEST;
final Response.StatusType input = Status.BAD_REQUEST;
final ResponseEntity entity = unit.create(input,
@@ -173,7 +171,7 @@ public void mapsStatus() throws HttpMediaTypeNotAcceptableException {
}
@Test(expected = IllegalArgumentException.class)
- public void throwsOnUnknownStatus() throws HttpMediaTypeNotAcceptableException {
+ public void throwsOnUnknownStatus() {
final Response.StatusType input = mock(Response.StatusType.class);
when(input.getReasonPhrase()).thenReturn("L33t");
when(input.getStatusCode()).thenReturn(1337);
diff --git a/src/test/java/org/zalando/problem/spring/web/advice/ContentNegotiationTest.java b/src/test/java/org/zalando/problem/spring/web/advice/ContentNegotiationTest.java
index 72e80ee4..f606b81e 100644
--- a/src/test/java/org/zalando/problem/spring/web/advice/ContentNegotiationTest.java
+++ b/src/test/java/org/zalando/problem/spring/web/advice/ContentNegotiationTest.java
@@ -3,6 +3,9 @@
import org.junit.Ignore;
import org.junit.Test;
+import org.springframework.web.HttpMediaTypeNotAcceptableException;
+
+import javax.servlet.ServletException;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request;
@@ -52,12 +55,19 @@ public void specificJsonGivesProblem() throws Exception {
}
@Test
- public void nonJsonGivesEmpty() throws Exception {
+ public void nonJsonIsNotAcceptable() throws Exception {
mvc().perform(request(GET, url)
- .accept("application/atom+xml"))
+ .header("Accept", "application/atom+xml"))
.andExpect(status().isNotAcceptable())
.andExpect(content().string(""))
.andExpect(header().doesNotExist("Content-Type"));
}
+ @Test(expected = ServletException.class)
+ public void invalidMediaTypeIsNotAcceptable() throws Exception {
+ mvc().perform(request(GET, url)
+ .header("Accept", "application/"));
+
+ }
+
}
diff --git a/src/test/java/org/zalando/problem/spring/web/advice/FallbackTest.java b/src/test/java/org/zalando/problem/spring/web/advice/FallbackTest.java
index dcc5c831..c046f004 100644
--- a/src/test/java/org/zalando/problem/spring/web/advice/FallbackTest.java
+++ b/src/test/java/org/zalando/problem/spring/web/advice/FallbackTest.java
@@ -11,7 +11,9 @@
import static org.hamcrest.Matchers.is;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public final class FallbackTest implements AdviceTraitTesting {
diff --git a/src/test/java/org/zalando/problem/spring/web/advice/SpringAdviceTraitTest.java b/src/test/java/org/zalando/problem/spring/web/advice/SpringAdviceTraitTest.java
index b61943b8..988885ca 100644
--- a/src/test/java/org/zalando/problem/spring/web/advice/SpringAdviceTraitTest.java
+++ b/src/test/java/org/zalando/problem/spring/web/advice/SpringAdviceTraitTest.java
@@ -4,13 +4,10 @@
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.context.request.NativeWebRequest;
import org.zalando.problem.Problem;
import org.zalando.problem.ThrowableProblem;
-import java.util.Optional;
-
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
@@ -29,7 +26,7 @@ public final class SpringAdviceTraitTest {
};
@Test
- public void buildsOnThrowable() throws HttpMediaTypeNotAcceptableException {
+ public void buildsOnThrowable() {
final HttpStatusAdapter adapter = new HttpStatusAdapter(RESET_CONTENT);
final ResponseEntity result = unit.create(HttpStatus.RESET_CONTENT,
diff --git a/src/test/java/org/zalando/problem/spring/web/advice/example/ExampleRestController.java b/src/test/java/org/zalando/problem/spring/web/advice/example/ExampleRestController.java
index d8af9669..d0642538 100644
--- a/src/test/java/org/zalando/problem/spring/web/advice/example/ExampleRestController.java
+++ b/src/test/java/org/zalando/problem/spring/web/advice/example/ExampleRestController.java
@@ -32,7 +32,9 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.math.BigDecimal;
import java.time.OffsetDateTime;
+import java.util.Map;
import java.util.Set;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@@ -92,6 +94,21 @@ public ResponseEntity put(@RequestBody final String body) {
return ResponseEntity.ok(body);
}
+ @RequestMapping(path = "/json-object")
+ public void jsonObject(@RequestBody final Map body) {
+
+ }
+
+ @RequestMapping(path = "/json-decimal")
+ public void bigDecimal(@RequestBody final BigDecimal bigDecimal) {
+
+ }
+
+ @RequestMapping(path = "/json-user")
+ public void user(@RequestBody final User user) {
+
+ }
+
@RequestMapping(path = "/handler-params", method = GET)
public ResponseEntity params(
@RequestParam("params1") final String[] params1,
@@ -119,7 +136,7 @@ public ResponseEntity conversion(
@RequestMapping(path = "/handler-invalid-param", method = POST)
public void validRequestParam(@RequestBody final UserRequest user) {
- @Hack("I couldn't make Spring throw this implicitely using annotations...")
+ @Hack("I couldn't make Spring throw this implicitly using annotations...")
@Facepalm
@OhNoYouDidnt
final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
diff --git a/src/test/java/org/zalando/problem/spring/web/advice/example/User.java b/src/test/java/org/zalando/problem/spring/web/advice/example/User.java
new file mode 100644
index 00000000..b3c9cb07
--- /dev/null
+++ b/src/test/java/org/zalando/problem/spring/web/advice/example/User.java
@@ -0,0 +1,10 @@
+package org.zalando.problem.spring.web.advice.example;
+
+import lombok.Value;
+
+@Value
+public class User {
+
+ String name;
+
+}
diff --git a/src/test/java/org/zalando/problem/spring/web/advice/http/MethodNotAllowedAdviceTraitTest.java b/src/test/java/org/zalando/problem/spring/web/advice/http/MethodNotAllowedAdviceTraitTest.java
index 4c7eba52..2df50629 100644
--- a/src/test/java/org/zalando/problem/spring/web/advice/http/MethodNotAllowedAdviceTraitTest.java
+++ b/src/test/java/org/zalando/problem/spring/web/advice/http/MethodNotAllowedAdviceTraitTest.java
@@ -2,7 +2,6 @@
import org.junit.Test;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.context.request.NativeWebRequest;
import org.zalando.problem.Problem;
@@ -36,7 +35,7 @@ public void methodNotAllowed() throws Exception {
}
@Test
- public void noAllowIfNullAllowed() throws HttpMediaTypeNotAcceptableException {
+ public void noAllowIfNullAllowed() {
final MethodNotAllowedAdviceTrait unit = new MethodNotAllowedAdviceTrait() {
};
final ResponseEntity entity = unit.handleRequestMethodNotSupportedException(
@@ -46,7 +45,7 @@ public void noAllowIfNullAllowed() throws HttpMediaTypeNotAcceptableException {
}
@Test
- public void noAllowIfNoneAllowed() throws HttpMediaTypeNotAcceptableException {
+ public void noAllowIfNoneAllowed() {
final MethodNotAllowedAdviceTrait unit = new MethodNotAllowedAdviceTrait() {
};
final ResponseEntity entity = unit.handleRequestMethodNotSupportedException(
diff --git a/src/test/java/org/zalando/problem/spring/web/advice/io/MessageNotReadableAdviceTraitTest.java b/src/test/java/org/zalando/problem/spring/web/advice/io/MessageNotReadableAdviceTraitTest.java
index 2eb6a01e..008763c1 100644
--- a/src/test/java/org/zalando/problem/spring/web/advice/io/MessageNotReadableAdviceTraitTest.java
+++ b/src/test/java/org/zalando/problem/spring/web/advice/io/MessageNotReadableAdviceTraitTest.java
@@ -26,6 +26,61 @@ public void missingRequestBody() throws Exception {
.andExpect(jsonPath("$.detail", containsString("request body is missing")));
}
- // TODO: jackson stuff tests
+ @Test
+ public void malformedJsonRequestBody() throws Exception {
+ mvc().perform(request(PUT, "http://localhost/api/json-object")
+ .contentType("application/json")
+ .content("{"))
+ .andExpect(status().isBadRequest())
+ .andExpect(header().string("Content-Type", is("application/problem+json")))
+ .andExpect(jsonPath("$.type").doesNotExist())
+ .andExpect(jsonPath("$.title", is("Bad Request")))
+ .andExpect(jsonPath("$.status", is(400)))
+ .andExpect(jsonPath("$.detail", containsString("Unexpected end-of-input: expected close marker for OBJECT")))
+ .andExpect(jsonPath("$.detail", containsString("line: 1, column: 0")));
+ }
+
+ @Test
+ public void invalidFormat() throws Exception {
+ mvc().perform(request(PUT, "http://localhost/api/json-decimal")
+ .contentType("application/json")
+ .content("\"foobar\""))
+ .andExpect(status().isBadRequest())
+ .andExpect(header().string("Content-Type", is("application/problem+json")))
+ .andExpect(jsonPath("$.type").doesNotExist())
+ .andExpect(jsonPath("$.title", is("Bad Request")))
+ .andExpect(jsonPath("$.status", is(400)))
+ .andExpect(jsonPath("$.detail", containsString("Can not construct instance of java.math.BigDecimal from String value 'foobar': not a valid representation")));
+ }
+
+ @Test
+ public void noConstructor() throws Exception {
+ mvc().perform(request(PUT, "http://localhost/api/json-user")
+ .contentType("application/json")
+ .content("{}"))
+ .andExpect(status().isBadRequest())
+ .andExpect(header().string("Content-Type", is("application/problem+json")))
+ .andExpect(jsonPath("$.type").doesNotExist())
+ .andExpect(jsonPath("$.title", is("Bad Request")))
+ .andExpect(jsonPath("$.status", is(400)))
+ .andExpect(jsonPath("$.detail", containsString("Could not read document")))
+ .andExpect(jsonPath("$.detail", containsString("No suitable constructor found for type [simple type, class org.zalando.problem.spring.web.advice.example.User]")))
+ .andExpect(jsonPath("$.detail", containsString("can not instantiate from JSON object")))
+ .andExpect(jsonPath("$.detail", containsString("missing default constructor or creator, or perhaps need to add/enable type information?")));
+ }
+
+ @Test
+ public void wrongJsonTypeRequestBody() throws Exception {
+ mvc().perform(request(PUT, "http://localhost/api/json-object")
+ .contentType("application/json")
+ .content("[]"))
+ .andExpect(status().isBadRequest())
+ .andExpect(header().string("Content-Type", is("application/problem+json")))
+ .andExpect(jsonPath("$.type").doesNotExist())
+ .andExpect(jsonPath("$.title", is("Bad Request")))
+ .andExpect(jsonPath("$.status", is(400)))
+ .andExpect(jsonPath("$.detail", containsString("Can not deserialize instance of java.util.LinkedHashMap out of START_ARRAY token")))
+ .andExpect(jsonPath("$.detail", containsString("line: 1, column: 1")));
+ }
}
\ No newline at end of file