In Mule ESB's ALL control flow, how to merge two resulting JSON collections into a single list of JSON values?

StackOverflow https://stackoverflow.com/questions/22827979

  •  26-06-2023
  •  | 
  •  

Question

I have a 3.4.0 Mule flow (xml shown at the end) that uses the ALL flow control to send an identical query to two different remote RESTful web services (U.S. and E.U.), both of which return a list of JSON values. My problem is that the ALL flow control is returning a list of 2 lists of JSON values rather than what I want (a single merged list of the JSON values). i.e. I am getting this:

[[
{
    "StudyData": {
        "@id": "0e521e697c1f76f1603a21fff98dbeb5",
        "@xmlns:xsd": "http://www.w3.org/2001/XMLSchema",
        "@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
        "Base-Scanning-Parameters": {
            "Scanning": {
                "exposureMultiplier": "7"
            }
        },
        "Calibration": {
            "Directory": "D:\\Data\\CASE_00283\\MicroCal",
            "GUID": null,
            "Version": "2"
        },
        "Imager": {
            "DeviceId": "DEV000001",
            "Model": "DPI Dpca",
            "SerialNumber": "Apr 16 2012",
            "SystemSerialNumber": "DEV000001",
            "Version": "1.1.0"
        }
    }
}
], [
{
    "StudyData": {
        "@id": "59130b92f421ad1c0b2e610420c8bc16",
        "Base-Scanning-Parameters": {
            "Scanning": {
                "exposureMultiplier": "7"
            }
        },
        "Calibration": {
            "Directory": "D:\\Data\\CASE_00283\\MicroCal",
            "GUID": null,
            "Version": "2"
        },
        "Imager": {
            "DeviceId": "TestDevice",
            "Model": "DPI Dpca",
            "SerialNumber": "Apr 16 2012",
            "SystemSerialNumber": "1234567A",
            "Version": "1.1.0"
        }
    }
},
{
    "StudyData": {
        "@id": "7ae4c6840ef7bfa1b2f5f17290f78bcd",
        "Base-Scanning-Parameters": {
            "Scanning": {
                "exposureMultiplier": "7"
            }
        },
        "Calibration": {
            "Directory": "D:\\Data\\CASE_00283\\MicroCal",
            "GUID": null,
            "Version": "2"
        },
        "Imager": {
            "DeviceId": "TestDevice",
            "Model": "DPI Dpca",
            "SerialNumber": "Apr 16 2012",
            "SystemSerialNumber": "1234567A",
            "Version": "1.1.0"
        }
    }
}
]]

What I need instead is both lists of "StudyData" merged into a single list like so (I removed record details for space):

[
  {"StudyData": { ...
  },
  {"StudyData": { ...
  },
  {"StudyData": { ...
  }
]

The Mule XML for this flow is:

-------------- start Mule XML: --------------------------------

<flow name="federatedWebService" doc:name="federatedWebService">
    <copy-properties propertyName="http.method" doc:name="Copy http.method"/>
    <choice doc:name="Choice">
        <when expression="#[message.inboundProperties['http.method']=='GET']">
            <all doc:name="All">
                <processor-chain>
                    <logger message="Redirected GET to US, path is: #[path]" level="DEBUG" category="com.dpi.integration.federatedWebService" doc:name="Redirecting GET to US Path"/>
                    <https:outbound-endpoint exchange-pattern="request-response" host="${http.outbound.us.host}" port="${http.outbound.us.port}" path="#[path]" method="GET" followRedirects="true" connector-ref="HTTPSConnector" doc:name="US GET"/>
                    <set-variable variableName="USStatus" value="#[message.inboundProperties['http.status']]" doc:name="Set UStatus"/>
                    <logger message="US Response: #[USStatus]" level="DEBUG" category="com.dpi.integration.federatedWebService" doc:name="US Response"/>
                    <object-to-string-transformer doc:name="Object to String"/>
                    <logger message="US Response: #[message.payload]" level="INFO" doc:name="Logger"/>
                </processor-chain>
                <processor-chain>
                    <logger message="Redirected GET to EU, path is: #[path]" level="DEBUG" category="com.dpi.integration.federatedWebService" doc:name="Redirecting GET to EU Path"/>
                    <https:outbound-endpoint exchange-pattern="request-response" host="${http.outbound.eu.host}" port="${http.outbound.eu.port}" path="#[path]" method="GET" followRedirects="true" connector-ref="HTTPSConnector" doc:name="EU GET"/>
                    <set-variable variableName="EUStatus" value="#[message.inboundProperties['http.status']]" doc:name="Set EUStatus"/>
                    <logger message="EU Response: #[EUStatus]" level="DEBUG" category="com.dpi.integration.federatedWebService" doc:name="EU Response"/>
                    <object-to-string-transformer doc:name="Object to String"/>
                    <logger message="EU Response:  #[message.payload]" level="DEBUG" doc:name="Logger"/>
                </processor-chain>
            </all>
        </when>
        <otherwise>
            <logger message="Redirected #['http.method'] to US" level="DEBUG" category="com.dpi.integration.federatedWebService" doc:name="Redirected to US"/>
            <http:outbound-endpoint exchange-pattern="request-response" host="${http.outbound.us.host}" port="${http.outbound.us.port}" followRedirects="true" doc:name="US All Else"/>
        </otherwise>
    </choice>
    <object-to-string-transformer encoding="UTF-8" mimeType="application/json" doc:name="Object to String"/>
    <logger message="Response: #[message.payload]" level="DEBUG" category="com.dpi.integration.federatedWebService" doc:name="Response"/>
    <catch-exception-strategy doc:name="Catch Exception Strategy">
        <set-property propertyName="http.status" value="#[(USStatus == 404) ? EUStatus : USStatus]" doc:name="Set HTTP Status to USStatus"/>
        <choice doc:name="Choice">
            <when expression="#[USStatus == 404]">
                <set-payload value="Unable to locate the requested resource: #[message.inboundProperties['http.request.path']]" doc:name="404 Message"/>
            </when>
            <otherwise>
                <set-payload value="Unable to process the requested resource: #[message.inboundProperties['http.request.path']]" doc:name="Generic Error Message"/>
            </otherwise>
        </choice>
        <logger message="Unable to process the requested resource: #[message.inboundProperties['http.request.path']], US HTTP Status: #[USStatus], EU HTTP Status: #[EUStatus]" level="ERROR" category="com.dpi.integration.federatedWebService" doc:name="Error Message"/>
    </catch-exception-strategy>
</flow>

----------- end mule XML -------------------

Any suggestions would be greatly appreciated.

Thanks !!

-keith

Was it helpful?

Solution

You can use <json:json-to-object-transformer returnClass="java.util.List"/> on both JSON values, and then later flatten the list of lists with Groovy using payload.flatten().

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top