Deserialize/Pulling a Spring's RestTemplate response from Atom source - spring

I'm trying to use Spring's RestTemplate to get a response from an atom source. Is there a way to easily pull values from the response or deserialize it?
The response:
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns='http://www.w3.org/2005/Atom' xmlns:apps='http://schemas.google.com/apps/2006'>
<id>https://apps-apis.google.com/a/feeds/domain/2.0/blah/verification/mx</id>
<updated>2013-03-19T19:47:02.805Z</updated>
<apps:property name='verified' value='false'/>
</entry>

Parse the feed with Abdera or ROME. They have nice representations of Atom feeds and feed entries with all their composing types.

Related

How do you properly unmarshall an SOAP string with XML namespaces?

I'm having a hard time figuring out how to correctly and safely unmarshall a SOAP response with the following shape:
<xml>
<soap-env:Envelope
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header></soap-env:Header>
<soap-env:Body>
<n0:ZcustomerMasterInfoResponse
xmlns:n0="urn:sap-com:document:sap:soap:functions:mc-style">
<EOutput>
...Additional tags
</EOutput>
<n0:ZcustomerMasterInfoResponse/>
</soap-env:Body />
</soap:Envelop />
</xml>
This would be trivial with basic tags but there's quite a few namespaces such as soap-env, n0 etc. that are making it more complex to parse.

Consuming XML response from a REST call in Spring Integration

Seems to be a simple task but I cannot get my head around it.
I have a Spring integration chain which calls an external Webservice, which returns an XML. I would like to use that XML response in a downstream XpathRouter.
What expected-response-type should I use?
<int:chain input-channel="filesChannel">
<!-- ... some previous components in the chain -->
<int-http:outbound-gateway
http-method="POST"
url="http://web/service/url"
expected-response-type="java.lang.String" />
<int-xml:xpath-router default-output-channel="resultChannel">
<int-xml:xpath-expression expression="/order/status" />
<int-xml:mapping value="Error" channel="importErrorChannel" />
</int-xml:xpath-router>
</int:chain>
It doesn't seem like the xpath-router can consume the XML returned by the webservice. When I debug the router with a breakpoint on the following line:
Node node = this.converter.convertToNode(message.getPayload());
The node is null, although the message does contain valid XML.
Is it because I am not setting the right expected-response-type?
Here is the response XML I receive from the service:
<apiResponse version="1.0">
<orders>
<order>
<orderReference>test_2_3045342</orderReference>
<status>Error</status>
<errors>
<error>
<errorCode>1100</errorCode>
<errorMessage><![CDATA[ "Field is required: dropWindow" ]]></errorMessage>
</error>
</errors>
</order>
</orders>
</apiResponse>
Ok, I found my mistake - it was actually in the XPATH expression. It should have been //order/status to enable deep search.
The java.lang.String expected-response-type works just fine with XML XpathRouter.
Thanks

How to consume XML with more than one possible root element in Spring REST client

In my application I have to consume a service provided by a third party application. The response they provide is always 200 and they change the body based on whether data is available or not or error occurred, as given below
If data is there then
<products>
<product></product>
<product></product>
</products>
If data is empty then
<message> No record found </message>
If some validation failed then
<error>Invalid Id</error>
I am using RestTemplate.exchange to consume the service, my question is if there only single type of root element then we pass the respective class as ParameterizedTypeReference but here how to map the response and unmarshall it.
Use jaxb or jackson to unmarshall the xml.
The right thing to do here is to ask the third party to change their service response to have a root tag. The response object would then look something like this:
<response>
<products>
<product></product>
<product></product>
</products>
<message> No record found </message>
<error>Invalid Id</error>
</response>
With this, you will only need to be concerned about response object and you can check the presence of respective sub-tags.
Other option to make this work for you is to do the exchange by passing String.class as the type reference. Then you would need to do the check in your code to see if the string response returned is products or message or error

Soap Fault Details custom exception

In the process of moving to Spring WS and using JAXB from wsdl to generate the objects used in the Soap message. I am having an issue trying to get the Custom Exception into the details field of the Soap Fault message. The following is how the existing fault message is returned (FooException embedded in detail).
<env:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Header/>
<env:Body>
<env:Fault>
<faultcode>env:Server</faultcode>
<faultstring>Service specific exception: com.test.FooException: Invalid authentication credentials. Please try again.</faultstring>
<detail>
<n1:FooException xsi:type="n1:FooException" xmlns:n1="java:com.test">
<errorCode xsi:type="xsd:int">101</errorCode>
<errorReason xsi:type="xsd:string">InvalidUserCredentials:Invalid authentication credentials. Please try again</errorReason>
</n1:FooException>
</detail>
</env:Fault>
</env:Body>
</env:Envelope>
I have setup a customer exceptionResolver bean identifier in the spring config xml file.
<bean id="exceptionResolver" class="com.test.FacadeExceptionHandler">
<property name="order" value="1"></property>
<property name="defaultFault" value="SERVER"/>
<property name="exceptionMappings">
<value> com.test.FooException=SERVER,FaultMsg </value>
</property>
</bean>
I created the FacadeExceptionHandler and it is getting called, but I cannot figure out how to get the FooException into the details portion of the fault message.
Any help would be appreciated!!!
Thanks in advance for your help!
I think you almost get it all, in your FacadeExceptionHandler you must override the customizeFault method (doc) and then add the detail for the fault (you have your Exception as a parameter there).
All this custom detail handling for Soap Fault messages is explained in detail in this entry: http://www.stevideter.com/2009/02/18/of-exceptionresolvers-and-xmlbeans/
You cannot return to SOAP client fault with such depth of nested elements in <detail> element cause in Spring WS SoapFault has list of SoapFaultDetail which has list of SoapFaultDetailElement but SoapFaultDetailElement is just detail message in String. So in Spring WS max depth of SOAP Fault details is one.
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring>Сообщение не соответствуют схеме сервиса СМЭВ.</faultstring>
<detail>
<InvalidContent xmlns="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/faults/1.1">cvc-complex-type.2.4.a: Invalid content was found starting with element 'ns:SenderProvidedRequestData1'. One of '{"urn://x-artefacts-smev-gov-ru/services/message-exchange/types/1.1":SenderProvidedRequestData}' is expected.</InvalidContent>
<InvalidContent xmlns="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/faults/1.1">cvc-complex-type.2.3: Element 'ns:CallerInformationSystemSignature' cannot have character [children], because the type's content type is element-only.</InvalidContent>
<InvalidContent xmlns="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/faults/1.1">cvc-complex-type.2.4.b: The content of element 'ns:CallerInformationSystemSignature' is not complete. One of '{WC["http://www.w3.org/2000/09/xmldsig#"]}' is expected.</InvalidContent>
</detail>
</SOAP-ENV:Fault>

Validate XML against 2 XSD

I'm trying to parse and validate a SOAP request with SAX. Two XSD are necessary, one for SOAP envelope (http://schemas.xmlsoap.org/soap/envelope/) and the one I defined. I cannot find a way to properly validate the request against these two XSD.
Here's the code I use to parse the request and validate it against soapenv.xsd. It works fine. If I specify my XSD instead, the validation fails with "Cannot find the declaration of element 'soapenv:Envelope'".
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(true);
SAXParser saxParser = factory.newSAXParser();
saxParser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
saxParser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource", MyClass.class.getResourceAsStream("/xml/soapenv.xsd"));
InputSource is = new InputSource(MyClass.class.getResourceAsStream("/xml/request.xml"));
XMLReader reader = saxParser.getXMLReader();
reader.setContentHandler(new MyHandler());
reader.setErrorHandler(new MyErrorHandler());
reader.parse(is);
How can I specify a second XSD?
Is there a better way to parse and validate SOAP requests?
EDIT
As proposed, I created thirdpty.xsd that imports my two XSDs.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="thirdparty:general"
xmlns="thirdparty:general"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import schemaLocation="D:\ucfed\ValidateWSDL\src\xml\soapenv.xsd"
namespace="http://schemas.xmlsoap.org/soap/envelope/"/>
<xs:import schemaLocation="D:\ucfed\ValidateWSDL\src\xml\Presence.xsd"
namespace="thirdparty:presence"/>
</xs:schema>
I specify this new XSD for the validation:
saxParser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource", MyClass.class.getResourceAsStream("/xml/thidpty.xsd"));
But still, only the SOAP envelope XSD is used for validation. If a modify one element from my other XSD, the validation does not detect it.
Here is the xml I am trying to validate
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="thirdparty:presence">
<soapenv:Header/>
<soapenv:Body>
<urn:getPresenceQuery>
<urn:origAccount uri="test#origin.com"/>
<urn:destAccount uri="test#destination.com"/>
</urn:getPresenceQuery>
</soapenv:Body>
</soapenv:Envelope>
Other ideas ?
Write a driver schema document which imports the other two; validate against the driver.

Resources