...
Note |
---|
|
If you use multiple models, each model has to be placed in it's own package to prevent unpredictable results. From Camel 2.16 onwards this is no longer the case, as you can safely have multiple models in the same package, as you configure bindy using class names instead of package names now. |
Annotations
The annotations created allow to map different concept of your model to the POJO like :
...
For example the following uses the class BindyCsvDataFormat
(who correspond to the class associated with the CSV record type) which is configured with "com.acme.model"
package name to initialize the model objects configured in this package.
Code Block |
---|
// Camel 2.15 or older (configure by package name)
DataFormat bindy = new BindyCsvDataFormat("com.acme.model");
// Camel 2.16 onwards (configure by class name)
DataFormat bindy = new BindyCsvDataFormat(com.acme.model.MyModel.class); |
Setting locale
Bindy supports configuring the locale on the dataformat, such as
Code Block |
---|
BindyCsvDataFormat bindy = new BindyCsvDataFormat(// Camel 2.15 or older (configure by package name)
BindyCsvDataFormat bindy = new BindyCsvDataFormat("com.acme.model");
// Camel 2.16 onwards (configure by class name)
BindyCsvDataFormat bindy = new BindyCsvDataFormat(com.acme.model.MyModel.class);
bindy.setLocale("us"); |
Or to use the platform default locale then use "default" as the locale name. Notice this requires Camel 2.14/2.13.3/2.12.5.
Code Block |
---|
BindyCsvDataFormat bindy = new BindyCsvDataFormat("com.acme.model");
bindy.setLocale("default"); |
for older releases you can set it using Java code as shown
Code Block |
---|
// Camel 2.15 or older (configure by package name)
BindyCsvDataFormat bindy = new BindyCsvDataFormat("com.acme.model");
bindy.setLocale(Locale.getDefault().getISO3Country()); |
Unmarshaling
Code Block |
---|
from("file://inbox")
.unmarshal(bindy)
.to("direct:handleOrders");
|
// Camel 2.16 onwards (configure by class name)
BindyCsvDataFormat bindy = new BindyCsvDataFormat(com.acme.model.MyModel.class);
bindy.setLocale("default"); |
for older releases you can set it using Java code as shown
Code Block |
---|
// Camel 2.15 or older (configure by package name)
BindyCsvDataFormat bindy = new BindyCsvDataFormat("com.acme.model");
// Camel 2.16 onwards (configure by class name)
BindyCsvDataFormat bindy = new BindyCsvDataFormat(com.acme.model.MyModel.class);
bindy.setLocale(Locale.getDefault().getISO3Country()); |
Unmarshaling
Code Block |
---|
from("file://inbox")
.unmarshal(bindy)
.to("direct:handleOrders");
|
Alternatively, you can use a named Alternatively, you can use a named reference to a data format which can then be defined in your Registry e.g. your Spring XML file:
...
Code Block |
---|
List<Map<String, Object>> unmarshaledModels = (List<Map<String, Object>>) exchange.getIn().getBody();
int modelCount = 0;
for (Map<String, Object> model : unmarshaledModels) {
for (String className : model.keySet()) {
Object obj = model.get(className);
LOG.info("Count : " + modelCount + ", " + obj.toString());
}
modelCount++;
}
LOG.info("Total CSV records received by the csv bean : " + modelCount);
|
Assuming that you want to extract a single Order object from this map for processing in a route, you could use a combination of a Splitter and a Processor as per the following:
Code Block |
---|
from("file://inbox")
.unmarshal(bindy)
.split(body())
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
Message in = exchange.getIn();
Map<String, Object> modelMap = (Map<String, Object>) in.getBody();
in.setBody(modelMap.get(Order.class.getCanonicalName()));
}
})
.to("direct:handleSingleOrder")
.end();
|
Marshaling
To generate CSV records from a collection of model objects, you create the following route :
Code Block |
---|
from("direct:handleOrders")
.marshal(bindy)
.to("file://outbox")
|
Unit test
Here is two examples showing how to marshall or unmarshall a CSV file with Camel
Code Block |
---|
|
package org.apache.camel.dataformat.bindy.csv;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.camel.EndpointInject;
import org.apache.camel.Produce;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.dataformat.bindy.model.complex.twoclassesandonelink.Client;
import org.apache.camel.dataformat.bindy.model.complex.twoclassesandonelink.Order;
import org.apache.camel.spring.javaconfig.SingleRouteCamelConfiguration;
import org.junit.Test;
import org.springframework.config.java.annotation.Bean;
import org.springframework.config.java.annotation.Configuration;
import org.springframework.config.java.test.JavaConfigContextLoader;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
@ContextConfiguration(locations = "org.apache.camel.dataformat.bindy.csv.BindyComplexCsvMarshallTest$ContextConfig", loader = JavaConfigContextLoader.class)
public class BindyComplexCsvMarshallTest extends AbstractJUnit4SpringContextTests {
private List<Map<String, Object>> models = new ArrayList<Map<String, Object>>();
private String result = "10,A1,Julia,Roberts,BE123456789,Belgium Ventage 10/12,150,USD,14-01-2009";
@Produce(uri = "direct:start")
private ProducerTemplate template;
@EndpointInject(uri = "mock:result")
private MockEndpoint resultEndpoint;
@Test
public void testMarshallMessage() throws Exception {
resultEndpoint.expectedBodiesReceived(result);
template.sendBody(generateModel());
resultEndpoint.assertIsSatisfied();
}
private List<Map<String, Object>> generateModel() {
Map<String, Object> model = new HashMap<String, Object>();
Order order = new Order();
order.setOrderNr(10);
order.setAmount(new BigDecimal("150"));
order.setIsinCode("BE123456789");
order.setInstrumentName("Belgium Ventage 10/12");
order.setCurrency("USD");
Calendar calendar = new GregorianCalendar();
calendar.set(2009, 0, 14);
order.setOrderDate(calendar.getTime());
Client client = new Client();
client.setClientNr("A1");
client.setFirstName("Julia");
client.setLastName("Roberts");
order.setClient(client);
model.put(order.getClass().getName(), order);
model.put(client.getClass().getName(), client);
models.add(0, model);
return models;
}
@Configuration
public static class ContextConfig extends SingleRouteCamelConfiguration {
BindyCsvDataFormat camelDataFormat = new BindyCsvDataFormat("org.apache.camel.dataformat.bindy.model.complex.twoclassesandonelink");
@Override
@Bean
public RouteBuilder route() {
return new RouteBuilder() {
@Override
public void configure() {
from("direct:start").marshal(camelDataFormat).to("mock:result");
}
};
}
}
}
|
Code Block |
---|
|
package org.apache.camel.dataformat.bindy.csv;
import org.apache.camel.EndpointInject;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.spring.javaconfig.SingleRouteCamelConfiguration;
import org.junit.Test;
import org.springframework.config.java.annotation.Bean;
import org.springframework.config.java.annotation.Configuration;
import org.springframework.config.java.test.JavaConfigContextLoader;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
@ContextConfiguration(locations = "org.apache.camel.dataformat.bindy.csv.BindyComplexCsvUnmarshallTest$ContextConfig", loader = JavaConfigContextLoader.class)
public class BindyComplexCsvUnmarshallTest extends AbstractJUnit4SpringContextTests {
@EndpointInject(uri = "mock:result")
private MockEndpoint resultEndpoint;
@Test
public void testUnMarshallMessage() throws Exception {
resultEndpoint.expectedMessageCount(1);
resultEndpoint.assertIsSatisfied();
}
@Configuration
public static class ContextConfig extends SingleRouteCamelConfiguration {
BindyCsvDataFormat csvBindyDataFormat = new BindyCsvDataFormat("org.apache.camel.dataformat.bindy.model.complex.twoclassesandonelink");
@Override
@Bean
public RouteBuilder route() {
return new RouteBuilder() {
@Override
public void configure() {
from("file://src/test/data?noop=true").unmarshal(csvBindyDataFormat).to("mock:result");
}
};
}
}
}
|
In this example, BindyCsvDataFormat class has been instantiated in a traditional way but it is also possible to provide information directly to the function (un)marshal like this where BindyType corresponds to the Bindy DataFormat class to instantiate and the parameter contains the list of package names.
int modelCount = 0;
for (Map<String, Object> model : unmarshaledModels) {
for (String className : model.keySet()) {
Object obj = model.get(className);
LOG.info("Count : " + modelCount + ", " + obj.toString());
}
modelCount++;
}
LOG.info("Total CSV records received by the csv bean : " + modelCount);
|
Assuming that you want to extract a single Order object from this map for processing in a route, you could use a combination of a Splitter and a Processor as per the following:
Code Block |
---|
from("file://inbox")
.unmarshal(bindy)
.split(body())
.process(new Processor() {
|
Code Block |
---|
public static class ContextConfig extends SingleRouteCamelConfiguration {
@Override
@Bean
public RouteBuilder route() {
return new RouteBuilder() {
@Override
public void configureprocess(Exchange exchange) throws Exception {
Message in = from("direct:start")exchange.getIn();
Map<String, Object> modelMap = .marshal(Map<String, Object>) in.bindy(BindyType.Csv, "org.apache.camel.dataformat.bindy.model.simple.oneclass")getBody();
.to("mock:result"in.setBody(modelMap.get(Order.class.getCanonicalName()));
}
})
};
}
}.to("direct:handleSingleOrder")
.end();
|
Marshaling
To generate CSV records from a collection of model objects, you create the following route :
Code Block |
---|
from("direct:handleOrders")
.marshal(bindy)
.to("file://outbox")
|
Using Spring XML
This is really easy to use Spring as your favorite DSL language to declare the routes to be used for camel-bindy. The following example shows two routes where the first will pick-up records from files, unmarshal the content and bind it to their model. The result is then send to a pojo (doing nothing special) and place them into a queue.
The second route will extract the pojos from the queue and marshal the content to generate a file containing the csv record. The example above is for using Camel 2.16 onwards.
Code Block |
---|
|
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="bindyDataformat" class="org.apache.camel.dataformat.bindy.csv.BindyCsvDataFormat">
<constructor-arg value="org.apache.camel.bindy.model" />
</bean>
<bean id="csv" class="org.apache.camel.bindy.csv.HandleOrderBean" />
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd">
<!-- Queuing engine - ActiveMq - work locally in mode virtual memory -->
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="brokerURL" value="vm://localhost:61616"/>
</bean>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<jmxAgent
<dataFormats>
<bindy id="agentbindyDataformat" disabledtype="falseCsv" classType="org.apache.camel.bindy.model.Order"/>
</dataFormats>
<route>
<from uri="file://src/data/csv/?noop=true" />
<unmarshal ref="bindyDataformat" />
<to uri="bean:csv" />
<to uri="activemq:queue:in" />
</route>
<route>
<from uri="activemq:queue:in" />
<marshal ref="bindyDataformat" />
<to uri="file://src/data/csv/out/" />
</route>
</camelContext>
</beans>
|
...