簡體   English   中英

如何在JAX-RS Web服務中返回XML中的響應?

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

我正在使用JAX-RSJava 6以及Jersey 1.8開發REST服務,我的服務器是JBoss 5.1.0 GA ,我開始使用一個接收參數並返回空值的簡單端點。

本文之后 ,我將ExceptionMapper的預期異常映射到三個類:項目范圍內異常的AppException ,未找到記錄異常的NotFoundException和預期錯誤之外的任何其他異常的GenericException

我可以返回異常,因為application / json響應很好,但是當我嘗試將響應作為application / xml返回時,我從我的服務器獲得一個帶有HTTP 500狀態代碼的HTML頁面。

例如,如果我沒有將所需參數發送到我的端點,我會正確獲取其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"
}

但是如果我嘗試返回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>

我的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 + "'}";
    }
}

為什么我在指定時無法返回XML響應?

這是我正在使用的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());
        }
    }

}

在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;

此JAXB批注將告訴服務器將屬性而不是getter綁定到XML。 否則將生成錯誤,因為這會導致XML響應具有XML綁定的重復屬性(如重復的代碼元素)。

為什么?

默認情況下,如果某個類上沒有@XmlAccessorType,並且沒有使用@XmlAccessorType注釋其超類,則假定該類具有以下默認值:

@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)

接下來,如果我們查看有關XmlAccessType的文檔以了解PUBLIC_MEMBER,請注意以下內容:

除非由XmlTransient注釋,否則每個公共getter / setter對和每個公共字段都將自動綁定到XML。

因此,ErrorMessage的代碼變得沖突,因為XmlElement也用於將JavaBean屬性映射到XML。 因此,例如,屬性代碼不僅受XmlElement的約束,而且受其getter方法的約束。

為了克服這個問題,我們有兩個選擇:

選項1 :我們可以使用XmlAccessType.FIELD,以便只使用字段並省略getter。

選項2 :只需從類中刪除XmlElement注釋,在這種情況下,getter將僅決定綁定。

另外,不要忘記更新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