=== Reading

Most users of opencsv find themselves needing to read CSV files, and opencsv excels
at this. But then, opencsv excels at everything. :)

==== Parsing

It's unlikely that you will need to concern yourself with exactly how parsing
works in opencsv, but documentation wouldn't be documentation if it didn't cover
all of the obscure nooks and crannies. So here we go.

Parsers in opencsv implement the interface ICSVParser. You are free to write your
own, if you feel the need to. opencsv itself provides two parsers, detailed in the
following sections.

Although opencsv attempts to be simple to use for most use cases, and thus tries
not to make the choice of a parser obvious, you are still always free to instantiate
whichever parser suits your needs and pass it to the builder or reader you are using.

===== CSVParser

The original, tried and true parser that does fairly well everything you need to
do, and does it well. If you don't tell opencsv otherwise, it uses this parser.

The advantage of the CSVParser is that it's highly configurable and has the best chance of
parsing "non-standard" CSV data.  The disadvantage is that while highly configurable it was
found that there were RFC4180 data that it could not parse.  Thus the RFC4180Parser was created.

===== RFC4180Parser

https://www.rfc-editor.org/rfc/rfc4180.txt[RFC4180] defines a standard for
all of the nitty-gritty questions of just precisely how CSV files are to be
formatted, delimited, and escaped. Since opencsv predates RFC4180 by a few days
and every effort was made to preserve backwards compatibility, it was necessary
to write a new parser for full compliance with RFC4180.

The main difference between between the CSVParser and the RFC4180Parser is that the
CSVParser uses an escape character to denote "unprintable" characters while the RFC4180 spec
takes all characters between the first and last quote as gospel (with the exception of the double quote
which is escaped by a double quote).

==== Reading into an array of strings

At the most basic, you can use opencsv to parse an input and return a String[], thus:
[source, java]
----
     CSVReader reader = new CSVReader(new FileReader("yourfile.csv"));
     String [] nextLine;
     while ((nextLine = reader.readNext()) != null) {
        // nextLine[] is an array of values from the line
        System.out.println(nextLine[0] + nextLine[1] + "etc...");
     }
----

One step up is reading all lines of the input file at once into a List<String[]>, thus:
[source, java]
----
     CSVReader reader = new CSVReader(new FileReader("yourfile.csv"));
     List<String[]> myEntries = reader.readAll();
----

The last option for getting at an array of strings is to use an iterator:
[source, java]
----
     CSVIterator iterator = new CSVIterator(new CSVReader(new FileReader("yourfile.csv")));
     for(String[] nextLine : iterator) {
        // nextLine[] is an array of values from the line
        System.out.println(nextLine[0] + nextLine[1] + "etc...");
     }
----

or:
[source, java]
----
     CSVReader reader = new CSVReader(new FileReader("yourfile.csv"));
     for(String[] nextLine : reader.iterator()) {
        // nextLine[] is an array of values from the line
        System.out.println(nextLine[0] + nextLine[1] + "etc...");
     }
----

==== Reading into beans

Arrays of strings are all good and well, but there are simpler, more modern ways
of data processing. Specifically, opencsv can read a CSV file directly into a list
of beans. Quite often, that's what we want anyway, to be able to pass the data
around and process it as a connected dataset instead of individual fields whose
position in an array must be intuited. We shall start with the easiest and most
powerful method of reading data into beans, and work our way down to the cogs
that offer finer control, for those who have a need for such a thing.

Performance always being one of our top concerns, reading is multi-threaded.
There are two performance choices left in your hands:

. Time vs. memory: The classic trade-off. If memory is not a problem, read using CsvToBean.parse() or CsvToBean.stream(), which will read all beans at once and are multi-threaded. If your memory is limited, use CsvToBean.iterator() and iterate over the input. Only one bean is read at a time, making multi-threading impossible and slowing down reading, but only one object is in memory at a time (assuming you process and release the object for the garbage collector immediately).
. Ordered vs. unordered. opencsv preserves the order of the data given to it by default. Maintaining order when using parallel programming requires some extra effort which means extra CPU time. If order does not matter to you, use CsvToBeanBuilder.withOrderedResults(false). The performance benefit is not large, but it is measurable. The ordering or lack thereof applies to data as well as any captured exceptions.

Let it be mentioned here that although the authors of opencsv aren't thrilled
about the idea of using Java 8's Optional for accessor methods (that is,
returning an Optional of your real data type from a getter or requiring an
Optional of your real data type for a setter), we do support it as long as the
actual field in your bean is not an Optional, but rather whatever data type the
Optional wraps. If your getter returns an empty Optional, opencsv uses null.

The bean work was begun by Kyle Miller and extended by Tom Squires and Andrew Jones.

===== Annotations

By simply defining a bean and annotating the fields, opencsv can do all of the
rest. When we write "bean", that's a loose approximation of the requirements.
Actually, if you use annotations, opencsv uses reflection (not introspection) on
reading, so all you need is a POJO (plain old Java object) that does not have to
conform to the Java Bean Specification, but is required to be public and have a
public nullary constructor. If getters and setters are present and accessible,
they are used. Otherwise, opencsv bypasses access control restrictions to get to
member variables.

Besides the basic mapping strategy, there are various mechanisms for processing
certain kinds of data.

====== Annotating by header name
CSV files should have header names for all fields in the file, and these can
be used to great advantage. By annotating a bean field with the name of the header
whose data should be written in the field, opencsv can do all of the matching
and copying for you. This also makes you independent of the order in which the
headers occur in the file. For data like this:

----
     firstName,lastName,visitsToWebsite
     John,Doe,12
     Jane,Doe,23
----
you could create the following bean:
[source, java]
----
     public class Visitors {

     @CsvBindByName
     private String firstName;

     @CsvBindByName
     private String lastName;

     @CsvBindByName
     private int visitsToWebsite;

     // Getters and setters go here.
     }
----

Here we simply name the fields identically to the header names. After that,
reading is a simple job:
[source, java]
----
     List<Visitors> beans = new CsvToBeanBuilder(FileReader("yourfile.csv"))
       .withType(Visitors.class).build().parse();
----

This will give you a list of the two beans as defined in the example input file.
Note how type conversions to basic data types (wrapped and unwrapped primitives,
enumerations, and Strings) occur automatically.

Input can get more complicated, though, and opencsv gives you the tools to deal
with that. Let's start with the possibility that the header names can't be
mapped to Java field names:

----
     First name,Last name,1 visit only
     John,Doe,true
     Jane,Doe,false
----
In this case, we have spaces in the names and one header with a number as the
initial character. Other problems can be encountered, such as international
characters in header names. Additionally, we would like to require that at least
the name be mandatory. For this case, our bean doesn't look much different:
[source, java]
----
     public class Visitors {

     @CsvBindByName(column = "First Name", required = true)
     private String firstName;

     @CsvBindByName(column = "Last Name", required = true)
     private String lastName;

     @CsvBindByName(column = "1 visit only")
     private boolean onlyOneVisit;

     // Getters and setters go here.
     }
----
The code for reading remains unchanged.

Now let's say that your data for whatever reason look like this:

----
     First name,Last name,1 visit only
     John middle:Bubba,Doe,true
     Jane middle:Rachel,Doe,false
----

Someone has included the person's middle name in the field for the first name.
But we really only want the first name. Do we have to write a custom converter?
No, friends, there is an easier way:

[source, java]
----
     @CsvBindByName(column = "First Name", required = true, capture="([^ ]+) .*")
     private String firstName;
----
The capture option to all of the binding annotations (except the custom binding
annotations, of course) allows you to tell opencsv just what part of the input
field should actually be considered significant. opencsv takes the contents of
the first capture group. In this example, we take everything up to but not
including the first space and discard the rest. Please read the Javadoc for
more details and handling of edge cases.

====== Annotating by column position
Not every scribe of CSV files is kind enough to provide header names. This is a
no-no, but we're not here to condemn the authors of poor data exports. Our goal
is to provide our users with everything they could possibly need to parse CSV
files, no matter how bad, as long as they're still logically coherent in some
way.

To that end, we have also accounted for the possibility that there are no
headers, and data must be divined from column position. We will return to our
previous input file sans header names:

----
     John,Doe,12
     Jane,Doe,23
----

The bean for these data would be:

[source, java]
----
     public class Visitors {

     @CsvBindByPosition(position = 0)
     private String firstName;

     @CsvBindByPosition(position = 1)
     private String lastName;

     @CsvBindByPosition(position = 2)
     private int visitsToWebsite;

     // Getters and setters go here.
     }
----

Besides that, the annotations behave the same as their header name counterparts.

====== Enumerations

Enumerations work exactly like regular primitive fields. There is only one more
thing to say about them: input is checked against the declared values of the
enumeration type **without regard to case**. On writing, the enumeration value
will always be written exactly as declared.

====== Locales, dates, numbers
We've considered simple data types, but we haven't considered more complex yet
common data types. We have also not considered locales other than the default
locale or formatting options beyond those provided by a locale. Here we shall
do all of this at the same time. Consider this input file:

----
     username,valid since,annual salary
     user1,01.01.2010,100.000€
     user2,31.07.2014,50.000€
----
The dates are dd.MM.yyyy, the salaries use a dot as the thousands delimiter,
and a currency symbol is in use.
For this input we create the following bean:
[source, java]
----
     public class Employees {

     @CsvBindByName(required = true)
     private String username;

     @CsvBindByName(column = "valid since")
     @CsvDate("dd.MM.yyyy")
     private Date validSince;

     @CsvBindByName(column = "annual salary", locale = "de-DE")
     @CsvNumber("#.###¤")
     private int salary;

     // Getters and setters go here.
     }
----
The date is handled with the annotation @CsvDate in addition to the mapping annotation.
@CsvDate can take a format string, and incidentally handles all common date-type
classes. See the Javadocs for more details. The format of the salary, including
thousands separator and currency symbol, are dealt with using a combination of
the German locale, one of many countries where the thousands
separator is a dot, and @CsvNumber.

====== Collection-based bean fields (one-to-many mappings)
CSV files are lists, right? Well, some people like lists within lists. For them,
we have the ability to annotate bean fields that are declared to be some type
implementing java.util.Collection. When using CsvBindAndSplitByName or
CsvBindAndSplitByPosition, one field in the CSV file is taken to be a list of
data that are separated by a delimiter of some kind. The input is split along
this delimiter and the results are put in a Collection and assigned to the bean
field. What kind of Collection? Any kind you want. If opencsv knows it, it
instantiates an implementing class for you. If opencsv doesn't know it, you can
educate opencsv. Every reasonable Collection-based interface from the JDK is
known, and well as Bag and SortedBag from Apache Commons Collections. Some
examples would doubtless illuminate my meaning.

[source, java]
----
     public class Student {

     @CsvBindAndSplitByName(elementType = Float.class)
     Collection<Float> testScores;

     @CsvBindAndSplitByName(elementType = Double.class, collectionType = LinkedList.class)
     List<? extends Number> quizScores;

     @CsvBindAndSplitByName(elementType = Date.class, splitOn = ";+", writeDelimiter = ";")
     @CsvDate("yyyy-MM-dd")
     SortedSet<Date> tardies;

     @CsvBindAndSplitByName(elementType= Teacher.class, splitOn = "\\|", converter = TextToTeacher.class)
     List<Teacher> teachers;

     @CsvBindByName
     int studentID;

     // Getters and setters go here
----

This shows us much of the power of these annotations in a few lines. Let's take
the first field. It is defined to be a Collection of Floats. Note, please, the
annotation @CsvBindAndSplitByName (or the equivalent for position) always
requires the type of an element of the collection being created. Nothing else
is mandatory. In particular, Collection itself has no directly implementing
classes, but please note, we didn't indicate to opencsv which kind of collection
we want. opencsv chooses one for us.

The next field is a List of something derived from Number. This is where it
becomes apparent why the element type is mandatory -- it cannot always be
determined. Besides that, in this line we are not satisfied with the List
implementation opencsv chooses, so we specify LinkedList with the collectionType
parameter to the annotation.

The third field is a SortedSet of dates (when a student was tardy to
class). Sorted for convenience, and a set to avoid clerical errors of double
entry. For this field we have specified that the string separating elements of
this list in the input is one or more semicolons. This string is always
interpreted as a regular expression. Interestingly, in case we write these data
out to a CSV file later, the elements of the list should be separated with a
single semicolon. Perhaps someone is trying to convert the data from a older
format or remove redundancies.

The forth field is a list of teachers the student has. This field demonstrates
the combination of collection-based fields and custom converters. The
converter, which must be derived from AbstractCsvConverter, could look like this:

[source, java]
----
     public class TextToTeacher extends AbstractCsvConverter {

       @Override
       public Object convertToRead(String value) {
           Teacher t = new Teacher();
           String[] split = value.split("\\.", 2);
           t.setSalutation(split[0]);
           t.setSurname(split[1]);
           return t;
       }

       @Override
       public String convertToWrite(Object value) {
           Teacher t = (Teacher) value;
           return String.format(""%s.%s", t.getSalutation(), t.getSurname());
       }

     }
----

The corresponding data structure would be:

[source, java]
----
     public class Teacher {
       private String salutation;
       private String surname;

       // Getters and setters go here
     }
----

The final field is simply for student identification.

The input to be mapped to this bean could look like this:

----
     studentID,testScores,quizScores,tardies,teachers
     1,100.0 97.2 18.9,77 90.3 88.8,,Mr.Stone|Mrs.Mason
     2,56.6 97.2 90.0,82.0 79.6 66.9,2017-01-02;2017-03-04;;;2017-03-04;;2017-05-31,Ms.Currie|Mr.Feynman
----

The first student has never been tardy, so that list will be empty (but never
null). The school secretary accidentally entered a tardy for the second student
twice, but this will be eliminated by the SortedSet.

Let's say you want to tell opencsv which Collection implementation to use,
perhaps because you want to make certain it's one that will perform better for
your usage pattern, or perhaps because you want to use one opencsv knows nothing
about, like your own implementation. There are two ways of doing this. We
already saw one: specify the implementation you want to use in the annotation
with the parameter "collectionType". The only stipulations on the implementing
class are that it be public and have a nullary constructor. The other way is to
declare the type of the bean field using the implementing class rather than the
interface implemented, thus:

[source, java]
----
     public class MySuperDuperIntegerList extends ArrayList<Integer> {

     // Do something super duper.

     }

     public class DataClass {

     @CsvBindAndSplitByName(elementType = Integer.class)
     MySuperDuperIntegerList myList;

     // Getter and setter go here
     }
----

Here, instead of declaring List<Integer> myList, we used the implementing class.
opencsv will respect this and instantiate the class specified. That class can
be parameterized, naturally (e.g. MySuperDuperList<Integer>).

All of the other features you know, love, and depend on, such as a field being
required, or support for locales, is equally well supported for Collection-based
members.

For details on which subinterfaces of Collection opencsv knows and exactly what
implementation opencsv uses for those interfaces if you don't specify one, see
the Javadoc for the annotations CsvBindAndSplitByName or
CsvBindAndSplitByPosition.

====== MultiValuedMap-based bean fields (many-to-one mappings)
If Collection-based bean fields were there to split one element into many,
MultiValuedMap-based bean fields are there to consolidate many elements into
one. What if you have the following input?

----
     Album,Artist,Artist,Artist,Track1,Track2,Track3,Track4
     We are the World,Michael Jackson,Lionel Richie,Stevie Wonder,We are the World,We are the World (instrumental),Did this album,Have any other tracks?
----

The first difficulty you will encounter is that three columns have the same
name. The second difficulty is that the number of tracks in the header might
increase over time, but you want them all. Both problems are easily solved, as
are all problems in the opencsv-world:

[source, java]
----
     public class Album {

       @CsvBindByName(column = "Album")
       private String albumTitle;

       @CsvBindAndJoinByName(column = "Artist", elementType = String.class)
       private MultiValuedMap<String, String> artists;

       @CsvBindAndJoinByName(column = "Track[0-9]+", elementType = String.class, mapType = HashSetValuedHashMap.class, required = true)
       private MultiValuedMap<String, String> tracks;

       // Getters and setters go here
     }
----

The first field is unimportant for this illustration.

The second field is a MultiValuedMap that collects all of the values under all
of the columns with the name "Album". If you are not familiar with
MultiValuedMap, it is a part of Apache Commons Collections. The first parameter
is the index, and the second parameter is the value. In the case of
CsvBindAndJoinByName, the index should always be a string. The value should be
of a type to which the elementType from the annotation is assignable.

Why would we choose to use such a cumbersome data type as a MultiValuedMap to
implement this feature? Why not a simple List and everyone is happy? Two
reasons: First, someone will want to know what the header was actually named on
reading, and second, opencsv needs to know what the header is named when it
writes beans to a CSV file. And really, at least for reading, a MultiValuedMap
isn't that cumbersome: Mostly you will want a list of all values, not caring
about which header they were under, and that can simply be had by calling
values() on the field.

Back to our topic, the second field will be a MultiValuedMap with exactly one
key: "Artist". Under this key, there will be a list with up to three entries, in
this case "Michael Jackson", "Lionel Richie" and "Stevie Wonder". It only
remains to note that the type of the elements being read must always be
specified for the same reason it is necessary for Collection-based bean fields.

The third field sums up most of the rest of the features this annotation
provides. As you can see, the definition of the column names is a regular
expression. Naturally, the "column" attribute of CsvBindAndJoinByName is always
interpreted as a regular expression. In this annotation we have also requested
a specific implementation of MultiValuedMap, which opencsv will honor. We have
decided that this field is mandatory, which in this case means that at least one
matching header must be in the input, and every record must have a non-empty
value for at least one of the matching columns. Given the input from above, this
MultiValuedMap will have four entries, one for each column, and each of these
entries will have a list of one element as its value. The elements will be the
track titles.

All of the usual features apply: conversion locale, combination with CsvDate,
custom converters as with collection-based fields, and specifying your own
implementation of MultiValuedMap either through the annotation or by defining
the field with the specific implementation (default implementations for the
applicable interface are documented in the Javadoc for CsvBindAndJoinByName).
The latter being said, if the MultiValuedMap is already present (and possibly
contains values), say through the use of a constructor, it will not be
overwritten, but rather added to.

What about precedence? To stay with our running example, what if after extending
the number of track titles in the input significantly (which would require no
changes to the bean), we hire some junior programmer who doesn't get it, and he
adds the following field to the bean:
[source, java]
----
     @CsvBindByName(column = "Track21")
     private String track21;
----
What does opencsv do with this? It follows the general computing principle of
"specific trumps general": It puts any information found under the header
"Track21" into the new field, not the MultiValuedMap. Obviously this doesn't
exist for the sole purpose of creating mistakes; you can use it to your
advantage if you want one otherwise matching column to be treated individually.

Since we're on the topic of precedence, what happens if two regular expressions
from CsvBindAndJoinByName match one and the same input header name? Don't do
this. The results are undefined.

While minding the last caveat, it is possible to use this feature to collect
everything not otherwise mapped:
[source, java]
----
     public class Demonstration {

       @CsvBindByName(column = "index")
       private String index;

       @CsvBindAndJoinByName(column = ".*", elementType = String.class)
       private MultiValuedMap<String, String> theRest;

       // Getters and setters go here
     }
----

There is another way one could possibly use this feature: Let's say you get
input of the same information from two different sources, and for reasons that
are beyond your control, they have different header names. Perhaps they are in
different languages. In one file, the header is:

----
studentID,given name,surname
----

And in another file, it's:

----
Schueler-ID,Vorname,Nachname
----

You really don't want two beans for the same thing. You can simply do this:
[source, java]
----
     public class Student {

       @CsvBindAndJoinByName(column = "(student|Schueler-)ID")
       private MultiValuedMap<String, Integer> id;

       @CsvBindAndJoinByName(column = "(given |Vor)name")
       private MultiValuedMap<String, String> givenName;

       @CsvBindAndJoinByName(column = "(sur|Nach)name")
       private MultiValuedMap<String, String> surname;

       // Getters and setters go here
     }
----
The only down side is, you will have to unpack the values with code like:
[source, java]
----
     bean.getSurname().values().toArray(new String[1])[0];
----

But wait! That's not all! Using CsvBindAndJoinByPosition we can do the same
thing with input that does not include headers. Let's just say for the sake of
argument that our album example from earlier now no longer includes headers, and
that the structure grew over time. Perhaps the first version of the CSV file
only included one artist, and the other two fields for artist were added at two
different points in time after that. The tracks grew over time as well. So now
our input looks like this:

----
     We are the World,Michael Jackson,We are the World,We are the World (instrumental),Lionel Richie,Did this album,Stevie Wonder,Have any other tracks?
----

In other words, first the album name, then the first artist, followed by two
tracks, then the second artist followed by one more track, then the third artist
again followed by one track. The bean for these data would look like this:

[source, java]
----
     public class Album {

       @CsvBindByPosition(position = 0)
       private String albumName;

       @CsvBindAndJoinByPosition(position = "1,4,6", elementType = String.class)
       MultiValuedMap<Integer, String> artists;

       @CsvBindAndJoinByPosition(position = "2-3,5,7-", elementType = String.class)
       MultiValuedMap<Integer, String> tracks;

       // Getters and setters go here
     }
----

The first thing to notice in this example is that we have used
CsvBindAndJoinByPosition, which takes a list of zero-based column numbers and
ranges as its most important argument. The list is comma-separated, and can
include any number of column indices as well as closed (e.g. "3-5") and
half-open (e.g. "-5" or "10-") ranges.

The next thing to notice in this example is that for CsvBindAndJoinByPosition,
the index type to MultiValuedMap must be Integer. Values are saved under the
index of the column position they were found in.

The last thing to notice is that as long as new column positions are added to
the end of the file and these are all new tracks, they will all be placed in the
variable "tracks" because the column position definition from the
CsvBindAndJoinByPosition annotation defines an open range starting at index 7.

As with a header-based mapping, it is possible to create a mop-up field, if no
other fields are mapped with CsvBindAndJoinByPosition, by mapping to a
MultiValuedMap using the fully open range expression "-".

Writing with CsvBindAndJoinByName and CsvBindAndJoinByPosition are slightly more
complicated. Both include ambiguous information about the source of the data,
one in the form of regular expressions, and the other in the form of ranges.
Once the data have been read in, there is no way from this information alone
to determine which column each header came from. That, as we have already said,
is why we use a MultiValuedMap: the index gives us this vital information. That
said, it should be obvious that when writing, the MultiValuedMap must be
completely filled out for every bean before sending it off to be written. That
is, every index that is expected in the output must be present in the map and
have at least a null value.

====== Custom converters
Now, we know that input data can get very messy, so we have provided our users
with the ability to deal with the messiest of data by allowing you to define your
own custom converters. The custom converters here are used at the level of the
entire field, not like the custom converters previously covered in
collection-based and MultiValuedMap-based bean fields. Every converter must be
derived from AbstractBeanField, must be public, and must have a public nullary
constructor. For reading, the convert() method must be overridden. opencsv
provides two custom converters in the package com.opencsv.bean.customconverter.
These can be useful converters themselves, but they also exist for instructive
purposes: If you want to write your own custom converter, look at these for
examples of how it's done.

Let's use two as illustrations. Let's say we have the following input file:

----
     cluster,nodes,production
     cluster1,node1 node2,wahr
     cluster2,node3 node4 node5,falsch
----

In this file we have a list of server clusters. The cluster name comes first,
followed by a space-delimited list of names of servers in the cluster. The final
field indicates whether the cluster is in production use or not, but the truth
value uses German. Here is the appropriate bean, using the custom converters
opencsv provides:

[source, java]
----
     public class Cluster {

       @CsvBindByName
       private String cluster;

       @CsvCustomBindByName(converter = ConvertSplitOnWhitespace.class)
       private String[] nodes;

       @CsvCustomBindByName(converter = ConvertGermanToBoolean.class)
       private boolean production;

       // Getters and setters go here.
     }
----

More than that is not necessary. If you need boolean values in other languages,
take a gander at the code in ConvertGermanToBoolean; Apache BeanUtils provides
a slick way of converting booleans.

The corresponding annotations for custom converters based on column position are
also provided.

====== Recursion into subordinate beans

Sometimes we want to split the input into a hierarchy of beans instead of
having it all in one flat bean. We can do this with the annotation @CsvRecurse.

Let's say we have the following input:

----
title,author given name,author surname,publisher,date
Space Opera 2.0,Andrew,Jones,NoWay Publishers,3019
----

We could put all of this in one bean, of course, but we could also create the
following beans:

[source,java]
----
public class Book {
    @CsvBindByName
    private String title;

    @CsvRecurse
    private Author author;

    @CsvRecurse
    private PublishingInformation publish;

    // Accessor methods go here.
}

public class Author {
    @CsvBindByName(column = "author given name")
    private String givenName;

    @CsvBindByName(column = "author surname")
    private String surname;

    // Accessor methods go here.
}

public class PublishingInformation {
    @CsvBindByName
    private String publisher;

    @CsvBindByName
    @CsvDate("yyyy")
    private Year date;

    // Accessor methods go here.
}
----

This way, your data can be hierarchical.

If you want to split the data among completely unrelated beans, create a
containing bean for the beans you actually need, thus:

[source,java]
----
public class Container {
    @CsvRecurse
    private BeanTheFirst bean1;

    @CsvRecurse
    private BeanTheSecond bean2;

    @CsvRecurse
    private BeanTheThird bean3;

    // Accessor methods go here.
}
----

Then simply extract the subordinate beans you need after parsing.

opencsv will instantiate the entire hierarchy of subordinate beans while
reading data in, even if it does not need a subordinate bean for a particular
dataset because all associated input fields are empty. opencsv will, however,
always check first to see if the subordinate bean has already been created (by
the constructor of the enclosing bean), and will not replace it if it exists.
As a result, any subordinate beans must either have an accessible nullary
constructor, or they must be created by the enclosing bean.

Access to subordinate beans is accomplished the same way it is in the rest of
opencsv: accessor methods where available, and Reflection otherwise.

===== Reading into beans without annotations

If annotations are anathema to you, you can bypass them with carefully
structured data and beans.

====== Reading without annotations, column positions

Here's how you can map to a bean based on the field positions in your CSV file:

[source, java]
----
    ColumnPositionMappingStrategy strat = new ColumnPositionMappingStrategy();
    strat.setType(YourOrderBean.class);
    String[] columns = new String[] {"name", "orderNumber", "id"}; // the fields to bind to in your bean
    strat.setColumnMapping(columns);

    CsvToBean csv = new CsvToBean();
    List list = csv.parse(strat, yourReader);
----

====== Reading without annotations, exact header names

With a header name mapping strategy, things are even easier. As long as you do
not annotate anything in the bean, the header name mapping strategy will assume
that all columns may be matched to a member variable of the bean with
precisely the same name (save capitalization). Every field is considered
optional.

If no annotations of any kind are present, the header name mapping strategy is
automatically chosen for you.

====== Reading without annotations, fuzzy header names

If you explicitly specify the mapping strategy FuzzyMappingStrategy, all
annotated member variables are respected, if any are present, and if any input
fields are left unmapped, they will be mapped to the best non-annotated member
variable. "Best" means the closest fuzzy string match between available header
names and available member variable names, case insensitive.

If we have the following input header names:

----
joined header 1,joined header 2,split header,first header,second header,mispeling
----

We could write the following bean:

[source, java]
----
public class MyBean {

    @CsvBindAndJoinByName(column = "joined header [0-9]", elementType = String.class)
    private MultiValuedMap<String, String> joinedFields;

    @CsvBindAndSplitByName(column = "split header", elementType = String.class)
    private List<String> splitFields;

    private Integer firstHeader;

    private Date secondHeader;

    private String misspelling;
}
----

And use this code for reading:

[source, java]
----
MappingStrategy<MyBean> strategy = new FuzzyMappingStrategy<>();
strategy.setType(MyBean.class);
List<MyBean> beans = new CsvToBeanBuilder(FileReader("yourfile.csv"))
    .withMappingStrategy(strategy)
    .build()
    .parse();
----

Everything will work like you want it to with a minimum of annotating. Both
@CsvBindAndJoinByName() as well as @CsvBindAndSplitByName() will be honored
exactly, consuming the headers from the input they are meant to consume. After
that, the fuzzy mapping strategy will compute that the header name
"first header" is closest to the member variable name "firstHeader",
"second header" is closest to "secondHeader", and "mispeling" is closest to
"misspelling". The mappings will be initialized appropriately.

The dangers of this mapping strategy should be obvious. Even though the
algorithm for computing the closest match is stable, the results might not
be obvious to you. If you have headers named "header&nbsp;&nbsp;1" (with two
spaces) and "header 11", and only one member variable named "header1" (perhaps
you wish to ignore "header 11" in the input), it is non-deterministic which of
the two input columns will be mapped to the member variable "header1". You
might accidentally get stuck with the wrong mapping.

A similar problem can arise if the structure of your input data is not stable.
If someone else is in control of the input and may add or delete columns at any
time, fuzzy mappings that have worked fine for a long time may stop working
because the new input file has a better match between header name and member
variable.

Finally, if you have headers that should remain unmatched and member variables
without annotations that should also remain unmatched, you will have a problem.
This mapping strategy will map any unused field to the best unused member
variable, no matter how poor the match. If you need to get around this, the
best way is to annotate the member variable to be skipped and map it to a
fictitious but optional header.

Nonetheless, if you know your data and a mismapping will not cause catastrophic
failure of a critical system, this mapping strategy can save you some
burdensome annotating for obvious mappings.

Since this matching strategy only makes sense for reading, it is not supported
for writing, but it should behave exactly as HeaderColumnNameMappingStrategy.

===== Skipping, filtering, verifying, and ignoring
With some input it can be helpful to skip the first few lines. opencsv provides
for this need with CsvToBeanBuilder.withSkipLines(), which ultimately is used on
the appropriate constructor for CSVReader, if you would prefer to do everything
without the use of the builders. This will skip the first few lines of the raw
input, not the CSV data, in case some input provides heaven knows what before the
first line of CSV data, such as a legal disclaimer or copyright information.

So, for example, you can skip the first two lines by doing:

[source, java]
----
     CSVReader reader = new CSVReader(new FileReader("yourfile.csv"), '\t', '\'', 2);
----

or for reading with annotations:
[source, java]
----
     CsvToBean csvToBean = new CsvToBeanBuilder(new FileReader("yourfile.csv"))
       .withSeparator('\t').withQuoteChar('\'').withSkipLines(2).build();
----

Verifying is slightly different. With verifying, a complete finished bean
is checked for desirability and consistency. By implementing BeanVerifier and
passing it to CsvToBeanBuilder.withVerifier(), each bean will be vetted before
being returned to the calling code. Beans can be silently filtered if they are
simply undesirable data sets, or if the data are inconsistent and this is
considered an error for the surrounding logic, CsvConstraintViolationException
may be thrown. Incidentally, though it is a well-kept secret, the bean passed
to a BeanVerifier is not a copy, so any changes made to the bean will be kept.
This is a way to get a postprocessor for beans into opencsv.

Ignoring applies to fields in beans, and can be achieved via annotation or
method call. If a bean you are manipulating (for reading or writing) includes
fields that you want opencsv to ignore (even if they already bear binding
annotations from opencsv), you can add @CsvIgnore to them and opencsv will
skip them in all reading and writing operations. If you have no source control
over the beans you use, you can use the withIgnoreField() method of the
appropriate builder or the ignoreFields() method of the mapping strategy to
achieve the same effect.