Abrufen von Raw-XML aus SOAPMessage in Java

79

Ich habe einen SOAP WebServiceProvider in JAX-WS eingerichtet, aber ich habe Probleme herauszufinden, wie das unformatierte XML von einem SOAPMessage-Objekt (oder einem beliebigen Knotenobjekt) abgerufen werden kann. Hier ist ein Beispiel des Codes, den ich gerade habe, und wo ich versuche, das XML abzurufen:

@WebServiceProvider(wsdlLocation="SoapService.wsdl")
@ServiceMode(value=Service.Mode.MESSAGE)
public class SoapProvider implements Provider<SOAPMessage>
{
    public SOAPMessage invoke(SOAPMessage msg)
    {
        // How do I get the raw XML here?
    }
}

Gibt es eine einfache Möglichkeit, das XML der ursprünglichen Anforderung abzurufen? Wenn es eine Möglichkeit gibt, das unformatierte XML durch Einrichten eines anderen Anbietertyps (z. B. Quelle) zu erhalten, wäre ich auch dazu bereit.

Dan Lew
quelle

Antworten:

152

Sie könnten es auf diese Weise versuchen.

SOAPMessage msg = messageContext.getMessage();
ByteArrayOutputStream out = new ByteArrayOutputStream();
msg.writeTo(out);
String strMsg = new String(out.toByteArray());
Smith Torsahakul
quelle
4
Dies berücksichtigt nicht die Zeichenkodierung
Artbristol
Verbraucht es viel Speicher mit so etwas wie dem Erstellen von DOM-Objekten oder ähnlichem? Oder wird es wirklich die Rohzeichenfolge aus der HTTP-Antwort geben, ohne die XML intern zu analysieren?
Ruslan
21

Wenn Sie ein SOAPMessageoder haben SOAPMessageContext, können Sie ein verwenden Transformer, indem Sie es in ein SourceVia konvertieren DOMSource:

            final SOAPMessage message = messageContext.getMessage();
            final StringWriter sw = new StringWriter();

            try {
                TransformerFactory.newInstance().newTransformer().transform(
                    new DOMSource(message.getSOAPPart()),
                    new StreamResult(sw));
            } catch (TransformerException e) {
                throw new RuntimeException(e);
            }

            // Now you have the XML as a String:
            System.out.println(sw.toString());

Dadurch wird die Codierung berücksichtigt, sodass Ihre "Sonderzeichen" nicht entstellt werden.

Artbristol
quelle
Ist die Bereitstellung lösungsspeicherintensiv?
Lospejos
12

Es stellt sich heraus, dass man das unformatierte XML mithilfe von Provider <Quelle> auf folgende Weise erhalten kann:

import java.io.ByteArrayOutputStream;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.ws.Provider;
import javax.xml.ws.Service;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceProvider;

@ServiceMode(value=Service.Mode.PAYLOAD)
@WebServiceProvider()
public class SoapProvider implements Provider<Source>
{
    public Source invoke(Source msg)
    {
        StreamResult sr = new StreamResult();

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        sr.setOutputStream(out);

        try {
            Transformer trans = TransformerFactory.newInstance().newTransformer();
            trans.transform(msg, sr);

            // Use out to your heart's desire.
        }
        catch (TransformerException e) {
            e.printStackTrace();
        }    

        return msg;
    }
}

Ich brauchte diese Lösung letztendlich nicht, also habe ich diesen Code nicht selbst ausprobiert - es könnte einige Anpassungen erfordern, um richtig zu werden. Ich weiß jedoch, dass dies der richtige Weg ist, um das unformatierte XML von einem Webdienst abzurufen.

(Ich bin mir nicht sicher, wie ich das machen soll, wenn Sie unbedingt ein SOAPMessage-Objekt haben müssen, aber wenn Sie das rohe XML sowieso verarbeiten wollen, warum sollten Sie ein übergeordnetes Objekt verwenden?)

Dan Lew
quelle
A StringWriterist eine gute Alternative zur ByteArrayOutputStream+ StreamResult-Kombination, wenn Sie das XML als Stringmit der richtigen Codierung
wünschen
12

Verwenden Sie zum Debuggen nur einen Zeilencode -

msg.writeTo(System.out);

Shahadat Hossain Khan
quelle
Das OP debuggt nicht unbedingt in System.out (was für einen Webserver nicht unbedingt bequem zugänglich ist) - möglicherweise muss er / sie das ursprüngliche XML über einen Socket senden, irgendwo speichern oder seine Statistiken berechnen.
Nanofarad
Sie können leicht an einen ByteArrayOutputStreamKonvertiten schreiben, um String... scheint mir einfach
vikingsteve
7

Wenn Sie die XML-Zeichenfolge in XML formatieren müssen, versuchen Sie Folgendes:

String xmlStr = "your-xml-string";
Source xmlInput = new StreamSource(new StringReader(xmlStr));
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
transformer.transform(xmlInput,
        new StreamResult(new FileOutputStream("response.xml")));
Hari
quelle
Ist es möglich, zwischen Leerzeichen und Tabulatoren zu wählen, um diese Formatierung durchzuführen? Übrigens, ich weiß, dass Registerkarten nicht angezeigt werden.
Philippe Gioseffi
7

Verwenden von Transformer Factory: -

public static String printSoapMessage(final SOAPMessage soapMessage) throws TransformerFactoryConfigurationError,
            TransformerConfigurationException, SOAPException, TransformerException
    {
        final TransformerFactory transformerFactory = TransformerFactory.newInstance();
        final Transformer transformer = transformerFactory.newTransformer();

        // Format it
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

        final Source soapContent = soapMessage.getSOAPPart().getContent();

        final ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
        final StreamResult result = new StreamResult(streamOut);
        transformer.transform(soapContent, result);

        return streamOut.toString();
    }
Sireesh Yarlagadda
quelle
3

das funktioniert

 final StringWriter sw = new StringWriter();

try {
    TransformerFactory.newInstance().newTransformer().transform(
        new DOMSource(soapResponse.getSOAPPart()),
        new StreamResult(sw));
} catch (TransformerException e) {
    throw new RuntimeException(e);
}
System.out.println(sw.toString());
return sw.toString();
user2900572
quelle
Keine Erklärung erforderlich.
Martin Kersten
0

Wenn Sie den Client-Code haben, müssen Sie nur die folgenden zwei Zeilen hinzufügen, um die XML-Anforderung / Antwort zu erhalten. Hier _callistorg.apache.axis.client.Call

String request = _call.getMessageContext().getRequestMessage().getSOAPPartAsString();
String response = _call.getMessageContext().getResponseMessage().getSOAPPartAsString();
ARIJIT
quelle
0

Es ist ein ziemlich alter Thread, aber kürzlich hatte ich ein ähnliches Problem. Ich habe einen Downstream-Seifendienst von einem Rest-Service aus aufgerufen und musste die XML-Antwort vom Downstream-Server unverändert zurückgeben.

Also habe ich einen SoapMessageContext-Handler hinzugefügt, um die XML-Antwort zu erhalten. Dann habe ich die Antwort-XML als Attribut in den Servlet-Kontext eingefügt.

public boolean handleMessage(SOAPMessageContext context) {

            // Get xml response
            try {

                ServletContext servletContext =
                        ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getServletContext();

                SOAPMessage msg = context.getMessage();

                ByteArrayOutputStream out = new ByteArrayOutputStream();
                msg.writeTo(out);
                String strMsg = new String(out.toByteArray());

                servletContext.setAttribute("responseXml", strMsg);

                return true;
            } catch (Exception e) {
                return false;
            }
        }

Dann habe ich die XML-Antwortzeichenfolge in der Service-Schicht abgerufen.

ServletContext servletContext =
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getServletContext();

        String msg = (String) servletContext.getAttribute("responseXml");

Ich hatte noch keine Gelegenheit, es zu testen, aber dieser Ansatz muss threadsicher sein, da er den Servlet-Kontext verwendet.

Oguz Demir
quelle