Jersey ExceptionMapper 不映射异常

Posted

技术标签:

【中文标题】Jersey ExceptionMapper 不映射异常【英文标题】:Jersey ExceptionMapper doesn't map exceptions 【发布时间】:2015-03-14 23:57:23 【问题描述】:

我的 Spring Boot + Jersey REST 服务没有按预期工作。

在 UserController 中引发了 EmailExistsException,但我只收到错误 500。一直。而且我的异常没有被记录。

我怀疑异常处理存在一些配置问题,但不知道在哪里进行设置。有什么建议吗?

@POST
@Path("register")
@Produces(MediaType.APPLICATION_JSON)
public Response register(NewUserPayload newUserPayload) throws EmailExistsException, MessagingException

EmailExistsExceptionMapper

@Provider
public class EmailExistsExceptionMapper extends AbstractExceptionMapper       implements
    ExceptionMapper<EmailExistsException>

@Override
public Response toResponse(EmailExistsException e)

    ResponseEntity re = new ResponseEntity(org.springframework.http.HttpStatus.BAD_REQUEST);

    return this.errorResponse(HttpStatus.BAD_REQUEST_400, re, e);


AbstractExceptionMapper

@Slf4j
public abstract class AbstractExceptionMapper

protected Response errorResponse(int status, ResponseEntity responseEntity, Throwable t)

    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    t.printStackTrace(pw);
    log.error(sw.toString()); // logging stack trace.

    return customizeResponse(status, responseEntity);


private Response customizeResponse(int status, ResponseEntity responseEntity)

    return Response.status(status).entity(responseEntity).build();


build.gradle

compile("org.springframework.boot:spring-boot-starter-web") 
    exclude module: 'spring-boot-starter-tomcat'

compile "org.springframework.boot:spring-boot-starter-jetty"
compile "org.springframework.boot:spring-boot-starter-security"
compile "org.springframework.boot:spring-boot-starter-aop"
compile "org.springframework.boot:spring-boot-starter-data-jpa"
compile "org.springframework.boot:spring-boot-starter-thymeleaf"
compile "org.springframework.boot:spring-boot-starter-jersey"
compile 'org.springframework.boot:spring-boot-starter-mail'

【问题讨论】:

【参考方案1】:

解决了我的问题的答案:

我已经放了 packages("package.name");这是我的根包名,异常映射器就像一个魅力。

@Component
@ApplicationPath("/api")
public class JerseyConfig extends ResourceConfig

public JerseyConfig()

    packages("package.name");
    register(UserController.class);
    register(TimezoneController.class);


【讨论】:

jersey documentation 中没有关于此配置的信息。 package 声明会避免你声明控制器吗? 我在网上的一些代码 sn-p 中找到了它。我现在在 Scala,所以无法告诉你更多关于它的信息。 谢谢!事实证明,您必须明确地 register(YourExceptionMapper.class) 或通过 packages("YourExceptionMapperPackage") 将其放入扫描包中。在找到您的答案之前,我花了几个小时试图弄清楚这一点。【参考方案2】:

您是否已将自定义 ExceptionMapper 配置为 jax-rs 提供程序,并且您确定您的异常被包装到 EmailExistsException 中吗?你可能需要看看这篇文章。

JAX-RS using exception mappers

【讨论】:

它有一个 @Provider 注释,是的,我确信它会被包装和抛出。另一件事是,当我尝试在 EmailExistsExceptionMapper 中放置断点时,它在调试模式下的 IDEA 中并不存在。似乎不知何故它没有被使用?可能缺少一些配置,但在哪里?【参考方案3】:

我遇到了同样的问题

刚才在&lt;init-param&gt;&lt;param-value&gt;标签中提到了web.xml文件中的根包

然后它开始像魅力一样工作

<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>

【讨论】:

【参考方案4】:

如果您使用 ExceptionMapper,则必须注册您的异常映射器:

@Component
@Provider
public class ApiApplicationExceptionMapper implements ExceptionMapper<Exception> 

    @Override
    public Response toResponse(Exception exception) 
       ...
    

在 Jersey 配置类中,扫描带有 @Path 注释的 Jersey Endpoint 类和带有 @Provider 注释的自定义异常映射器进行注册:

@Configuration
public class JerseyConfig extends ResourceConfig 

    @Autowired
    ApplicationContext applicationContext;

    @PostConstruct
    public void init() 
        this.registerEndpoints();
        this.registerExceptionMappers();
    

    private void registerEndpoints() 
        Map<String, Object> beans = applicationContext.getBeansWithAnnotation(Path.class);
        for (Object apiClass : beans.values()) 
            logger.info("Jersey register: " + apiClass.getClass().getName());
            register(apiClass);
        
    

    private void registerExceptionMappers() 
        Map<String, Object> beans = applicationContext.getBeansWithAnnotation(Provider.class);
        for (Object exceptionMapper : beans.values()) 
            logger.info("Jersey exception mapper register: " + exceptionMapper.getClass().getName());
            register(exceptionMapper);
        
    

【讨论】:

以上是关于Jersey ExceptionMapper 不映射异常的主要内容,如果未能解决你的问题,请参考以下文章

使用 Jersey 的 ExceptionMapper 映射 Shiro 的 AuthenticationException

Jersey ExceptionMapper未被调用

Jersey ExceptionMapper 不映射异常

JAX-RS自定义ExceptionMapper不拦截RuntimeException

Jersey Exception Mapper不处理Resource Constructor中的异常

在ExceptionMapper中注入单例