diff --git a/spring-batch-core-tests/src/main/resources/META-INF/batch/footballJob.xml b/spring-batch-core-tests/src/main/resources/META-INF/batch/footballJob.xml
index c4f37849d..5e0f4aa44 100644
--- a/spring-batch-core-tests/src/main/resources/META-INF/batch/footballJob.xml
+++ b/spring-batch-core-tests/src/main/resources/META-INF/batch/footballJob.xml
@@ -11,7 +11,7 @@
+ commit-interval="#{jobParameters['commit.interval']}"/>
diff --git a/spring-batch-core-tests/src/main/resources/META-INF/batch/footballSkipJob.xml b/spring-batch-core-tests/src/main/resources/META-INF/batch/footballSkipJob.xml
index f66fda9e5..90102beb0 100644
--- a/spring-batch-core-tests/src/main/resources/META-INF/batch/footballSkipJob.xml
+++ b/spring-batch-core-tests/src/main/resources/META-INF/batch/footballSkipJob.xml
@@ -9,7 +9,7 @@
+ skip-limit="#{jobParameters['skip.limit']}">
diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/football/FootballJobSkipIntegrationTests.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/football/FootballJobSkipIntegrationTests.java
index f4c98a009..64e9cc49a 100644
--- a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/football/FootballJobSkipIntegrationTests.java
+++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/test/football/FootballJobSkipIntegrationTests.java
@@ -82,13 +82,15 @@ public class FootballJobSkipIntegrationTests {
catch (Exception e) {
// Ignore (wrong platform)
}
- JobExecution execution = jobLauncher.run(job, new JobParametersBuilder().addLong("run.id", 1L)
+ JobExecution execution = jobLauncher.run(job, new JobParametersBuilder().addLong("skip.limit", 0L)
.toJobParameters());
assertEquals(BatchStatus.COMPLETED, execution.getStatus());
for (StepExecution stepExecution : execution.getStepExecutions()) {
logger.info("Processed: " + stepExecution);
}
- execution = jobLauncher.run(job, new JobParametersBuilder().addLong("run.id", 2L).toJobParameters());
+ // They all skip on the second execution because of a primary key violation
+ execution = jobLauncher.run(job, new JobParametersBuilder().addLong("skip.limit", 100000L)
+ .toJobParameters());
assertEquals(BatchStatus.COMPLETED, execution.getStatus());
for (StepExecution stepExecution : execution.getStepExecutions()) {
logger.info("Processed: " + stepExecution);
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/ChunkElementParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/ChunkElementParser.java
index e688bf527..7f8bbf4fa 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/ChunkElementParser.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/ChunkElementParser.java
@@ -18,6 +18,7 @@ package org.springframework.batch.core.configuration.xml;
import java.util.List;
import org.springframework.batch.core.listener.StepListenerMetaData;
+import org.springframework.batch.core.step.skip.LimitCheckingItemSkipPolicy;
import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -118,8 +119,26 @@ public class ChunkElementParser {
}
String skipLimit = element.getAttribute("skip-limit");
+ boolean hasSkipPolicy = false;
if (StringUtils.hasText(skipLimit)) {
- propertyValues.addPropertyValue("skipLimit", skipLimit);
+ if (skipLimit.startsWith("#")) {
+ // It's a late binding expression, so we need step scope...
+ BeanDefinitionBuilder skipPolicy = BeanDefinitionBuilder
+ .genericBeanDefinition(LimitCheckingItemSkipPolicy.class);
+ skipPolicy.setScope("step");
+ handleExceptionElement(element, parserContext, skipPolicy.getBeanDefinition().getPropertyValues(),
+ "skippable-exception-classes", "skippableExceptionMap");
+ skipPolicy.addPropertyValue("skipLimit", skipLimit);
+ propertyValues.addPropertyValue("skipPolicy", skipPolicy.getBeanDefinition());
+ hasSkipPolicy = true;
+ }
+ else {
+ propertyValues.addPropertyValue("skipLimit", skipLimit);
+ }
+ }
+ if (!hasSkipPolicy) {
+ handleExceptionElement(element, parserContext, propertyValues, "skippable-exception-classes",
+ "skippableExceptionClasses");
}
handleItemHandler("skip-policy", "skipPolicy", null, false, element, parserContext, propertyValues,
@@ -148,9 +167,6 @@ public class ChunkElementParser {
propertyValues.addPropertyValue("processorTransactional", isProcessorTransactional);
}
- handleExceptionElement(element, parserContext, propertyValues, "skippable-exception-classes",
- "skippableExceptionClasses");
-
handleExceptionElement(element, parserContext, propertyValues, "retryable-exception-classes",
"retryableExceptionClasses");