3

When using Univocity FixedWidthParser, how can I add the record/line number as a field in the parsed bean?

  1. Is there an option where a bean property can be tagged as Record Number like:
   // Bean representing a record
   public class MyRecord {
  
          @RecordNumber //like this, record or line number from the context is assigned as value
          long recordNumber; 
      
          @Parsed
          String name;
         
          //other parsed fields
          }
      }
  1. I am using a InputValueSwitch. Is there a way where the context can be got within the rowProcessorSwitched() so that I can try:
final BeanListProcessor<MyRecord> myProcessor = new BeanListProcessor<MyRecord>(
                    MyRecord.class);

public void rowProcessorSwitched(RowProcessor from, RowProcessor to) {
    ParsingContext context = ... //how to get this?
    long lineNumber = context.currentLine(); //if i can get this...
    if (from == myProcessor){
      (MyRecord)myProcessor.getBeans().get(0).setRecordNumber(lineNumber); //...then this should be possible
      //other switch logic
    }
} 

Update: Within the InputSwitch, I have tried to implement processStarted

   ParsingContext refToContext = null;
   
   public void processStarted(ParsingContext context) {
     refToContext = context;
     super.processStarted(context);
  } 

and within the rowProcessorSwitched() use it like,

long lineNumber = refToContext.currentLine() - 1;

Is this a valid approach? Is it dependable - esp, when errors are faced during parsing.

GSai
  • 132
  • 2
  • 9
  • Was going to write an answer, but I don't have one for "how to use a custom row processor." Instead, I've been setting the property during my first loop through the beans. Sadly, it seems that the library owner is no longer active; doesn't respond to support emails, doesn't respond to issues on GitHub... – randy Jul 21 '21 at 13:23

1 Answers1

1

This solution doesn't use InputSwitch or InputValueSwitch, but does produce beans with a rowNumber property which represents their row number.

final BeanListProcessor<MyRecord> myProcessor = new BeanListProcessor(MyRecord.class) {

    public void beanProcessed(Object bean, Context context) {
        bean.setRowNumber(beans.size());  // +/- to adjust for header row(s)
        super.beanProcessed(bean, context);
    }
}

The only thing I have to do to trigger this is make sure this processor is assigned to the settings object of the parser, then call parse() on the instance of CsvParser to which I've assigned those settings.

CsvParserSettings csvSettings = new CsvParserSettings();
csvSettings.setProcessor(myProcessor);

CsvParser csvParser = new CsvParser(csvSettings);
csvParser.parse();

Note that I omitted the @Override annotation on the inner function. For whatever reason, in my production implementation, IntelliJ says this doesn't override the super class, but tests clearly show this working. I used IntelliJ's "Generate" option to stub this method, so who knows...

Also note that my production code is in Groovy, so please excuse any syntax issues; I'm converting to Java in my head.

randy
  • 369
  • 4
  • 12