ZiggyStardust
ZiggyStardust

Reputation: 425

How to use XStream in Mule?

I have written three classes implementing XStream. It marshalls/unmarshalls the following XML.

<Message calledProgram="XXX" programName="YYY">
  <Fields>
    <Field name="SupplierName" value="ABC"/>
    <Field name="SupplierNo" value="123456"/>
    <Field name="SupplierCountry" value="AA"/>
    <Field name="TermsOfDelivery" value="5"/>
    <Field name="PaymentTerms" value="90"/>
    <Field name="Currency" value="GBP"/>
  </Fields>
</Message>

How do I use these classes in Mule? It is one Class that uses the other two so it is just one class to use.

I will be receiving an XML like above. I want to transform it to an Object.

It works in plain Java, but how do I use it in a flow. Getting all possible Exceptions from Mule.

Exception in thread "main" org.mule.module.launcher.DeploymentInitException: InstantiationException: xxx.com.GenericClass
at org.mule.module.launcher.application.DefaultMuleApplication.init(DefaultMuleApplication.java:220)
at org.mule.module.launcher.application.ApplicationWrapper.init(ApplicationWrapper.java:64)
at org.mule.module.launcher.DefaultMuleDeployer.deploy(DefaultMuleDeployer.java:46)
at org.mule.tooling.server.application.ApplicationDeployer.run(ApplicationDeployer.java:56)
at org.mule.tooling.server.application.ApplicationDeployer.main(ApplicationDeployer.java:88)
Caused by: org.mule.api.config.ConfigurationException: Error creating bean with name 'MyB24Flow1': Invocation of init method failed; nested exception is org.mule.api.lifecycle.InitialisationException: Unable to initialize XStream (org.mule.api.lifecycle.InitialisationException) (org.mule.api.config.ConfigurationException)
at org.mule.config.builders.AbstractConfigurationBuilder.configure(AbstractConfigurationBuilder.java:52)
at org.mule.config.builders.AbstractResourceConfigurationBuilder.configure(AbstractResourceConfigurationBuilder.java:78)
at org.mule.context.DefaultMuleContextFactory.createMuleContext(DefaultMuleContextFactory.java:80)
at org.mule.module.launcher.application.DefaultMuleApplication.init(DefaultMuleApplication.java:208)
... 4 more


Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'MyB24Flow1': Invocation of init method failed; nested exception is org.mule.api.lifecycle.InitialisationException: Unable to initialize XStream
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1455)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
at org.mule.config.spring.SpringRegistry.doInitialise(SpringRegistry.java:89)
at org.mule.registry.AbstractRegistry.initialise(AbstractRegistry.java:109)
... 14 more
Caused by: org.mule.api.lifecycle.InitialisationException: Unable to initialize XStream
at org.mule.module.xml.transformer.AbstractXStreamTransformer.initialise(AbstractXStreamTransformer.java:52)
at org.mule.processor.chain.AbstractMessageProcessorChain.initialise(AbstractMessageProcessorChain.java:79)
at org.mule.construct.AbstractFlowConstruct.initialiseIfInitialisable(AbstractFlowConstruct.java:309)
at org.mule.construct.AbstractPipeline.doInitialise(AbstractPipeline.java:161)
at org.mule.construct.AbstractFlowConstruct$1.onTransition(AbstractFlowConstruct.java:111)
at org.mule.construct.AbstractFlowConstruct$1.onTransition(AbstractFlowConstruct.java:105)
at org.mule.lifecycle.AbstractLifecycleManager.invokePhase(AbstractLifecycleManager.java:141)
at org.mule.construct.FlowConstructLifecycleManager.fireInitialisePhase(FlowConstructLifecycleManager.java:81)
at org.mule.construct.AbstractFlowConstruct.initialise(AbstractFlowConstruct.java:104)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1581)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1522)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)
... 25 more

Update:

Though this is not my real code. But how do you mean OOTB? This doesn't work either. Have tried without the File-2-String as well.

<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:file="http://www.mulesoft.org/schema/mule/file" xmlns:mulexml="http://www.mulesoft.org/schema/mule/xml" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:spring="http://www.springframework.org/schema/beans" version="CE-3.3.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/xml         http://www.mulesoft.org/schema/mule/xml/current/mule-xml.xsd 
http://www.mulesoft.org/schema/mule/file     http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd 
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd 
http://www.mulesoft.org/schema/mule/core   http://www.mulesoft.org/schema/mule/core/current/mule.xsd ">
    <flow name="MyXStreamFlow1" doc:name="MyXStreamFlow1">
    <file:inbound-endpoint path="E:\JavaDev\Test" responseTimeout="10000" doc:name="File"/>
    <logger level="INFO" doc:name="Logger"/>
    <file:file-to-string-transformer doc:name="File to String"/>
    <logger message="WTF" level="INFO" doc:name="Logger"/>
    <mulexml:xml-to-object-transformer doc:name="XML to Object"/>
    <logger level="INFO" doc:name="Logger"/>
    <mulexml:object-to-xml-transformer doc:name="Object to XML"/>
    <logger level="INFO" doc:name="Logger"/>
</flow>

Here's my main Java Class.

package test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.io.xml.DomDriver;

@XStreamAlias("Message")
public class GenericClass {

@XStreamAlias("calledProgram")
@XStreamAsAttribute
private String calledProgram;

@XStreamAlias("programName")
@XStreamAsAttribute
private String programName;

@XStreamAlias("Fields")
private Fields flds = new Fields(
    new Field("nameValue1", "valueValue1"),
    new Field("nameValue2", "valueValue2"),
    new Field("nameValue3", "valueValue2"));

private static XStream xstream;

public GenericClass() {
    new GenericClass("calledProgram", "programName");
}

public GenericClass(String calledProgram, String programName) {
    xstream = new XStream(new DomDriver());
    xstream.processAnnotations(GenericClass.class);
    this.calledProgram = calledProgram;
    this.programName = programName;
}

public static void main(String[] args) {

    GenericClass msg = new GenericClass();

    // Unmarshall
    FileInputStream file = null;
    try {
        file = new FileInputStream(
                "E:\\JavaDev\\JRecordFiles\\Samples\\LevisTest.xml");
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
     msg = (GenericClass) xstream.fromXML(file);
     System.out.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + xstream.toXML(msg));
}
}

-

package test;

import com.thoughtworks.xstream.annotations.XStreamAsAttribute;


public class Field {

private String field;

@XStreamAsAttribute
private String name;

@XStreamAsAttribute
private String value;

/**
 * @param field
 */
public Field(String name, String value) {
    this.name = name;
    this.value = value;
}

/**
 * @return the field
 */
public String getField() {
    return field;
}

/**
 * @param field
 *            the field to set
 */
public void setField(String field) {
    this.field = field;
}

/**
 * @return the name
 */
public String getName() {
    return name;
}

/**
 * @param name
 *            the name to set
 */
public void setName(String name) {
    this.name = name;
}

/**
 * @return the value
 */
public String getValue() {
    return value;
}

/**
 * @param value
 *            the value to set
 */
public void setValue(String value) {
    this.value = value;
}

}

-

package test;

import java.util.Arrays;
import java.util.List;

import com.thoughtworks.xstream.annotations.XStreamImplicit;



public class Fields {

@XStreamImplicit(itemFieldName = "Field")
private List<Field> fields;

public Fields(Field... field) {
    this.fields = Arrays.asList(field);
}

/**
 * @return the fields
 */
public List<Field> getFields() {
    return fields;
}

/**
 * @param fields
 *            the fields to set
 */
public void setFields(List<Field> fields) {
    this.fields = fields;
}

}

How do I use XStream in Mule?

Upvotes: 3

Views: 2838

Answers (3)

TimPietrusky
TimPietrusky

Reputation: 778

The problem

The default Object to XML transformer only supports the alias annotation for classes:

<mulexml:object-to-xml-transformer doc:name="Object to XML">
    <mulexml:alias name="myAlias" class="com.my.package.MyClass"/>
</mulexml:object-to-xml-transformer>

and ignores every other annotation. There is a already an issue since July 2012 on the official bug tracker, but it's unresolved until now.

Solution: Custom XML to Object transformer

1. Create the transformer

Create a custom transformer in Java which extends AbstractMessageTransformer:

public class ObjectToXml extends AbstractMessageTransformer {

  public Object transformMessage(MuleMessage message, String outputEncoding) throws TransformerException {

    XStream xstream = new XStream();

    // The payload should be the object to transform into XML
    Object object = message.getPayload();

    // Register all annotations in the XStream instance 
    xstream.processAnnotations(object.getClass());

    // Convert the object to XML and set it as payload
    message.setPayload(xstream.toXML(object));

    return message;
  }
}

2. Use the custom transformer in your Mule flow

Add a Java Transfromer (not Java Component) to your flow:

<custom-transformer class="com.my.package.ObjectToXml" doc:name="Object to XML"/>

That's it!

Upvotes: 3

David Dossot
David Dossot

Reputation: 33413

I haven't been able to configure the xml-to-object-transformer so it works OOTB with your XStream annotated classes. The only way I've been able to load the XML sample above and have your flow process it successfully is by using Spring to instantiate and configure XStream as shown below:

<spring:beans>
    <spring:bean name="xStream" class="com.thoughtworks.xstream.XStream" />
    <spring:bean
        class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
        p:targetObject-ref="xStream"
        p:targetMethod="processAnnotations">
        <spring:property name="arguments">
            <spring:list>
                <spring:value>test.GenericClass</spring:value>
            </spring:list>
        </spring:property>
    </spring:bean>
</spring:beans>

With this in place I use the following in lieu of the xml-to-object-transformer:

<expression-transformer
    expression="#[app.registry.xStream.fromXML(message.payload)]" />

I realize this is not super great so hopefully someone else will have a better solution.

Upvotes: 2

genjosanzo
genjosanzo

Reputation: 3264

The Xml to object transformer internally uses Xstream so it should work OOTB.

Please provide the flow configuration and I will update my answer accordingly.

Upvotes: 0

Related Questions