See below for 1 update
I'm trying to inject a Service or DAO bean into my spring-batch ItemReader. However the injected reference is NULL. I tried this using @Autowire and explicit bean configuration in the XML file.
The job is being run from a spring-mvc application. This ItemReader requires DB access to load a list of ID's to process. The reader itereates through this list and the ItemWriter makes the necessary changes on the database for each ID using my existing Service and DAO Layers.
Here's my configuration (it is defined on a separate spring-batch.xml file included on the web.xml after the application context XML file.)
Also, in this version I'm trying to inject the JobService bean into the ItemReader using the XML configuration.
The general problem here is: how to inject other DAO's and/or Services into Item Readers and Writers?
<beans:bean id="jobRepository" class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
<beans:property name="dataSource" ref="dataSourceJNDI" />
<beans:property name="transactionManager" ref="transactionManager" />
<beans:property name="databaseType" value="mysql" />
</beans:bean>
<beans:bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<beans:property name="jobRepository" ref="jobRepository" />
</beans:bean>
<beans:bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
<beans:bean id="myItemReader" class="my.MyItemReader" scope="step">
<beans:property name="jobService">
<beans:bean class="my.JobService"></beans:bean>
</beans:property>
</beans:bean>
<job id="assignLeadBatch" restartable="false" job-repository="jobRepository">
<step id="step1">
<tasklet transaction-manager="dbOpsTransactionManager">
<chunk reader="myItemReader" writer="myItemWriter" commit-interval="10" />
</tasklet>
</step>
</job>
<beans:bean class="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor">
<beans:property name="jobRegistry" ref="jobRegistry" />
</beans:bean>
ItemReader:
@Scope(value = "step", proxyMode = ScopedProxyMode.INTERFACES)
@Component
public class MyItemReader implements ItemReader<Integer> {
JobService jobService;
private List<Integer> itemsList;
@Autowired
public AssignLeadsJobItemReader(@Value("#{jobParameters['jobKey']}") final String jobKey) {
MyJob alj = jobService.loadByKey(jobKey);
itemsList = new ArrayList<AssignLeadsJobItem>();
for(Integer i : myJob.getIdList()) {
itemsList.add(i);
}
}
@Override
public Integer read(){
if(itemsList == null || itemsList.size() == 0) {
return null;
} else {
return itemsList.remove(0);
}
}
public JobService getJobService() {
return jobService;
}
public void setJobService(JobService jobService) {
this.jobService = jobService;
}
}
Job Service:
@Service
@Transactional
public class JobService {
@Autowired
protected JobDAO jobDao;
@Autowired
protected SpringBatchService springBatchService;
public JobExecution startJob(String jobName, String jobKey) {
// Defined in a different Class without transactions.
return springBatchService.startJob("job_name", jobKey);
}
public MyJob loadByKey(String jobKey) {
return jobDao.loadByKey(jobKey);
}
}
UPDATE 1 I noticed that the error was caused by calling the reference on the ItemReader constructor. I changed the code thusly:
@Scope(value = "step", proxyMode = ScopedProxyMode.INTERFACES)
@Component
public class MyItemReader implements ItemReader<Integer> {
private JobService jobService;
private List<Integer> itemsList;
private String jobKey;
@Autowired
public MyItemReader(@Value("#{jobParameters['jobKey']}") final String jobKey) {
this.jobKey = jobKey;
this.itemsList = null;
}
@Override
public Integer read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
// ugly ugly ugly
if (itemsList == null) {
itemsList = new ArrayList<Integer>();
MyJob jobData = jobService.loadByKey(jobKey);
for (Integer i : jobData.getIdList()) {
itemsList.add(i);
}
}
if (itemsList.isEmpty()) {
return null;
} else {
return itemsList.remove(0);
}
}
}
Is there a way to put that ugly initialization in the constructor?