3

I'm trying to write unit tests for my Spring Batch job components, stating with my processor. According to all the information I've found online, I'm doing it correctly. But Spring can't find my processor bean when I try to autowire it into my test class.

The name of my processor class is BatchFileRecordProcessor. My test class is BatchFileRecordProcessorTest. Here's the code for the latter:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/launch-context.xml"})
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, StepScopeTestExecutionListener.class})
public class BatchFileRecordProcessorTest
{
    @Autowired
    private BatchFileRecordProcessor processor = new BatchFileRecordProcessor();

    @Inject
    private BatchFileRecord batchFileRecord;

    public StepExecution getStepExecution()
    {
        StepExecution stepExecution = MetaDataInstanceFactory.createStepExecution();
        stepExecution.getExecutionContext().putString("fileName", "part-r-00000");

        return stepExecution;
    }

    @Test
    public void process() throws Exception
    {
        batchFileRecord.setSomeField("someValue");
        batchFileRecord.setSomeOtherField("someOtherValue");

        List<SetIdentityLinkInput> inputs = processor.process(batchFileRecord);
        assertEquals(1, inputs.size());
    }
}

And here's my launch-context.xml file, where all my Spring configuration is located:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:batch="http://www.springframework.org/schema/batch"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="com.mobile.identity.batch" />

    <batch:job id="IdentitySojournerLogsBatch">
        <batch:validator ref="jobParametersValidator" />
        <batch:step id="batchJob.master">
            <batch:partition step="batchJob" partitioner="partitioner">
                <batch:handler grid-size="20" task-executor="partitionTaskExecutor" />
            </batch:partition>
        </batch:step>
        <batch:listeners>
            <batch:listener ref="jobListener"/>
        </batch:listeners>
    </batch:job>

    <bean id="partitioner" class="org.springframework.batch.core.partition.support.MultiResourcePartitioner" scope="step">
        <property name="resources" value="#{jobParameters['input.file.dir']}" />
    </bean>

    <bean id="partitionTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <property name="maxPoolSize" value="20" />
        <property name="corePoolSize" value="10" />
        <property name="queueCapacity" value="80" />
        <property name="WaitForTasksToCompleteOnShutdown" value="true" />
    </bean>

    <batch:step id="batchJob">
        <batch:tasklet>
            <batch:chunk reader="logFileReader" processor="batchFileRecordProcessor" writer="setIdentityLinkWriter" commit-interval="10" />
            <batch:listeners>
                <batch:listener ref="fileNameListener" />
                <batch:listener ref="logFileReaderListener" />
            </batch:listeners>
        </batch:tasklet>
    </batch:step>

    <bean id="logFileReaderParent" class="org.springframework.batch.item.file.FlatFileItemReader" abstract="true">
        <property name="lineMapper">
            <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
                <property name="lineTokenizer">
                    <bean class="com.mobile.identity.batch.components.AmpersandDelimitedNameValuePairTokenizer">
                        <property name="names" value="isErrorRecord,deviceId,provider,deviceType,operatingSystem,operatingSystemVersion,idfaTag,timestamp,identifierCount,identifierString" />
                    </bean>
                </property>
                <property name="fieldSetMapper">
                    <bean class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
                        <property name="prototypeBeanName" value="batchFileRecord" />
                    </bean>
                </property>
            </bean>
        </property>
    </bean>

    <bean id="logFileReader" scope="step" autowire-candidate="false" parent="logFileReaderParent">
        <property name="resource" value="#{stepExecutionContext[fileName]}" />
    </bean>

    <bean id="batchFileRecordProcessor" class="com.mobile.identity.batch.components.BatchFileRecordProcessor" autowire-candidate="true" scope="step" />

    <bean id="batchFileRecord" class="com.mobile.identity.batch.model.BatchFileRecord" scope="prototype" />
</beans>

Here's the exception I get when I try to run my test class:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.mobile.identity.batch.components.BatchFileRecordProcessorTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mobile.identity.batch.components.BatchFileRecordProcessor com.mobile.identity.batch.components.BatchFileRecordProcessorTest.processor; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.mobile.identity.batch.components.BatchFileRecordProcessor] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:374)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:290)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:202)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:65)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mobile.identity.batch.components.BatchFileRecordProcessor com.mobile.identity.batch.components.BatchFileRecordProcessorTest.processor; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.mobile.identity.batch.components.BatchFileRecordProcessor] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:506)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:284)
    ... 29 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.mobile.identity.batch.components.BatchFileRecordProcessor] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:924)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:793)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:707)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478)
    ... 31 more

2014/04/08 22-13-59,938:ERR:ERROR[Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@569cc9e9] to prepare test instance [com.mobile.identity.batch.components.BatchFileRecordProcessorTest@4f8c0c6b]]

[org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues threw org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.mobile.identity.batch.components.BatchFileRecordProcessorTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mobile.identity.batch.components.BatchFileRecordProcessor com.mobile.identity.batch.components.BatchFileRecordProcessorTest.processor; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.mobile.identity.batch.components.BatchFileRecordProcessor] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}]

I tried stepping through the Spring code in IntelliJ's debugger when attempting to run the unit test; Spring appears to be finding my batchFileRecordProcessor bean definition in launch-context.xml, but it's not determining it to be a suitable autowire candidate for the dependency in my test class for some reason. I tried adding the 'autowire-candidate="true"' attribute to the batchFileRecordProcessor bean definition in launch-context.xml, but that didn't change the output. Kinda stumped at this point.

EDIT: Thanks for the responses. The call to the BatchFileRecordProcessor constructor was a mistake, left over from when I was trying an alternate approach that didn't involve dependency injection.

Here's the BatchFileRecordProcessor class definition: I've snipped out all the business logic methods which are (I assume) irrelevant to this issue:

/**
 *
 */
@Component("batchFileRecordProcessor")
@Scope("step")
public class BatchFileRecordProcessor implements ItemProcessor<BatchFileRecord, List<SetIdentityLinkInput>>
{
    /**
     */
    @Override
    public List<SetIdentityLinkInput> process(BatchFileRecord record) throws Exception
    {
        ...Bunch of stuff...
    }

    /**
     *
     * @param fileName
     */
    @Value("#{stepExecutionContext[fileName]}")
    public void setFileName(String fileName)
    {
        this.fileName = jobUtils.getFileNameFromFullPath(fileName);
    }
}

Note that I do have one method that's getting a step execution parameter injected; not sure if that's relevant at all.

I tried adding the nested aop:scoped-proxy tag as per the suggestion, and am now getting a different exception:

java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:157)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:290)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:202)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:65)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'batchFileRecordProcessor' defined in BeanDefinition defined in class path resource [launch-context.xml]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy22]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy22
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:567)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:103)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:1)
    at org.springframework.test.context.support.DelegatingSmartContextLoader.loadContext(DelegatingSmartContextLoader.java:228)
    at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:124)
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:148)
    ... 27 more
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy22]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy22
    at org.springframework.aop.framework.Cglib2AopProxy.getProxy(Cglib2AopProxy.java:213)
    at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:112)
    at org.springframework.aop.scope.ScopedProxyFactoryBean.setBeanFactory(ScopedProxyFactoryBean.java:109)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1475)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1443)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
    ... 40 more
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy22
    at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
    at net.sf.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
    at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
    at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
    at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
    at org.springframework.aop.framework.Cglib2AopProxy.getProxy(Cglib2AopProxy.java:201)
    ... 45 more

2014/04/09 09-46-30,053:ERR:ERROR[Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@aa0399b] to prepare test instance [com.mobile.identity.batch.components.BatchFileRecordProcessorTest@1d25f490]]

[org.springframework.test.context.TestContext.getApplicationContext threw java.lang.IllegalStateException: Failed to load ApplicationContext]
magnetichf
  • 33
  • 1
  • 5

3 Answers3

3

This is a bit late, but instead of @Autowired, try this annotation:

@Resource(name="batchFileRecordProcessor") 

This will explicitly instruct Spring to wire that bean to your class. From there, you should get an error message from Spring about WHY it doesn't like the expected bean.

In my case I got an error like this:

Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: 
Bean named 'applicationEnrichmentProcessor' must be of type [com.xxxx.YyyyProcessor], 
but was actually of type [com.sun.proxy.$Proxy24]

After reading Fixing BeanNotOfRequiredTypeException on Spring proxy cast on a non-singleton bean? and this Spring forum post, I found the problem was solved by adding this annotation:

@EnableAspectJAutoProxy(proxyTargetClass=true) 

This causes Spring's proxy mechanism to proxy your class, rather than the class's interfaces, as described in the Spring documentation.

Since your BatchFileRecordProcessor implements an ItemProcessor interface, I suspect this is your problem as well.

Community
  • 1
  • 1
JBCP
  • 13,109
  • 9
  • 73
  • 111
1

You've declared

<bean id="batchFileRecordProcessor" class="com.mobile.identity.batch.components.BatchFileRecordProcessor" autowire-candidate="true" scope="step" />

Because of the scope, Spring will create a proxy for your bean and inject that. By default, it will use JDK proxies which don't work with class types, only interface types. As such, no bean will exist in your context which is of type BatchFileRecordProcessor and therefore none will be available to satisfy the @Autowired dependency. Instead, only a bean of some Proxy type will exist.

You can force Spring to use CGLIB proxies that do work with class types

<bean id="batchFileRecordProcessor" class="com.mobile.identity.batch.components.BatchFileRecordProcessor" autowire-candidate="true" scope="step">
    <aop:scoped-proxy proxy-target-class="true"/>
</bean>

I'm sure right now why you get the exception (well I know why, but I'm not sure how to fix it in XML). If you're using annotations, we're set. Get rid of the <bean> declaration and change your @Component to

@Component("batchFileRecordProcessor")
@Scope(value = "step", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class BatchFileRecordProcessor implements ItemProcessor<BatchFileRecord, List<SetIdentityLinkInput>>
{
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • Yeah, sorry, the call to the BatchFileRecordProcessor constructor was a mistake, left over from when I was trying an alternate approach that didn't involve dependency injection. I've edited my original question to include the BatchFileRecordProcessor class definition and the new exception I'm getting with the tag. – magnetichf Apr 09 '14 at 17:40
  • @magnetichf See my edit. Why is your class annotated with `@Component` but still declaring a ``? You're going to end up with duplicate beans. Anyway, I'm not sure right now how to fix the issue you are having with XML, but if you can simply go the Java annotations route, that should be enough. – Sotirios Delimanolis Apr 09 '14 at 17:44
  • My launch-context.xml didn't originally have the bean definition for BatchFileRecordProcessor; I added it during the course of trying different things to get this working. Anyway, I removed it from launch-context.xml, and modified the @Scope annotation as you have it above, but unfortunately I'm still getting the "org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy22]" exception listed above in my question. Argh! But thanks again for your help. – magnetichf Apr 09 '14 at 18:34
  • @mag I'm not somewhere I can look into this right now. I'll try to answer later. – Sotirios Delimanolis Apr 09 '14 at 18:37
0

I just had the same issue.

Resolved by using :

<bean class="org.springframework.batch.core.scope.StepScope">
    <property name="autoProxy" value="false" />
</bean>

as mentioned here.

I'm now able to keep @Autowired annotation in my test class and

@Component
@StepScope
public class CustomProcessor implements ItemProcessor<String, Void> {
    ...
}
Community
  • 1
  • 1
Ludovic Guillaume
  • 3,237
  • 1
  • 24
  • 41