@Provider
public class RuntimeExceptionMapper implements ExceptionMapper<RuntimeException> {
private static final Logger LOGGER = Logger.getLogger(RuntimeExceptionMapper.class.getName());
@Override
public Response toResponse(final RuntimeException e) {
// taken from http://stackoverflow.com/questions/13716793/jersey-how-to-register-a-exceptionmapper-that-omits-some-subclasses
if (e instanceof WebApplicationException) {
return ((WebApplicationException) e).getResponse();
}
LOGGER.log(Level.WARNING, "RuntimeException occurred", e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Sorry, something went wrong")
.build();
}
}
Entries tagged [jersey]
Jersey 1.x ExceptionMapper examples
TweetPosted on Saturday Oct 29, 2016 at 12:42PM in Technology
CAUTION: this posting is about Jersey 1.x which is obsoleted. If you use more modern JAX-RS implementation such as Jersey 2.x or above, please check if there are any better approaches.
JAX-RS (Jersey) provides a mechanism called ExceptionMapper which is an universal way to map an exception that thrown by a JAX-RS implementation itself or application code, to any HTTP response. In this posting, I’ll introduce some basic but useful usages of it that I have found.
ExceptionMapper for RuntimeException
When your resource method throw an Exception, say, an unintentional NullPointerException which caused by a bug or something, typically this produces a 500 Error page which created by your application container. You can catch, log those exceptions and produce a customer-friendly response with an ExceptionMapper which is something like following:
ExceptionMapper for NotFoundException
When your app receive a request which has no corresponding resource method, typically this produces a 404 Error page created by your container as well as an uncaught Exception. You can handle this situation with an ExceptionMapper as follows:
@Provider
public class NotFoundExceptionMapper implements ExceptionMapper<NotFoundException> {
private static final Logger LOGGER = Logger.getLogger(NotFoundExceptionMapper.class.getName());
@Override
public Response toResponse(final NotFoundException e) {
LOGGER.log(Level.FINE, "NotFoundException occurred", e);
return Response.status(Response.Status.NOT_FOUND)
.entity("Check the destination path of your request - we have no API here")
.build();
}
}
ExceptionMapper for ParamExceptionMapper
Let’s say you have a value class which is something like following:
public class EmployeeId {
private final long value;
public EmployeeId(final long value) {
if (value < 1) {
throw new IllegalArgumentException("EmployeeId must be larger than zero");
}
this.value = value;
}
public EmployeeId(final String value) {
this(Long.parseLong(value));
}
// getter and toString omitted
}
And you have a resource method which receives an EmployeeId
as follows:
@Path("myresource")
public class MyResource {
@GET
@Path("emp")
@Produces(MediaType.TEXT_PLAIN)
public String emp(@QueryParam("id") EmployeeId id) {
...
}
}
When the resource method receives a valid id
, say 123
, Jersey automatically constructs an EmployeeId
instance and passes it to the application code. That’s fine, but consider if a malicious user has sent an invalid value, say -1
. Typically this produces an error page which created by your container as well. You may want to return a more informational response with HTTP status code 400
with an ExceptionMapper which is something like:
@Provider
public class ParamExceptionMapper implements ExceptionMapper<ParamException> {
private static final Logger LOGGER = Logger.getLogger(ParamExceptionMapper.class.getName());
@Override
public Response toResponse(final ParamException e) {
LOGGER.log(Level.FINE, "ParamException occurred", e);
final StringBuilder sb = new StringBuilder("Your parameter '" + e.getParameterName() + "' is invalid");
final Throwable cause = e.getCause();
if (cause instanceof IllegalArgumentException) {
final String message = cause.getMessage();
if (message != null && !message.isEmpty()) {
sb.append(": ").append(message);
}
}
return Response.status(Response.Status.BAD_REQUEST)
.entity(sb.toString())
.build();
}
}
Conclusion
ExceptionMapper helps making error responses of your REST APIs more helpful. And it reduces repetitive exception handling code in your resource classes that tend to be tons of boilarplate.
You can obtain complete code based on Jersey 1.x and testcases that powered by Arquillian, Embedded Tomcat and Apache HttpClient, from my GitHub repository.
Tags: arquillian jax-rs jersey
Lean example of Tomcat 8 + Guice 4 + Jersey 2.19
TweetPosted on Wednesday Aug 05, 2015 at 02:36PM in Technology
Jersey is the RI of JAX-RS. in this entry, I introduce you how to use Jersey 2.19 with Guice 4 on Tomcat 8. it looks like there are some issues exist as follows but thanks to https://github.com/Squarespace/jersey2-guice , I’ve succeeded to use them anyway.
The entire project which based on Maven can be obtained from My GitHub repository.
Dependencies
<dependencyManagement> <dependencies> <dependency> <groupId>org.glassfish.jersey</groupId> <artifactId>jersey-bom</artifactId> <version>2.19</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-servlet</artifactId> </dependency> <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>4.0</version> </dependency> <dependency> <groupId>com.google.inject.extensions</groupId> <artifactId>guice-servlet</artifactId> <version>4.0</version> </dependency> <dependency> <groupId>com.squarespace.jersey2-guice</groupId> <artifactId>jersey2-guice</artifactId> <version>0.10</version> </dependency> </dependencies>
web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <servlet> <servlet-name>Jersey Web Application</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>jersey.config.server.provider.packages</param-name> <param-value>guice.tomcat.jersey</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Jersey Web Application</servlet-name> <url-pattern>/webapi/*</url-pattern> </servlet-mapping> <listener> <listener-class>guice.tomcat.MyJerseyGuiceServletContextListener</listener-class> </listener> <filter> <filter-name>guiceFilter</filter-name> <filter-class>com.google.inject.servlet.GuiceFilter</filter-class> </filter> <filter-mapping> <filter-name>guiceFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
MyJerseyGuiceServletContextListener.java
In this example, we use the servlet context listener named JerseyGuiceServletContextListener
which comes from jersey2-guice
artifact as parent class.
public class MyJerseyGuiceServletContextListener extends JerseyGuiceServletContextListener { @Override protected List<? extends Module> modules() { return Collections.singletonList(new ServletModule() { @Override protected void configureServlets() { bind(MyService.class).to(MyServiceImpl.class); } }); } }
Service class
We use very simple pair of an interface and implementation that creates a simple greeting message, which used in a past entry so omitted for simplicity.
MyResource.java
This is an simple implementation of JAX-RS resource class. placed under guice.tomcat.jersey
package. the preceding service class named MyService
will be injected by @javax.inject.Inject
annotation.
@Path("myresource") public class MyResource { @Inject private MyService myService; @GET @Produces(MediaType.TEXT_PLAIN) public String getIt() { return myService.hello("Jersey"); } }
Test run
$ curl http://localhost:8080/webapi/myresource Hello, Jersey