7

I am trying to parse a csv file using Jackson CsvParser into an object that also contains a list of another class.

So the first 2 columns contain data that needs to be bound to the parent class and the data afterwards would need to be bound to another class.

public class Person {
    private String name;
    private String age;
    private List<CarDetails> carDetails;

    //Getters+setters
}

public class CarDetails {
    private String carMake;
    private String carRegistration;

    //Getters+setters
}

The log to be parsed would look like:

John Doe, 30, Honda, D32GHF

Or in another log of users all with 2 cars it may look like:

Jane Doe, 29, Mini, F64RTZ, BMW, T56DFG 

To parse the initial 2 items of data to the "Person" class is no problem.

CsvMapper mapper = new CsvMapper();
CsvSchema schema = CsvSchema.builder()
    .addColumn("name")
    .addColumn("age")

for(numberOfCars=2; numberOfCars!=0 ; numberOfCars--)
    schema = schema.rebuild()
        .addColumn("carMake")
        .addColumn("carRegistration")

MappingIterator<Map.Entry> it = mapper
    .reader(Person.class)
    .with(schema)
    .readValues(personLog);
    List<Person> people = new ArrayList<Person>();
    while (it.hasNextValue()) {
        Person person = (Person) it.nextValue();
        people.add(person);
    }

But I do not know how to parse the CarDetails. It seems like I have to be able to search for the value, create a new CarDetails object and add it to the Person object, but I can't see how to extract that information.


My solution is the following:

List<Person> people = new ArrayList<Person>();

MappingIterator<Map<?,?>> it = mapper.reader(schema).withType(Map.class).readValues(personLog);
while(it.hasNextValue()) {
    Person person = new Person();
    CarDetails = new CarDetails();
    Map<?,?> result = it.nextValue();
    person.setName(result.get("name").toString());
    carDetails.setCarMake(result.get("carMake").toString());
    person.addCarDetails(carDetails);
    people.add(person);
}    
DanF7
  • 171
  • 1
  • 2
  • 6

1 Answers1

6

If you look at the Javadoc for CsvMapper.readerWithSchemaFor, it states:

no CSV types can be mapped to arrays or Collections

David Grant
  • 13,929
  • 3
  • 57
  • 63
  • 1
    Yes it seems there isn't a clean way to do this. However in the mean time I've decided to just dump everything into a map and use the schema to identify keys and populate the classes manually. Was hoping there was a better way. Thanks for your input. (I'll post my solution as an update and accept your answer). – DanF7 Sep 26 '12 at 14:30
  • Note that if you add a custom serializer and deserializer, you can do this kind of conversion. You could even use standard JSON `ObjectMapper` for this. – StaxMan Jul 17 '13 at 04:05
  • 1
    With later versions (2.5 and above), Jackson actually DOES support simple List/array types, where value are scalars like Strings, enums or numbers. Separators is by default semicolon (";"), but can be configured to another character. This would not unfortunately work for your case since you are using same separator as columns; and value types are more complex as well. But I thought it worth mentioning if others are looking for simpler List/array usage. – StaxMan Dec 15 '15 at 03:27