Thursday, September 3, 2015

Mule Message Enricher ClassCastException Workaround

Mule's message enricher is buggy.  In my flow I have the following:

<enricher doc:name="map channel id">
       <flow-ref name="ChannelEnrichmentFlow" doc:name="channel enrichment flow" />
       <enrich target="#[payload.channelId]" source="#[payload[0].get('CHANNELID')]"></enrich>
       <enrich target="#[payload.uom]" source="#[payload[0].get('UOM')]"></enrich>
       <enrich target="#[payload.uomConversionFactor]" source="#[payload[0].get('UOMCONVERSIONFACTOR')]"></enrich>
</enricher>

Intermittently Mule will report a ClassCastException:

Message               : Execution of the expression "payload.channelId=__object_for_enrichment" failed. (org.mule.api.expression.ExpressionRuntimeException). Message payload is of type: StormSnapshotData
Code                  : MULE_ERROR--2
--------------------------------------------------------------------------------
Exception stack is:
1. java.lang.ClassCastException@13838f4b (java.lang.IllegalArgumentException)
  sun.reflect.GeneratedMethodAccessor99:-1 (null)
2. unable to bind property (java.lang.RuntimeException)
  org.mule.mvel2.optimizers.impl.refl.nodes.SetterAccessor:43 (null)
3. Execution of the expression "payload.channelId=__object_for_enrichment" failed. (org.mule.api.expression.ExpressionRuntimeException)

The following code is equivalent to the enricher and does not cause exceptions:

<enricher target="#[flowVars['resultSet']]" source="#[payload[0]]" doc:name="map channel id">
       <flow-ref name="ChannelEnrichmentFlow" doc:name="channel enrichment flow" />
</enricher>

<expression-transformer expression="#[payload.setChannelId(flowVars['resultSet']['CHANNELID']);payload.setUom(flowVars['resultSet']['UOM']);payload.setUomConversionFactor(flowVars['resultSet']['UOMCONVERSIONFACTOR']);message.payload]" doc:name="enrich payload"/>

This targets the enricher to a local variable (a map), then uses an expression transformer to call setters on the payload object, passing values from the map as parameters. The payload is a Java bean.