diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java
index a8984d09c..7468b77a8 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java
@@ -335,9 +335,9 @@ InitializingBean {
if (execution.getStatus().isLessThanOrEqualTo(BatchStatus.STOPPED)
&& execution.getStepExecutions().isEmpty()) {
ExitStatus exitStatus = execution.getExitStatus();
- execution
- .setExitStatus(exitStatus.and(ExitStatus.NOOP
- .addExitDescription("All steps already completed or no steps configured for this job.")));
+ ExitStatus newExitStatus =
+ ExitStatus.NOOP.addExitDescription("All steps already completed or no steps configured for this job.");
+ execution.setExitStatus(exitStatus.and(newExitStatus));
}
execution.setEndTime(new Date());
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/BatchScopeSupport.java b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/BatchScopeSupport.java
new file mode 100644
index 000000000..f65d9dc57
--- /dev/null
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/BatchScopeSupport.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2013 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.scope;
+
+import org.springframework.aop.scope.ScopedProxyUtils;
+import org.springframework.batch.core.scope.context.StepContext;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.config.BeanDefinitionVisitor;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.config.Scope;
+import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.core.Ordered;
+import org.springframework.util.Assert;
+import org.springframework.util.StringValueResolver;
+
+/**
+ * ScopeSupport.
+ *
+ * @author Michael Minella
+ * @since 3.0
+ */
+public abstract class BatchScopeSupport implements Scope, BeanFactoryPostProcessor, Ordered {
+
+ private boolean autoProxy = true;
+
+ private boolean proxyTargetClass = false;
+
+ private String name;
+
+ private int order = Ordered.LOWEST_PRECEDENCE;
+
+ /**
+ * @param order the order value to set priority of callback execution for
+ * the {@link BeanFactoryPostProcessor} part of this scope bean.
+ */
+ public void setOrder(int order) {
+ this.order = order;
+ }
+
+ @Override
+ public int getOrder() {
+ return order;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Public setter for the name property. This can then be used as a bean
+ * definition attribute, e.g. scope="job".
+ *
+ * @param name the name to set for this scope.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Flag to indicate that proxies should use dynamic subclassing. This allows
+ * classes with no interface to be proxied. Defaults to false.
+ *
+ * @param proxyTargetClass set to true to have proxies created using dynamic
+ * subclasses
+ */
+ public void setProxyTargetClass(boolean proxyTargetClass) {
+ this.proxyTargetClass = proxyTargetClass;
+ }
+
+ /**
+ * Flag to indicate that bean definitions need not be auto proxied. This gives control back to the declarer of the
+ * bean definition (e.g. in an @Configuration class).
+ *
+ * @param autoProxy the flag value to set (default true)
+ */
+ public void setAutoProxy(boolean autoProxy) {
+ this.autoProxy = autoProxy;
+ }
+
+ public abstract String getTargetNamePrefix();
+
+ /**
+ * Register this scope with the enclosing BeanFactory.
+ *
+ * @see BeanFactoryPostProcessor#postProcessBeanFactory(ConfigurableListableBeanFactory)
+ *
+ * @param beanFactory the BeanFactory to register with
+ * @throws BeansException if there is a problem.
+ */
+ @Override
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+
+ beanFactory.registerScope(name, this);
+
+ if(!autoProxy) {
+ return;
+ }
+
+ Assert.state(beanFactory instanceof BeanDefinitionRegistry,
+ "BeanFactory was not a BeanDefinitionRegistry, so JobScope cannot be used.");
+ BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
+
+ for (String beanName : beanFactory.getBeanDefinitionNames()) {
+ if (!beanName.startsWith(getTargetNamePrefix())) {
+ BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
+ // Replace this or any of its inner beans with scoped proxy if it
+ // has this scope
+ boolean scoped = name.equals(definition.getScope());
+ Scopifier scopifier = new Scopifier(registry, name, proxyTargetClass, scoped);
+ scopifier.visitBeanDefinition(definition);
+
+ if (scoped && !definition.isAbstract()) {
+ createScopedProxy(beanName, definition, registry, proxyTargetClass);
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Wrap a target bean definition in a proxy that defers initialization until
+ * after the {@link StepContext} is available. Amounts to adding
+ * <aop-auto-proxy/> to a step scoped bean.
+ *
+ * @param beanName the bean name to replace
+ * @param definition the bean definition to replace
+ * @param registry the enclosing {@link BeanDefinitionRegistry}
+ * @param proxyTargetClass true if we need to force use of dynamic
+ * subclasses
+ * @return a {@link BeanDefinitionHolder} for the new representation of the
+ * target. Caller should register it if needed to be visible at top level in
+ * bean factory.
+ */
+ protected static BeanDefinitionHolder createScopedProxy(String beanName, BeanDefinition definition,
+ BeanDefinitionRegistry registry, boolean proxyTargetClass) {
+
+ BeanDefinitionHolder proxyHolder;
+
+ proxyHolder = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(definition, beanName), registry,
+ proxyTargetClass);
+
+ registry.registerBeanDefinition(beanName, proxyHolder.getBeanDefinition());
+
+ return proxyHolder;
+
+ }
+
+ /**
+ * Helper class to scan a bean definition hierarchy and force the use of
+ * auto-proxy for step scoped beans.
+ *
+ * @author Dave Syer
+ *
+ */
+ protected static class Scopifier extends BeanDefinitionVisitor {
+
+ private final boolean proxyTargetClass;
+
+ private final BeanDefinitionRegistry registry;
+
+ private final String scope;
+
+ private final boolean scoped;
+
+ public Scopifier(BeanDefinitionRegistry registry, String scope, boolean proxyTargetClass, boolean scoped) {
+ super(new StringValueResolver() {
+ @Override
+ public String resolveStringValue(String value) {
+ return value;
+ }
+ });
+ this.registry = registry;
+ this.proxyTargetClass = proxyTargetClass;
+ this.scope = scope;
+ this.scoped = scoped;
+ }
+
+ @Override
+ protected Object resolveValue(Object value) {
+
+ BeanDefinition definition = null;
+ String beanName = null;
+ if (value instanceof BeanDefinition) {
+ definition = (BeanDefinition) value;
+ beanName = BeanDefinitionReaderUtils.generateBeanName(definition, registry);
+ }
+ else if (value instanceof BeanDefinitionHolder) {
+ BeanDefinitionHolder holder = (BeanDefinitionHolder) value;
+ definition = holder.getBeanDefinition();
+ beanName = holder.getBeanName();
+ }
+
+ if (definition != null) {
+ boolean nestedScoped = scope.equals(definition.getScope());
+ boolean scopeChangeRequiresProxy = !scoped && nestedScoped;
+ if (scopeChangeRequiresProxy) {
+ // Exit here so that nested inner bean definitions are not
+ // analysed
+ return createScopedProxy(beanName, definition, registry, proxyTargetClass);
+ }
+ }
+
+ // Nested inner bean definitions are recursively analysed here
+ value = super.resolveValue(value);
+ return value;
+
+ }
+ }
+}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/JobScope.java b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/JobScope.java
index e8de653a8..d49667a5f 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/JobScope.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/JobScope.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006-2007 the original author or authors.
+ * Copyright 2006-2013 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.
@@ -19,8 +19,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.scope.context.JobContext;
import org.springframework.batch.core.scope.context.JobSynchronizationManager;
-import org.springframework.batch.core.scope.util.ContextFactory;
-import org.springframework.batch.core.scope.util.JobContextFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.ObjectFactory;
@@ -32,31 +30,34 @@ import org.springframework.beans.factory.config.Scope;
* job. All objects in this scope are <aop:scoped-proxy/> (no need to
* decorate the bean definitions).
*
- *
+ *
* In addition, support is provided for late binding of references accessible
* from the {@link JobContext} using #{..} placeholders. Using this feature,
* bean properties can be pulled from the job or job execution context and the
* job parameters. E.g.
- *
+ *
*
* <bean id="..." class="..." scope="job">
* <property name="name" value="#{jobParameters[input]}" />
* </bean>
- *
+ *
* <bean id="..." class="..." scope="job">
* <property name="name" value="#{jobExecutionContext['input.stem']}.txt" />
* </bean>
*
- *
+ *
* The {@link JobContext} is referenced using standard bean property paths (as
* per {@link BeanWrapper}). The examples above all show the use of the Map
* accessors provided as a convenience for job attributes.
- *
+ *
* @author Dave Syer
* @author Jimmy Praet (create JobScope based on {@link StepScope})
- * @since 2.0
+ * @author Michael Minella
+ * @since 3.0
*/
-public class JobScope extends ScopeSupport {
+public class JobScope extends BatchScopeSupport {
+
+ private static final String TARGET_NAME_PREFIX = "jobScopedTarget.";
private Log logger = LogFactory.getLog(getClass());
@@ -67,20 +68,15 @@ public class JobScope extends ScopeSupport {
*/
public static final String ID_KEY = "JOB_IDENTIFIER";
- /**
- * The ContextFactory.
- */
- private static final ContextFactory CONTEXT_FACTORY = new JobContextFactory();
-
public JobScope() {
- super("job", CONTEXT_FACTORY);
+ super();
+ setName("job");
}
/**
- * If Spring 3.0 is available, this will be used to resolve expressions in
- * job-scoped beans. This method is part of the Scope SPI in Spring 3.0,
- * but should just be ignored by earlier versions of Spring.
+ * This will be used to resolve expressions in job-scoped beans.
*/
+ @Override
public Object resolveContextualObject(String key) {
JobContext context = getContext();
// TODO: support for attributes as well maybe (setters not exposed yet
@@ -91,8 +87,9 @@ public class JobScope extends ScopeSupport {
/**
* @see Scope#get(String, ObjectFactory)
*/
+ @SuppressWarnings("rawtypes")
+ @Override
public Object get(String name, ObjectFactory objectFactory) {
-
JobContext context = getContext();
Object scopedObject = context.getAttribute(name);
@@ -118,6 +115,7 @@ public class JobScope extends ScopeSupport {
/**
* @see Scope#getConversationId()
*/
+ @Override
public String getConversationId() {
JobContext context = getContext();
return context.getId();
@@ -126,6 +124,7 @@ public class JobScope extends ScopeSupport {
/**
* @see Scope#registerDestructionCallback(String, Runnable)
*/
+ @Override
public void registerDestructionCallback(String name, Runnable callback) {
JobContext context = getContext();
logger.debug(String.format("Registered destruction callback in scope=%s, name=%s", this.getName(), name));
@@ -135,6 +134,7 @@ public class JobScope extends ScopeSupport {
/**
* @see Scope#remove(String)
*/
+ @Override
public Object remove(String name) {
JobContext context = getContext();
logger.debug(String.format("Removing from scope=%s, name=%s", this.getName(), name));
@@ -144,7 +144,7 @@ public class JobScope extends ScopeSupport {
/**
* Get an attribute accessor in the form of a {@link JobContext} that can
* be used to store scoped bean instances.
- *
+ *
* @return the current job context which we can use as a scope storage
* medium
*/
@@ -156,4 +156,8 @@ public class JobScope extends ScopeSupport {
return context;
}
-}
\ No newline at end of file
+ @Override
+ public String getTargetNamePrefix() {
+ return TARGET_NAME_PREFIX;
+ }
+}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/ScopeSupport.java b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/ScopeSupport.java
deleted file mode 100644
index ded838484..000000000
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/ScopeSupport.java
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright 2006-2007 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.scope;
-
-import org.springframework.aop.scope.ScopedProxyUtils;
-import org.springframework.batch.core.scope.util.ContextFactory;
-import org.springframework.batch.core.scope.util.PlaceholderProxyFactoryBean;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.beans.factory.config.BeanDefinitionHolder;
-import org.springframework.beans.factory.config.BeanDefinitionVisitor;
-import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
-import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.beans.factory.config.Scope;
-import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-import org.springframework.core.Ordered;
-import org.springframework.util.Assert;
-import org.springframework.util.ReflectionUtils;
-import org.springframework.util.StringValueResolver;
-
-/**
- * ScopeSupport.
- *
- * @author Dave Syer
- */
-public abstract class ScopeSupport implements Scope, BeanFactoryPostProcessor, Ordered {
-
- private static boolean springThreeDetected;
-
- private static boolean cachedSpringThreeResult;
-
- private int order = Ordered.LOWEST_PRECEDENCE;
-
- private String name;
-
- private boolean proxyTargetClass = false;
-
- private ContextFactory contextFactory;
-
- /**
- * ScopeSupport constructor.
- *
- * @param defaultScopeName the default scope name
- * @param contextFactory the ContextFactory
- */
- protected ScopeSupport(String defaultScopeName, ContextFactory contextFactory) {
- this.name = defaultScopeName;
- this.contextFactory = contextFactory;
- }
-
- /**
- * Flag to indicate that proxies should use dynamic subclassing. This allows
- * classes with no interface to be proxied. Defaults to false.
- *
- * @param proxyTargetClass set to true to have proxies created using dynamic
- * subclasses
- */
- public void setProxyTargetClass(boolean proxyTargetClass) {
- this.proxyTargetClass = proxyTargetClass;
- }
-
- /**
- * @param order the order value to set priority of callback execution for
- * the {@link BeanFactoryPostProcessor} part of this scope bean.
- */
- public void setOrder(int order) {
- this.order = order;
- }
-
- public int getOrder() {
- return order;
- }
-
- /**
- * Public setter for the name property. This can then be used as a bean
- * definition attribute, e.g. scope="step".
- *
- * @param name the name to set for this scope.
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * Return the scope name.
- *
- * @return the scope name
- */
- public String getName() {
- return name;
- }
-
- /**
- * Register this scope with the enclosing BeanFactory.
- *
- * @see BeanFactoryPostProcessor#postProcessBeanFactory(ConfigurableListableBeanFactory)
- *
- * @param beanFactory the BeanFactory to register with
- * @throws BeansException if there is a problem.
- */
- public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
-
- beanFactory.registerScope(name, this);
-
- Assert.state(beanFactory instanceof BeanDefinitionRegistry,
- "BeanFactory was not a BeanDefinitionRegistry, so scope cannot be used.");
- BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
-
- for (String beanName : beanFactory.getBeanDefinitionNames()) {
- BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
- // Replace this or any of its inner beans with scoped proxy if it
- // has this scope
- boolean scoped = name.equals(definition.getScope());
- Scopifier scopifier = new Scopifier(registry, name, proxyTargetClass, scoped, contextFactory);
- scopifier.visitBeanDefinition(definition);
- if (scoped) {
- if (!isSpringThree()) {
- new ExpressionHider(name, scoped).visitBeanDefinition(definition);
- }
- createScopedProxy(beanName, definition, registry, proxyTargetClass, contextFactory);
- }
- }
-
- }
-
- private static boolean isSpringThree() {
- if (!cachedSpringThreeResult) {
- springThreeDetected = ReflectionUtils.findMethod(Scope.class, "resolveContextualObject",
- new Class>[] { String.class }) != null;
- cachedSpringThreeResult = true;
- }
- return springThreeDetected;
- }
-
- /**
- * Wrap a target bean definition in a proxy that defers initialization until
- * after the context is available. Amounts to adding
- * <aop-auto-proxy/> to a scoped bean. Also if Spring EL is not
- * available will enable a weak version of late binding as described in the
- * class-level docs.
- *
- * @param beanName the bean name to replace
- * @param definition the bean definition to replace
- * @param registry the enclosing {@link BeanDefinitionRegistry}
- * @param proxyTargetClass true if we need to force use of dynamic
- * subclasses
- * @param contextFactory the ContextFactory
- * @return a {@link BeanDefinitionHolder} for the new representation of the
- * target. Caller should register it if needed to be visible at top level in
- * bean factory.
- */
- private static BeanDefinitionHolder createScopedProxy(String beanName, BeanDefinition definition,
- BeanDefinitionRegistry registry, boolean proxyTargetClass, ContextFactory contextFactory) {
-
- BeanDefinitionHolder proxyHolder;
-
- if (isSpringThree()) {
- proxyHolder = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(definition, beanName), registry,
- proxyTargetClass);
- }
- else {
- // Create the scoped proxy...
- proxyHolder = PlaceholderProxyFactoryBean.createScopedProxy(new BeanDefinitionHolder(definition, beanName),
- registry, proxyTargetClass, contextFactory);
- // ...and register it under the original target name
- }
- registry.registerBeanDefinition(beanName, proxyHolder.getBeanDefinition());
-
- return proxyHolder;
-
- }
-
- /**
- * Helper class to scan a bean definition hierarchy and force the use of
- * auto-proxy for scoped beans.
- *
- * @author Dave Syer
- *
- */
- private static class Scopifier extends BeanDefinitionVisitor {
-
- private final boolean proxyTargetClass;
-
- private final BeanDefinitionRegistry registry;
-
- private final String scope;
-
- private final boolean scoped;
-
- private final ContextFactory contextFactory;
-
- public Scopifier(BeanDefinitionRegistry registry, String scope, boolean proxyTargetClass, boolean scoped,
- ContextFactory contextFactory) {
- super(new StringValueResolver() {
- public String resolveStringValue(String value) {
- return value;
- }
- });
- this.registry = registry;
- this.proxyTargetClass = proxyTargetClass;
- this.scope = scope;
- this.scoped = scoped;
- this.contextFactory = contextFactory;
- }
-
- @Override
- protected Object resolveValue(Object value) {
-
- BeanDefinition definition = null;
- String beanName = null;
- if (value instanceof BeanDefinition) {
- definition = (BeanDefinition) value;
- beanName = BeanDefinitionReaderUtils.generateBeanName(definition, registry);
- }
- else if (value instanceof BeanDefinitionHolder) {
- BeanDefinitionHolder holder = (BeanDefinitionHolder) value;
- definition = holder.getBeanDefinition();
- beanName = holder.getBeanName();
- }
-
- if (definition != null) {
- boolean nestedScoped = scope.equals(definition.getScope());
- boolean scopeChangeRequiresProxy = !scoped && nestedScoped;
- if (!isSpringThree()) {
- new ExpressionHider(scope, nestedScoped).visitBeanDefinition(definition);
- }
- if (scopeChangeRequiresProxy) {
- // Exit here so that nested inner bean definitions are not
- // analysed
- return createScopedProxy(beanName, definition, registry, proxyTargetClass, contextFactory);
- }
- }
-
- // Nested inner bean definitions are recursively analysed here
- value = super.resolveValue(value);
- return value;
-
- }
-
- }
-
- /**
- * Helper class to scan a bean definition hierarchy and hide placeholders
- * from Spring EL.
- *
- * @author Dave Syer
- *
- */
- private static class ExpressionHider extends BeanDefinitionVisitor {
-
- private static final String PLACEHOLDER_PREFIX = "#{";
-
- private static final String PLACEHOLDER_SUFFIX = "}";
-
- private static final String REPLACEMENT_PREFIX = "%{";
-
- private final String scope;
-
- private final boolean scoped;
-
- private ExpressionHider(String scope, final boolean scoped) {
- super(new StringValueResolver() {
- public String resolveStringValue(String value) {
- if (scoped && value.contains(PLACEHOLDER_PREFIX) && value.contains(PLACEHOLDER_SUFFIX)) {
- value = value.replace(PLACEHOLDER_PREFIX, REPLACEMENT_PREFIX);
- }
- return value;
- }
- });
- this.scope = scope;
- this.scoped = scoped;
- }
-
- @Override
- protected Object resolveValue(Object value) {
- BeanDefinition definition = null;
- if (value instanceof BeanDefinition) {
- definition = (BeanDefinition) value;
- }
- else if (value instanceof BeanDefinitionHolder) {
- BeanDefinitionHolder holder = (BeanDefinitionHolder) value;
- definition = holder.getBeanDefinition();
- }
- if (definition != null) {
- String otherScope = definition.getScope();
- boolean scopeChange = !scope.equals(otherScope);
- if (scopeChange) {
- new ExpressionHider(otherScope == null ? scope : otherScope, !scoped)
- .visitBeanDefinition(definition);
- // Exit here so that nested inner bean definitions are not
- // analysed by both visitors
- return value;
- }
- }
- // Nested inner bean definitions are recursively analysed here
- value = super.resolveValue(value);
- return value;
- }
-
- }
-
-}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/StepScope.java b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/StepScope.java
index 3be3bce90..0959d4d70 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/StepScope.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/StepScope.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006-2007 the original author or authors.
+ * Copyright 2006-2013 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.
@@ -19,8 +19,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.scope.context.StepContext;
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
-import org.springframework.batch.core.scope.util.ContextFactory;
-import org.springframework.batch.core.scope.util.StepContextFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.ObjectFactory;
@@ -32,38 +30,41 @@ import org.springframework.beans.factory.config.Scope;
* step. All objects in this scope are <aop:scoped-proxy/> (no need to
* decorate the bean definitions).
* <bean id="..." class="..." scope="step">
* <property name="parent" ref="#{stepExecutionContext[helper]}" />
* </bean>
- *
+ *
* <bean id="..." class="..." scope="step">
* <property name="name" value="#{stepExecutionContext['input.name']}" />
* </bean>
- *
+ *
* <bean id="..." class="..." scope="step">
* <property name="name" value="#{jobParameters[input]}" />
* </bean>
- *
+ *
* <bean id="..." class="..." scope="step">
* <property name="name" value="#{jobExecutionContext['input.stem']}.txt" />
* </bean>
*
- *
+ *
* The {@link StepContext} is referenced using standard bean property paths (as
* per {@link BeanWrapper}). The examples above all show the use of the Map
* accessors provided as a convenience for step and job attributes.
- *
+ *
* @author Dave Syer
+ * @author Michael Minella
* @since 2.0
*/
-public class StepScope extends ScopeSupport {
+public class StepScope extends BatchScopeSupport {
+
+ private static final String TARGET_NAME_PREFIX = "stepScopedTarget.";
private Log logger = LogFactory.getLog(getClass());
@@ -74,20 +75,15 @@ public class StepScope extends ScopeSupport {
*/
public static final String ID_KEY = "STEP_IDENTIFIER";
- /**
- * The ContextFactory.
- */
- private static final ContextFactory CONTEXT_FACTORY = new StepContextFactory();
-
public StepScope() {
- super("step", CONTEXT_FACTORY);
+ super();
+ setName("step");
}
/**
- * If Spring 3.0 is available, this will be used to resolve expressions in
- * step-scoped beans. This method is part of the Scope SPI in Spring 3.0,
- * but should just be ignored by earlier versions of Spring.
+ * This will be used to resolve expressions in step-scoped beans.
*/
+ @Override
public Object resolveContextualObject(String key) {
StepContext context = getContext();
// TODO: support for attributes as well maybe (setters not exposed yet
@@ -98,8 +94,9 @@ public class StepScope extends ScopeSupport {
/**
* @see Scope#get(String, ObjectFactory)
*/
+ @SuppressWarnings("rawtypes")
+ @Override
public Object get(String name, ObjectFactory objectFactory) {
-
StepContext context = getContext();
Object scopedObject = context.getAttribute(name);
@@ -125,6 +122,7 @@ public class StepScope extends ScopeSupport {
/**
* @see Scope#getConversationId()
*/
+ @Override
public String getConversationId() {
StepContext context = getContext();
return context.getId();
@@ -133,6 +131,7 @@ public class StepScope extends ScopeSupport {
/**
* @see Scope#registerDestructionCallback(String, Runnable)
*/
+ @Override
public void registerDestructionCallback(String name, Runnable callback) {
StepContext context = getContext();
logger.debug(String.format("Registered destruction callback in scope=%s, name=%s", this.getName(), name));
@@ -142,6 +141,7 @@ public class StepScope extends ScopeSupport {
/**
* @see Scope#remove(String)
*/
+ @Override
public Object remove(String name) {
StepContext context = getContext();
logger.debug(String.format("Removing from scope=%s, name=%s", this.getName(), name));
@@ -151,7 +151,7 @@ public class StepScope extends ScopeSupport {
/**
* Get an attribute accessor in the form of a {@link StepContext} that can
* be used to store scoped bean instances.
- *
+ *
* @return the current step context which we can use as a scope storage
* medium
*/
@@ -163,4 +163,8 @@ public class StepScope extends ScopeSupport {
return context;
}
+ @Override
+ public String getTargetNamePrefix() {
+ return TARGET_NAME_PREFIX;
+ }
}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/context/JobContext.java b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/context/JobContext.java
index acdd5e0b1..b838d0485 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/scope/context/JobContext.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/scope/context/JobContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006-2007 the original author or authors.
+ * Copyright 2006-2013 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.
@@ -41,9 +41,10 @@ import org.springframework.util.Assert;
* based on bean paths. Has public getters for the job execution and
* convenience methods for accessing commonly used properties like the {@link ExecutionContext} associated with the job
* execution.
- *
+ *
* @author Dave Syer
* @author Jimmy Praet (create JobContext based on {@link StepContext})
+ * @since 3.0
*/
public class JobContext extends SynchronizedAttributeAccessor {
@@ -59,19 +60,19 @@ public class JobContext extends SynchronizedAttributeAccessor {
/**
* Convenient accessor for current job name identifier.
- *
+ *
* @return the job name identifier of the enclosing {@link JobInstance} associated with the current
* {@link JobExecution}
*/
public String getJobName() {
- Assert.state(jobExecution.getJobInstance() != null, "StepExecution does not have a JobInstance");
+ Assert.state(jobExecution.getJobInstance() != null, "JobExecution does not have a JobInstance");
return jobExecution.getJobInstance().getJobName();
}
/**
* Convenient accessor for System properties to make it easy to access them
* from placeholder expressions.
- *
+ *
* @return the current System properties
*/
public Properties getSystemProperties() {
@@ -94,7 +95,7 @@ public class JobContext extends SynchronizedAttributeAccessor {
*/
public Map