自定义jersey param抛出异常时的MultiException

时间:2015-04-29 19:07:46

标签: java jax-rs jersey-2.0 dropwizard

注意:https://gist.github.com/SrikanthRao/c9fc35e6fe22a74ab40c

提供了重现此问题的所有代码

http://localhost:8080/date/bean?date=2014-13-23(使用BeanParam)生成  " {"代码":500,"消息":"处理您的请求时出错。它已被记录(ID 48be9aa43bd49547)。"}"不添加MultiExceptionMapper到泽西。

如果我将MultiExceptionMapper添加到jersey,则上面的url会导致

"日期不是YYYY-MM-DD格式或无效"

http://localhost:8080/date?date=2014-13-23(直接@QueryParam参数)生成 "日期不是YYYY-MM-DD格式或无效"

几个问题:

  1. 这是以更干净的方式处理输入验证的正确方法吗?
  2. 我希望这可以工作而无需添加我自己的MultiExceptionMapper。 Jersey不支持在资源方法中作为@BeanParam注入的POJO中的自定义*参数吗?
  3. 这是请求时生成的堆栈跟踪(不将MultiExceptionMapper添加到jersey)。当然删除了很长的痕迹。如果您需要完整的堆栈跟踪,请告诉我。

        ERROR [2015-05-04 18:48:33,366] io.dropwizard.jersey.errors.LoggingExceptionMapper: Error handling a request: 0f23e4de758653d6
        ! javax.ws.rs.WebApplicationException: HTTP 400 Bad Request
        ! at io.dropwizard.jersey.params.AbstractParam.<init>(AbstractParam.java:28) ~[dropwizard-jersey-0.8.1.jar:0.8.1]
        ! at com.fun.myapp.LocalDateTimeParam.<init>(LocalDateTimeParam.java:20) ~[classes/:na]
        ! at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_45]
    ...
    ...
    Causing: org.glassfish.hk2.api.MultiException: A MultiException has 3 exceptions.  They are:
    ! 1. javax.ws.rs.WebApplicationException: HTTP 400 Bad Request
    ! 2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.fun.myapp.PaginationFilters errors were found
    ! 3. java.lang.IllegalStateException: Unable to perform operation: resolve on com.fun.myapp.PaginationFilters
    ! 
    ! at org.jvnet.hk2.internal.Collector.throwIfErrors(Collector.java:88) ~[hk2-locator-2.4.0-b10.jar:na]
    ! at org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:252) ~[hk2-locator-2.4.0-b10.jar:na]
    ! at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:360) ~[hk2-locator-2.4.0-b10.jar:na]
    ! at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:471) ~[hk2-locator-2.4.0-b10.jar:na]
    ....
    ....
    WARN  [2015-05-04 18:48:33,401] org.glassfish.jersey.internal.Errors: The following warnings have been detected: WARNING: Unknown HK2 failure detected:
    MultiException stack 1 of 3
    javax.ws.rs.WebApplicationException: HTTP 400 Bad Request
        at io.dropwizard.jersey.params.AbstractParam.<init>(AbstractParam.java:28)
        at com.fun.myapp.LocalDateTimeParam.<init>(LocalDateTimeParam.java:20)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    ...
    ...
    MultiException stack 2 of 3
    java.lang.IllegalArgumentException: While attempting to resolve the dependencies of com.fun.myapp.PaginationFilters errors were found
        at org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:249)
        at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:360)
        at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:471)
    ...
    ...
    MultiException stack 3 of 3
    java.lang.IllegalStateException: Unable to perform operation: resolve on com.fun.myapp.PaginationFilters
        at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:389)
        at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:471)
        at org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:162)
    

    我在dropwizard用户google群组中提出了这个问题 - https://groups.google.com/forum/#!topic/dropwizard-user/yW-RXSSlspY

2 个答案:

答案 0 :(得分:4)

问题1

根据dropwizard的核心文档,我看到了两种可能的输入验证实现:

  • 通过验证注释
  

您可以将验证注释添加到表示类的字段并验证它们......

这似乎不适合您的情况。实际上,LocalDateTime没有可用的注释,并且创建一个注释导致解析LocalDateTime两次:用于验证和设置bean字段。

  • 通过错误处理:
  

如果你想要更多的控制,你也可以在你的环境中声明JerseyProviders,通过调用JerseyEnvironment#register(Object)来实现javax.ws.rs.ext.ExceptionMapper ...

要回答你的第一个问题,我会说在你的情况下使用异常映射器完全没问题。

问题2 调试两个isValidDate方法显示@BeanParam版本使用ClazzCreator.java而@QueryParam不使用。该类负责创建bean类实例。如果您检查the class的第226行,您将看到它在解析具有多个错误的输入时收集多个异常。这应该允许报告与不同bean字段相关的几个错误,包括一些后续异常。

答案是Jeysey在POJO中支持* Params。但是,在@BeanParam的上下文中封装成MultiException的相关异常。 因此,如果您计划将其他字段添加到PaginationFilters,则应考虑在映射的异常消息中报告多个错误。

答案 1 :(得分:0)

1 /为了验证日期,我更喜欢自己解析“日期”。它简单而干净。这是一些有效的代码:

package com.rizze.stackoverflow;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;



@Path("/test")
public class TestRessource {


    @GET    
    @Path("is")
    @Produces({"application/json"})
    public Response isDateValid(@QueryParam("date") String dateString){

        if(dateString == null) 
            return Response.status(400).entity("date is null").build();
        Date thedate =null;
        try {
            thedate = new SimpleDateFormat("yyyy-mm-dd").parse(dateString);
        } 
        catch (ParseException e) {
            return Response.status(400).entity("date malformed").build();
        }
        System.out.println("time:"+thedate.getTime());
        return Response.ok()
                .entity("{\"time\":"+ thedate.getTime() +"}")
                .header("source", "com.rizze")
                .build();
    }
}

在此代码中,您将调用

http://localhost:8080/test/is?date=2014-12-12

将返回:

{"time":1389496320000}

看一下要点:https://gist.github.com/jeorfevre/6e46ae8d9232f7f9d7cc

2 /为了捕获异常,一个好的做法是通过Providers捕获服务器级异常(通过向应用程序注册提供程序)。 对于应用程序级异常,请使用response.status(异常状态)自行利用异常.....

请看一下我的fork gist,我添加了一个_ServerError.class,我在应用程序中注册了它:

  //register a mapper by rizze
        environment.jersey().register(_ServerError.class);

请查看cristal明确的官方文件: official jersey representation doc