raghav
raghav

Reputation: 362

Get the object which failed validation Spring Batch validation

I am having this task to process input .csv, .txt files and store the data into a database. I am using Spring Batch for this purpose. Before dumping the data into database, I have to perform some validation checks on the data. I am using Spring Batch's ValidatingItemProcessor and Hibernate's JSR-303 reference implementation hibernate validator for the same. The code looks something like:

public class Person{

@Pattern(regexp = "someregex")
String name;
@NotNull
String address;
@NotNull
String age;

//getters and setters

}

And then I wrote a validator which looks something like this --

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.ValidatorFactory;

import org.springframework.batch.item.validator.ValidationException;
import org.springframework.beans.factory.InitializingBean;

import org.springframework.batch.item.validator.Validator;

 class MyBeanValidator implements Validator<Person>, InitializingBean{

   private javax.validation.Validator validator;

        @Override
        public void afterPropertiesSet() throws Exception {
            ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
            validator = validatorFactory.usingContext().getValidator();
        }

        @Override
        public void validate(Person person) throws ValidationException {
            Set<ConstraintViolation<Object>> constraintViolations =  validator.validate(person);

            if(constraintViolations.size() > 0) {
                generateValidationException(constraintViolations);
            }

        }
private void generateValidationException(Set<ConstraintViolation<Object>>   constraintViolations) {
            StringBuilder message = new StringBuilder();

            for (ConstraintViolation<Object> constraintViolation : constraintViolations) {
                message.append(constraintViolation.getMessage() + "\n");
            }

            throw new ValidationException(message.toString());
}

And then I have a processor which subclasses Spring Batch's ValidatingItemProcessor.

 public class ValidatingPersonItemProcessor extends    ValidatingItemProcessor<Person>{


@Override
public Person process(Person person) {

//some code
 }

The records that pass validation checks would be passed on to another processor for further processing but the failed ones will be cleaned and then passed on to next processor.

  1. Now I want to catch hold of records which failed validation. My objective is to report all input records that failed validation and clean those records further before I could pass on those records to next processor for further processing. How can I achieve this?

  2. Will the Spring Batch process terminate if validation fails for some input? If yes, how to avoid that? My Processor configuration looks something like :

    <batch:chunk reader="personItemReader" writer="personDBWriter"  processor="personProcessor"
                commit-interval="100" skip-limit="100">
                <batch:skippable-exception-classes>
                    <batch:include   class="org.springframework.batch.item.validator.ValidationException"/>
                </batch:skippable-exception-classes>
                <batch:listeners>
                    <batch:listener>
                        <bean
                               class="org.someorg.poc.batch.listener.PersonSkipListener" />
                    </batch:listener>
                </batch:listeners>
            </batch:chunk>
    <bean id="personProcessor"
    class="org.springframework.batch.item.support.CompositeItemProcessor">
      <property name="delegates">
        <list>
          <ref bean="validatingPersonItemProcessor" />
          <ref bean="personVerifierProcessor" />
       </list>
      </property>
    </bean>
       <bean id="validatingPersonItemProcessor" class="org.someorg.poc.batch.processor.ValidatingPersonItemProcessor" scope="step">
       <property name="validator" ref="myBeanValidator" />
       </bean>
    
         <bean id="myBeanValidator" class="org.someorg.poc.batch.validator.MyBeanValidator">
    </bean>
    
        <bean id="personVerifierProcessor" class="org.someorg.poc.batch.processor.PersonVerifierProcessor"     scope="step"/>
       </beans>
    

Upvotes: 1

Views: 5674

Answers (1)

Asoub
Asoub

Reputation: 2371

I guess your validatingPersonItemProcessor bean has his validator parameter set with your myBeanValidator. So the Exception will be thrown by the processor.

Create your own SkipListener. Here you put the logic on what happens when an item is not validated (writtes to a file, a DB, etc.), in the onSkipInProcess();.

You need to add the ValidationException you throw in <batch:skippable-exception-classes> so they will be caught (and doesn't terminate your batch), and add your SkipListener in the <batch:listeners>, so it will be call when an exception is thrown.

EDIT: Answer to comment. If your processor is a ValidatingItemProcessor and you set the validator, it should automatically call validate. However if you make your own ValidatingItemProcessor by extending it, you should explicitely call super.process(yourItem); (process() of ValidatingItemProcessor ) to validate your item.

Upvotes: 3

Related Questions