21

So I'm building a web application, we are using JPA and Jersey to consume/produces JSON data.

I have a custom "EntityException" aswell as a custom "EntityExceptionMapper"

Here's the mapper:

  @Provider
public class EntityExceptionMapper implements ExceptionMapper<EntityException> {
   
    public EntityExceptionMapper() {
        System.out.println("Mapper created");
    }

    @Override
    public Response toResponse(EntityException e) {
        System.out.println("This doesnt print!");
        return Response.serverError().build();
    }
}

My Exception:

public class EntityException extends Exception implements Serializable{
    
  public EntityException(String message) {
      super(message);
      System.out.println("This prints...");
  }

}

And I'm calling it from a REST call:

@POST
@Path("/test")
@Produces(MediaType.APPLICATION_JSON)
public String test() throws EntityException{
    throw new EntityException("This needs to be send as response!!");
    //return "test";
}

My problem is that, when the above exception is thrown, I get in the constructor (prints: "This prints...") Edit: I also get the: "Mapper created!"

But my response is empty, and I don't get to the sys out of my toResponse method. This is really similar to the example on the jersey website:

https://jersey.java.net/nonav/documentation/1.12/jax-rs.html#d4e435

What am I missing??

Antonio Petricca
  • 8,891
  • 5
  • 36
  • 74
alex
  • 343
  • 1
  • 2
  • 8
  • Do you get this: "Mapper created" ? Maybe your mapper is not recognized properly. Lower the logging level of jersey to see what classes are being scanned. – Piotr Gwiazda Mar 14 '14 at 18:48
  • Yes I'm getting the "Mapper created" (edited, thanks) – alex Mar 14 '14 at 18:59
  • What do you get as a result? You should get empty 500 response based on your code. – Piotr Gwiazda Mar 14 '14 at 19:02
  • 1
    If you use javax.ws.rs.core.Application to register resources. You can add EntityExceptionMapper.class into set of resource types. Something likes this: classes.add(EntityExceptionMapper.class); – LHA Mar 14 '14 at 19:09
  • I get a 204 no content (as my toResponse never seems to be called), following your comment Loc, I tried with something that would be already registered (to see if it would work) I tried extending WebApplicationException, and now it works! I will look into either using that as a type for my exception or registering my own. I think this is about to get solved! Thanks a lot. – alex Mar 14 '14 at 19:14
  • @LocHa using `classes.add(EntityExceptionMapper.class);` worked for me thanks a lot `@Provider` does not seems to work – PHP Avenger Nov 14 '14 at 09:49
  • The first time that I got what I'm looking for from the questions and not from the answer! Thanks a lot! – Ahmed Aziz Nov 15 '22 at 13:07

12 Answers12

17

I am using deployment agnostic application model so the following worked for me:

public class MyApplication extends Application {
    public Set<Class<?>> getClasses() {
        Set<Class<?>> s = new HashSet<Class<?>>();
        s.add(HelloWorldResource.class);

        /** you need to add ExceptionMapper class as well **/
        s.add(EntityExceptionMapper.class)
        return s;
    }
}
bluetech
  • 1,380
  • 3
  • 13
  • 22
6

I had a similar problem where the ExceptionMapper had the proper @Provider annotation and the rest of the code was identical to Jersey's example but still wasn't registered properly.

Well it turns out I had to register manually my custom ExceptionMapper within my HttpServlet with the method addExceptionMapper. Because it's now manually registered, the @Provider annotation can be safely removed.

So with the following ExceptionMapper (I'm catching every RuntimeException to rethrow them as 400)

public class MyCustomExceptionHandler implements ExceptionMapper<RuntimeException> {

  @Override
  public Response toResponse(RuntimeException exception) {
    return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build();
  }
}

I had to add the 2nd line in my init :

HttpServlet serviceServlet = jerseyServletFactory.create(someResource);
jerseyServletFactory.addExceptionMapper(new MyCustomExceptionHandler()); //<--

httpServer.register(serviceServlet, "/api");
httpServer.start();
Pierre-Luc Pineault
  • 8,993
  • 6
  • 40
  • 55
5

I have encountered the same issue while develop sample REST API. While creating REST API i have given base package name like org.manish.rest.message, I supposed to create every other packages under the base package like this


  1. model - org.manish.rest.message.model
  2. database - org.manish.rest.message.database
  3. resource - org.manish.rest.message.resource

in web.xml init param was given like this

 <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>org.manish.rest.message</param-value>
 </init-param>

It means, i have registered my base package in web.xml, what ever package i will create under this; will be consider by JAX-RS based on my call and requirement. But when i created my exception package by mistake i put package name org.manish.rest.exception. Since this was not registered in web.xml so my complete exception class was not considered to handle exception by JAX-RS. As a correction, i have just modified my exception package name from org.manish.rest.exception to org.manish.rest.message.exception

After that i executed once in post man and i got expected result.

Hope this can solve your query.

Thanks Manish

Kushwaha
  • 850
  • 10
  • 13
3

I used spring to wire up jersey app and used @Component with @Provider.

When I moved to jersey v > 2.5, it stopped working.

I resolved this very issue by putting @Singleton annotation instead of @Component alongside @Provider, like this:

@Provider
@Singleton
public class EntityExceptionMapper implements ExceptionMapper<EntityException> {...
mSolujic
  • 146
  • 4
2

I had the same problem and was able to fix it by including the package of my ExceptionMapper in the jersey.config.server.provider.packages in my web.xml file. Below is a snippet from my web.xml.

<servlet>
    <servlet-name>voteride-servlet</servlet-name>
    <servlet-class>
        org.glassfish.jersey.servlet.ServletContainer
    </servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>
            com.voteride.ws;com.voteride.errorHandling;org.codehaus.jackson.jaxrs
        </param-value>
    </init-param>
    <init-param>
        <param-name>jersey.config.server.provider.scanning.recursive</param-name>
        <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
2

Try to register your exception mapper class in your X extends ResourceConfig file. register(CustomExceptionMapper.class); this line will help application to find your mapper class and return whatever you have written inside the toResponse method of mapper class

avinash
  • 501
  • 2
  • 8
  • 16
  • That's basically almost the same as this answer above: https://stackoverflow.com/a/30627548/666414 because `Application` extends `ResourceConfig`; you could have added a comment there... – maxxyme Jul 18 '19 at 13:41
1

I'm using the Jersey JdkHttpServerFactory, and I just had to add the ExceptionMapper class as a resource, just like my other controller resources:

import com.sun.net.httpserver.HttpServer;
import javax.ws.rs.core.UriBuilder;
import java.net.URI;
import java.util.HashSet;
import java.util.Set;
import org.glassfish.jersey.jdkhttp.JdkHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;

// ...

Set<Class> resources = new HashSet<>();
// Add whatever other resource classes you have...

//--->>> Add the exception mapper <<<---
resources.add(EntityExceptionMapper.class);

ResourceConfig resources = new ResourceConfig(resources);
URI uri = UriBuilder.fromUri("http://localhost/").build();
HttpServer server = JdkHttpServerFactory.createHttpServer(uri, resources);
brianmearns
  • 9,581
  • 10
  • 52
  • 79
1

I am still using jersey 1.17 , spring and jersy-spring

@Component annotation fixes this

Kalpesh Soni
  • 6,879
  • 2
  • 56
  • 59
0

I had the same problem. I just had to modify the web.xml. Previously in my web.xml file param-value was com.two95.restful.resource I just changed to root package com.two95.restful. Then it started working like a charm with just the @Provider annotation.

<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>com.two95.restful</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
Ben Green
  • 3,953
  • 3
  • 29
  • 49
SM ANSARI
  • 335
  • 3
  • 13
0

I also face the same issue.Just add the package name that have the ExceptionMappperHandler classes.

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <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>Service,Utilities.ExceptionMapper</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

Here,service contain all service classes and Utilities.ExceptionMapper contains all exceptionMapper. Hope its help

0

If you're using Guice, try this in you configure method

install(new ComponentScanModule("com.acme.application", Provider.class));

 
Johan Perez
  • 171
  • 1
  • 4
0

I fixed it by:

import org.glassfish.jersey.internal.spi.AutoDiscoverable;
import org.glassfish.jersey.server.ServerProperties;

public class JerseySpiConfigurator implements AutoDiscoverable {

    @Override
    public void configure(FeatureContext context) {
        context.property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true); 
    }
}
Antonio Petricca
  • 8,891
  • 5
  • 36
  • 74