Tuesday, September 1, 2009

Mule: Using JiBX in Mule

Below I'd like to share my attempt to use JiBX inside of Mule to transform incoming XML message into a domain object and back again on the way out. In short, I created a request and response transformer that extended AbstractTransformer.

To start, I had the following domain objects:

   class Person {
String firstName
String lastName
Address addresss

class Address {
String city
String state

And a sample XML message where a Person has an Address:


The binding file I used to test out my transformers:

  <?xml version="1.0" encoding="UTF-8"?>
<mapping name="person" class="Person">
<value name="firstname" field="firstName"/>
<value name="lastname" field="lastName"/>
<structure name="address" field="address" class="Address">
<value name="city" field="city" />
<value name="state" field="state" />

Ok, now to something more interesting with that out of the way... the transformer to turn an incoming XML message to a Person object to use in my service component. Below is one representation of the transformer in Groovy with the types releated to JiBX declared:

class JibxXmlToObject extends AbstractJibxTransformer {
protected Object doTransform(Object src, String encoding) throws TransformerException {
def transformedObject
try {
Reader reader = new StringReader((String) src)
IBindingFactory factory = BindingDirectory.getFactory(Class.forName(getTargetClassName()))
IUnmarshallingContext context = factory.createUnmarshallingContext()
transformedObject = context.unmarshalDocument(reader)
catch(e) {
throw new TransformerException(this, e)

return transformedObject

To test out my transformer originally, I originally hard-coded the target class name:

  IBindingFactory factory = BindingDirectory.getFactory(Class.forName("org.prystasj.Person"))

In my Mule configuration, I will be declaring it however. If the transformer was a Java class, I might have to have getters and setters to allow for the target class name to be injected. Below is my declaration of the transformer as a custom transformer:

  <custom-transformer name="XmlToPerson" class="org.prystasj.transformers.JibxXmlToObject">
<spring:property name="targetClass" value="org.prystasj.Person"/>
  <file:endpoint name="XmlInboundEndpoint"

And here are the outgoing side of things, transforming a Person back to XML:
public class JibxObjectToXml extends AbstractJibxTransformer {
protected Object doTransform(Object src, String encoding) throws TransformerException {
String xml
try {
def writer = new StringWriter()
IBindingFactory factory = BindingDirectory.getFactory(Class.forName(getTargetClassName()))
IMarshallingContext context = factory.createMarshallingContext()
context.marshalDocument(src, encoding, null, writer)
xml = writer.toString()
} catch(e) {
throw new TransformerException(this, e)

return xml

And the corresponding Mule configuration:

  <custom-transformer name="PersonToXml" class="org.prystasj.transformers.JibxObjectToXml">
<spring:property name="targetClass" value="org.prystasj.Person"/>
  <file:endpoint name="XmlOutboundEndpoint"

Putting the pieces together with a service definition, this example would take a Person in XML and echo it back out in XML after performing both transforms:

  <model name="XmlPersonModel">
<service name="XmlInputService">
<file:inbound-endpoint ref="XmlInboundEndpoint"/>
<file:outbound-endpoint ref="XmlOutboundEndpoint"/>

A more useful service component could be used to manipulate the incoming person in some way.

No comments:

Post a Comment