package org.supercsv.io;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.exception.SuperCSVException;
import org.supercsv.exception.SuperCSVReflectionException;
import org.supercsv.prefs.CsvPreference;
import org.supercsv.util.BeanInterfaceProxy;
import org.supercsv.util.MethodCache;
import org.supercsv.util.Util;
/**
* This class reads a line from a csv file, instantiates a bean and populate its fields.
*
* @author Kasper B. Graversen
*/
public class CsvBeanReader extends AbstractCsvReader implements ICsvBeanReader {
/**
* object used for storing intermediate result of a processing of cell processors and before put into maps/objects etc..
* due to the typing, we cannot use super.line
*/
protected List<? super Object> lineResult = new ArrayList<Object>();
protected MethodCache cache = new MethodCache();
/**
* Create a csv reader with a specific preference. Note that the <tt>reader</tt> provided in the argument will be
* wrapped in a <tt>BufferedReader</tt> before accessed.
*/
public CsvBeanReader(final Reader reader, final CsvPreference preferences) {
setPreferences(preferences);
setInput(reader);
}
/**
* Creates an object of the type or if it is an interface, create a proxy instance implementing the interface type.
*
* @param clazz
* the type to instantiate. If the type is a class type, an instance can be created straight away. If the
* type is an interface type, a proxy is created on the fly which acts as an implementation.
* @param nameMapping
* @return A filled object
* @throws InstantiationException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
<T> T fillObject(final Class<T> clazz, final String[] nameMapping) throws SuperCSVReflectionException {
try {
// create a proxy instance if an interface type is provided
final T resultBean;
if( clazz.isInterface() ) {
resultBean = (T) new BeanInterfaceProxy().createProxy(clazz);
} else {
resultBean = clazz.newInstance();
}
// map results into an object by traversing the list of nameMapping and for each non-null,
// map that name to an entry in the lineResult
// map results to the setter methods
for( int i = 0; i < nameMapping.length; i++ ) {
// don't call a set-method in the bean, if there is no result to store
if( nameMapping[i] == null ) {
continue;
}
try {
// System.out.println(String.format("mapping[i]= %s, lR[%d] = %s val '%s'", nameMapping[i], i,
// lineResult
// .get(i).getClass(), lineResult.get(i)));
cache.getSetMethod(resultBean, nameMapping[i], lineResult.get(i).getClass())//
.invoke(resultBean, lineResult.get(i));
}
catch(final IllegalArgumentException e) {
throw new SuperCSVException("Method set" + nameMapping[i].substring(0, 1).toUpperCase()
+ nameMapping[i].substring(1) + "() does not accept input \"" + lineResult.get(i) + "\" of type "
+ lineResult.get(i).getClass().getName(), null, e);
}
}
return resultBean;
}
catch(final InstantiationException e) {
throw new SuperCSVReflectionException("Error while filling an object", e);
}
catch(final IllegalAccessException e) {
throw new SuperCSVReflectionException("Error while filling an object", e);
}
catch(final InvocationTargetException e) {
throw new SuperCSVReflectionException("Error while filling an object", e);
}
}
/**
* {@inheritDoc}
*/
public <T> T read(final Class<T> clazz, final String... nameMapping) throws IOException, SuperCSVReflectionException {
if( tokenizer.readStringList(super.line) ) {
lineResult.clear();
lineResult.addAll(super.line);
return fillObject(clazz, nameMapping);
}
return null; // EOF
}
/**
* {@inheritDoc}
*/
public <T> T read(final Class<T> clazz, final String[] nameMapping, final CellProcessor[] processors)
throws IOException, SuperCSVReflectionException, SuperCSVException {
if( tokenizer.readStringList(super.line) ) {
Util.processStringList(lineResult, super.line, processors, tokenizer.getLineNumber());
return fillObject(clazz, nameMapping);
}
return null; // EOF
}
}
|