diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractStepParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractStepParser.java
index a431d4027..e71024087 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractStepParser.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractStepParser.java
@@ -111,6 +111,7 @@ public abstract class AbstractStepParser {
boolean stepUnderspecified) {
bd.setBeanClass(StepParserStepFactoryBean.class);
+ bd.setAttribute("isNamespaceStep", true);
String taskletRef = taskletElement.getAttribute(TASKLET_REF_ATTR);
@SuppressWarnings("unchecked")
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/CoreNamespaceBeanDefinitionUtils.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/CoreNamespaceBeanDefinitionUtils.java
index 693ddd779..53849077c 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/CoreNamespaceBeanDefinitionUtils.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/CoreNamespaceBeanDefinitionUtils.java
@@ -15,10 +15,8 @@
*/
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.PropertyValue;
-import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@@ -29,29 +27,38 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
public class CoreNamespaceBeanDefinitionUtils {
/**
- * @param name the name of a bean definition in the bean factory
+ * @param beanName the name of a bean definition in the bean factory
* @param beanFactory a {@link BeanFactory}
* @return TRUE if the bean represents an {@link AbstractStep} (or
- * {@link StepParserStepFactoryBean}).
+ * {@link StepParserStepFactoryBean}).
*/
- public static boolean isAbstractStep(String name, ConfigurableListableBeanFactory beanFactory) {
- if (beanFactory.isFactoryBean(name)) {
- return beanFactory.isTypeMatch(BeanFactory.FACTORY_BEAN_PREFIX + name, StepParserStepFactoryBean.class);
+ public static boolean isAbstractStep(String beanName, ConfigurableListableBeanFactory beanFactory) {
+ if (beanFactory.isFactoryBean(beanName)) {
+ return beanFactory.isTypeMatch(BeanFactory.FACTORY_BEAN_PREFIX + beanName, StepParserStepFactoryBean.class);
}
- return beanFactory.isTypeMatch(name, AbstractStep.class);
+ return beanFactory.isTypeMatch(beanName, AbstractStep.class);
}
/**
- * @param name a bean definition name
+ * @param beanName a bean definition name
* @param propertyName the name of the property
* @param beanFactory a {@link BeanFactory}
- * @return The {@link PropertyValue} for the {@link JobRepository} of the
- * bean. Search parent hierarchy if necessary. Return null if none is found.
+ * @return The {@link PropertyValue} for the property of the bean. Search
+ * parent hierarchy if necessary. Return null if none is found.
*/
- public static PropertyValue getPropertyValue(String name, String propertyName,
+ public static PropertyValue getPropertyValue(String beanName, String propertyName,
ConfigurableListableBeanFactory beanFactory) {
- PropertyValues jobDefPvs = beanFactory.getMergedBeanDefinition(name).getPropertyValues();
- return jobDefPvs.getPropertyValue(propertyName);
+ return beanFactory.getMergedBeanDefinition(beanName).getPropertyValues().getPropertyValue(propertyName);
}
+ /**
+ * @param beanName a bean definition name
+ * @param attributeName the name of the property
+ * @param beanFactory a {@link BeanFactory}
+ * @return The value for the attribute of the bean. Search parent hierarchy
+ * if necessary. Return null if none is found.
+ */
+ public static Object getAttribute(String beanName, String attributeName, ConfigurableListableBeanFactory beanFactory) {
+ return beanFactory.getMergedBeanDefinition(beanName).getAttribute(attributeName);
+ }
}
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 1f4bf7187..630442fbf 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
@@ -24,6 +24,7 @@ import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.transaction.PlatformTransactionManager;
@@ -47,44 +48,60 @@ public class CoreNamespacePostProcessor implements BeanPostProcessor, BeanFactor
private ApplicationContext applicationContext;
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ for (String beanName : beanFactory.getBeanDefinitionNames()) {
+ injectJobRepositoryIntoSteps(beanName, beanFactory);
+ overrideStepClass(beanName, beanFactory);
+ }
+ }
+
/**
* 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)
+ * @param beanName
+ * @param beanFactory
*/
- public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
- for (String beanName : beanFactory.getBeanDefinitionNames()) {
- BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
- if (bd.hasAttribute(JOB_FACTORY_PROPERTY_NAME)) {
- MutablePropertyValues pvs = (MutablePropertyValues) bd.getPropertyValues();
- if (CoreNamespaceBeanDefinitionUtils.isAbstractStep(beanName, beanFactory)) {
- String jobName = (String) bd.getAttribute(JOB_FACTORY_PROPERTY_NAME);
- 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);
- }
+ private void injectJobRepositoryIntoSteps(String beanName, ConfigurableListableBeanFactory beanFactory) {
+ BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
+ if (bd.hasAttribute(JOB_FACTORY_PROPERTY_NAME)) {
+ MutablePropertyValues pvs = (MutablePropertyValues) bd.getPropertyValues();
+ if (CoreNamespaceBeanDefinitionUtils.isAbstractStep(beanName, beanFactory)) {
+ String jobName = (String) bd.getAttribute(JOB_FACTORY_PROPERTY_NAME);
+ PropertyValue jobRepository = CoreNamespaceBeanDefinitionUtils.getPropertyValue(jobName,
+ JOB_REPOSITORY_PROPERTY_NAME, 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);
}
}
}
}
/**
- * @param jobName
+ * If any of the beans in the parent hierarchy is a <step/> with a
+ * <tasklet/>, then the bean class must be
+ * {@link StepParserStepFactoryBean}.
+ *
+ * @param beanName
* @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) {
- return CoreNamespaceBeanDefinitionUtils.getPropertyValue(jobName, JOB_REPOSITORY_PROPERTY_NAME, beanFactory);
+ private void overrideStepClass(String beanName, ConfigurableListableBeanFactory beanFactory) {
+ BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
+ Object isNamespaceStep = CoreNamespaceBeanDefinitionUtils
+ .getAttribute(beanName, "isNamespaceStep", beanFactory);
+ if (isNamespaceStep != null && (Boolean) isNamespaceStep == true) {
+ ((AbstractBeanDefinition) bd).setBeanClass(StepParserStepFactoryBean.class);
+ }
+ }
+
+ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ return injectDefaults(bean);
}
/**
@@ -96,10 +113,10 @@ public class CoreNamespacePostProcessor implements BeanPostProcessor, BeanFactor
* {@link StepParserStepFactoryBean} without a transactionManager.
*
*
- * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object,
- * java.lang.String)
+ * @param bean
+ * @return
*/
- public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ private Object injectDefaults(Object bean) {
if (bean instanceof JobParserJobFactoryBean) {
JobParserJobFactoryBean fb = (JobParserJobFactoryBean) bean;
JobRepository jobRepository = fb.getJobRepository();
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 bfe414ac4..091973650 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
@@ -317,15 +317,73 @@ public class StepParserTests {
}
@Test
- public void testTaskletElementOverridesParentBeanClass() {
+ public void testInlineTaskletElementOverridesParentBeanClass() {
ApplicationContext ctx = stepParserParentAttributeTestsCtx;
assertTrue(ctx.containsBean("&s12"));
Object factoryBean = ctx.getBean("&s12");
assertTrue(factoryBean instanceof StepParserStepFactoryBean);
+ assertTrue(ctx.containsBean("dummyStep"));
+ Object dummyStep = ctx.getBean("dummyStep");
+ assertTrue(dummyStep instanceof DummyStep);
+
assertTrue(ctx.containsBean("s12"));
Object bean = ctx.getBean("s12");
assertTrue(bean instanceof TaskletStep);
}
+
+ @Test
+ public void testTaskletElementOverridesChildBeanClass() {
+ ApplicationContext ctx = stepParserParentAttributeTestsCtx;
+
+ assertTrue(ctx.containsBean("&s13"));
+ Object factoryBean = ctx.getBean("&s13");
+ assertTrue(factoryBean instanceof StepParserStepFactoryBean);
+
+ assertTrue(ctx.containsBean("s13"));
+ Object bean = ctx.getBean("s13");
+ assertTrue(bean instanceof TaskletStep);
+
+ assertTrue(ctx.containsBean("&dummyStepWithTaskletOnParent"));
+ Object dummyStepFb = ctx.getBean("&dummyStepWithTaskletOnParent");
+ assertTrue(dummyStepFb instanceof StepParserStepFactoryBean);
+
+ assertTrue(ctx.containsBean("dummyStepWithTaskletOnParent"));
+ Object dummyStep = ctx.getBean("dummyStepWithTaskletOnParent");
+ assertTrue(dummyStep instanceof TaskletStep);
+
+ assertTrue(ctx.containsBean("&standaloneStepWithTasklet"));
+ Object standaloneStepFb = ctx.getBean("&standaloneStepWithTasklet");
+ assertTrue(standaloneStepFb instanceof StepParserStepFactoryBean);
+
+ assertTrue(ctx.containsBean("standaloneStepWithTasklet"));
+ Object standaloneStep = ctx.getBean("standaloneStepWithTasklet");
+ assertTrue(standaloneStep instanceof TaskletStep);
+ }
+
+ @Test
+ public void testTaskletElementOverridesParentBeanClass() {
+ ApplicationContext ctx = stepParserParentAttributeTestsCtx;
+
+ assertTrue(ctx.containsBean("&s14"));
+ Object factoryBean = ctx.getBean("&s14");
+ assertTrue(factoryBean instanceof StepParserStepFactoryBean);
+
+ assertTrue(ctx.containsBean("s12"));
+ Object bean = ctx.getBean("s12");
+ assertTrue(bean instanceof TaskletStep);
+
+ assertTrue(ctx.containsBean("&standaloneStepWithTaskletAndDummyParent"));
+ Object standaloneWithTaskletFb = ctx.getBean("&standaloneStepWithTaskletAndDummyParent");
+ assertTrue(standaloneWithTaskletFb instanceof StepParserStepFactoryBean);
+
+ assertTrue(ctx.containsBean("standaloneStepWithTaskletAndDummyParent"));
+ Object standaloneWithTasklet = ctx.getBean("standaloneStepWithTaskletAndDummyParent");
+ assertTrue(standaloneWithTasklet instanceof TaskletStep);
+
+ assertTrue(ctx.containsBean("dummyStep"));
+ Object dummyStep = ctx.getBean("dummyStep");
+ assertTrue(dummyStep 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 3fa9a82a1..c3b8268b0 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
@@ -39,8 +39,10 @@
+
+
-
+
@@ -90,6 +92,17 @@
+
+
+
+
+
+
+
+
+
+