Spring batch itemwriter interface - java

The write method of Itemwriter has been changed in the spring version 5.
#Override
public void write(List<? extends List<DataDTO>> items) throws Exception{
for(List<DataDTO> sublist:items){
writer.write(sublist);
}
The above writer is FlatFileItemWriter.
I changed to the following
#Override
public void write(Chunk<? extends List<DataDTO>> items) throws Exception{
for(List<DataDTO> sublist:items){
writer.write((Chunk<? extends DataDTO>)sublist);
}
}
Is this correct way of replacing/fix? need some help.
Im expecting the correct fix.

Related

Apache camel process(processor) method is not being called

I saw in another post how manually adding the camel context and starting it should work, but it hasn't for me. I double checked the from, and to paths and they seem to be correct. Not sure why it's not calling the method and would appreciate some advice
public class CsvRouteBuilder extends DdsRouteBuilder {
private CsvConverterProcessor csvConverterProcessor;
private CamelContext camelContext;
#Autowired
public CsvRouteBuilder(CsvConverterProcessor csvConverterProcessor) throws Exception {
this.csvConverterProcessor = csvConverterProcessor;
camelContext.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("{{input.files.csv}}")
.routeId("CSVConverter")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("hitting");
}
})
.to("{{output.files.csv}}");
}
});
camelContext.start();
}
The processor is not called simply because your route is not properly declared such that Spring Boot is not aware of it.
The proper way is to make your class extend RouteBuilder to define your route(s) and annotate your class with #Component to mark it as candidate for auto-detection when using annotation-based configuration and classpath scanning.
Your code should rather be something like this:
#Component
public class CsvRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
from("{{input.files.csv}}")
.routeId("CSVConverter")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("hitting");
}
})
.to("{{output.files.csv}}");
}
}

Spring Batch - Using an ItemWriter with List of Lists

Our processor returns a List<?> (effectively passing a List<List<?>>) to our ItemWriter.
Now, we observed that the JdbcBatchItemWriter is not programmed to handle item instanceof List. We also observed to process item instanceof List; we need to write a custom ItemSqlParameterSourceProvider.
But the sad part is that it returns SqlParameterSource which can handle only one item and again not capable of handling a List.
So, can someone help us understand how to handle list of lists in the JdbcBatchItemWriter?
Typically, the design pattern is:
Reader -> reads something, returns ReadItem
Processor -> ingests ReadItem, returns ProcessedItem
Writer -> ingests List<ProcessedItem>
If your processor is returning List<Object>, then you need your Writer to expect List<List<Object>>.
You could do this by wrapping your JdbcBatchItemWriter as a delegate in an ItemWriter that looks something like this:
public class ListUnpackingItemWriter<T> implements ItemWriter<List<T>>, ItemStream, InitializingBean {
private ItemWriter<T> delegate;
#Override
public void write(final List<? extends List<T>> lists) throws Exception {
final List<T> consolidatedList = new ArrayList<>();
for (final List<T> list : lists) {
consolidatedList.addAll(list);
}
delegate.write(consolidatedList);
}
#Override
public void afterPropertiesSet() {
Assert.notNull(delegate, "You must set a delegate!");
}
#Override
public void open(ExecutionContext executionContext) {
if (delegate instanceof ItemStream) {
((ItemStream) delegate).open(executionContext);
}
}
#Override
public void update(ExecutionContext executionContext) {
if (delegate instanceof ItemStream) {
((ItemStream) delegate).update(executionContext);
}
}
#Override
public void close() {
if (delegate instanceof ItemStream) {
((ItemStream) delegate).close();
}
}
public void setDelegate(ItemWriter<T> delegate) {
this.delegate = delegate;
}
}
public class ListUnpackingItemWriter<T> implements FlatFileItemWriter<List<T>>, ItemStream, InitializingBean {
#Override
public void afterPropertiesSet() {
setLineAggregator(item -> String.join("\n", item.stream().map(T::toString).collect(Collectors.toList())));
}
}
Just added a custom line aggregator to the above solution, this helps in writing the content to a file by using FlatFileItemWriter<List<T>>. You can replace T with actual class name to avoid compilation error while calling toString() method.

Camel and ActiveMQ

I´m very new on the camel world, that is why I´m asking for your help.
Let me tell you what I would like to do:
I have this basic Camel standalone project:
package maventest1;
public class JmsToSql {
private Main main;
public static void main(String[] args) throws Exception {
JmsToSql example = new JmsToSql();
example.boot();
}
public void boot() throws Exception {
main = new Main();
main.enableHangupSupport();
main.bind("foo", new MyBean());
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
main.bind("test-jms",JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
main.addRouteBuilder(new MyRouteBuilder());
main.run();
}
private static class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
from("timer:foo?delay=2000")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
//NOT SURE THIS IS THE RIGHT WAY
from("test-jms:queue:order1")
.to("test-jms:queue:order2");
}
})
.beanRef("foo");
}
}
public static class MyBean {
public void callMe() {
System.out.println("MyBean.calleMe method has been called");
}
}
}
All I want to do is read all the messages from an activeMQ queue and pass them into another queue. Does anybody know how I can do this?
Thanks in advance =D
Just do a route from JMS to JMS
private static class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
from("test-jms:queue:order1")
.to("test-jms:queue:order2");
}
As you are new to Camel, I recommend to also read this article first
http://java.dzone.com/articles/open-source-integration-apache
And if you want to have great documentation and tutorials, then pickup one of the Camel books
http://camel.apache.org/books

JerseyTest and JUnit throws NullPointerException

I have some problems with the jersey test framework. If i use the #Before and #After annotations, then the target method throws a NullPointerException.
I thought JerseyTest works with JUnit? Where is my problem?
Jersey: 2.12
JUnit: 4.11
Code that fails:
public class MyResourceTest extends JerseyTest {
#Before
public void setUp() { }
#After
public void tearDown() { }
#Override
protected Application configure() {
return new ResourceConfig(MyResource.class);
}
#Test
public void SHOULD_RETURN_BAD_REQUEST() throws IOException {
System.out.println(target("myPath"));
assertEquals(1, 1);
}
}
Result:
java.lang.NullPointerException at
org.glassfish.jersey.test.JerseyTest.target(JerseyTest.java:566) at
org.glassfish.jersey.test.JerseyTest.target(JerseyTest.java:580) at
foo.bar.MyResourceTest.SHOULD_RETURN_BAD_REQUEST(MyResourceTest.java:43)
Code that works:
public class MyResourceTest extends JerseyTest {
#Override
protected Application configure() {
return new ResourceConfig(MyResource.class);
}
#Test
public void SHOULD_RETURN_BAD_REQUEST() throws IOException {
System.out.println(target("myPath"));
assertEquals(1, 1);
}
}
Result:
JerseyWebTarget { http://localhost:9998/myPath }
Your methods seem to override some important initialization made in parent JerseyTest.
Try to name them differently. E.g.:
#Before
public void setUpChild() { }
#After
public void tearDownChild() { }
I came here because I was using JUnit 5 and it seems that it wasn't seeing the #Before and #After annotations on the JerseyTest setup/tearDown methods. I had to override them and use the new JUnit 5 annotations
public class MyResourceTest extends JerseyTest {
#BeforeEach
#Override
public void setUp() throws Exception {
super.setUp();
}
#AfterEach
#Override
public void tearDown() throws Exception {
super.tearDown();
}
#Override
protected Application configure() {
return new ResourceConfig(MyResource.class);
}
#Test
public void SHOULD_RETURN_BAD_REQUEST() throws IOException {
System.out.println(target("myPath"));
assertEquals(1, 1);
}
}

How to test multiple RouteBuilders in Apache Camel

I want to test multiple camel RouteBuilder in a single unit test
what I have:
Custom camel processor that changes state
public class MyProcessor implements Processor {
MyState state;
public MyProcessor(MyState state) {this.state = state;}
#Override
public void process(Exchange exchange) throws Exception {
state.setState(state.getState() + 5);
}}
Two simple RouteBuilders: first routes messages from "direct:start" to "direct:endroute1" second pick up messages from "direct:endroute1" and routes somewhere "mock:endroute2"
public class MyRouteBuilder1 extends RouteBuilder {
MyState state;
public MyRouteBuilder1(MyState state) {this.state = state;}
#Override
public void configure() throws Exception {
from("direct:start").process(new MyProcessor(state)).to("direct:endroute1");
}}
public class MyRouteBuilder2 extends RouteBuilder {
MyState state;
public MyRouteBuilder2(MyState state) {this.state = state;}
#Override
public void configure() throws Exception {
from("direct:endroute1").process(new MyProcessor(state)).to("mock:endroute2");
}}
Writing unit test for a single route builder is straightforward:
public class MyTest extends CamelTestSupport {
MyState state = new MyStateImpl();
#EndpointInject(uri = "mock:result")
protected MockEndpoint resultEndpoint;
#Test
public void testSingleRoute() throws Exception {
resultEndpoint.expectedMessageCount(1);
template.sendBody("direct:start", new Object());
assertTrue(state.getState() == 5);
resultEndpoint.assertIsSatisfied();
}
#Override
protected RouteBuilder createRouteBuilder() {
return new MyRouteBuilder1(state) {
public void configure() throws Exception{
super.configure();
from("direct:endroute1").to("mock:result");
}
};
}
}
What I really want to do is somehow to override CamelTestSupport.createRouteBuilder that will test whole chain of message processing from direct:start to mock:endroute2. As a result state.getState() should be 10
Try to override method:
protected RouteBuilder[] createRouteBuilders() {...}
from CamelTestSupport. It's available since version 2.17
you can just add multiple RouteBuilders to the context using the context.addRoutes(RouteBuilder) API
see this unit test for an example:
https://svn.apache.org/repos/asf/camel/trunk/camel-core/src/test/java/org/apache/camel/builder/AddRoutesAtRuntimeTest.java
You could use one RouteBuilder including the routes of multiple other RouteBuilders.

Categories