Mule 3.3 can automatically unmarshall an XML string to an object using JAXB given that:
1. you first register your jaxb annotated classes with spring.
2. there is a component that requires such type as input
So I have managed to do the transformation, but I had to create a "DumbTransformer" that does nothing. It has a method that returns the same object it receives. I need it in order to trigger the XML to Object conversion so that I can further process the message.
Flow Example:
<spring:beans>
<spring:bean id="dumbTransformer" class="foo.bar.DumbTransformer"/>
</spring:beans>
<flow name="main" doc:name="main">
<vm:inbound-endpoint path="in" doc:name="VM" />
<component doc:name="Java">
<spring-object bean="dumbTransformer"/>
</component>
<splitter expression="#[payload.items]" doc:name="Split Items"/>
<logger message="#[payload]" level="INFO" doc:name="Log Item"/>
<vm:outbound-endpoint path="out" doc:name="VM" />
</flow>
DumbTransformer.java
package foo.bar;
#ContainsTransformerMethods
public class InvoiceUnmarshaller extends AbstractTransformer {
#Transformer
public MyJaxbAnnotatedClass foo(#Payload MyJaxbAnnotatedClass i) {
return i;
}
}
Is there a way to acomplish this without having to create such DumbTransformers?
Thanks.
As you guessed it, the JAXB deserialization doesn't occur because there is no component to satisfy:
there is a component that requires such type as input
So what if you had an auto-transformer to do just that:
<auto-transformer returnClass="foo.bar.MyJaxbAnnotatedClass" />
The Mule XML Module provides OOTB a JAXB Transformer. I would rather leverage mule capabilities whenever possible rather than writing custom code
Related
I'm currently working with citrus-framework to test an application.
One of my interfaces uses Protobuf and I would like to implement a protobuf-to-json-transformer which is compatible with spring-integration to use it similarly like the following but with my transformer instead of the object-to-string-transformer:
<int:channel id="configRawReplies" />
<int:object-to-string-transformer id="configtransformer" input-channel="configRawReplies" output-channel="configResponse" />
<int:channel id="configResponse">
<int:queue />
</int:channel>
for now I have a prototyp exactly like object-to-string-transformer and I'm loading it with:
<bean id="Proto2Json" class="com.nobody.citrus.transformer.ProtoToJSONString">
<property name="input-channel" value="none"/>
<property name="output-channel" value="none"/>
</bean>
but it fails.
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'Proto2Json' defined in URL [file:/Users/nobody/DevOops/test/citrus-scala/target/test-classes/citrus-context.xml]:
Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException:
Invalid property 'input-channel' of bean class [com.pme.citrus.transformer.ProtoToJSONString]:
Bean property 'input-channel' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
Does somebody have an idea or an hint where to look on the web?
BR
That's correct. You really need to follow a design in the ObjectToStringTransformer to implement your own AbstractPayloadTransformer. And that one has to be as a plain <bean> definition in your application context.
Only the problem that you don't understand why we really have all those custom tags to utilize input-channel and output-channel attributes as well. The point is that this
<int:object-to-string-transformer>, for example, provides for the application context several beans, including the mentioned ObjectToStringTransformer instance, a MessageTransformingHandler and, finally, ConsumerEndpointFactoryBean to connect a MessageHandler with an inputChannel.
So, what you are missing here is a generic <int:transformer> definition for your custom AbstractPayloadTransformer implementation:
<bean id="Proto2Json" class="com.nobody.citrus.transformer.ProtoToJSONString"/>
<int:tranformer ref="Proto2Json" input-channel="configRawReplies" output-channel="configResponse"/>
Please, read more Reference Manual to avoid similar discussions in the future:
https://docs.spring.io/spring-integration/reference/html/overview.html#programming-tips
https://docs.spring.io/spring-integration/reference/html/messaging-transformation-chapter.html
So this one makes me wonder. I have a Mule integration with a couple of flows in it and they all work nice. Except for the last one.
If I end that one in a file endpoint, it works as expected. But if I end it in my WS POST service.. I get an error complaining about multiple JAXB contexts.
I have multiple JAXB contexts but as said they work fine if I'm not trying to post my JSON to that REST service.
And somehow, I can't see that my HTTP endpoint has anything to do with JAXB either so I guess it's a misguiding error?
But then, what is wrong with my HTTP endpoint, I use it as inbound in the other flows and also tried to create an entirely new one for this particular flow, but still this nagging about JAXB.
<http:request-config name="WS" host="127.0.0.1" port="81" doc:name="HTTP Request Configuration" basePath="WSService"/>
<http:request-config name="MQService" host="127.0.0.1" port="82" doc:name="HTTP Request Configuration" />
<mulexml:jaxb-context name="JAXB_A" packageNames="se.razorlib.SystemAProduct" doc:name="JAXB Context"/>
<mulexml:jaxb-context name="JAXB_B" packageNames="se.razorlib.SystemAPurchase" doc:name="JAXB Context"/>
<mulexml:jaxb-context name="JAXB_C" packageNames="se.razorlib.SystemAOrder" doc:name="JAXB Context"/>
<context:property-placeholder location="razorlib.properties"/>
<flow name="ProductToSystemA">
....
<http:request config-ref="WS" path="Product/REST/GetProduct/{id}/{index}" method="GET" doc:name="WS">
<http:request-builder>
<http:uri-param paramName="id" value="${WS.id}"/>
<http:uri-param paramName="index" value="1"/>
</http:request-builder>
</http:request>
.....
</flow>
<flow name="PurchaseToSystemA">
.....
</flow>
.....
and this particular flow
<flow name="PurchaseDeliver">
<file:inbound-endpoint path="C:\temp\fileIn" responseTimeout="10000" doc:name="FileIn"/>
<mulexml:jaxb-xml-to-object-transformer returnClass="se.razorlib.SystemAPurchase.Header" encoding="UTF-16" jaxbContext-ref="JAXB_B" doc:name="XML to JAXB Object"/>
<custom-transformer returnClass="java.util.List" encoding="utf-16" class="se.razorlib.Transformer.Map2ZZPurchase" doc:name="Map2ZZ"/>
<json:object-to-json-transformer encoding="UTF-16" doc:name="Object to JSON"/>
<logger message="'Payload ' #[payload]" level="INFO" doc:name="Logger"/>
<http:request config-ref="WS" path="PurchaseSvc/REST/Deliver/{id}" method="POST" doc:name="WSDeliver">
<http:request-builder>
<http:uri-param paramName="id" value="${WS.id}"/>
</http:request-builder>
</http:request>
<!-- <file:outbound-endpoint path="C:\temp\fileOut" responseTimeout="10000" doc:name="File" outputPattern="inkop2ZZ-#[function:dateStamp].json" mimeType="text/json" encoding="UTF-8"/> -->
<catch-exception-strategy doc:name="Catch Exception Strategy">
<logger message="Oh no!!" level="INFO" doc:name="Logger"/>
<file:outbound-endpoint path="C:\temp\fileError" responseTimeout="10000" doc:name="File" outputPattern="error-inkop2ZZ-#[function:dateStamp].xml" mimeType="text/xml" encoding="UTF-8"/>
</catch-exception-strategy>
</flow>
The error I get is this one:
Root Exception stack trace:
org.mule.api.registry.RegistrationException: More than one object of type class javax.xml.bind.JAXBContext registered but only one expected.
Regards
I have seen a similar scenario's, this might be because of Multiple jaxb-context. Resolved by placing all the packages in one Context
<mulexml:jaxb-context name="JaxbContext" packageNames="se.razorlib.SystemAProduct:se.razorlib.SystemAPurchase:se.razorlib.SystemAOrder"/>
In flow
<mulexml:jaxb-xml-to-object-transformer returnClass="se.razorlib.SystemAPurchase.Header" encoding="UTF-16" jaxbContext-ref="JaxbContext" doc:name="XML to JAXB Object"/>
Hope this helps.
First I would not be surprised that the file endpoint gave no error. The file doesn't care what it gets. It just wants ones and zeros. I somewhat agree with the answer above but I think you only need to reference the package for the three Java bindings.
<mulexml:jaxb-context name="myJaxb" packageNames="se.razorlib"/>
You are defining the context for JAXB transformations. The package says it all.
In my application i have a router that dinamically send XML tag to the appropiate channel:
<!-- Route each tag to the appropiate channel -->
<int-xml:xpath-router id="router" input-channel="routerChannel" evaluate-as-string="true">
<int-xml:xpath-expression expression="concat(name(./node()), 'Channel')" />
</int-xml:xpath-router>
Using this XML this route each tag to serviceChannel and activityChannel
<root>
<service attr1="x" attr2="y" />
<activity anotherAttr="W" />
</root>
My service activator(S) POJO are something like this:
class Service {
private String attr1;
private String attr2;
/* Setter and getter omitted */
}
And this is the applicationContext.xml configuration:
<!-- Service activators -->
<int:service-activator input-channel="serviceChannel" method="schedule">
<bean class="it.mypkg.Service" />
</int:service-activator>
The router send the entire Node to bean and i will need to extract the attributes "by hand".
There is a way to "unmarshall" the Node so in attr1 and attr2 i will get the value provided in XML ?
Usally i do this with a simple Unmarshaller (using JAXB) and adding the annotations #XmlRootElement, #XmlAttribute and so on.
I think before pass to POJO i will need to use SI-XML UnmarshallingTransformer but i really dont know how to do this... moreover this should be "enough general" to handle all tags (sure, all POJO classes like Service and Activity will have #XmlAttribute etc)
Use an Unmarshalling Transformer and then route on the unmarshalled objects.
The generated classes from my WSDL using wsimport are not having equals() and hashcode() methods. How can I customize and generate the client classes to get equals() and hashcode() methods.
I am not sure about using JAXB to achieve this.
In Axis2.0 generated stubs these methods are generated but not sure why such a basic thing is not available in JAXWS!
You can use the JAXB2 Basics Plugin to generate equals() and hashcode() methods:
https://github.com/highsource/jaxb2-basics
http://confluence.highsource.org/display/J2B/JAXB2+Basics+Plugins
If you are looking to generate hashcode() and equals() using wsimport in maven, check this answer on how to generate value constructors, but also includes the configuration for generating hashcode() and equals() too:
How do I make wsimport generate constructors?
More information on how it worked.
I have to add classpath to jaxb2-commons and without which wsimport runs without complaining but nothing happens! After adding the classpath as below
<path id="jaxb2-commons.classpath">
<fileset dir="${dir.toolchain}/noarch/jaxb2-basics-dist-0.6.0">
<include name="**/*.jar" />
</fileset>
</path>
the below wsimport worked as expected
<wsimport wsdl="#{dir-wsdl}/#{name-wsdl}"
taskname="wsimport-#{service}"
destdir="#{dest-dir}"
sourcedestdir="#{source-dest-dir}"
package="#{package}"
keep="#{keep}"
verbose="#{verbose}"
xdebug="#{xdebug}"
xnocompile="#{xnocompile}"
target="2.1">
<binding dir="#{dir-wsdl}" includes="bindings-wsdl-#{name-wsdl}.xml, bindings-schema-#{name-wsdl}.xml" />
<xjcArg value="-Xequals" />
<xjcArg value="-XhashCode" />
<xjcArg value="-XtoString" />
<!-- Generates per-package jaxb.index file which lists all of the schema-derived classes in this package.-->
<xjcArg value="-Xjaxbindex" />
<xjcArg value="-Xsetters" />
</wsimport>
Info: C# , VS2010 Beta 2 , DSL ToolKit Beta 2
I am trying to create the following generated XML in my DSL Diagram when used
<Method>
...
<FilterDescriptors>
<FilterDescriptor Type="Comparison" Name="EmployeeKey" />
</FilterDescriptors>
...
</Method>
This is how the Method and Filter Descriptor Domain Classes look
I believe I have set the multiplicity correct:
Method should only have 1 Filter Descriptor
A Filter Descriptor can have many Filter Descriptors i.e
<FilterDescriptors>
<FilterDescriptor Type="Comparison" Name="EmployeeKey" />
<FilterDescriptor Type="Wildcard" Name="EmployeeName" />
</FilterDescriptors>
The issue is that the output XML is like this:
<FilterDescriptors>
<FilterDescriptor>
<FilterDescriptors>
<FilterDescriptor Type="Comparison" Name="EmployeeKey" />
</FilterDescriptors>
</FilterDescriptor>
</FilterDescriptors>
We have this same pattern is several locations in our DSL Diagram and was hoping there is a something simple to resolve this rather than overriding the ReadElements and WriteElements of each domain class
Have you posted this in the DSL Tools forum at http://social.msdn.microsoft.com/Forums/en-US/dslvsarchx/threads? I don't see a thread there for it.