The goal of this component is to allow the parsing/binding of
non-structured data (or to be more precise non-XML data)
to/from Java Beans that have binding mappings defined with annotations.
Using Bindy, you can bind data from sources such as :

CSV records,

Fixed-length records,

FIX messages,

or almost any other non-structured data

to one or many Plain Old Java Object (POJO). Bindy converts the data
according to the type of the java property. POJOs can be linked together
with one-to-many relationships available in some cases. Moreover, for
data type like Date, Double, Float, Integer, Short, Long and BigDecimal,
you can provide the pattern to apply during the formatting of the
property.

For the BigDecimal numbers, you can also define the precision and the
decimal or grouping separators.

To work with camel-bindy, you must first define your model in a package
(e.g. com.acme.model) and for each model class (e.g. Order, Client,
Instrument, …​) add the required annotations (described hereafter) to
the Class or field.

*Multiple models*

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.

Options

The Bindy dataformat supports 5 options which are listed below.

Name

Default

Java Type

Description

type

BindyType

Whether to use csv, fixed or key value pairs mode. The default value is either Csv or KeyValue depending on chosen dataformat.

classType

String

Name of model class to use.

locale

String

To configure a default locale to use, such as us for united states. To use the JVM platform default locale then use the name default

unwrapSingleInstance

true

Boolean

When unmarshalling should a single instance be unwrapped and returned instead of wrapped in a java.util.List.

contentTypeHeader

false

Boolean

Whether the data format should set the Content-Type header with the type from the data format if the data format is capable of doing so. For example application/xml for data formats marshalling to XML, or application/json for data formats marshalling to JSon etc.

Annotations

The annotations created allow to map different concept of your model to
the POJO like :

KeyValuePairField (for key = value format like we have in FIX
financial messages),

Section (to identify header, body and footer section),

OneToMany,

BindyConverter (since 2.18.0),

FormatFactories (since 2.18.0)

This section will describe them :

1. CsvRecord

The CsvRecord annotation is used to identified the root class of the
model. It represents a record = a line of a CSV file and can be linked
to several children model classes.

Annotation name

Record type

Level

CsvRecord

csv

Class

Parameter name

type

Info

separator

string

mandatory - can be ',' or ';' or 'anything'. This value is interpreted
as a regular expression. If you want to use a sign which has a special
meaning in regular expressions, e.g. the '|' sign, than you have to mask
it, like '|'

skipFirstLine

boolean

optional - default value = false - allow to skip the first line of the
CSV file

crlf

string

optional - possible values = WINDOWS,UNIX,MAC, or custom; default value.
WINDOWS - allow to define the carriage return character to use. If you
specify a value other than the three listed before, the value you enter
(custom) will be used as the CRLF character(s)

Camel 2.13/2.12.2: optional - default value = false - if enabled then
the last column is auto spanned to end of line, for example if its a
comment, etc this allows the line to contain all characters, also the
delimiter char.

isOrdered

boolean

optional - default value = false - allow to change the order of the
fields when CSV is generated

quote

String

Camel 2.8.3/2.9: option - allow to specify a quote character of the
fields when CSV is generated. This annotation is associated to the root class of the model and must be
declared one time.

quoting

boolean

*Camel 2.11:*optional - default value = false - Indicate if the values (and headers)
must be quoted when marshaling when CSV is generated.

endWithLineBreak

boolean

Camel 2.21: optional - default value = true - Indicate if the CSV generated file
should end with a line break.

When the field to be parsed of the CSV record contains ',' or ';' which
is also used as separator, we whould find another strategy
to tell camel bindy how to handle this case. To define the field
containing the data with a comma, you will use simple or double quotes
as delimiter (e.g : '10', 'Street 10, NY', 'USA' or "10", "Street 10,
NY", "USA").
Remark : In this case, the first and last character of the line which
are a simple or double quotes will removed by bindy

From Camel 2.8.3/2.9 or never bindy will automatic detect if the
record is enclosed with either single or double quotes and automatic
remove those quotes when unmarshalling from CSV to Object. Therefore do
not include the quotes in the separator, but simple do as below:

If the platform where camel-bindy will run is not Windows but Macintosh
or Unix, than you can change the crlf property like this. Three values
are available : WINDOWS, UNIX or MAC

@CsvRecord(separator = ",", crlf="MAC")public Class Order {
}

Additionally, if for some reason you need to add a different line ending
character, you can opt to specify it using the crlf parameter. In the
following example, we can end the line with a comma followed by the
newline character:

@CsvRecord(separator = ",", crlf=",\n")public Class Order {
}

case 8 : isOrdered

Sometimes, the order to follow during the creation of the CSV record
from the model is different from the order used during the parsing.
Then, in this case, we can use the attribute isOrdered = true to
indicate this in combination with attribute 'position' of the DataField
annotation.

3. DataField

The DataField annotation defines the property of the field. Each
datafield is identified by its position in the record, a type (string,
int, date, …​) and optionally of a pattern

Annotation name

Record type

Level

DataField

all

Property

Parameter name

type

Info

pos

int

mandatory - The input position of the field. digit number starting
from 1 to …​ - See the position parameter.

pattern

string

optional - default value = "" - will be used to format Decimal, Date,

length

int

optional - represents the length of the field for fixed length format

precision

int

optional - represents the precision to be used when the Decimal number
will be formatted/parsed

pattern

string

optional - default value = "" - is used by the Java formatter
(SimpleDateFormat by example) to format/validate data. If using pattern,
then setting locale on bindy data format is recommended. Either set to a
known locale such as "us" or use "default" to use platform default
locale. Notice that "default" requires Camel 2.14/2.13.3/2.12.5.

position

int

optional - must be used when the position of the field in the CSV
generated (output message) must be different compare to input position
(pos). See the pos parameter.

The position attribute will inform bindy how to place the field in the
CSV record generated. By default, the position used corresponds to the
position defined with the attribute 'pos'. If the position is different
(that means that we have an asymetric processus comparing marshaling
from unmarshaling) than we can use 'position' to indicate this.

4. FixedLengthRecord

The FixedLengthRecord annotation is used to identified the root class of
the model. It represents a record = a line of a file/message containing
data fixed length formatted and can be linked to several children model
classes. This format is a bit particular beause data of a field can be
aligned to the right or to the left.
When the size of the data does not fill completely the length of the
field, we can then add 'padd' characters.

Annotation name

Record type

Level

FixedLengthRecord

fixed

Class

Parameter name

type

Info

crlf

string

optional - possible values = WINDOWS,UNIX,MAC, or custom; default value.
WINDOWS - allow to define the carriage return character to use. If you
specify a value other than the three listed before, the value you enter
(custom) will be used as the CRLF character(s). This option is used only during marshalling,
whereas unmarshalling uses system default JDK provided line delimiter unless eol is customized

eol

string

optional - default="" which is empty string. Character to be used to process
considering end of line after each record while unmarshalling (optional - default = ""
which help default JDK provided line delimiter to be used unless any other line delimiter
provided). This option is used only during unmarshalling, where marshalling uses system default
provided line delimiter as "WINDOWS" unless any other value is provided

paddingChar

char

mandatory - default value = ' '

length

int

mandatory = size of the fixed length record

hasHeader

boolean

Camel 2.11 - optional - Indicates that the record(s) of this type may
be preceded by a single header record at the beginning of the file /
stream

hasFooter

boolean

Camel 2.11 - optional - Indicates that the record(s) of this type may
be followed by a single footer record at the end of the file / stream

skipHeader

boolean

Camel 2.11 - optional - Configures the data format to skip marshalling
/ unmarshalling of the header record. Configure this parameter on the
primary record (e.g., not the header or footer).

skipFooter

boolean

Camel 2.11 - optional - Configures the data format to skip marshalling
/ unmarshalling of the footer record Configure this parameter on the
primary record (e.g., not the header or footer)..

isHeader

boolean

Camel 2.11 - optional - Identifies this FixedLengthRecord as a header
record

isFooter

boolean

Camel 2.11 - optional - Identifies this FixedLengthRecords as a footer
record

ignoreTrailingChars

boolean

Camel 2.11.1 - optional - Indicates that characters beyond the last
mapped filed can be ignored when unmarshalling / parsing. This annotation is associated to the root class of the model and must be
declared one time.

The hasHeader/hasFooter parameters are mutually exclusive with
isHeader/isFooter. A record may not be both a header/footer and a
primary fixed-length record.

case 1 : Simple fixed length record

This simple example shows how to design the model to parse/format a
fixed message

Sometimes, the default padding defined for record cannnot be applied to
the field as we have a number format where we would like to padd with
'0' instead of ' '. In this case, you can use in the model the attribute
paddingField to set this value.

As of Camel 2.11 the 'pos' value(s) in a fixed-length record may
optionally be defined using ordinal, sequential values instead of
precise column numbers.

case 5 : Fixed length record with record-defined field length

Occasionally a fixed-length record may contain a field that define the
expected length of another field within the same record. In the
following example the length of the instrumentNumber field value is
defined by the value of instrumentNumberLen field in the record.

Bindy will discover fixed-length header and footer records that are
configured as part of the model – provided that the annotated classes
exist either in the same package as the primary @FixedLengthRecord
class, or within one of the configured scan packages. The following text
illustrates two fixed-length records that are bracketed by a header
record and footer record.

It is common to integrate with systems that provide fixed-length records
containing more information than needed for the target use case. It is
useful in this situation to skip the declaration and parsing of those
fields that we do not need. To accomodate this, Bindy will skip forward
to the next mapped field within a record if the 'pos' value of the next
declared field is beyond the cursor position of the last parsed field.
Using absolute 'pos' locations for the fields of interest (instead of
ordinal values) causes Bindy to skip content between two fields.

Similarly, it is possible that none of the content beyond some field is
of interest. In this case, you can tell Bindy to skip parsing of
everything beyond the last mapped field by setting the
ignoreTrailingChars property on the @FixedLengthRecord declaration.

5. Message

The Message annotation is used to identified the class of your model who
will contain key value pairs fields. This kind of format is used mainly
in Financial Exchange Protocol Messages (FIX). Nevertheless, this
annotation can be used for any other format where data are identified by
keys. The key pair values are separated each other by a separator which
can be a special character like a tab delimitor (unicode representation
: \u0009) or a start of heading (unicode representation : \u0001)

*"FIX information"*

More information about FIX can be found on this web site :
http://www.fixprotocol.org/. To work with
FIX messages, the model must contain a Header and Trailer classes linked
to the root message class which could be a Order class. This is not
mandatory but will be very helpful when you will use camel-bindy in
combination with camel-fix which is a Fix gateway based on quickFix
project http://www.quickfixj.org/.

Annotation name

Record type

Level

Message

key value pair

Class

Parameter name

type

Info

pairSeparator

string

mandatory - can be '=' or ';' or 'anything'

keyValuePairSeparair

string

mandatory - can be '\u0001', '\u0009', '#' or 'anything'

crlf

string

optional - possible values = WINDOWS,UNIX,MAC, or custom; default value
= WINDOWS - allow to define the carriage return character to use. If you
specify a value other than the three listed before, the value you enter
(custom) will be used as the CRLF character(s)

type

string

optional - define the type of message (e.g. FIX, EMX, …​)

version

string

optional - version of the message (e.g. 4.1)

isOrdered

boolean

optional - default value = false - allow to change the order of the
fields when FIX message is generated. This annotation is associated to the message class of the model and must
be declared one time.

case 1 : separator = 'u0001'

The separator used to segregate the key value pair fields in a FIX
message is the ASCII '01' character or in unicode format '\u0001'. This
character must be escaped a second time to avoid a java runtime error.
Here is an example :

The ASCII character like tab, …​ cannot be displayed in WIKI page. So,
have a look to the test case of camel-bindy to see exactly how the FIX
message looks like (src\test\data\fix\fix.txt) and the Order, Trailer,
Header classes
(src\test\java\org\apache\camel\dataformat\bindy\model\fix\simple\Order.java)

6. KeyValuePairField

The KeyValuePairField annotation defines the property of a key value
pair field. Each KeyValuePairField is identified by a tag (= key) and
its value associated, a type (string, int, date, …​), optionaly a
pattern and if the field is required

Annotation name

Record type

Level

KeyValuePairField

Key Value Pair - FIX

Property

Parameter name

type

Info

tag

int

mandatory - digit number identifying the field in the message - must be
unique

7. Section

In FIX message of fixed length records, it is common to have different
sections in the representation of the information : header, body and
section. The purpose of the annotation @Section is to inform bindy about
which class of the model represents the header (= section 1), body (=
section 2) and footer (= section 3)

Using the Java DSL

The next step consists in instantiating the DataFormat bindy class
associated with this record type and providing Java package name(s) as
parameter.

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.

The Camel route will pick-up files in the inbox directory, unmarshall
CSV records into a collection of model objects and send the collection
to the route referenced by 'handleOrders'.

The collection returned is a List of Map objects. Each Map within the
list contains the model objects that were marshalled out of each line of
the CSV. The reason behind this is that each line can correspond to
more than one object. This can be confusing when you simply expect one
object to be returned per line.

Take care of the fact that Bindy uses CHARSET_NAME property or the CHARSET_NAME header as define in the
Exchange interface to do a characterset conversion of the inputstream received for unmarshalling.
In some producers (e.g. file-endpoint) you can define a characterset. The characterset conversion
can already been done by this producer. Sometimes you need to remove this property or header from the
exchange before sending it to the unmarshal. If you don’t remove it the conversion might be done twice
which might lead to unwanted results.

Marshaling

To generate CSV records from a collection of model objects, you create
the following route :

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.