5

i'm new to working with SOAP API's

I have a soap response from an API

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<LoginResponse xmlns="http://test.org/ADMail_Service">
<LoginResult>
<ErrorMessage>Successful login</ErrorMessage>
<Status>true</Status>
</LoginResult>
</LoginResponse>
</soapenv:Body>
</soapenv:Envelope>

I'm trying to transform this into an object.

From reading articles online I'm trying to use JAXB to do this, but my object is empty.

Here's the code for reading the response. I wrote the response to an xml file for test purposes:

try {
    XMLInputFactory xif = XMLInputFactory.newFactory();
    XMLStreamReader xsr = xif.createXMLStreamReader(new FileReader("input.xml"));
    xsr.nextTag(); // Advance to Envelope tag

    xsr.nextTag(); // Advance to Body tag
    xsr.nextTag();
    xsr.nextTag();


    JAXBContext jc = JAXBContext.newInstance(LoginResult.class);
    Unmarshaller unmarshaller = jc.createUnmarshaller();
    JAXBElement<LoginResult> je = unmarshaller.unmarshal(xsr, LoginResult.class);

    System.out.println(je.getName());
    System.out.println(je.getValue());
} catch (XMLStreamException e) {
    e.printStackTrace();
} catch (JAXBException e) {
    e.printStackTrace();
} catch (FileNotFoundException e) {
    e.printStackTrace();
}

The LoginResult class:

public class LoginResult {
    private String errorMessage;
    private String status;

    public String getErrorMessage() {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    public String getStatus() {
        return status;
    }

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

Thanks in advance!

Ayo K
  • 1,719
  • 2
  • 22
  • 34

4 Answers4

7

you can use this code to retrieve a POJO, and also add an @XmlRootElement as header to your POJO.

(I did'nt test the code below)

XMLInputFactory xif = XMLInputFactory.newFactory();
        XMLStreamReader xsr = xif.createXMLStreamReader(new FileReader("input.xml"));
        xsr.nextTag(); // Advance to Envelope tag

        xsr.nextTag(); // Advance to Body tag
        xsr.nextTag();
        xsr.nextTag();

        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        StringWriter stringWriter = new StringWriter();
        transformer.transform(new StAXSource(xsr), new StreamResult(stringWriter));
        StringReader sr = new StringReader(stringWriter.toString());
        JAXBContext jaxbContext = JAXBContext.newInstance(LoginResult.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        LoginResult loginResult = (LoginResult) unmarshaller.unmarshal(sr);

EDIT :

I found a solution for you:

    @XmlRootElement(name = "LoginResult", namespace = "http://test.org/ADMail_Service")
@XmlAccessorType(XmlAccessType.FIELD)
public class LoginResult {
    @XmlElement(name = "ErrorMessage", namespace = "http://test.org/ADMail_Service")
    private String errorMessage;
    @XmlElement(name = "Status", namespace = "http://test.org/ADMail_Service")
    private String status;

    public String getErrorMessage() {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    public String getStatus() {
        return status;
    }

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


public static void main(String[] args) {
        try {
            XMLInputFactory xif = XMLInputFactory.newFactory();
            XMLStreamReader xsr = xif.createXMLStreamReader(new FileReader("input.xml"));
            xsr.nextTag(); // Advance to Envelope tag

            xsr.nextTag(); // Advance to Body tag
            xsr.nextTag();
            xsr.nextTag();


            JAXBContext jc = JAXBContext.newInstance(LoginResult.class);
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            JAXBElement<LoginResult> je = unmarshaller.unmarshal(xsr, LoginResult.class);

            System.out.println(je.getName());
            System.out.println(je.getValue());
            System.out.println(je.getValue().getErrorMessage());
        } catch (XMLStreamException e) {
            e.printStackTrace();
        } catch (JAXBException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }
Zibaire
  • 119
  • 5
  • nope doesn't work I get `javax.xml.bind.UnmarshalException: unexpected element (uri:"http://test.org/ADMail_Service", local:"LoginResult"). Expected elements are (none)` – Ayo K Nov 16 '17 at 16:10
  • hi @Ayok, with my second solution I think you did't obtain an error. – Zibaire Nov 17 '17 at 08:56
  • Thanks it Works @Zibaire. I'll mark as correct answer because it directly solves the problem. – Ayo K Nov 17 '17 at 10:13
  • 1
    However I think the approach of @Mickaël B is more appropriate – Ayo K Nov 17 '17 at 10:13
  • if i have and both in single xml then xsr.nextTag() work for this case? – Hitesh Dec 09 '19 at 10:30
5

IMO, you should consider using tools to handle SOAP messages instead of doing it on your own.

Examples :


EDIT

There's a few things to say about your comment so I'll put my answer here.

First,

I have nothing to do with the API, all I do is make a POST request...

You have nothing to do with the API but you make a POST request to the API. I think this is a figure of speech, right ?...

and there's no wsdl....

You can almost always get the WSDL of a SOAP webservice with this little trick. Just add ?wsdl at the end of the SOAP webservice URL.

Example :

Here's the URL of a SOAP webservice on the web (a real one) : http://www.webservicex.com/stockquote.asmx

You can get its WSDL like this : http://www.webservicex.com/stockquote.asmx?wsdl

So the only option is to parse the response

IMO, there's almost always more than one solution to a problem in software development.

Mickael
  • 4,458
  • 2
  • 28
  • 40
  • I have nothing to do with the API, all I do is make a `POST` request and there's no wsdl. It just returns an xml response. So the only option is to parse the response – Ayo K Nov 16 '17 at 15:54
  • This Spring Boot solution does not work. I get a Factory method 'quoteClient' threw exception; nested exception is java.lang.NoSuchMethodError – NaN May 22 '18 at 15:35
  • @PSyLoCKe You should consider creating your own question because you're probably having a different problem. – Mickael May 23 '18 at 12:01
0

After sometimes, I found this code for parsing soapxml object to java object.

private <T> T getJavaObjectFromSoapXml(String responseFilePath, Class<T> clazz) {
try {
  XMLInputFactory xif = XMLInputFactory.newFactory();
  StreamSource xml = new StreamSource(getClass().getResourceAsStream(responseFilePath));
  XMLStreamReader xsr = xif.createXMLStreamReader(xml);
  xsr.nextTag();
  while (!xsr.getLocalName().equalsIgnoreCase(clazz.getSimpleName())) {
    xsr.nextTag();
  }

  JAXBContext jc = JAXBContext.newInstance(clazz);
  Unmarshaller unmarshaller = jc.createUnmarshaller();

  JAXBElement<T> je = unmarshaller.unmarshal(xsr, clazz);
  return je.getValue();
} catch (Exception e) {
  e.printStackTrace();
  return null;
}
}
m.nguyencntt
  • 935
  • 13
  • 19
0
public  <T> T getJavaObjectFromSoapXml(String response, Class<T> clazz) {
        try {
            XMLInputFactory xif = XMLInputFactory.newFactory();
            StreamSource xml = new StreamSource(response);
            XMLStreamReader xsr = xif.createXMLStreamReader(new StringReader(response));
            xsr.nextTag();
            while (!xsr.getLocalName().equalsIgnoreCase(clazz.getSimpleName())) {
                log.info("TAG :{}",xsr.nextTag());
            }

            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            StringWriter stringWriter = new StringWriter();
            transformer.transform(new StAXSource(xsr), new StreamResult(stringWriter));
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();

            Document document = builder.parse(new InputSource(new StringReader(stringWriter.toString())));
            JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            T t = (T) unmarshaller.unmarshal(document);
            return t;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
Brian Brix
  • 449
  • 4
  • 12