diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/CoreNamespacePostProcessor.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/CoreNamespacePostProcessor.java index 8dfaf699c..318e38ed2 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/CoreNamespacePostProcessor.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/CoreNamespacePostProcessor.java @@ -16,6 +16,7 @@ package org.springframework.batch.core.configuration.xml; import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.AbstractStep; import org.springframework.beans.BeansException; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.PropertyValue; @@ -50,7 +51,8 @@ public class CoreNamespacePostProcessor implements BeanPostProcessor, BeanFactor private ApplicationContext applicationContext; /** - * Inject job-repository from a job into its steps. + * Automatically inject job-repository from a job into its steps. Only + * inject if the step is an AbstractStep or StepParserStepFactoryBean. * * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory) */ @@ -59,30 +61,85 @@ public class CoreNamespacePostProcessor implements BeanPostProcessor, BeanFactor BeanDefinition bd = beanFactory.getBeanDefinition(beanName); MutablePropertyValues pvs = (MutablePropertyValues) bd.getPropertyValues(); if (pvs.contains(JOB_FACTORY_PROPERTY_NAME)) { - String jobName = (String) pvs.getPropertyValue(JOB_FACTORY_PROPERTY_NAME).getValue(); - PropertyValue jobRepository = getJobRepository(beanFactory, jobName); - if (jobRepository != null) { - pvs.addPropertyValue(jobRepository); - } - else { - RuntimeBeanReference jobRepositoryBeanRef = new RuntimeBeanReference(DEFAULT_JOB_REPOSITORY_NAME); - pvs.addPropertyValue(JOB_REPOSITORY_PROPERTY_NAME, jobRepositoryBeanRef); + if (isAbstractStep(bd, beanFactory)) { + String jobName = (String) pvs.getPropertyValue(JOB_FACTORY_PROPERTY_NAME).getValue(); + PropertyValue jobRepository = getJobRepository(jobName, beanFactory); + if (jobRepository != null) { + // Set the job's JobRepository onto the step + pvs.addPropertyValue(jobRepository); + } + else { + // No JobRepository found, so inject the default + RuntimeBeanReference jobRepositoryBeanRef = new RuntimeBeanReference( + DEFAULT_JOB_REPOSITORY_NAME); + pvs.addPropertyValue(JOB_REPOSITORY_PROPERTY_NAME, jobRepositoryBeanRef); + } } pvs.removePropertyValue(JOB_FACTORY_PROPERTY_NAME); } } } - private PropertyValue getJobRepository(ConfigurableListableBeanFactory beanFactory, String jobName) { + /** + * @param bd + * @param beanFactory + * @return TRUE if the bean represents an AbstractStep (or + * StepParserStepFactoryBean). + */ + private boolean isAbstractStep(BeanDefinition bd, ConfigurableListableBeanFactory beanFactory) { + Class stepClass = getClass(bd, beanFactory); + return StepParserStepFactoryBean.class.isAssignableFrom(stepClass) + || AbstractStep.class.isAssignableFrom(stepClass); + } + + /** + * @param bd + * @param beanFactory + * @return The class of the bean. Search parent hierarchy if necessary. + * Return null if none is found. + */ + private Class getClass(BeanDefinition bd, ConfigurableListableBeanFactory beanFactory) { + // Get the declared class of the bean + String className = bd.getBeanClassName(); + if (StringUtils.hasText(className)) { + try { + return Class.forName(className); + } + catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + else { + // Search the parent until you find it + String parentName = bd.getParentName(); + if (StringUtils.hasText(parentName)) { + return getClass(beanFactory.getBeanDefinition(parentName), beanFactory); + } + else { + return null; + } + } + } + + /** + * @param jobName + * @param beanFactory + * @return The {@link PropertyValue} for the {@link JobRepository} of the + * bean. Search parent hierarchy if necessary. Return null if none + * is found. + */ + private PropertyValue getJobRepository(String jobName, ConfigurableListableBeanFactory beanFactory) { BeanDefinition jobDef = beanFactory.getBeanDefinition(jobName); PropertyValues jobDefPvs = jobDef.getPropertyValues(); if (jobDefPvs.contains(JOB_REPOSITORY_PROPERTY_NAME)) { + // return the job repository property return jobDefPvs.getPropertyValue(JOB_REPOSITORY_PROPERTY_NAME); } else { + // Search the parent until you find it String parentName = jobDef.getParentName(); if (StringUtils.hasText(parentName)) { - return getJobRepository(beanFactory, parentName); + return getJobRepository(parentName, beanFactory); } else { return null; diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/DummyStep.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/DummyStep.java new file mode 100644 index 000000000..b5c1f625b --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/DummyStep.java @@ -0,0 +1,50 @@ +/* + * Copyright 2006-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.core.configuration.xml; + +import org.springframework.batch.core.JobInterruptedException; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.StepExecution; +import org.springframework.beans.factory.BeanNameAware; + +/** + * @author Dan Garrette + * @since 2.0.1 + */ +public class DummyStep implements Step, BeanNameAware { + + private String name; + + public String getName() { + return name; + } + + public void setBeanName(String name) { + this.name = name; + } + + public void execute(StepExecution stepExecution) throws JobInterruptedException { + System.out.println("EXECUTING " + getName()); + } + + public int getStartLimit() { + return 100; + } + + public boolean isAllowStartIfComplete() { + return false; + } +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserTests.java index b3bb5163a..15a60632a 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/StepParserTests.java @@ -308,4 +308,14 @@ public class StepParserTests { } return property; } + + @Test + public void testNonAbstractStep() { + ApplicationContext ctx = new ClassPathXmlApplicationContext( + "org/springframework/batch/core/configuration/xml/StepParserParentAttributeTests-context.xml"); + + assertTrue(ctx.containsBean("s11")); + Object bean = ctx.getBean("s11"); + assertTrue(bean instanceof DummyStep); + } } diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserParentAttributeTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserParentAttributeTests-context.xml index 3e1cbc634..f830b1734 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserParentAttributeTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepParserParentAttributeTests-context.xml @@ -34,7 +34,8 @@ - + + @@ -84,6 +85,8 @@ + +