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");