ExceptionMapper not handling Exception subclasses

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

ExceptionMapper not handling Exception subclasses

Gregg Carrier
Hi all -

Having a problem that I'm sure must be straightforward, but I'm not sure what I'm doing wrong. I have a set of Exceptions that have a common parent class. My ExceptionMapper is not called when one of the subclasses is thrown. Here's what I have:

ExceptionMapper:
@Provider
@Component
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class BasicExceptionMapper implements ExceptionMapper<ParentException> { //ParentException is never thrown

    @Override
    public Response toResponse(ParentException exception) {
        //create a Response ...
    }

}

ParentException:
public class ParentException extends Exception {
    //... some constructors
}

Subclass exception:
public class SpecificException extends ParentException {
    //... some constructors
}

Resource method:
    @POST
    @Path("test")
    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Response doTest() throws SpecificException {
        if (true) throw new SpecificException();
    }

When I call my resource method, it hangs until the request times out.

If I change the handler signature to handle SpecificException, it works as expected and returns quickly with the expected response.

So, what do I have wrong? Any help much appreciated. Thanks!

Gregg
Reply | Threaded
Open this post in threaded view
|

Re: ExceptionMapper not handling Exception subclasses

mathewch
Hi Gregg,

I too have an ExceptionMapping framework for my service implementation. But never had to declare the resource method with the *Exception signature. To avoid that use the type RuntimeException. Also make sure the providers are getting registered. For your reference, I have my exceptions handled in the following way:

1). Base exception class:
public class ServiceException extends RuntimeException {

    private static final long serialVersionUID = -339330063981442247L;
    final protected int       responseStatusCode;
    protected FaultInfo       faultInfo        = null;

    public ServiceException(String message, int responseStatusCode) {
        super(message);
        this.responseStatusCode = responseStatusCode;
    }

    public ServiceException(String message, int responseStatusCode, FaultInfo faultInfo) {
        this(message, responseStatusCode);
        this.faultInfo = faultInfo;
    }

    public ServiceException(int responseStatusCode, FaultInfo faultInfo) {
        this(faultInfo.getReason(), responseStatusCode);
        this.faultInfo = faultInfo;
    }

    public int getResponseStatusCode() {
        return responseStatusCode;
    }

    public FaultInfo getFaultInfo() {
        return faultInfo;
    }
}

2). An exception type:
public class NotFoundException extends ServiceException {
    private static final long serialVersionUID     = -3357251481427760852L;
    public static final int   RESPONSE_STATUS_CODE = HttpURLConnection.HTTP_NOT_FOUND;

    public NotFoundException(String message) {
        super(message, RESPONSE_STATUS_CODE);
    }

    public NotFoundException(String message, FaultInfo faultInfo) {
        super(message, RESPONSE_STATUS_CODE, faultInfo);
    }

    public NotFoundException(FaultInfo faultInfo) {
        super(RESPONSE_STATUS_CODE, faultInfo);
    }
}


3). A fault object to hold the full exception details
/**
 *
 *     A JAXB type representing an exception for a service request.
 *      
 *
 *
 *
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "errorCode",
    "reason",
    "resource",
    "exception"
})
@XmlRootElement(name = "FaultInfo")
public class FaultInfo
    implements Serializable
{

    private final static long serialVersionUID = 1L;
    @XmlElement(namespace = "..........")
    protected Integer errorCode;
    @XmlElement(namespace = "...............")
    protected String reason;
    @XmlElement(namespace = "...................")
    protected String resource;
    @XmlElement(namespace = "............")
    protected String exception;

    /**
     * Gets the value of the errorCode property.
     *
     * @return
     *     possible object is
     *     {@link Integer }
     *    
     */
    public Integer getErrorCode() {
        return errorCode;
    }

    /**
     * Sets the value of the errorCode property.
     *
     * @param value
     *     allowed object is
     *     {@link Integer }
     *    
     */
    public void setErrorCode(Integer value) {
        this.errorCode = value;
    }

    /**
     * Gets the value of the reason property.
     *
     * @return
     *     possible object is
     *     {@link String }
     *    
     */
    public String getReason() {
        return reason;
    }

    /**
     * Sets the value of the reason property.
     *
     * @param value
     *     allowed object is
     *     {@link String }
     *    
     */
    public void setReason(String value) {
        this.reason = value;
    }

    /**
     * Gets the value of the resource property.
     *
     * @return
     *     possible object is
     *     {@link String }
     *    
     */
    public String getResource() {
        return resource;
    }

    /**
     * Sets the value of the resource property.
     *
     * @param value
     *     allowed object is
     *     {@link String }
     *    
     */
    public void setResource(String value) {
        this.resource = value;
    }

    /**
     * Gets the value of the exception property.
     *
     * @return
     *     possible object is
     *     {@link String }
     *    
     */
    public String getException() {
        return exception;
    }

    /**
     * Sets the value of the exception property.
     *
     * @param value
     *     allowed object is
     *     {@link String }
     *    
     */
    public void setException(String value) {
        this.exception = value;
    }

}

4). The provider for the NotFoundException:
@Provider
public class NotFoundExceptionMapper implements ExceptionMapper<NotFoundException> {

    public Response toResponse(NotFoundException ex) {
        return Response.status(ex.getResponseStatusCode()).entity(ex.getFaultInfo()).type(MediaType.APPLICATION_XML).build();
    }
}

5). The exception is thrown in the service as follows:
FaultInfo fault = new FaultInfo();
fault.setErrorCode(ServiceErrorCode.NO_RECORDS_FOUND);
fault.setReason("Couldn't find any receipts in the search");
throw new NotFoundException(fault);

This works as expected but don't know it can be solution to your problem.

Thanks,
Mathew
Reply | Threaded
Open this post in threaded view
|

Re: ExceptionMapper not handling Exception subclasses

Gregg Carrier
Thanks Matthew -

Looking at number 4 in your example, it looks like you have an ExceptionMapper per specific Exception type - ie - there's a mapper for every subclass of ServiceException rather than one catch-all for ServiceException. I'm trying to avoid that and the docs lead me to believe it's possible, but I can't get it working.

Thanks for your detailed example!

Gregg

On Tue, Jun 29, 2010 at 9:13 AM, mathewch <[hidden email]> wrote:

Hi Gregg,

I too have an ExceptionMapping framework for my service implementation. But
never had to declare the resource method with the *Exception signature. To
avoid that use the type RuntimeException. Also make sure the providers are
getting registered. For your reference, I have my exceptions handled in the
following way:

1). Base exception class:
public class ServiceException extends RuntimeException {

   private static final long serialVersionUID = -339330063981442247L;
   final protected int       responseStatusCode;
   protected FaultInfo       faultInfo        = null;

   public ServiceException(String message, int responseStatusCode) {
       super(message);
       this.responseStatusCode = responseStatusCode;
   }

   public ServiceException(String message, int responseStatusCode,
FaultInfo faultInfo) {
       this(message, responseStatusCode);
       this.faultInfo = faultInfo;
   }

   public ServiceException(int responseStatusCode, FaultInfo faultInfo) {
       this(faultInfo.getReason(), responseStatusCode);
       this.faultInfo = faultInfo;
   }

   public int getResponseStatusCode() {
       return responseStatusCode;
   }

   public FaultInfo getFaultInfo() {
       return faultInfo;
   }
}

2). An exception type:
public class NotFoundException extends ServiceException {
   private static final long serialVersionUID     = -3357251481427760852L;
   public static final int   RESPONSE_STATUS_CODE =
HttpURLConnection.HTTP_NOT_FOUND;

   public NotFoundException(String message) {
       super(message, RESPONSE_STATUS_CODE);
   }

   public NotFoundException(String message, FaultInfo faultInfo) {
       super(message, RESPONSE_STATUS_CODE, faultInfo);
   }

   public NotFoundException(FaultInfo faultInfo) {
       super(RESPONSE_STATUS_CODE, faultInfo);
   }
}


3). A fault object to hold the full exception details
/**
 *
 *                              A JAXB type representing an exception for a service request.
 *
 *
 *
 *
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
   "errorCode",
   "reason",
   "resource",
   "exception"
})
@XmlRootElement(name = "FaultInfo")
public class FaultInfo
   implements Serializable
{

   private final static long serialVersionUID = 1L;
   @XmlElement(namespace = "..........")
   protected Integer errorCode;
   @XmlElement(namespace = "...............")
   protected String reason;
   @XmlElement(namespace = "...................")
   protected String resource;
   @XmlElement(namespace = "............")
   protected String exception;

   /**
    * Gets the value of the errorCode property.
    *
    * @return
    *     possible object is
    *     {@link Integer }
    *
    */
   public Integer getErrorCode() {
       return errorCode;
   }

   /**
    * Sets the value of the errorCode property.
    *
    * @param value
    *     allowed object is
    *     {@link Integer }
    *
    */
   public void setErrorCode(Integer value) {
       this.errorCode = value;
   }

   /**
    * Gets the value of the reason property.
    *
    * @return
    *     possible object is
    *     {@link String }
    *
    */
   public String getReason() {
       return reason;
   }

   /**
    * Sets the value of the reason property.
    *
    * @param value
    *     allowed object is
    *     {@link String }
    *
    */
   public void setReason(String value) {
       this.reason = value;
   }

   /**
    * Gets the value of the resource property.
    *
    * @return
    *     possible object is
    *     {@link String }
    *
    */
   public String getResource() {
       return resource;
   }

   /**
    * Sets the value of the resource property.
    *
    * @param value
    *     allowed object is
    *     {@link String }
    *
    */
   public void setResource(String value) {
       this.resource = value;
   }

   /**
    * Gets the value of the exception property.
    *
    * @return
    *     possible object is
    *     {@link String }
    *
    */
   public String getException() {
       return exception;
   }

   /**
    * Sets the value of the exception property.
    *
    * @param value
    *     allowed object is
    *     {@link String }
    *
    */
   public void setException(String value) {
       this.exception = value;
   }

}

4). The provider for the NotFoundException:
@Provider
public class NotFoundExceptionMapper implements
ExceptionMapper<NotFoundException> {

   public Response toResponse(NotFoundException ex) {
       return
Response.status(ex.getResponseStatusCode()).entity(ex.getFaultInfo()).type(MediaType.APPLICATION_XML).build();
   }
}

5). The exception is thrown in the service as follows:
FaultInfo fault = new FaultInfo();
fault.setErrorCode(ServiceErrorCode.NO_RECORDS_FOUND);
fault.setReason("Couldn't find any receipts in the search");
throw new NotFoundException(fault);

This works as expected but don't know it can be solution to your problem.

Thanks,
Mathew
--
View this message in context: http://jersey.576304.n2.nabble.com/ExceptionMapper-not-handling-Exception-subclasses-tp5235614p5235654.html
Sent from the Jersey mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: ExceptionMapper not handling Exception subclasses

mathewch
Hi Gregg,

If you don't want to have many types mappers and exception, you could have a generic service exception like:

@Provider
public class ServiceExceptionMapper implements ExceptionMapper<ServiceException> {

    public Response toResponse(ServiceException ex) {
        return Response.status(ex.getResponseStatusCode()).entity(ex.getFaultInfo()).build();
    }
}

I do have exceptions and mappers for type of exception I want to address. That was part of my application requirement as well. For all other types of exceptions I use a generic exception type:

FaultInfo fault = new FaultInfo();
fault.setErrorCode(ServiceErrorCode.INTERNAL_SERVER_ERROR);
fault.setReason(ex.getMessage());
fault.setResource(uriInfo.getPath());
fault.setException(StackTraceUtil.getStackTraceAsString(ex));
GenericServiceException ge = new GenericServiceException(fault);    
ge.initCause(ex.getCause());
throw ge;

Hope this helps.

Thanks,
Mathew
Reply | Threaded
Open this post in threaded view
|

Re: ExceptionMapper not handling Exception subclasses

Paul Sandoz
Administrator
In reply to this post by Gregg Carrier
Hi Greg,

What version of Jersey are you using?

What you want to do should be possible. There are unit tests in place testing this functionality.

When you say:

  "When I call my resource method, it hangs until the request times out."

that is odd behavior perhaps something else is going on? any clues in the server log?

Paul. 

On Jun 29, 2010, at 6:30 PM, Gregg Carrier wrote:

Thanks Matthew -

Looking at number 4 in your example, it looks like you have an ExceptionMapper per specific Exception type - ie - there's a mapper for every subclass of ServiceException rather than one catch-all for ServiceException. I'm trying to avoid that and the docs lead me to believe it's possible, but I can't get it working.

Thanks for your detailed example!

Gregg

On Tue, Jun 29, 2010 at 9:13 AM, mathewch <[hidden email]> wrote:

Hi Gregg,

I too have an ExceptionMapping framework for my service implementation. But
never had to declare the resource method with the *Exception signature. To
avoid that use the type RuntimeException. Also make sure the providers are
getting registered. For your reference, I have my exceptions handled in the
following way:

1). Base exception class:
public class ServiceException extends RuntimeException {

   private static final long serialVersionUID = -339330063981442247L;
   final protected int       responseStatusCode;
   protected FaultInfo       faultInfo        = null;

   public ServiceException(String message, int responseStatusCode) {
       super(message);
       this.responseStatusCode = responseStatusCode;
   }

   public ServiceException(String message, int responseStatusCode,
FaultInfo faultInfo) {
       this(message, responseStatusCode);
       this.faultInfo = faultInfo;
   }

   public ServiceException(int responseStatusCode, FaultInfo faultInfo) {
       this(faultInfo.getReason(), responseStatusCode);
       this.faultInfo = faultInfo;
   }

   public int getResponseStatusCode() {
       return responseStatusCode;
   }

   public FaultInfo getFaultInfo() {
       return faultInfo;
   }
}

2). An exception type:
public class NotFoundException extends ServiceException {
   private static final long serialVersionUID     = -3357251481427760852L;
   public static final int   RESPONSE_STATUS_CODE =
HttpURLConnection.HTTP_NOT_FOUND;

   public NotFoundException(String message) {
       super(message, RESPONSE_STATUS_CODE);
   }

   public NotFoundException(String message, FaultInfo faultInfo) {
       super(message, RESPONSE_STATUS_CODE, faultInfo);
   }

   public NotFoundException(FaultInfo faultInfo) {
       super(RESPONSE_STATUS_CODE, faultInfo);
   }
}


3). A fault object to hold the full exception details
/**
 *
 *                              A JAXB type representing an exception for a service request.
 *
 *
 *
 *
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
   "errorCode",
   "reason",
   "resource",
   "exception"
})
@XmlRootElement(name = "FaultInfo")
public class FaultInfo
   implements Serializable
{

   private final static long serialVersionUID = 1L;
   @XmlElement(namespace = "..........")
   protected Integer errorCode;
   @XmlElement(namespace = "...............")
   protected String reason;
   @XmlElement(namespace = "...................")
   protected String resource;
   @XmlElement(namespace = "............")
   protected String exception;

   /**
    * Gets the value of the errorCode property.
    *
    * @return
    *     possible object is
    *     {@link Integer }
    *
    */
   public Integer getErrorCode() {
       return errorCode;
   }

   /**
    * Sets the value of the errorCode property.
    *
    * @param value
    *     allowed object is
    *     {@link Integer }
    *
    */
   public void setErrorCode(Integer value) {
       this.errorCode = value;
   }

   /**
    * Gets the value of the reason property.
    *
    * @return
    *     possible object is
    *     {@link String }
    *
    */
   public String getReason() {
       return reason;
   }

   /**
    * Sets the value of the reason property.
    *
    * @param value
    *     allowed object is
    *     {@link String }
    *
    */
   public void setReason(String value) {
       this.reason = value;
   }

   /**
    * Gets the value of the resource property.
    *
    * @return
    *     possible object is
    *     {@link String }
    *
    */
   public String getResource() {
       return resource;
   }

   /**
    * Sets the value of the resource property.
    *
    * @param value
    *     allowed object is
    *     {@link String }
    *
    */
   public void setResource(String value) {
       this.resource = value;
   }

   /**
    * Gets the value of the exception property.
    *
    * @return
    *     possible object is
    *     {@link String }
    *
    */
   public String getException() {
       return exception;
   }

   /**
    * Sets the value of the exception property.
    *
    * @param value
    *     allowed object is
    *     {@link String }
    *
    */
   public void setException(String value) {
       this.exception = value;
   }

}

4). The provider for the NotFoundException:
@Provider
public class NotFoundExceptionMapper implements
ExceptionMapper<NotFoundException> {

   public Response toResponse(NotFoundException ex) {
       return
Response.status(ex.getResponseStatusCode()).entity(ex.getFaultInfo()).type(MediaType.APPLICATION_XML).build();
   }
}

5). The exception is thrown in the service as follows:
FaultInfo fault = new FaultInfo();
fault.setErrorCode(ServiceErrorCode.NO_RECORDS_FOUND);
fault.setReason("Couldn't find any receipts in the search");
throw new NotFoundException(fault);

This works as expected but don't know it can be solution to your problem.

Thanks,
Mathew
--
View this message in context: http://jersey.576304.n2.nabble.com/ExceptionMapper-not-handling-Exception-subclasses-tp5235614p5235654.html
Sent from the Jersey mailing list archive at Nabble.com.

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]