[英]How to return Response in XML in JAX-RS web service?
我正在使用JAX-RS和Java 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響應?
@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.