Validate parsed fields using Univocity Parser

710 Views Asked by At

I wanted to know if there is a way to check and validate a field when using the CsvRoutines package. Basically I want to process a row if the first column has only numbers and skip/possibly throw an exception otherwise. I'm guessing @Validate annotation released in 2.7.0 can be used to achieve this. But I would like to know if there is any other way to achieve the same with earlier versions like 2.5.9?

1

There are 1 best solutions below

3
Jeronimo Backes On BEST ANSWER

Author of the library here. There's no other way other than updating to the latest version. Is there any reason in particular why you can't upgrade?

Update: you can put the @Parsed annotations on the class' getters or setters and perform the validations in them. That is probably the cleanest way to go about it. For example:

class Test {

    private Integer number;

    //accepts a String here... so this is straight from the parser before it tries to convert anything into an integer - which lets you validate or throw a custom exception
    @Parsed
    void setNumber(String number){
        try{
            this.number = Integer.valueOf(number);
        } catch(NumberFormatException e){
            throw new IllegalArgumentException(number + " is not a valid integer");
        }
    }

}

Another alternative is to use a custom conversion class. Copy the code of class ValidatedConversion, used in the newest version, then create subclass like:

public static class RangeLimiter extends ValidatedConversion {
    int min;
    int max;

    public RangeLimiter(String[] args) {
        super(false, false); //not null, not blank
        min = Integer.parseInt(args[0]);
        max = Integer.parseInt(args[1]);
    }

    protected void validate(Object value) {
        super.validate(value); //runs the existing validations for not null and not blank
        int v = ((Number) value).intValue();
        if (v < min || v > max) {
            throw new DataValidationException("out of range: " + min + " >= " + value + " <=" + max);
        }
    }
}

Now on your code, use this:

@Parsed(field = "number")
@Convert(conversionClass = RangeLimiter.class, args = {"1", "10"}) //min = 1, max = 10
public int number;

I didn't test this against an old version. I think you may need to set flag applyDefaultConversion=false in the @Parsed annotation, and make your conversion class convert a String into an int in addition to run the validations.

All in all, that's quite a bit of work that can easily be avoided just by upgrading to the latest version.