42BV / CSVeed

Light-weight, easy-to-use Java-based CSV utility
Apache License 2.0
100 stars 22 forks source link

NullPointerException with Bean writing with custom mapped column names #46

Open jnash67 opened 10 years ago

jnash67 commented 10 years ago

I'm getting a NullPointerException in the constructor of HeaderImpl.

public HeaderImpl(Line row) { this.header = row; Column currentColumn = new Column(); for (String headerCell : header) { this.indexToName.put(currentColumn, headerCell); this.nameToIndex.put(headerCell.toLowerCase(), currentColumn); currentColumn = currentColumn.nextColumn(); } } I suspect the issue is that the loop for

(String headerCell : header) { is iterating through every property picked up by introspection, and ignoring the fact that properties may have been manually mapped. For reading purposes, I generate I create my BeanInstructions (formerly BeanReaderInstructions) as follows:

private static BeanInstructions getListedPropertiesBeanInstructions(Class clazz, Collection pids) { BeanInstructions bi = new BeanInstructionsImpl(clazz); bi.setMapper(TolerantColumnNameMapper.class); for (String pid : pids) { try { bi.mapColumnNameToProperty(pid, pid); } catch (CsvException ce) { ce.printStackTrace(); } } return bi; } TolerantColumnNameMapper is a ColumnNameMapper that tolaterates missing column names when reading. If I have an old zip file and I've added a field to a Bean, it just gives a warning when the zip file is missing something as opposed to throwing an exception and terminating out of the entire reading process:

import org.csveed.api.Header; import org.csveed.bean.ColumnNameMapper; import org.csveed.common.Column; import org.csveed.report.CsvException; import org.slf4j.Logger; import org.slf4j.LoggerFactory;

public class TolerantColumnNameMapper extends ColumnNameMapper { private final static Logger LOGGER = LoggerFactory.getLogger(TolerantColumnNameMapper.class);

@Override
protected void checkKey(Header header, Column key) {
    try {
        header.getIndex(key.getColumnName());
    } catch (CsvException err) {
        LOGGER.warn("In class " + this.beanInstructions.getBeanClass().getSimpleName() + " -- This is probably a new " +
                "field.  Issue will go away when CSV file is persisted.");
    }
}

}

jnash67 commented 10 years ago

Better formatted version of above:

I'm getting a NullPointerException in the constructor of HeaderImpl.

public HeaderImpl(Line row) {
this.header = row;
Column currentColumn = new Column();
for (String headerCell : header) {
this.indexToName.put(currentColumn, headerCell);
this.nameToIndex.put(headerCell.toLowerCase(), currentColumn);
currentColumn = currentColumn.nextColumn();
}
}

I suspect the issue is that the loop for

(String headerCell : header) {

is iterating through every property picked up by introspection, and ignoring the fact that properties may have been manually mapped. For reading purposes, I generate I create my BeanInstructions (formerly BeanReaderInstructions) as follows:

private static BeanInstructions getListedPropertiesBeanInstructions(Class clazz,
Collection pids) {
BeanInstructions bi = new BeanInstructionsImpl(clazz);
bi.setMapper(TolerantColumnNameMapper.class);
for (String pid : pids) {
try {
bi.mapColumnNameToProperty(pid, pid);
} catch (CsvException ce) {
ce.printStackTrace();
}
}
return bi;
}

TolerantColumnNameMapper is a ColumnNameMapper that tolaterates missing column names when reading. If I have an old zip file and I've added a field to a Bean, it just gives a warning when the zip file is missing something as opposed to throwing an exception and terminating out of the entire reading process:

import org.csveed.api.Header;
import org.csveed.bean.ColumnNameMapper;
import org.csveed.common.Column;
import org.csveed.report.CsvException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TolerantColumnNameMapper<T> extends ColumnNameMapper<T> {
    private final static Logger LOGGER = LoggerFactory.getLogger(TolerantColumnNameMapper.class);

    @Override
    protected void checkKey(Header header, Column key) {
        try {
            header.getIndex(key.getColumnName());
        } catch (CsvException err) {
            LOGGER.warn("In class " + this.beanInstructions.getBeanClass().getSimpleName() + " -- This is probably a new " +
                    "field.  Issue will go away when CSV file is persisted.");
        }
    }
}
robert-bor commented 10 years ago

I understand the use case, although I have been unable to reproduce the error. Would you be able to provide a compact unit test that traps the error?