Finkelson
Finkelson

Reputation: 3023

Spring: DI of Spring Batch beans does not work

I want to inject a bean from one context to my controller bean in MVC context. Here is my bean definition from MVC context:

<import resource="another.context.xml"/>

<bean name="myController" class="com.test.spring.web.Controller">
    <property name="batchJobRepository" ref="batchJobRepository"/>
</bean>

In the another context I defined a Spring Batch Job repository:

<bean id="batchJobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
    <property name="transactionManager" ref="transactionManager"/>
</bean>

My controller:

@Controller
public class MyController {
    private MapJobRepositoryFactoryBean batchJobRepository;

    @RequestMapping("/batch/test")
    @ResponseBody
    public String batch() {
            Set<JobExecution> jes = batchJobRepository
                .getJobExecutionDao()
                .findRunningJobExecutions("firstJob");

            for (JobExecution je : jes) {
                System.out.println(je.isRunning());
            }
            return "Done!";
    }

The problem is a tricky one. I got an error:

Caused by: org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'myController' defined in class path resource [META-INF/spring/controllers.xml]: 
Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: 
Failed to convert property value of type 'com.sun.proxy.$Proxy25 implementing org.springframework.batch.core.repository.JobRepository,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type 'org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean' for property 'batchJobRepository'; 
nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy25 implementing org.springframework.batch.core.repository.JobRepository,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean] for property 'batchJobRepository': no matching editors or conversion strategy found

How can I fix it?

UPD

Added controller details.

UPD2

I tried to use

<aop:scoped-proxy proxy-target-class="true"/>

in batchJobRepository bean. But result is the same: Failed to convert property value of type 'com.sun.proxy.$Proxy17 implementing org.springframework.batch.core.repository.JobRepository

Upvotes: 2

Views: 1672

Answers (2)

JamesENL
JamesENL

Reputation: 6540

This problem is caused because you are using the MapJobRepositoryFactoryBean incorrectly. This bean is actually a factory bean, that will return instances of JobRepository.

Your stacktrace is essentially saying that it can't cast a bean of type JobRepository to MapJobRepositoryFactoryBean and set the property in the controller. It should also be noted that MapJobRepositoryFactoryBean is a purely in-memory implementation, and will not connect to your database to manage job state.

Change your controller code to the following:

@Controller
public class MyController {
    private JobRepository batchJobRepository;

    @RequestMapping("/batch/test")
    @ResponseBody
    public String batch() {
        Set<JobExecution> jes = batchJobRepository
            .getJobExecutionDao()
            .findRunningJobExecutions("firstJob");
        for (JobExecution je : jes) {
            System.out.println(je.isRunning());
        }
        return "Done!";
    }
}

A more elegant solution would be to declare a JobExplorer bean as follows:

<bean id="jobExplorer" 
    class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean">
    <property name="dataSource" ref="dataSource" />
</bean>

<bean id="myController" class="com.test.spring.web.Controller">
    <property name="jobExplorer" ref="jobExplorer"/>
</bean>

and then use the JobExplorer bean in your controller like so:

@Controller
public class MyController {
    private JobExplorer jobExplorer;

    @RequestMapping("/batch/test")
    @ResponseBody
    public String batch() {
        Set<JobExecution> jes = jobExplorer
            .findRunningJobExecutions("firstJob");
        for (JobExecution je : jes) {
            System.out.println(je.isRunning());
        }
        return "Done!";
    }
}

I don't know why you thought that setting your aop config to use Aspect-J would help, but it won't and you shouldn't be using load time weaving if you don't need it.

Upvotes: 3

Paulo Galdo Sandoval
Paulo Galdo Sandoval

Reputation: 2203

You should use the anotation @Autowired on your DI.

@Autowired
    private MapJobRepositoryFactoryBean batchJobRepository;

also add the folowing line on your spring context:

<!--AUTOWIRED-->
<context:component-scan base-package="com.system.rest.app.controller" /> 

Upvotes: -1

Related Questions