Unable to transform from SOAP response with CDATA block to a POJO in FSW 6

Solution Unverified - Updated

Environment

  • Red Hat JBoss Fuse Service Works (FSW)
    • 6.0.0

Issue

We have a Switchyard project which is using a component reference with a SOAP binding. This SOAP service is not a very common SOAP service in the sense that the response of the operation contains CDATA blocks which in turn contains the XML structure we need:

For example:


<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns2:GetStatisticsResponse xmlns:ns2="http://web.service.com/">
         <return><![CDATA[<statistics name="Foo">
    <value>100</value>
    <clickthrough>20</clickthrough>
</statistics>]]></return>
      </ns2:GetStatisticsResponse>
   </soap:Body>
</soap:Envelope>

We are interested in the statistics element and its subelements within the CDATA block.

Our problem is that we need a transformer to go from this SOAP response to a POJO which contains the Java representation of this statistics element.

We do not want to parse the DOM ourselves via a Java transformer, but want to use Smooks for this. We were able to transform the SOAP response to a String, but we would need an additional transformation to parse this String into XML fields to populate the POJO with. How can this be done in FSW 6?

Resolution

To perform the transformation, use a multi-hop/chained transformation feature:

FSW 6.0 allows to chain transformers. Say you had a transformer that went from A->B and another that went from B->C. If you had an invocation where the consumer was using type A and the provider was using type C, then the runtime will invoke the A->B and the B->C transformers to achieve A->C.

For the SOAP response, there are two transformers invoked:

  <transform:transform.java from="{http://web.service.com/}GetStatisticsResponse" to="{urn:web.service.com}StatisticsCData" bean="CDataReturn”/>

The above transformer transforms the SOAP reply which contains the GetStatisticsResponse element into an intermediate object which is just the content of the return element (CDATA containing the element). This transformer is implemented in Java:

@Named("CDataReturn")
public class CDataExtractor {
	
	@Transformer(from = "{http://web.service.com/}GetStatisticsResponse",
				 to = "{urn:web.service.com}StatisticsCData")
    public String transform(Element from) {
		String value = null;
        NodeList nodes = from.getElementsByTagName("return");
        if(nodes.getLength() > 0 ){
            value = nodes.item(0).getChildNodes().item(0).getNodeValue();
        }
		return value;
    }
}

The next transformer then takes care of transforming from the element to the Statistics Java model using JAXB:

  <transform:transform.jaxb from="{urn:web.service.com}StatisticsCData" to="java:com.sample.model.Statistics" contextPath="com.sample.model”/>

FSW 6.0 knows from the contracts on the reference definitions that it needs to go from {http://web.service.com/}GetStatisticsResponse to java:com.sample.model.Statistics and will automatically invoke both transformers to make that happen.

Root Cause

FSW 6.0 provides a chained transformation feature which can be used for transformations which can be accomplished only in multiple steps.

SBR

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.