Skip to content
Advertisement

UNIVOCITY-PARSERS for csv to bean object stopping as soon as error has occured

I’m using UNIVOCITY-PARSERS for converting csv file rows into java objects.

while processing the file, if it encounters any problem any of the column in row, then it parsing getting stopped in that row and throwing exception. But i need something which will continue till end of the file just by skipping the row which has error. But i didn’t any utility classes in the api.

MY Bean class

public class ItemcodeBean {

@Trim
@NullString(nulls = { " ", "" }) 
@Parsed(field = "ItemCode")
 private String itemCode;

@Trim 
@NullString(nulls = { " ", "" })
@Parsed(field = "PartNumber") 
private String partNumber;

@Trim 
@NullString(nulls = { " ", "" }) 
@Parsed(field = "ModelNumber") 
private String modelNumber;

}

My Main Class

public class TestClass {

    private  BeanListProcessor<ItemcodeBean>
            rowProcessor = null;
    private CsvParser parser = null;
    public static void main(String[] args) {
        TestClass testClass = new TestClass();
        testClass.init();
        try{
            ItemcodeBean itemcodeBean;
            while ((itemcodeBean = testClass.getRowData()) != null){
                System.out.println(itemcodeBean.toString());
            }
        }catch (Throwable ex){
            System.out.println(ex.getLocalizedMessage());
        }

    }

    private BeanListProcessor<ItemcodeBean> init() {
        // BeanListProcessor converts each parsed row to an instance of a given class, then stores each instance into a list.
              this.rowProcessor =
                new BeanListProcessor<ItemcodeBean>(ItemcodeBean.class);

        CsvParserSettings parserSettings = new CsvParserSettings();
        parserSettings.setProcessor(rowProcessor);
        parserSettings.setHeaderExtractionEnabled(true);
        // skip leading whitespaces
        parserSettings.setIgnoreLeadingWhitespaces(true);

        //skip trailing whitespaces
        parserSettings.setIgnoreTrailingWhitespaces(true);
        //skip empty lines
        parserSettings.setSkipEmptyLines(true);

        File file = new File("C:\Users\abhishyam.c\Downloads\Itemcode_Template.csv");
        this.parser = new CsvParser(parserSettings);
        //parser.parse(file);
        parser.beginParsing(file);
        return rowProcessor;
    }

    private ItemcodeBean getRowData() throws Throwable {
        String[] row;
        try {
            while ((row = parser.parseNext()) != null){
                return rowProcessor.createBean(row, parser.getContext());
            }
        }catch (DataProcessingException e){
            throw new DataProcessingException(e.getColumnName(),e);
        }
       // parser.stopParsing();
        return null;
    }
}

Advertisement

Answer

Just use an error handler and it will keep going unless you throw the exception yourself:

    //Let's set a RowProcessorErrorHandler to log the error. The parser will keep running.
    settings.setProcessorErrorHandler(new RowProcessorErrorHandler() {
        @Override
        public void handleError(DataProcessingException error, Object[] inputRow, ParsingContext context) {
            println(out, "Error processing row: " + Arrays.toString(inputRow));
            println(out, "Error details: column '" + error.getColumnName() + "' (index " + error.getColumnIndex() + ") has value '" + inputRow[error.getColumnIndex()] + "'");
        }
    });

UPDATE: You can prevent the row to be discarded by using a RetryableErrorHandler instead. This is a special implementation added to version 2.3.0, and allows the user to call the methods setDefaultValue() to assign a value to the problematic column, and keepRecord to prevent the record from being discarded.

Example:

settings.setProcessorErrorHandler(new RetryableErrorHandler<ParsingContext>() {
    @Override
    public void handleError(DataProcessingException error, Object[] inputRow, ParsingContext context) {
        //if there's an error in the first column, assign 50 and proceed with the record.
        if (error.getColumnIndex() == 0) { 
            setDefaultValue(50);
        } else { //else keep the record anyway. Null will be used instead.
            keepRecord();
        }
    }
});

Note that if error.getColumnIndex() returns -1, there’s nothing that can be done to save the record, and it will be skipped regardless. You can use this to log the error details.

Advertisement