This page demonstrates how to configure your CSV Field Mappings to allow you to convert Java Objects into CSV.
Note that any CSV file should be valid as long as it complies with RFC 4180. If you wish to process non-compliant CSV files, you will have to wait until the next release of the CSV Object Mapper.
For the purposes of this demo, let's say that we have a CSV file with the following content:
"First Name", "Last Name", "Street Address", "City", "State", "Zip Code", "Home Phone Number", "Cell Phone Number" "John", "Doe", "123 Test Dr.", "Test City", "HI", "11111", 1231231234, 5554443333 "Jane", "Doe", "321 Tset Dr.", "Tset City", "IA", "99999", 4324324321, 3334445555
Note that the Java Objects to which you map your CSV may be POJOs employing the standard [set/get]ter properties. However, your Objects may be much more "fancy" if you like.
For the purposes of this demo, we want to map to a Java Object that looks like this:
public class Person { private String firstName; private String lastName; private String streetAddress; private String city; private String state; private Integer zipCode; private String homePhoneNumber; private String cellPhoneNumber; public void setFirstName(String firstName) { this.firstName = firstName; } public String getFirstName() { return firstName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getLastName() { return lastName; } public void setStreetAddress(String streetAddress) { this.streetAddress = streetAddress; } public String getStreetAddress() { return streetAddress; } public void setCity(String city) { this.city = city; } public String getCity() { return city; } public void setState(String state) { this.state = state; } public String getState() { return state; } public void setZipCode(Integer zipCode) { this.zipCode = zipCode; } public Integer getZipCode() { return zipCode; } public void setHomePhoneNumber(String homePhoneNumber) { this.homePhoneNumber = homePhoneNumber; } public String getHomePhoneNumber() { return homePhoneNumber; } public void setCellPhoneNumber(String cellPhoneNumber) { this.cellPhoneNumber = cellPhoneNumber; } public String getCellPhoneNumber() { return cellPhoneNumber; } }
We also have a pre-existing mapping file which we want to expand with mapping information for converting Java Objects into CSV. It looks like this:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <bean id="csvToObjectMapper" class="com.projectnine.csvmapper.CsvToObjectMapper"> <property name="csvMappingDefinitions"> <map> <entry key="personMappingDefinition" value-ref="personMappingDefinition" /> </map> </property> </bean> <bean id="personMappingDefinition" class="com.projectnine.csvmapper.CsvMappingDefinition"> <property name="fieldMappings"> <list> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setFirstName(%ARGUMENT%)" /> <property name="columnIndex" value="0" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setLastName(%ARGUMENT%)" /> <property name="columnIndex" value="1" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setStreetAddress(%ARGUMENT%)" /> <property name="columnIndex" value="2" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setCity(%ARGUMENT%)" /> <property name="columnIndex" value="3" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setState(%ARGUMENT%)" /> <property name="columnIndex" value="4" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setZipCode(%ARGUMENT%)" /> <property name="columnIndex" value="5" /> <property name="formatter" ref="integerFormatter" /> <property name="validationCommand" ref="numericalValidator" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setHomePhoneNumber(%ARGUMENT%)" /> <property name="columnIndex" value="6" /> <property name="formatter" ref="phoneNumberFormatter" /> <property name="validationCommand" ref="phoneNumberValidation" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setCellPhoneNumber(%ARGUMENT%)" /> <property name="columnIndex" value="7" /> <property name="formatter" ref="phoneNumberFormatter" /> <property name="validationCommand" ref="phoneNumberValidation" /> </bean> </list> </property> <property name="beanClassName" value="Person" /> <property name="expectedNumberOfFields" value="8" /> </bean> <bean id="integerFormatter" class="com.projectnine.csvmapper.example.IntegerFormatter"> </bean> <bean id="phoneNumberFormatter" class="com.projectnine.csvmapper.examples.PhoneNumberFormatter"> <property name="separator" value="." /> </bean> <bean id="tenCharacterValidator" class="com.projectnine.csvmapper.RegularExpressionCsvFieldValidator"> <property name="regularExpressions"> <list> <value>.{10}</value> </list> </property> <property name="required" value="true" /> </bean> <bean id="numericalValidator" class="com.projectnine.csvmapper.RegularExpressionCsvFieldValidator"> <property name="regularExpressions"> <list> <value>\d+</value> </list> </property> </bean> <bean id="phoneNumberValidation" class="org.apache.commons.chain.impl.ChainBase"> <constructor-arg> <list> <ref bean="tenCharacterValidator" /> <ref bean="numericalValidator" /> </list> </constructor-arg> </bean> </beans>
We want to be able to convert a Person Object into CSV.
This is where the ObjectToCsvMapper comes in.
In order to configure a CsvFieldMapping for conversion of an Object to CSV, we merely define the objectToCsvExpression property of the CsvFieldMapping. For instance, I would adjust my existing CsvFieldMappings as such:
... <property name="fieldMappings"> <list> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setFirstName(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getFirstName()" /> <property name="columnIndex" value="0" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setLastName(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getLastName()" /> <property name="columnIndex" value="1" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setStreetAddress(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getStreetAddress()" /> <property name="columnIndex" value="2" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setCity(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getCity()" /> <property name="columnIndex" value="3" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setState(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getState()" /> <property name="columnIndex" value="4" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setZipCode(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getZipCode()" /> <property name="columnIndex" value="5" /> <property name="formatter" ref="integerFormatter" /> <property name="validationCommand" ref="numericalValidator" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setHomePhoneNumber(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getHomePhoneNumber()" /> <property name="columnIndex" value="6" /> <property name="formatter" ref="phoneNumberFormatter" /> <property name="validationCommand" ref="phoneNumberValidation" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setCellPhoneNumber(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getCellPhoneNumber()" /> <property name="columnIndex" value="7" /> <property name="formatter" ref="phoneNumberFormatter" /> <property name="validationCommand" ref="phoneNumberValidation" /> </bean> </list> </property> ...
Let's take a closer look at the objectToCsvExpression. For instance, person.getCellPhoneNumber(). It looks like a call to the getCellPhoneNumber() method on an Object reference called "person". That's definitely what it is, but how does the mapper know about this "person" Object?
You tell it about it:
... <bean id="personMappingDefinition" class="com.projectnine.csvmapper.CsvMappingDefinition"> <property name="fieldMappings"> ... </property> <property name="beanClassName" value="Person" /> <property name="expectedNumberOfFields" value="8" /> <property name="beanVariableName" value="person" /> </bean> ...
Here is the final configuration:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"> <bean id="csvToObjectMapper" class="com.projectnine.csvmapper.CsvToObjectMapper"> <property name="csvMappingDefinitions"> <map> <entry key="personMappingDefinition" value-ref="personMappingDefinition" /> </map> </property> </bean> <bean id="personMappingDefinition" class="com.projectnine.csvmapper.CsvMappingDefinition"> <property name="fieldMappings"> <list> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setFirstName(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getFirstName()" /> <property name="columnIndex" value="0" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setLastName(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getLastName()" /> <property name="columnIndex" value="1" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setStreetAddress(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getStreetAddress()" /> <property name="columnIndex" value="2" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setCity(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getCity()" /> <property name="columnIndex" value="3" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setState(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getState()" /> <property name="columnIndex" value="4" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setZipCode(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getZipCode()" /> <property name="columnIndex" value="5" /> <property name="formatter" ref="integerFormatter" /> <property name="validationCommand" ref="numericalValidator" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setHomePhoneNumber(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getHomePhoneNumber()" /> <property name="columnIndex" value="6" /> <property name="formatter" ref="phoneNumberFormatter" /> <property name="validationCommand" ref="phoneNumberValidation" /> </bean> <bean class="com.projectnine.csvmapper.CsvFieldMapping"> <property name="csvToObjectExpression" value="setCellPhoneNumber(%ARGUMENT%)" /> <property name="objectToCsvExpression" value="person.getCellPhoneNumber()" /> <property name="columnIndex" value="7" /> <property name="formatter" ref="phoneNumberFormatter" /> <property name="validationCommand" ref="phoneNumberValidation" /> </bean> </list> </property> <property name="beanClassName" value="Person" /> <property name="expectedNumberOfFields" value="8" /> <property name="beanVariableName" value="person" /> </bean> <bean id="integerFormatter" class="com.projectnine.csvmapper.example.IntegerFormatter"> </bean> <bean id="phoneNumberFormatter" class="com.projectnine.csvmapper.examples.PhoneNumberFormatter"> <property name="separator" value="." /> </bean> <bean id="tenCharacterValidator" class="com.projectnine.csvmapper.RegularExpressionCsvFieldValidator"> <property name="regularExpressions"> <list> <value>.{10}</value> </list> </property> <property name="required" value="true" /> </bean> <bean id="numericalValidator" class="com.projectnine.csvmapper.RegularExpressionCsvFieldValidator"> <property name="regularExpressions"> <list> <value>\d+</value> </list> </property> </bean> <bean id="phoneNumberValidation" class="org.apache.commons.chain.impl.ChainBase"> <constructor-arg> <list> <ref bean="tenCharacterValidator" /> <ref bean="numericalValidator" /> </list> </constructor-arg> </bean> </beans>
In general, invokation consists of four steps: load the configuration, collect the Java Objects from which you want to generate CSV, instantiate a com.projectnine.csvmapper.ObjectToCsvMapper that corresponds to your chosen mapping, and spit out some CSV.
Here is how that might look in code:
import java.util.List; import java.util.Vector; import com.projectnine.csvmapper.ObjectToCsvMapper; public class ExampleMappingObjectToCsv { public static void main(String[] args) throws Exception { Person p = new Person(); // Set some properties // Either spit out CSV to a file from a List List<Person> list = new Vector<Person>(); list.add(p); ObjectToCsvMapper objectToCsvMapper = new ObjectToCsvMapper( "personMappingDefinition", "/path/to/some/file.csv"); objectToCsvMapper.writeObjectsToCsv(list); // Or spit out a single line of CSV based on an Object System.out.println(ObjectToCsvMapper.convertObjectToCsv(p, "personMappingDefinition")); } }