Issue
I am converting JSON to CSV using Spring Boot 2.6.2, Apache Camel 2.25.0, JDK 1.8.
Below is the Camel Route code snippet that I am using for this:
@Override
public void configure() throws Exception {
// Receive from JSON file
from("file:files/input")
.log("Received file - ${body}")
// transform JSON to CSV format
.unmarshal().json()
.marshal().csv()
// Write to output file
.log("Writing file - ${body}")
.to("file:files/output");
}
Source Code: https://github.com/DebeshNayak/camel-json-to-csv
This application builds successfully, but during runtime, I am getting the below error:
2022-01-04 11:10:47.813 INFO 14788 --- [e://files/input] route1 : Received file - {
"fname": "debesh",
"lname": "nayak"
}
2022-01-04 11:10:47.862 ERROR 14788 --- [e://files/input] o.a.camel.processor.DefaultErrorHandler : Failed delivery for (MessageId: ID-Debesh-Lenovo-i5-1641274844914-0-2 on ExchangeId: ID-Debesh-Lenovo-i5-1641274844914-0-1). Exhausted after delivery attempt: 1 caught: com.thoughtworks.xstream.mapper.CannotResolveClassException: fname
Message History
---------------------------------------------------------------------------------------------------------------------------------------
RouteId ProcessorId Processor Elapsed (ms)
[route1 ] [route1 ] [file://files/input ] [ 60]
[route1 ] [log1 ] [log ] [ 20]
[route1 ] [unmarshal1 ] [unmarshal[org.apache.camel.model.dataformat.JsonDataFormat@5bb0a7b2] ] [ 28]
Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------
com.thoughtworks.xstream.mapper.CannotResolveClassException: fname
at com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper.java:81) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.mapper.DynamicProxyMapper.realClass(DynamicProxyMapper.java:55) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.mapper.PackageAliasingMapper.realClass(PackageAliasingMapper.java:88) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.mapper.ClassAliasingMapper.realClass(ClassAliasingMapper.java:79) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.mapper.ArrayMapper.realClass(ArrayMapper.java:74) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.mapper.SecurityMapper.realClass(SecurityMapper.java:71) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:125) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.mapper.CachingMapper.realClass(CachingMapper.java:47) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.core.util.HierarchicalStreams.readClassType(HierarchicalStreams.java:29) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:133) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1487) ~[xstream-1.4.11.1.jar:1.4.11.1]
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1455) ~[xstream-1.4.11.1.jar:1.4.11.1]
at org.apache.camel.dataformat.xstream.AbstractXStreamWrapper.unmarshal(AbstractXStreamWrapper.java:374) ~[camel-xstream-2.25.0.jar:2.25.0]
at org.apache.camel.processor.UnmarshalProcessor.process(UnmarshalProcessor.java:69) ~[camel-core-2.25.0.jar:2.25.0]
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:548) ~[camel-core-2.25.0.jar:2.25.0]
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201) [camel-core-2.25.0.jar:2.25.0]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:138) [camel-core-2.25.0.jar:2.25.0]
at org.apache.camel.processor.Pipeline.process(Pipeline.java:101) [camel-core-2.25.0.jar:2.25.0]
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201) [camel-core-2.25.0.jar:2.25.0]
at org.apache.camel.component.file.GenericFileConsumer.processExchange(GenericFileConsumer.java:454) [camel-core-2.25.0.jar:2.25.0]
at org.apache.camel.component.file.GenericFileConsumer.processBatch(GenericFileConsumer.java:223) [camel-core-2.25.0.jar:2.25.0]
at org.apache.camel.component.file.GenericFileConsumer.poll(GenericFileConsumer.java:187) [camel-core-2.25.0.jar:2.25.0]
at org.apache.camel.impl.ScheduledPollConsumer.doRun(ScheduledPollConsumer.java:174) [camel-core-2.25.0.jar:2.25.0]
at org.apache.camel.impl.ScheduledPollConsumer.run(ScheduledPollConsumer.java:101) [camel-core-2.25.0.jar:2.25.0]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_312]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [na:1.8.0_312]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_312]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [na:1.8.0_312]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_312]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_312]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_312]
In my project I am using below Maven dependency in the pom.xml:
<properties>
<java.version>1.8</java.version>
<camel.version>2.25.0</camel.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-stream-starter</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jackson</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-xstream</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-csv</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
But while using Apache Camel 3.4.2, it is working properly.
Solution
Camel supports a couple of different JSON libraries, and it just so happens that Camel 3 changed its default JSON library from XStream to Jackson, which might be why the code isn't working here. (See CAMEL-5836 for info about the change). The default library is used whenever you use the .json()
keyword on its own.
So if you want to use this code with Camel 2.x, or to customise the JSON marshalling/unmarshalling in any way, you can instantiate Jackson explicitly first, and then refer to it in the route, e.g.:
JacksonDataFormat json = new JacksonDataFormat();
// You can also set any Jackson options here
from("file:files/input")
.log("Received file - ${body}")
// transform JSON to CSV format, referring to the "json" object above
.unmarshal(json)
.marshal().csv()
// Write to output file
.log("Writing file - ${body}")
.to("file:files/output");
}
Working with Jackson is a lot simpler than XStream, because it can unmarshal to a simple Java object like a Map, without much configuration.
Answered By - Tom Donohue
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.