diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/SkipLimitStepFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/SkipLimitStepFactoryBean.java index a0c8ea668..8eb878b38 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/SkipLimitStepFactoryBean.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/SkipLimitStepFactoryBean.java @@ -1,5 +1,7 @@ package org.springframework.batch.core.step; +import java.util.Arrays; + import org.springframework.batch.repeat.exception.SimpleLimitExceptionHandler; /** @@ -10,6 +12,8 @@ public class SkipLimitStepFactoryBean extends DefaultStepFactoryBean { private int skipLimit = 0; + private Class[] skippableExceptionClasses = new Class[]{ Exception.class }; + /** * Public setter for a limit that determines skip policy. If this value is * positive then an exception in chunk processing will cause the item to be @@ -22,6 +26,17 @@ public class SkipLimitStepFactoryBean extends DefaultStepFactoryBean { public void setSkipLimit(int skipLimit) { this.skipLimit = skipLimit; } + + /** + * Public setter for exception classes that when raised won't crash the job + * but will result in transaction rollback and the item which handling caused + * the exception will be skipped. + * + * @param skippableExceptionClasses defaults to Exception + */ + public void setSkippableExceptionClasses(Class[] exceptionClasses) { + this.skippableExceptionClasses = exceptionClasses; + } /** * Uses the {@link #skipLimit} value to configure item handler and @@ -38,7 +53,10 @@ public class SkipLimitStepFactoryBean extends DefaultStepFactoryBean { * to absorb exceptions at the step level because the failed items * will never re-appear after a rollback. */ - itemHandler.setItemSkipPolicy(new LimitCheckingItemSkipPolicy(skipLimit)); + itemHandler.setItemSkipPolicy(new LimitCheckingItemSkipPolicy(skipLimit, Arrays.asList(skippableExceptionClasses))); + SimpleLimitExceptionHandler exceptionHandler = new SimpleLimitExceptionHandler(); + exceptionHandler.setLimit(skipLimit); + exceptionHandler.setExceptionClasses(skippableExceptionClasses); setExceptionHandler(new SimpleLimitExceptionHandler(skipLimit)); getStepOperations().setExceptionHandler(getExceptionHandler()); } @@ -50,5 +68,4 @@ public class SkipLimitStepFactoryBean extends DefaultStepFactoryBean { step.setItemHandler(itemHandler); } - } diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/exception/SimpleLimitExceptionHandler.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/exception/SimpleLimitExceptionHandler.java index 0254f657b..ab64586ab 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/exception/SimpleLimitExceptionHandler.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/exception/SimpleLimitExceptionHandler.java @@ -37,7 +37,7 @@ public class SimpleLimitExceptionHandler implements ExceptionHandler { private RethrowOnThresholdExceptionHandler delegate = new RethrowOnThresholdExceptionHandler(); - private Class type = Exception.class; + private Class[] exceptionClasses = new Class[] { Exception.class }; /** * Flag to indicate the the exception counters should be shared between @@ -68,8 +68,10 @@ public class SimpleLimitExceptionHandler implements ExceptionHandler { super(); delegate.setExceptionClassifier(new ExceptionClassifierSupport() { public Object classify(Throwable throwable) { - if (type.isAssignableFrom(throwable.getClass())) { - return TX_INVALID; + for (int i = 0; i < exceptionClasses.length; i++) { + if (exceptionClasses[i].isAssignableFrom(throwable.getClass())) { + return TX_INVALID; + } } return super.classify(throwable); } @@ -106,13 +108,15 @@ public class SimpleLimitExceptionHandler implements ExceptionHandler { } /** - * Setter for the Throwable type that this handler counts. Defaults to - * {@link Exception}. + * Setter for the Throwable exceptionClasses that this handler counts. Defaults to + * {@link Exception}. If more exceptionClasses are specified handler uses single + * counter that is incremented when one of the recognized exception + * exceptionClasses is handled. * * @param type */ - public void setType(Class type) { - this.type = type; + public void setExceptionClasses(Class[] classes) { + this.exceptionClasses = classes; } } diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/repeat/exception/SimpleLimitExceptionHandlerTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/repeat/exception/SimpleLimitExceptionHandlerTests.java index 16c017bdc..815f67151 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/repeat/exception/SimpleLimitExceptionHandlerTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/repeat/exception/SimpleLimitExceptionHandlerTests.java @@ -63,7 +63,7 @@ public class SimpleLimitExceptionHandlerTests extends TestCase { final int MORE_THAN_ZERO = 1; handler.setLimit(MORE_THAN_ZERO); - handler.setType(IllegalArgumentException.class); + handler.setExceptionClasses(new Class[] { IllegalArgumentException.class }); try { handler.handleException(new RepeatContextSupport(null), throwable); @@ -82,7 +82,7 @@ public class SimpleLimitExceptionHandlerTests extends TestCase { public void testLimitedExceptionTypeNotThrown() throws Exception { final int MORE_THAN_ZERO = 1; handler.setLimit(MORE_THAN_ZERO); - handler.setType(RuntimeException.class); + handler.setExceptionClasses(new Class[] {RuntimeException.class} ); try { handler.handleException(new RepeatContextSupport(null), new RuntimeException("foo")); @@ -101,7 +101,7 @@ public class SimpleLimitExceptionHandlerTests extends TestCase { final int MORE_THAN_ZERO = 1; handler.setLimit(MORE_THAN_ZERO); - handler.setType(RuntimeException.class); + handler.setExceptionClasses(new Class[] {RuntimeException.class}); RepeatContextSupport parent = new RepeatContextSupport(null); @@ -125,7 +125,7 @@ public class SimpleLimitExceptionHandlerTests extends TestCase { final int MORE_THAN_ZERO = 1; handler.setLimit(MORE_THAN_ZERO); - handler.setType(RuntimeException.class); + handler.setExceptionClasses(new Class[] { RuntimeException.class } ); handler.setUseParent(true); RepeatContextSupport parent = new RepeatContextSupport(null);