Jersey ExceptionMapper not being invoked

2020-04-07 04:25发布

问题:

I am trying to invoke this exception mapper to return a 404 not found response but it keeps returning 500 internal error. Jersey version is 2.22.1. Code snippet below. Appreciate all help.

Thanks.

Exception mapper class.

package org.learn.rest.messengerdemo.exception;

import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

@Provider
public class DataNotFoundExceptionMapper implements  ExceptionMapper<DataNotFoundException>{

    @Override
    public Response toResponse(DataNotFoundException ex) {
        return Response.status(Response.Status.FORBIDDEN).build();
    }
}

Exception Class.

package org.learn.rest.messengerdemo.exception;

public class DataNotFoundException extends RuntimeException{

    private static final long serialVersionUID = 2176642539344388961L;

    public DataNotFoundException(String message)
    {
        super(message);
    }
}

Service class's method that throws.

public Message getMessage(long messageId) {
    Message message =  messages.get(messageId);
    if(message == null)
    {
        throw new DataNotFoundException("Message with id " + messageId + " not found");
    }
    return message;
}

And the resource class.

@GET
@Path("/{messageId}")
public Message getMessage(@PathParam("messageId") long messageId) {
    return messageService.getMessage(messageId);
}

回答1:

Looking at the web.xml from your previous question, you have this

<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>org.learn.rest.messengerdemo.resources</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

What this init-parm jersey.config.server.provider.packages says is that Jersey should scan the named package for @Path annotated resource class and @Provider annotated provider classes and register them.

You only have the resources package org.learn.rest.messengerdemo.resources listed, but you ExceptionMapper is in a different package. The default behavior is to scan recursively, meaning sub-packages also. So if you listed org.learn.rest.messengerdemo instead, you would hit both the resources package and the exceptions package. Or you could list both packages, separated by comma or semi-colon. Either way would work

<param-value>org.learn.rest.messengerdemo</param-value>
<!-- OR -->
<param-value>
    org.learn.rest.messengerdemo.resources,
    org.learn.rest.messengerdemo.exception
</param-value>


回答2:

Please note that this is not problem of annotation. i have seen people given comments that due to @Provider annotation its not registered, if you have imported correct provider it will work. Please find my solution below

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



回答3:

I'd like to propose another option ... change the mapper package to match the resource package where the exception could normally be caught.

Assuming the resource classes package is:

package org.learn.rest.messengerdemo.resources;

change the mapper class package from:

package org.learn.rest.messengerdemo.exception;

to:

package org.learn.rest.messengerdemo.resources;

That way you won't be fiddling with framework generated files or uncommon syntax.

I still don't grasp why a try/catch isn't used but I'm rebuilding my Java knowledge so I won't inject an opinion or request any. If its current practice then I'll learn that soon enough. And mappers are an interesting opportunity at that.