简体   繁体   English

如何在JAX-RS Web服务中返回XML中的响应?

[英]How to return Response in XML in JAX-RS web service?

I'm developing a REST service using JAX-RS with Java 6 and Jersey 1.8 and my server is JBoss 5.1.0 GA , I've started with a simple endpoint that receives a parameter and return a null value. 我正在使用JAX-RSJava 6以及Jersey 1.8开发REST服务,我的服务器是JBoss 5.1.0 GA ,我开始使用一个接收参数并返回空值的简单端点。

Following this article , I mapped my expected exceptions with ExceptionMapper to three classes: AppException for exceptions within the scope of the project, NotFoundException for exceptions of records not found and GenericException for any other exception outside the expected errors. 本文之后 ,我将ExceptionMapper的预期异常映射到三个类:项目范围内异常的AppException ,未找到记录异常的NotFoundException和预期错误之外的任何其他异常的GenericException

I can return the exceptions as application/json responses just fine, but when I try to return a response as an application/xml , I get an HTML page from my server with HTTP 500 status code. 我可以返回异常,因为application / json响应很好,但是当我尝试将响应作为application / xml返回时,我从我的服务器获得一个带有HTTP 500状态代码的HTML页面。

For example, if I don't send the required parameter to my endpoint, I get a HTTP 400 status code with its JSON response correctly: 例如,如果我没有将所需参数发送到我的端点,我会正确获取其JSON响应的HTTP 400状态代码:

{
    "status": 400,
    "message": "org.xml.sax.SAXParseException: Premature end of file.",
    "developerMessage": "javax.ws.rs.WebApplicationException: org.xml.sax.SAXParseException: Premature end of file.... 40 more\r\n"
}

But if I try to return a XML response I get this HTML page: 但是如果我尝试返回XML响应,我会得到这个HTML页面:

<html>
    <head>
        <title>JBoss Web/2.1.3.GA - Informe de Error</title>
    </head>
    <body>
        <h1>Estado HTTP 500 - </h1>
        <HR size="1" noshade="noshade">
            <p>
                <b>type</b> Informe de estado
            </p>
            <p>
                <b>mensaje</b>
                <u></u>
            </p>
            <p>
                <b>descripción</b>
                <u>El servidor encontró un error interno () que hizo que no pudiera rellenar este requerimiento.</u>
            </p>
            <HR size="1" noshade="noshade">
                <h3>JBoss Web/2.1.3.GA</h3>
     </body>
  </html>

My ErrorMessage class looks as described in the article I linked: 我的ErrorMessage类看起来像我链接的文章中描述的:

import java.lang.reflect.InvocationTargetException;

import javax.ws.rs.core.Response;

import org.apache.commons.beanutils.*;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import com.sun.jersey.api.NotFoundException;

@XmlRootElement(name = "errorMessage")
public class ErrorMessage {

    @XmlElement(name = "status")
    int status;

    @XmlElement(name = "message")
    String message;

    @XmlElement(name = "developerMessage")
    String developerMessage;

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getDeveloperMessage() {
        return developerMessage;
    }

    public void setDeveloperMessage(String developerMessage) {
        this.developerMessage = developerMessage;
    }

    public ErrorMessage(AppException ex) {
        try {
            BeanUtils.copyProperties(this, ex);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public ErrorMessage(NotFoundException ex) {
        this.status = Response.Status.NOT_FOUND.getStatusCode();
        this.message = ex.getMessage();
    }

    public ErrorMessage() {
    }

    @Override
    public String toString(){
        return "ErrorMessage{" + "status=" + status + ", message='" + message + '\'' + ", developerMessage='" + developerMessage + "'}";
    }
}

Why am I unable to return a XML response when specified? 为什么我在指定时无法返回XML响应?

This is the GenericExceptionMapper class I'm using 这是我正在使用的GenericExceptionMapper类

@Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {

    @Override
    public Response toResponse(Throwable exception) {

        ErrorMessage errorMessage = new ErrorMessage();     
        setHttpStatus(exception, errorMessage);
        errorMessage.setMessage(exception.getMessage());
        StringWriter errorStackTrace = new StringWriter();
        exception.printStackTrace(new PrintWriter(errorStackTrace));
        errorMessage.setDeveloperMessage(errorStackTrace.toString());
        // The only change is the MediaType.APPLICATION_XML, originally it was MediaType.APPLICATION_JSON
        return Response.status(errorMessage.getStatus()).entity(errorMessage).type(MediaType.APPLICATION_XML).build();
    }
    private void setHttpStatus(Throwable ex, ErrorMessage errorMessage) {
        if(ex instanceof WebApplicationException ) { 
            errorMessage.setStatus(((WebApplicationException)ex).getResponse().getStatus());
        } else {
            errorMessage.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
        }
    }

}

Providing the @XmlAccessorType(XmlAccessType.FIELD) above your ErrorMessage class should solve the problem : 在ErrorMessage类之上提供@XmlAccessorType(XmlAccessType.FIELD)应该可以解决问题:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ErrorMessage {

    /** contains the same HTTP Status code returned by the server */
    @XmlElement(name = "status")
    int status;

This JAXB annotation will tell the server to bind attributes instead of getters to your XML. 此JAXB批注将告诉服务器将属性而不是getter绑定到XML。 Otherwise an error will be generated as this causes your XML response to have duplicate properties for XML binding(like duplicate code elements). 否则将生成错误,因为这会导致XML响应具有XML绑定的重复属性(如重复的代码元素)。

WHY? 为什么?

By default, if @XmlAccessorType on a class is absent, and none of its super classes is annotated with @XmlAccessorType, then the following default on the class is assumed: 默认情况下,如果某个类上没有@XmlAccessorType,并且没有使用@XmlAccessorType注释其超类,则假定该类具有以下默认值:

@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER) @XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)

Next if we look into the documentation on XmlAccessType to understand PUBLIC_MEMBER here is what it has to say: 接下来,如果我们查看有关XmlAccessType的文档以了解PUBLIC_MEMBER,请注意以下内容:

Every public getter/setter pair and every public field will be automatically bound to XML, unless annotated by XmlTransient. 除非由XmlTransient注释,否则每个公共getter / setter对和每个公共字段都将自动绑定到XML。

So the code of ErrorMessage became conflicting as XmlElement was also used to map JavaBean property to XML. 因此,ErrorMessage的代码变得冲突,因为XmlElement也用于将JavaBean属性映射到XML。 Therefore for example the property code was not only bound by XmlElement but also by it's getter method. 因此,例如,属性代码不仅受XmlElement的约束,而且受其getter方法的约束。

To overcome this problem we have two options: 为了克服这个问题,我们有两个选择:

Option 1 :We can use XmlAccessType.FIELD so that only the fields are used and getters are omitted. 选项1 :我们可以使用XmlAccessType.FIELD,以便只使用字段并省略getter。

Option 2 :Simply remove the XmlElement annotations from the class in which case the getters will only decide the binding. 选项2 :只需从类中删除XmlElement注释,在这种情况下,getter将仅决定绑定。

Also, don't forget to update the toResponse message of your mapper class to reflect the output is XML: 另外,不要忘记更新mapper类的toResponse消息以反映输出是XML:

@Override
    public Response toResponse(AppException ex) {
        return Response.status(ex.getStatus())
                .entity(new ErrorMessage(ex))
                .type(MediaType.APPLICATION_XML).
                build();
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM