Wie erfolgt die Rücksendung von Response in XML JAX-RS web service?
Ich bin die Entwicklung eines REST-service mit JAX-RS mit Java 6 und Jersey 1.8 und mein server ist JBoss 5.1.0 GA, ich habe angefangen mit einem einfachen Endpunkt, der erhält einen parameter und einen null-Wert zurück.
Folgenden dieser Artikel, erstellte ich mir meine erwarteten Ausnahmen mit ExceptionMapper zu drei Klassen: AppException für Ausnahmen im Rahmen des Projekts, NotFoundException für die Ausnahmen von den Aufzeichnungen nicht gefunden und GenericException für alle anderen Ausnahmen außerhalb der erwartete Fehler.
Ich zurückkehren kann, die Ausnahmen application/json Antworten ganz gut, aber wenn ich versuche, eine Antwort zurück wie ein application/xml, erhalte ich eine HTML-Seite von meinem server mit HTTP 500 status-code.
Zum Beispiel, wenn ich nicht senden Sie die erforderlichen parameter an meinem Endpunkt, bekomme ich eine HTTP 400 status-code mit seiner JSON-Antwort, richtig:
{
"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"
}
Aber wenn ich versuchen, wieder eine XML-Antwort, die ich bekommen diese HTML-Seite:
<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>
Meine ErrorMessage Klasse aussieht wie in dem Artikel beschrieben, die ich verlinkt:
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 + "'}";
}
}
Warum bin ich nicht in der Lage, um wieder eine XML-Antwort, wenn angegeben?
Dies ist die GenericExceptionMapper Klasse ich bin mit
@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());
}
}
}
- Einen HTTP 500 status bedeutet in der Regel eine Ausnahme auf dem server aufgetreten. Schau mal in deinen server-log für, die Ausnahme, und umfassen den gesamten stack trace (einschließlich aller "Verursacht Durch" - Abschnitte), die in Ihrer Frage.
- Wenn Sie mit dem JBoss generierte Fehlerseite, muss Ihr code geworfen haben eine nicht abgefangene Ausnahme, die nicht behandelt (oder nicht richtig behandelt) durch die
ExceptionMapper
in dem Jersey-framework. Was war die Ausnahme? Meine erste Vermutung wäre, dass Sie nicht alle geeignetenMessageBodyWriter
konfiguriert für dieapplication/xml
AntwortContent-Type
- der log von JBoss wirft nur eine Zeile welche ist die, die erwischt werden sollte, indem ExceptionMapper
2015-02-04 13:37:22,229 ERROR [STDERR] (http-localhost%2F127.0.0.1-8080-1) [Fatal Error] :-1:-1: Premature end of file.
- aber meine
toResponse
Methode ist die gleiche wie in der Artikel, den ich verlinkte, ich nur ändern Sie den Typ von MediaType.APPLICATION_JSON bis MediaType.APPLICATION_XML, wenn es JSON bekomme ich eine Fehlermeldung als Antwort im JSON-genau so, wie ich will, aber wenn das XML bekomme ich die HTML-Fehler-Seite. Siehe meine bearbeitete Antwort zu überprüfen, meine Klasse für die Zuordnung sind die Ausnahme, Sie werden sehen, es ist das gleiche wie im Artikel. - Dieser Artikel scheint nicht zu befassen mit der richtigen Konfiguration von Jersey. Das JDK noch Jersey haben die native Unterstützung für das Lesen/schreiben von JSON oder XML. In Jersey Sprachgebrauch, die Sie benötigen, um die richtigen
MessageBodyWriter
Implementierungen auf Ihrem Classpath eingetragen Jersey zu unterstützen, schreiben verschiedene MediaType-basierte Reaktionen (z.B. JSON oder XML). Überprüfen Sie die Echtzeit-Dokumentation für details, wie man XML arbeiten: jersey.java.net/documentation/1.18/xml.html - Ja ich habe die Dokumentation gelesen und so bekam ich zu wissen, ExceptionMapper, der Artikel ist ein Beispiel, wie man es verwenden, um zurück in JSON verbunden an das Ende.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Bereitstellung der @XmlAccessorType(XmlAccessType.FELD) über Ihre ErrorMessage-Klasse sollte das problem lösen :
Dieser JAXB-annotation teilt dem server zu binden Attribute anstelle von get zu Ihrem XML. Ansonsten wird ein Fehler generiert, da dies bewirkt, dass Ihre XML-Antwort mit doppelten Eigenschaften für XML binding(wie doppelte code-Elemente).
WARUM?
Weiter, wenn wir den Blick in die Dokumentation auf XmlAccessType zu verstehen PUBLIC_MEMBER hier ist, was es zu sagen hat:
So, dass der code der Fehlermeldung wurde widersprüchlich, da XmlElement wurde auch verwendet, um anzeigen JavaBean-Eigenschaft XML. Also zum Beispiel die Eigenschaft code war nicht nur gebunden von XmlElement-Objekten, aber auch durch die get-Methode.
Dieses problem zu überwinden, haben wir zwei Möglichkeiten:
Option 1:Wir können XmlAccessType.FELD, so dass nur die Felder verwendet werden und Getter weggelassen.
Option 2:entfernen Sie Einfach die XmlElement-Anmerkungen aus der Klasse, in dem Fall wird der Getter wird nur entscheiden, ob die Bindung.
Auch, vergessen Sie nicht, aktualisieren Sie die toResponse Nachricht an die mapper-Klasse zu reflektieren, die Ausgabe ist XML:
getStatus/setStatus
per Konvention den Namen des Elements werden solltestatus
, die den gleichen Namen wie die Sie eingereicht haben, also das doppelte. Wenn Sie geben Sie den access-Typ als Feld, dann die Eigenschaften nicht verwendet werden.