Return 5xx HTTP status for invalid target types with Jackson

InvalidDefinitionException has been introduced in Jackson 2.9 to be
able to differentiate invalid data sent from the client (should still
generate a 4xx HTTP status code) from server side errors like beans with
no default constructor (should generate a 5xx HTTP status code).

Issue: SPR-14925
This commit is contained in:
Sebastien Deleuze
2017-04-05 10:36:01 +02:00
parent 454e61e8ac
commit ed8565894a
5 changed files with 85 additions and 1 deletions

View File

@@ -17,22 +17,29 @@
package org.springframework.http.converter;
import org.springframework.core.NestedRuntimeException;
import org.springframework.http.HttpStatus;
import java.util.Optional;
/**
* Thrown by {@link HttpMessageConverter} implementations when a conversion attempt fails.
*
* @author Arjen Poutsma
* @author Sebastien Deleuze
* @since 3.0
*/
@SuppressWarnings("serial")
public class HttpMessageConversionException extends NestedRuntimeException {
private final HttpStatus errorStatus;
/**
* Create a new HttpMessageConversionException.
* @param msg the detail message
*/
public HttpMessageConversionException(String msg) {
super(msg);
this.errorStatus = null;
}
/**
@@ -42,6 +49,25 @@ public class HttpMessageConversionException extends NestedRuntimeException {
*/
public HttpMessageConversionException(String msg, Throwable cause) {
super(msg, cause);
this.errorStatus = null;
}
/**
* Create a new HttpMessageConversionException.
* @since 5.0
* @param msg the detail message
* @param cause the root cause (if any)
* @param errorStatus the HTTP error status related to this exception
*/
public HttpMessageConversionException(String msg, Throwable cause, HttpStatus errorStatus) {
super(msg, cause);
this.errorStatus = errorStatus;
}
/**
* Return the HTTP error status related to this exception if any.
*/
public Optional<HttpStatus> getErrorStatus() {
return Optional.ofNullable(errorStatus);
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.http.converter;
import org.springframework.http.HttpStatus;
/**
* Thrown by {@link HttpMessageConverter} implementations when the
* {@link HttpMessageConverter#read} method fails.
@@ -43,4 +45,15 @@ public class HttpMessageNotReadableException extends HttpMessageConversionExcept
super(msg, cause);
}
/**
* Create a new HttpMessageNotReadableException.
* @since 5.0
* @param msg the detail message
* @param cause the root cause (if any)
* @param errorStatus the HTTP error status related to this exception
*/
public HttpMessageNotReadableException(String msg, Throwable cause, HttpStatus errorStatus) {
super(msg, cause, errorStatus);
}
}

View File

@@ -36,12 +36,14 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractGenericHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
@@ -235,6 +237,9 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
}
return this.objectMapper.readValue(inputMessage.getBody(), javaType);
}
catch (InvalidDefinitionException ex) {
throw new HttpMessageNotReadableException("Could not read document: " + ex.getMessage(), ex, HttpStatus.INTERNAL_SERVER_ERROR);
}
catch (IOException ex) {
throw new HttpMessageNotReadableException("Could not read document: " + ex.getMessage(), ex);
}