I am trying to persist a person class which has a list of pets to a CSV file and read it back to the corresponding objects. I am able to write it properly but unable to read. Please see below -
Person.java
import java.util.ArrayList;
import java.util.List;
public class Person {
private String name;
private List<Pet> pets;
public Person() {
}
public Person(final String name, final List<Pet> pets) {
this.name = name;
this.pets = pets;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the pets
*/
public List<Pet> getPets() {
return pets;
}
/**
* @param pets
* the pets to set
*/
public void setAddPet(final Pet pet) {
if (pets == null) {
pets = new ArrayList<Pet>();
}
pets.add(pet);
}
/**
* @param name
* the name to set
*/
public void setName(final String name) {
this.name = name;
}
/**
* @param pets
* the pets to set
*/
public void setPets(final List<Pet> pets) {
this.pets = pets;
}
@Override
public String toString() {
return String.format("Person [name=%s, pets=%s]", name, pets);
}
}
Pet.java
public class Pet {
private String typeOfAnimal;
private String color;
public Pet() {
}
public Pet(final String typeOfAnimal, final String color) {
this.typeOfAnimal = typeOfAnimal;
this.color = color;
}
/**
* @return the color
*/
public String getColor() {
return color;
}
/**
* @return the typeOfAnimal
*/
public String getTypeOfAnimal() {
return typeOfAnimal;
}
/**
* @param color
* the color to set
*/
public void setColor(final String color) {
this.color = color;
}
/**
* @param typeOfAnimal
* the typeOfAnimal to set
*/
public void setTypeOfAnimal(final String typeOfAnimal) {
this.typeOfAnimal = typeOfAnimal;
}
@Override
public String toString() {
return String.format("Pet [typeOfAnimal=%s, color=%s]", typeOfAnimal, color);
}
}
Writer.java
import java.io.FileWriter;
import java.util.Arrays;
import java.util.List;
import org.supercsv.cellprocessor.constraint.NotNull;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.io.dozer.CsvDozerBeanWriter;
import org.supercsv.io.dozer.ICsvDozerBeanWriter;
import org.supercsv.prefs.CsvPreference;
public class Writer {
private static final String[] HEADERS = new String[] { "name", "pets" };
private static final CellProcessor[] processors = new CellProcessor[] { new NotNull(),
new NotNull() };
private static final String CSV_FILENAME = "C:\\Users\\Desktop\\Test.csv";
public static void writeWithDozerCsvBeanWriter() throws Exception {
// create the survey responses to write
final Person person1 = new Person("Dereck", Arrays.asList(new Pet("Dog",
"Black")));
final Person person2 =
new Person("Gavin", Arrays.asList(new Pet("Squirrel", "Brown"), new Pet("Cat",
"White")));
final List<Person> people = Arrays.asList(person1, person2);
ICsvDozerBeanWriter beanWriter = null;
try {
beanWriter =
new CsvDozerBeanWriter(new FileWriter(CSV_FILENAME),
CsvPreference.STANDARD_PREFERENCE);
// configure the mapping from the fields to the CSV columns
beanWriter.configureBeanMapping(Person.class, HEADERS);
// write the header
beanWriter.writeHeader(HEADERS);
// write the beans
for (final Person person : people) {
beanWriter.write(person, processors);
}
} finally {
if (beanWriter != null) {
beanWriter.close();
}
}
}
}
Reader.java
import java.io.FileReader;
import org.supercsv.cellprocessor.Optional;
import org.supercsv.cellprocessor.constraint.NotNull;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.io.CsvBeanReader;
import org.supercsv.io.ICsvBeanReader;
import org.supercsv.prefs.CsvPreference;
public class Reader {
private static final String CSV_FILENAME = "C:\\Users\\Desktop\\Test.csv";
/**
* An example of reading using CsvBeanReader.
*/
public static void readWithCsvBeanReader() throws Exception {
ICsvBeanReader beanReader = null;
try {
beanReader =
new CsvBeanReader(new FileReader(CSV_FILENAME),
CsvPreference.STANDARD_PREFERENCE);
// the header elements are used to map the values to the bean (names must
match)
final String[] header = beanReader.getHeader(true);
// set up the field mapping and processors dynamically
final String[] fieldMapping = new String[header.length];
final CellProcessor[] processors = new CellProcessor[header.length];
for (int i = 0; i < header.length; i++) {
if (i < 1) {
// normal mappings
fieldMapping[i] = header[i];
processors[i] = new NotNull();
} else {
// attribute mappings
fieldMapping[i] = "AddPet";
processors[i] = new Optional(new ParsePersonPet(header));
}
}
Person person;
while ((person = beanReader.read(Person.class, fieldMapping, processors)) !=
null) {
System.out.println(String.format("person=%s", person));
}
} finally {
if (beanReader != null) {
beanReader.close();
}
}
}
}
ParsePersonPet.java
import org.supercsv.cellprocessor.CellProcessorAdaptor;
import org.supercsv.util.CsvContext;
public class ParsePersonPet extends CellProcessorAdaptor {
private final String[] header;
public ParsePersonPet(final String[] header) {
this.header = header;
}
@Override
public Object execute(final Object value, final CsvContext context) {
if (value == null) {
return null;
}
final Pet pet = new Pet();
pet.setTypeOfAnimal((String) value);
return pet;
}
}
Currently, its being written to the csv as below -
But when I read it back and print it, it prints as below -
person=Person [name=Dereck, pets=[Pet [typeOfAnimal=[Pet [typeOfAnimal=Dog,
color=Black]], color=null]]]
person=Person [name=Gavin, pets=[Pet [typeOfAnimal=[Pet [typeOfAnimal=Squirrel,
color=Brown], Pet [typeOfAnimal=Cat, color=White]], color=null]]]
I know the problem is in the ParsePersonPet.java at
pet.setTypeOfAnimal((String) value);
But the value seems to be coming back as a String as Pet [typeOfAnimal=Dog, color=Black]
Do I have to use String Tokenizer and set the appropriate values? It could be quite tedious right? What do I do here?
Thanks
Update: I got the code to work by changing my ParsePersonPet to below -
import org.supercsv.cellprocessor.CellProcessorAdaptor;
import org.supercsv.util.CsvContext;
public class ParsePersonPet extends CellProcessorAdaptor {
private final String[] header;
public ParsePersonPet(final String[] header) {
this.header = header;
}
@Override
public Object execute(final Object value, final CsvContext context) {
if (value == null) {
return null;
}
final String str = (String) value;
final Pet pet = new Pet();
pet.setTypeOfAnimal(getValue("typeOfAnimal", str));
pet.setColor(getValue("color", str));
return pet;
}
public String getValue(final String strValueToSearchFor, final String str) {
if (str.contains(strValueToSearchFor)) {
final int startIndex =
str.lastIndexOf(strValueToSearchFor) + strValueToSearchFor.length() + 1;
int endIndex = str.indexOf(",", startIndex);
if (endIndex == -1) {
endIndex = str.indexOf("]", startIndex);
}
return str.substring(startIndex, endIndex);
}
return null;
}
}
I need to know how to avoid the setAddpet and use setPets instead and also what do I do if I have a map of pets instead of a list.
Thanks