Here is another option:
The opencsv library has a lot of useful and flexible annotations, but in this specific case, I would not use any of them.
Instead, I would use the opencsv CSVReaderHeaderAware
class. Using this will allow you to keep your two Book
and Author
classes. The only thing I would change is to add constructors to each class as follows:
Book:
public class Book {
private final String title;
private final Author author1;
private final Author author2;
public Book(String title, Author author1, Author author2) {
this.title = title;
this.author1 = author1;
this.author2 = author2;
}
public String getTitle() {
return title;
}
public Author getAuthor1() {
return author1;
}
public Author getAuthor2() {
return author2;
}
}
Author:
public class Author {
private final String givenName;
private final String surname;
public Author(String givenName, String surname) {
this.givenName = givenName;
this.surname = surname;
}
public String getGivenName() {
return givenName;
}
public String getSurname() {
return surname;
}
}
To populate a list of Book
objects from a CSV file, do this:
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import com.opencsv.CSVReaderHeaderAware;
import com.opencsv.exceptions.CsvValidationException;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
...
public static void main(String[] args) throws FileNotFoundException,
IOException, CsvValidationException {
String bookFile = "/path/to/titles.csv";
CSVReaderHeaderAware csvReader = new CSVReaderHeaderAware(new FileReader(bookFile));
List<Book> books = new ArrayList();
Map<String, String> bookRecord;
while ((bookRecord = csvReader.readMap()) != null) {
books.add(handleBook(bookRecord));
}
}
private static Book handleBook(Map<String, String> bookRecord) {
Author author1 = new Author(
bookRecord.get("author1 given name"),
bookRecord.get("author1 surname")
);
Author author2 = new Author(
bookRecord.get("author2 given name"),
bookRecord.get("author2 surname")
);
return new Book(bookRecord.get("title"), author1, author2);
}
Each row of data from the CSV file is read into a Map
object, where the file headers are the map's keys (you need make sure the file headers are unique). The Map's corresponding values represent one row of data from the CSV file.
The only downside to this is you may need to cast string values to other data types - although not in this case, because the data items are already strings.