JAXB2 Transformers in Mule2

Currently I am looking into the possiblities Mule has to offer for our project. One of the things that must be done is to transform a message on our (Tibco) queue to a JAXB object so we can use the object as parameter in our call to an EJB3 bean. How to call a EJB3 bean from Mule I have explained here. In this post I want to show how we setup our JAXB transformer. This transformer isn’t standard available in Mule but, as you will see, it is pretty easy to create your own transformer.
I created my transformer based on this article. In my situation I have my JAXB classes generated in the package ‘net.pascalalma.types’ (I take this post as an example for my JAXB module).
The first step is to create a Maven project. You can choose a specific Mule archetype but in this case I chose the default archetype for a Maven project.
I added the following classes to the project that together make up the Jaxb Transformer:
The base class is formed by the AbstractJaxbTransformer class:

package net.pascalalma.mule.transformer;

import javax.xml.bind.JAXBContext;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.transformer.AbstractTransformer;

/**
 * Abstract transformer when using JAXB.
 */
public abstract class AbstractJaxbTransformer extends AbstractTransformer {

    private JAXBContext jaxbContext;
    private String jaxbContextPackage;

    @Override
    public void initialise() throws InitialisationException {
        try {
            jaxbContext = JAXBContext.newInstance(getJaxbContextPackage());
        } catch (Exception e) {
            throw new InitialisationException(e, this);
        }
    }

    public JAXBContext getJaxbContext() {
        return jaxbContext;
    }

    public void setJaxbContext(JAXBContext jaxbContext) {
        this.jaxbContext = jaxbContext;
    }

    public String getJaxbContextPackage() {
        return jaxbContextPackage;
    }

    public void setJaxbContextPackage(String jaxbContextPackage) {
        this.jaxbContextPackage = jaxbContextPackage;
    }
}

As we will see in the Mule configuration we will pass the package with which the JAXB Context must be initialized in this class. Now lets look at the classes that will do the actual work. One is the JaxbObjectToXml class:

package net.pascalalma.mule.transformer;

import java.io.StringReader;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.mule.api.transformer.TransformerException;

/**
 * Transforms JAXB XML to named JAXB Object
 */
public class JaxbXmlToObject extends AbstractJaxbTransformer {

    public JaxbXmlToObject() {
        registerSourceType(String.class);
        setReturnClass(Object.class);
    }

    protected Object doTransform(Object payload, String encodingType) throws TransformerException {
        Object element;

        try {
            Unmarshaller unmarshaller = getJaxbContext().createUnmarshaller();
            element = unmarshaller.unmarshal(new StringReader((String) payload));
        } catch (JAXBException e) {
            throw new TransformerException(this, e);
        }
        return element;
    }
}

The other one is the JaxbObjectToXml class:

package net.pascalalma.mule.transformer;

import java.io.StringWriter;
import java.io.Writer;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import org.mule.api.transformer.TransformerException;

public class JaxbObjectToXml extends AbstractJaxbTransformer {

    public JaxbObjectToXml() {
        registerSourceType(Object.class);
        setReturnClass(String.class);
    }
    protected Object doTransform(Object payload, String arg1) throws TransformerException {
        try {
            Marshaller marshaller = getJaxbContext().createMarshaller();

            Writer out = new StringWriter();
            marshaller.marshal(payload, out);

            return out.toString();

        } catch (JAXBException e) {
            throw new TransformerException(this, e);
        }
    }
}

That’s it! After compiling these classes we can use them in Mule to transform an incoming JMS TextMessage to a JAXB object. To test this transformer I make use of a VM queue in Mule. Here is my Mule configuration (muleproject-functional-test-config.xml) for the test class:

<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns="http://www.mulesource.org/schema/mule/core/2.2"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:spring="http://www.springframework.org/schema/beans"
       xmlns:test="http://www.mulesource.org/schema/mule/test/2.2"
       xmlns:jms="http://www.mulesource.org/schema/mule/jms/2.2"
       xmlns:stdio="http://www.mulesource.org/schema/mule/stdio/2.2"
       xmlns:vm="http://www.mulesource.org/schema/mule/vm/2.2"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="
       http://www.mulesource.org/schema/mule/core/2.2 http://www.mulesource.org/schema/mule/core/2.2/mule.xsd
       http://www.mulesource.org/schema/mule/test/2.2 http://www.mulesource.org/schema/mule/test/2.2/mule-test.xsd
       http://www.mulesource.org/schema/mule/jms/2.2 http://www.mulesource.org/schema/mule/jms/2.2/mule-jms.xsd
       http://www.mulesource.org/schema/mule/stdio/2.2 http://www.mulesource.org/schema/mule/stdio/2.2/mule-stdio.xsd
       http://www.mulesource.org/schema/mule/vm/2.2 http://www.mulesource.org/schema/mule/vm/2.2/mule-vm.xsd
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">

    <spring:beans>
        <jee:remote-slsb id="testEJB" jndi-name="CustomerLoggerRemote"
                         business-interface="net.pascalalma.services.CustomerLoggerRemote"
                         >
            <jee:environment>
                java.naming.factory.initial=org.apache.openejb.client.LocalInitialContextFactory
            </jee:environment>
        </jee:remote-slsb>
    </spring:beans>

    <jms:jmsmessage-to-object-transformer name="JmsToObject"/>

    <custom-transformer name="JaxbXmlToObject" class="net.pascalalma.mule.transformer.JaxbXmlToObject"
      returnClass="net.pascalalma.schema.customer.Customer">
        <spring:property name="jaxbContextPackage" value="net.pascalalma.schema.customer"/>
    </custom-transformer>

    <model name="main">
        <service name="testService" >
            <inbound>
                <vm:inbound-endpoint path="myqueue" synchronous="true" >
                    <!--<transformer ref="JmsToObject"/>-->
                    <transformer ref="JaxbXmlToObject"/>
                </vm:inbound-endpoint>
            </inbound>
            <component>
                <spring-object bean="testEJB" />
            </component>
            <default-service-exception-strategy>
                <vm:outbound-endpoint path="error" />
            </default-service-exception-strategy>
        </service>
    </model>
</mule>

As you can see I have defined a JmsToObject translator but I am not needing this in this test case since I use a vm queue as input. But when you are using a real JMS queue as input you must uncomment the transformer so it is used before the custom transformer.
Here is the code of my test class:

package net.pascalalma.mule.transformer;

import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.mule.api.MuleMessage;
import org.mule.module.client.MuleClient;
import org.mule.tck.FunctionalTestCase;

public class TransformerTestCase extends FunctionalTestCase {

    private Context context = null;

    protected String getConfigResources() {
        return "muleproject-functional-test-config.xml";
    }

    public TransformerTestCase() throws NamingException {
        super();

        Properties props = new Properties();
        props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
                "org.apache.openejb.client.LocalInitialContextFactory");
        context = new InitialContext(props);
    }

    public void testRequestReplyJms() throws Exception {

        MuleClient client = new MuleClient();

        MuleMessage msg = client.send("vm://myqueue", getTestCustomerXml(), null);

    }

    private String getTestCustomerXml() {
        return "\n" +
                "\t1\n" +
                "\tPalma IT\n" +
                "\t<address>Papendrecht, Holland</address>\n" +
                "\n";
    }
}

To complete this example here is the pom file and here is an overview of the complete project in Netbeans:

Advertisement

About Pascal Alma

Pascal is a senior IT consultant and has been working in IT since 1997. He is monitoring the latest development in new technologies (Mobile, Cloud, Big Data) closely and particularly interested in Java open source tool stacks, cloud related technologies like AWS and mobile development like building iOS apps with Swift. Specialties: Java/JEE/Spring Amazon AWS API/REST Big Data Continuous Delivery Swift/iOS
This entry was posted in Mule, XML/ XSD/ XSLT and tagged , , . Bookmark the permalink.