dur dur - 6 months ago 47
JSON Question

JAX-RS response with HTTP status 500 instead of HTTP status 400

Sometimes JAR-RS clients are sending wrong syntactical request body. The server should response with HTTP status 400 (Bad Request), but it responses with HTTP status 500 (Internal Server Error).

Code:

JAX-B model class:

@XmlRootElement(namespace = "http://www.test.com/test")
@XmlAccessorType(value = XmlAccessType.FIELD)
public class TestModel {

@XmlElement
private String id;
}


JAX-RS resource class:

@Path("test")
public class TestResource {

@POST
@Consumes(MediaType.APPLICATION_JSON)
public void create(TestModel testModel) {
// some code
}
}


CXF configuration:

<jaxrs:server address="/rest" id="test" staticSubresourceResolution="true">
<jaxrs:serviceBeans>
<ref bean="testResource" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider" />
</jaxrs:providers>
</jaxrs:server>


Example:

Request body:

{"id2": "test"}


The
id2
is wrong, so client should get a HTTP status 400, but it gets HTTP status 500.

Server log:

Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "id2" (class test.TestModel), not marked as ignorable (one known property: "id"])
at [Source: org.apache.cxf.transport.http.AbstractHTTPDestination$1@6f30793d; line: 1, column: 10] (through reference chain: test.TestModel["id2"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:51)
at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:839)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1045)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1352)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1330)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:264)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:125)
at com.fasterxml.jackson.databind.ObjectReader._bind(ObjectReader.java:1470)
at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:912)
at com.fasterxml.jackson.jaxrs.base.ProviderBase.readFrom(ProviderBase.java:811)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBodyReader(JAXRSUtils.java:1343)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBody(JAXRSUtils.java:1294)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameter(JAXRSUtils.java:826)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.processParameters(JAXRSUtils.java:789)
at org.apache.cxf.jaxrs.interceptor.JAXRSInInterceptor.processRequest(JAXRSInInterceptor.java:212)
... 68 more


Is there a way to configure Jackson and/or CXF to return HTTP status 400 for wrong syntactical request body without schema validation or bean validation?

Answer

The problem is that exceptions that aren't mapped to response (by way of ExceptionMappers), translate to a general server error response, as the runtime has no idea what to do with the exception.

The jackson-jaxrs-provider module has ExceptionMappers to handle the Jackson base exception class JsonMappingException and JsonParseException. The mappers are JsonMappingExceptionMapper and JsonParseExceptionMapper, respectively. These mappers will map the exception to a 400 response along with the exception message as the response body. If you do not like this response body, you can just write your own mapper.

Comments