使用Jackson

时间:2016-02-02 08:47:08

标签: java hibernate validation jersey jackson

我正在使用Jersey实现REST API。我想验证我的服务的所有输入(查询参数,路径参数,DTO),并且我正在研究一些选项 - 看起来它的工作是Jersey Bean Validation。我还希望强烈输入服务中的所有内容 - 例如,而不是使用String来表示所有数据位,您可以使用这样的函数:

public Order getOrder(String customerId);

而是为每个数据位定义类型(这样做的好处是让编译器捕获传递给函数的不正确数据,能够混淆toString方法中的基础值进行日志记录,知道如果你有一个实例,那么value绝对有效),所以你最终会得到这样的函数:

public Order getOrder(CustomerId customerId);

这样的类型:

public class CustomerId {

    private final String value;

    public CustomerId(String value) {
        this.value = validate(value);
    }

    public String getValue() {
        return value;
    }

    private String validate(String value) {
        // Do some validation here
    }
}

Jersey Bean Validation示例不使用上面的强类型。例如:

@Path("/")
class MyResourceClass {

    @POST
    @Consumes("application/x-www-form-urlencoded")
    public void registerUser(
        @Pattern(regexp="[a-zA-Z -]{1,50}") @FormParam("name") String name) {
        ...
    }
}

验证的内置很好,因为你可以免费获得一些功能:

  • 任何验证错误时返回400错误请求异常
  • 可选择在响应中包含验证错误
  • 如果验证失败,您的函数中的所有代码都不会被执行

然而,有一些问题:

  • 您必须记住在数据的每个地方都包含注释 可以输入到您的系统,因此难以始终如一地应用
  • 您最终可能会对类型
  • 的有效定义有不同的定义
  • 您没有获得上述强类型权益

有谁知道如何获得所有这些好处。我尝试定义这样的类型:

public class CustomerId {

    private final String value;

    public CustomerId(String value) {
        this.value = validate(value);
    }

    public String getValue() {
        return value;
    }

    private String validate(String value) {
        if (!Pattern.matches("[a-zA-Z -]{1,50}", value)) {
            throw new ConstraintViolationException(new HashSet<ConstraintViolation<?>>());
        }
        return value;
    }
}

但似乎泽西没有以同样的方式处理异常,如果验证失败,你获得的响应代码是404而不是400。

有谁知道如何充分利用两个世界?

1 个答案:

答案 0 :(得分:1)

这是关于构造@XxxParam s

时如何处理错误的规范
  

...如果[...]注释了@MatrixParam@QueryParam@PathParam,则实现必须生成NotFoundException(404状态)的实例,包装抛出的异常而没有实体;如果字段或属性使用@HeaderParam@CookieParam注释,那么实现必须生成一个实例   BadRequestException(400状态)包装抛出的异常而没有实体。

虽然此处未列出,但@FormParam属于400括号。

  

“有没有人知道如何充分利用两个世界?”

我们可以通过抛出WebApplicationException来覆盖此行为。然后,我们可以为异常创建ExceptionMapper,然后委派给通常处理ExceptionMapper的{​​{1}}。我找不到关于此行为的任何清除详细信息。我的意思是你会期望ConstraintViolationException应该被调用,但如果它不是ExceptionMapper的实例则不会。因此,您可以将异常扩展为WebApplicationException

WebApplicationException

然后为它创建一个public static class MyException extends WebApplicationException { private final ConstraintViolationException cve; public MyException(ConstraintViolationException cve) { this.cve = cve; } public ConstraintViolationException getConstraintViolationException() { return cve; } } 。在映射器中,我们只需委托original mapper that handles ConstraintViolationException

ExceptionMapper

然后你可以抛出public static class MyExceptionMapper implements ExceptionMapper<MyException> { @Context private Providers providers; @Override public Response toResponse(MyException exception) { ExceptionMapper<ValidationException> mapper = providers.getExceptionMapper(ValidationException.class); return mapper.toResponse(exception.getConstraintViolationException()); } } 。如果您不关心错误响应正文,并且您想要的只是400状态,则可以忘记上面的所有内容并简单地抛出MyException。或者,如果您不关心BadRequestException映射器发出的响应实体,您可以在ConstraintViolationException中创建自己的响应,或在MyExceptionMapper内创建Response } class并将CustomerId构造函数传递给它。所以你有一些选择。

我可以看到这种方法令人头疼的是你需要创建自己的BadRequestException。那可以很快变老。

我能看到的另一种方法是使用ConstraintViolation@BeanParam

@Valid

这种方法的问题在于您的bean现在卡在public static class CustomerId { @FormParam("cust") @Pattern(regexp="[a-zA-Z -]{1,50}") private String value; public void setValue(String value) { this.value = value; } public String getValue() { return value; } } @POST @Path("form") @Consumes("application/x-www-form-urlencoded") public String postForm(@BeanParam @Valid CustomerId custId) { ,并且无法与其他@FormParam重复使用。

所以你需要做出一些权衡。希望这能为您提供一些好的信息。

更新

哦,我能想到的最后一个选项,与上面的第二个选项类似,但你没有被绑定到bean中的@XxxParam

@XxxParam

认为最后一个选项可能是要走的路,但你仍然需要记住总是使用public static class CustomerId { //@FormParam("cust") @javax.validation.constraints.Pattern(regexp="[a-zA-Z -]{1,50}") private String value; public CustomerId(String value) { //this.value = validate(value); this.value = value; } ... } @POST @Path("form") @Consumes("application/x-www-form-urlencoded") public String postForm(@FormParam("cust") @Valid CustomerId custId) { 进行注释,这听起来像是你试图避免的。