I need some help with understanding how Websphere Liberty (18.0.0.1) handles exceptions thrown within a JAX-RS endpoint invocation. I'm using Liberty feature jaxrs-2.0
, so the implementation should be provided by WLP.
Now, my application has a POST HTTP endpoint accepting JSON payload and I'd like to provide a custom error messages for all the possible wrong client inputs.
Here's one case that works in a way I expected it:
- Client sends
application/xml
instead ofapplication/json
- There's a
ClientErrorException
thrown by the container - I can use my own exception mapper (implementing
ExceptionMapper<WebApplicationException>
to handle this exception (actually to handle all the web application exception, which I'm fine with) - This way I can format the error message, mark error with ID, whatever is needed. That's good
And here's the case not working for me:
- Client sends
application/json
, but with empty body - The core exception in this case is
java.io.EOFException: No content to map to Object due to end of input
- yeah, that looks accurate - Now what I can't figure out - instead of wrapping this
EOFException
into some kind ofWebApplicationException
(which I could handle easily), WLP is wrapping the exception issue intoJaxRsRuntimeException
A couple of points here:
- I don't want to create a mapper implementing
ExceptionMapper<JaxRsRuntimeException>
because that exception is not a part of JAX-RS 2.0 spec and I'd have to provide the import to JaxRsRuntimeException and wire the application with some Liberty-specific library. - A possible solution is to have my mapper implement a generic
ExceptionMapper<RuntimeException>
and string check if it finds exception of classname 'JaxRsRuntimeException' and then handle it. But that just doesn't seem right to me.
So, is that a WLP design not to give me a WebApplicationException in this case? What would be the elegant solution to handle this scenario?
Thanks
EDIT: Added some parts of source code.
REST endpoint and resource method:
@Path("/books")
public class BookEndpoint {
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response createBook(Book book, @Context UriInfo uriInfo) {
bookDao.create(book);
UriBuilder builder = uriInfo.getAbsolutePathBuilder();
builder.path(Integer.toString(book.getId()));
return Response.created(builder.build()).entity(book).build();
}
}
Entity with JAXB annotations:
@XmlRootElement
public class Book {
private int id;
private String title;
// getters, setters
}
Exception stack trace:
com.ibm.ws.jaxrs20.JaxRsRuntimeException: java.io.EOFException: No content to map to Object duto end of input
at org.apache.cxf.jaxrs.utils.JAXRSUtils.toJaxRsRuntimeException(JAXRSUtils.java:1928)
at [internal classes]
at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:201)
at [internal classes]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.EOFException: No content to map to Object duto end of input
at org.codehaus.jackson.map.ObjectMapper._initForReading(ObjectMapper.java:2775)
at [internal classes]
at java.security.AccessController.doPrivileged(Native Method)
at org.apache.cxf.jaxrs.utils.JAXRSUtils.readFromMessageBodyReader(JAXRSUtils.java:1413)
at [internal classes]
... 48 more