JAX-RS(Jersey)自定义异常,支持XML或JSON。

46

我有一个使用Jersey构建的REST服务。

我希望能够根据发送到服务器的MIME类型设置我的自定义异常编写器的MIME类型。当收到json时返回application/json,当收到xml时返回application/xml

现在,我硬编码了application/json,但这使得XML客户端无法识别。

public class MyCustomException extends WebApplicationException {
     public MyCustomException(Status status, String message, String reason, int errorCode) {
         super(Response.status(status).
           entity(new ErrorResponseConverter(message, reason, errorCode)).
           type("application/json").build());
     }
}

我可以利用什么上下文获取当前请求的Content-Type

谢谢!


基于答案的更新

对于其他有兴趣获取完整解决方案的人:

public class MyCustomException extends RuntimeException {

    private String reason;
    private Status status;
    private int errorCode;

    public MyCustomException(String message, String reason, Status status, int errorCode) {
        super(message);
        this.reason = reason;
        this.status = status;
        this.errorCode = errorCode;
    }

    //Getters and setters
}

与一个ExceptionMapper一起使用

@Provider
public class MyCustomExceptionMapper implements ExceptionMapper<MyCustomException> {

    @Context
    private HttpHeaders headers;

    public Response toResponse(MyCustomException e) {
        return Response.status(e.getStatus()).
                entity(new ErrorResponseConverter(e.getMessage(), e.getReason(), e.getErrorCode())).
                type(headers.getMediaType()).
                build();
    }
}

ErrorResponseConverter是一个自定义的JAXB POJO。


ErrorResponseConverter类会是什么样子? - heyomi
@Oskar:请展示你的ErrorResponseConverter实现。谢谢! - Christian Junk
1
@dreboy 这只是一些POJO,将返回给用户包含错误信息。您可以为Jackson/JAXB/任何其他支持各种内容类型进行注释。 - ach
@ach 我想通了。虽然谢谢你的回复! - heyomi
2个回答

26
您可以尝试将 @javax.ws.rs.core.Context javax.ws.rs.core.HttpHeaders 字段/属性添加到您的根资源类、资源方法参数或自定义的 javax.ws.rs.ext.ExceptionMapper 中,并调用 HttpHeaders.getMediaType()。

ExceptionMapper是正确的选择。谢谢!我做了一个: public class MyCustomException extends RuntimeException连同一个: public class MyCustomExceptionMapper implements ExceptionMapper<MyCustomException>实现:public Response toResponse(PlacesException e) { return Response.status(e.getStatus()). entity(new ErrorResponseConverter(e.getMessage(), e.getReason(), e.getErrorCode())). type(headers.getMediaType()). build(); } - Oskar

16

headers.getMediaType() 方法返回实体的媒体类型,而不是 Accept 头。将异常转换为适当的方式是使用 Accept 头,以便客户端能够按照请求的格式获取响应。如果您的请求如上所示(请注意 JSON Accept 头,但 XML 实体),您将收到 XML 响应。

POST http://localhost:8080/service/giftcard/invoice?draft=true HTTP/1.1
Accept: application/json
Authorization: Basic dXNlcjp1c2Vy
Content-Type: application/xml
User-Agent: Jakarta Commons-HttpClient/3.1
Host: localhost:8080
Proxy-Connection: Keep-Alive
Content-Length: 502
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><sample><node1></node1></sample>

正确的实现方式是再次使用 Accept 头:

public Response toResponse(final CustomException e) {
    LOGGER.debug("Mapping CustomException with status + \"" + e.getStatus() + "\" and message: \"" + e.getMessage()
            + "\"");
    ResponseBuilder rb = Response.status(e.getStatus()).entity(
            new ErrorResponseConverter(e.getMessage(), e.getReason(), e.getErrorCode()));

    List<MediaType> accepts = headers.getAcceptableMediaTypes();
    if (accepts!=null && accepts.size() > 0) {
        //just pick the first one
        MediaType m = accepts.get(0);
        LOGGER.debug("Setting response type to " + m);
        rb = rb.type(m);
    }
    else {
        //if not specified, use the entity type
        rb = rb.type(headers.getMediaType()); // set the response type to the entity type.
    }
    return rb.build();
}

1
我同意你应该使用Accept:头而不是HttpHeaders.getMediaType()。我认为有歧义的是简单地选择第一个。对我来说,更有意义的是尝试使用与Jersey为请求匹配的资源的@Produces注释相对应的媒体类型。但是,我一时半会儿想不出如何将其连接起来。 - NBW
@domienic-d 实际上,关于这个问题似乎有一个开放的 JIRA https://java.net/jira/browse/JAX_RS_SPEC-323 - 因此,在这种情况下,我会说你现在的解决方案是最好的。 - NBW
JAX_RS_SPEC-323在java.net上已经不可用;此问题已迁移到:https://github.com/eclipse-ee4j/jaxrs-api/issues/328 - shelley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接