I am creating a generic adapter which would take XML message (with namepace) and convert it to JSON. I can remove the namespace using xslt and then use org.json api to conver to JSON and there are some other transformation and using the SI flow -
return IntegrationFlows
.from(org.springframework.integration.jms.dsl.Jms.messageDrivenChannelAdapter(
org.springframework.integration.jms.dsl.Jms.container(this.queueConnFactory, this.queue)
.transactionManager(transactionManager()).get()))
.transform(dynamicEnricherImpl.get(enricherName), "enrich")
.handle(publisher, "publishMessage")
.get();
I am looking if the same can be achieved using SPring Integration inner classes like ObjectToJSON transformer to remove the XML namespace and convert it to JSON. Please suggest
I don't understand how you really do a conversion from XML to JSON. Would you mind to share some sample with your XSLT and that org.json? And of course, with an original XML and final JSON.
What I would do in Spring Integration is something like UnmarshallingTransformer where we create some domain model from the XML using Marshaller abstraction.
Then when we have already a Java POJO it is easy to call the mentioned ObjectToJsonTransformer and you'll get a JSON on the output.
It is also possible to apply a XPathTransformer to get some value from the XML and so on.
Please, read more about XML support in docs: https://docs.spring.io/spring-integration/docs/5.3.0.M4/reference/html/xml.html#xml
Related
I'm trying to use resteasy-rxjava2 to provide an XML document using jaxb, within a vertx application (using a non-vertx legacy library we have). But I get:
Could not find MessageBodyWriter for response object of type:
org.jboss.resteasy.rxjava2.propagation.ContextPropagatorOnSingleAssemblyAction$ContextPropagatorSingle of media type:
application/xml;charset=UTF-8
From what I can tell, this comes down to the difference between a MessageBodyWriter and the AsyncResponseProvider that is in the resteasy-rxjava2 dependency for a Single (SingleProvider).
I have the following resteasy service definition
#GET
#Path(FdsnwsPaths.QUERY)
#Produces(MediaType.APPLICATION_XML)
#Stream
// CHECKSTYLE:OFF too many parameters
public Response getQuery(...)
How do I get resteasy to properly serve the data asynchrously, using the SingleProvider or otherwise.
The #Get method must return the Single explicitly or it doesn't work. (Can't use Response or Object). In my case, the Single contains the jaxb xml root element.
#GET
#Path(FdsnwsPaths.QUERY)
#Produces(MediaType.APPLICATION_XML)
#Stream
public Single<FDSNStationXML> getQuery(...)
Then, to make things more complicated, in order to handle specific exception types and map them to specific response status codes, I have to create a custom ExceptionMapper which creates the Response object I used to be able to create directly in the method. (in resteasy-vertx, I found no documentation on how to do this, but in my case, I am creating my own VertxRestEasyDeployment object so I can register the class of the ExceptionMapper(s) like this:
VertxResteasyDeployment deployment = new VertxResteasyDeployment();
deployment.getActualProviderClasses().addAll(providerClasses);
For reference, this is all being done with:
RestEasy 5.0.3.Final (including resteasy-rxjava2)
RxJava 2.2.20
Vertx 3.9.5
I want to transform a LinkedHashMap Payload to Object Payload in mule , i used the Byte Array to Object transformer but it dosent work for me , any idea guys ?
you can use dataweave to transform a payload of generic type (=java.util.Map) to a specific type (foo.bar.Type in the example):
%dw 1.0
%output application/java
---
payload as :object {
class: "foo.bar.Type"
}
You seem to mention specifically the Object type. A LinkedHashMap is already an instance of Object: every Java instances inherit from the root class Object.
If you want to transform your HashMap into a specific object such as JSON or a custom object such as com.mycompany.CompData, you have several possibilities depending on your use case:
use DataWeave as mentioned in other answers (require EE)
use a built-in transformer such as Object-to-JSON
implement your own Transformer by extending AbstractTransformer
Se the docs for details: https://docs.mulesoft.com/mule-user-guide/v/3.8/using-transformers
If you may be more specific as to what your use case is I'll gladly refine my answer ;)
You can use either dataweave or json to object transformer.
I have an integration with some flows and JAXBcontext declared like this
<mulexml:jaxb-context name="JaxbContext" packageNames="se.razorlib.SystemAProduct:se.razorlib.SystemAPurchase:se.razorlib.SystemAOrder"/>
In one of my flows I transform XML to Purchase and in another XML to Order, which are very similar objects.
However, in the Order flow JAXB transforms my XML to PurchaseObject instead of OrderObject, which of course throws me an error:
The object transformed is of type: "SimpleDataType{type=se.razorlib.SystemAPurchase.Header, mimeType='*/*', encoding='null'}", but the expected return type is "SimpleDataType{type=se.razorlib.SystemAOrder.Header, mimeType='*/*', encoding='null'}"
This is my configuration, how can I force a tranfsformation to the "right" object?
<file:inbound-endpoint path="C:\temp\OrderfileIn" responseTimeout="10000" doc:name="FileIn"/>
<mulexml:jaxb-xml-to-object-transformer jaxbContext-ref="JAXB_Context" doc:name="XML to JAXB Object" returnClass="se.razorlib.SystemAOrder.Header"/>
<custom-transformer returnClass="se.razorlib.SystemBOrder.SalesOrder" encoding="UTF-8" class="se.didriksson.Transformer.Map2SystemBOrder" doc:name="Map2B"/>
To pick the correct bean class you have to place the
#XmlRootElement(name = "Order")
Instead of order you may have to put the root element of your xml.
Another point
I also face an issue with mule 3.7 which is it doesn't read package.info file in the package
I am using SI 4.0 and trying to use object-to-map-transformer as below
<integration:object-to-map-transformer input-channel="inputChannel"
output-channel="outChannel" >
</integration:object-to-map-transformer>
I am sending a object like Person class on the inputChannel. But the moment I fire my test it fails with following error
Caused by: java.lang.IllegalStateException: Neither jackson-databind.jar,
nor jackson-mapper-asl.jar aren't presented in the classpath. at
org.springframework.integration.support.json.JacksonJsonUtils.<clinit>(JacksonJsonUtils.java:41)
I dont understand why it needs jackson. I looked at SI code and can see it needs Jackson class but why is this need - when I simply need to map a simple object to Map?
Thanks
The code to convert object to map looks like:
Map<String,Object> result = this.jsonObjectMapper.fromJson(this.jsonObjectMapper.toJson(payload), Map.class);
Since the out of the box implementation for the JsonObjectMapper is Jackson, it requires that the last one should be presented in the classpath.
We decided to use JSON notation for the Map presentation, since any object in JSON has map-based structure.
If you have another algorithm to do the same, the contribution is welcome!
Or you can simply implement your own Transformer with that logic and use it from generic <transformer>.
Basically, I have some models which all use JAXB. However, I have some highly custom functionality to convert to JSON and back so I want to write my own MessageBodyReader/Writer to do the job for me.
Right now, the writing portion is done: if i return one of my models from a REST resource, it goes through my writer. But when I try and accept a model as a FormParam, it doesnt use my MessageBodyReader and instead attempts to unmarshal it using JAXB (which fails).
So how I can tell Jersey to use my Reader instead?
public TestModel testProvider(#FormParam("model") TestModel input){ //doesnt work
return new TestModel(); //this part works!
}
Mark as #Provider
Add the configuration to your web.xml EX:
<init-param><param-name>com.sun.jersey.config.property.packages</param-name> <param-value> your.package.that.contains.the.provider </param-value> </init-param>
Since your writer works, but your reader does not, I'm guessing you have just missed something in your configuration. Some things to check:
Do you have the #Provider annotation on your reader?
Did you correctly implement the isReadable method on your reader?
Do you have the appropriate #Consumes annotation on the reader, does its media type match the media type specified on your service method?