Reputation: 5424
Consider Person and Address classes as:
class Person {
String name;
int age;
Address first;
Address second;
}
class Address {
String country;
String city;
}
I want to parse csv file to Person objects. sample csv file is:
NAME,AGE,COUNTERY_1,CITY_1,COUNTRY_2,CITY_2
john,50,USA,Arizona,UK,London
bob,27,France,paris,USA,Felorida
I write a model method:
CsvSchema bootstrapSchema = CsvSchema.emptySchema().withHeader();
CsvMapper mapper = new CsvMapper();
MappingIterator<Person> readValues = mapper
.readerWithTypedSchemaFor(Person.class)
.with(bootstrapSchema)
.readValues(file);
return readValues.readAll();
How to add Address class mapping to mapper?
Upvotes: 2
Views: 665
Reputation: 6289
You can't really do this with Jackson, but univocity-parsers can with its @Nested
annotation:
First define your Address
class like this:
public static class Address {
@Parsed
String country;
@Parsed
String city;
@Override
public String toString() {
return "Address{country='" + country + '\'' + ", city='" + city + '\'' + '}';
}
}
Now if you look at your input, we need to somehow associate the headers "country_1" and "city_1" with the fields in your Address
class. This is done using a custom HeaderTransformer
class that appends the index to the header name. Let's define it like this:
public static class SuffixAppender extends HeaderTransformer {
private String suffix;
public SuffixAppender(String... args) {
suffix = args[0];
}
@Override
public String transformName(Field field, String name) {
return name + "_" + suffix;
}
}
Now you can define your Person
class with nested Address
attributes:
public static class Person {
@Parsed
String name;
@Parsed
int age;
@Nested(headerTransformer = SuffixAppender.class, args = "1")
Address first;
@Nested(headerTransformer = SuffixAppender.class, args = "2")
Address second;
@Override
public String toString() {
return "Person{name='" + name + '\'' + ", age=" + age + ", first=" + first + ", second=" + second + '}';
}
}
The above instructs the parser to get the field names in Address
and append the given suffix to it with your SuffixAppender
. The result will be matched against the headers of your input.
Finally you are ready to parse. There are many ways to use the parser, but the simplest is:
String input = "" +
"NAME,AGE,COUNTRY_1,CITY_1,COUNTRY_2,CITY_2\n" +
"john,50,USA,Arizona,UK,London\n" +
"bob,27,France,paris,USA,Florida";
CsvParserSettings settings = new CsvParserSettings(); //configure the parser
settings.detectFormatAutomatically(); //detects line separators and delimiters
//parse the input with the settings above, into a list of Person objects
List<Person> personList = new CsvRoutines(settings).parseAll(Person.class, new StringReader(input));
Let's see the result with:
Person person1 = personList.get(0);
Person person2 = personList.get(1);
System.out.println(person1);
System.out.println(person2);
Output:
Person{name='john', age=50, first=Address{country='USA', city='Arizona'}, second=Address{country='UK', city='London'}}
Person{name='bob', age=27, first=Address{country='France', city='paris'}, second=Address{country='USA', city='Florida'}}
Hope it helps.
Disclaimer: I'm the author of this library. It's open source and free (Apache 2.0 license)
Upvotes: 2