在Java中,如何从Resteasy验证中返回有意义的JSON格式错误?

时间:2014-12-08 17:22:05

标签: java json web-services rest resteasy

我在请求/响应正文中有一个RESTFul API消耗/返回JSON。当客户端发送无效数据(有效的JSON但字段的值无效)时,我希望能够返回JSON结构(以及相关的400多个代码)。

然后,此结构允许前端在每个字段的基础上解析错误,并在输入字段旁边呈现错误。

E.g。理想输出:

{
  "errors":{
    "name":["invalid chars","too long","etc"]
    "otherfield":["etc"]
  }
}

我正在使用Resteasy作为API,并且使用违规异常很容易让它呈现JSON错误:

@Provider
@Component
public class ValidationExceptionHandler implements ExceptionMapper<ResteasyViolationException> {
    public Response toResponse(ResteasyViolationException exception) {
        Multimap<String,String> errors = ArrayListMultimap.create();

        Consumer<ResteasyConstraintViolation> consumer = (violation) -> {
            errors.put(violation.getPath(), violation.getMessage());
        };

        exception.getParameterViolations().forEach(consumer);

        Map<String, Map<String, Collection<String>>> top = new HashMap<>();

        top.put("errors", errors.asMap());

        return Response.status(Status.BAD_REQUEST).entity(top)
                .build();
    }
}

但是,错误路径(violation.getPath())是以属性为中心的,而不是以XmlElement-name为中心的。

E.g。以上输出:

{
  "errors":{"createCampaign.arg1.name":["invalid chars","etc"]}
}

我已经尝试从最后一个点删除索引以获取“名称”,但是该黑客还有其他问题。

E.g。如果我的“名称”属性不是“名称”,则它不起作用:

@XmlElement(name="name")
@NotNull
private String somethingelse;

“somethingelse”将返回给客户,但他们的客户不知道那是什么:

{
  "errors":{"somethingelse":["cannot be null"]}
}

客户端需要“名称”,因为这是他们发送字段时调用的字段。

我的资源:

package com.foo.api;

import org.springframework.stereotype.Service;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.foo.dto.CarDTO;

@Service
@Path("/car")
public class CarResource {

    @POST
    @Produces({MediaType.APPLICATION_JSON})
    @Consumes(MediaType.APPLICATION_JSON)
    public CarDTO create(
            @Valid CarDTO car
    ) {
        //do some persistence
        return car;
    }
}

示例dto:

package com.foo.dto;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Min;
import javax.validation.constraints.Max;
import javax.xml.bind.annotation.XmlElement;

public class CarDTO {
    @Min(1)
    @Max(10)
    @NotNull
    @XmlElement(name="gears")
    private int cogs;
}

2 个答案:

答案 0 :(得分:0)

可以使用自定义错误消息,因此您不需要查看路径

@NotNull(message="name cannot be null")

答案 1 :(得分:-1)

This article很好地描述了你需要做的事情。

基本上你应该实现ExceptionMapper

@Provider
public class ValidationExceptionMapper implements ExceptionMapper<ValidationException> {

    @Override
    public Response toResponse(ValidationException exception) {
        Response myResponse;
        // build your Response based on the data provided by the exception
        return myResponse;
    }

}