The gist is that the Spring Batch (v2) test framework has JobLauncherTestUtils.setJob
with an @Autowired
annotation. Our test suite has multiple Job
class providers. Since this class is not something I can modify, I'm not sure how I can qualify which job it gets autowired with, which may be different per test.
STDOUT [WARN ] [2015.04.15 11:14:42] support.GenericApplicationContext - Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jobLauncherTestUtilsForSnapshot': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void org.springframework.batch.test.JobLauncherTestUtils.setJob(org.springframework.batch.core.Job); nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.batch.core.Job] is defined: expected single matching bean but found 2: coverageRuleBatch,generateMetricsSnapshotJob
I've tried adding this JavaConfig which is recognized, but the error says it's still autocalling setJob
@Configuration
public class SpringTestConfiguration
{
@Bean
public JobLauncherTestUtils jobLauncherTestUtilsForSnapshot( final Job generateMetricsSnapshotJob )
{
JobLauncherTestUtils jobLauncherTestUtils = new JobLauncherTestUtils();
jobLauncherTestUtils.setJob( generateMetricsSnapshotJob );
return jobLauncherTestUtils;
}
}
note: I don't require a JavaConfig solution, but it'd be nice. Also, I'd like, if possible, to still Autowire fields like JobRepository, as there is only one.
The difference are that @Autowired and @Qualifier are the spring annotation while @Resource is the standard java annotation (from JSR-250) . Besides , @Resource only supports for fields and setter injection while @Autowired supports fields , setter ,constructors and multi-argument methods injection.
The @Qualifier annotation is used to resolve the autowiring conflict, when there are multiple beans of same type. The @Qualifier annotation can be used on any class annotated with @Component or on methods annotated with @Bean . This annotation can also be applied on constructor arguments or method parameters.
There are several reasons @Autowired might not work. When a new instance is created not by Spring but by for example manually calling a constructor, the instance of the class will not be registered in the Spring context and thus not available for dependency injection.
There may be a situation when you create more than one bean of the same type and want to wire only one of them with a property. In such cases, you can use the @Qualifier annotation along with @Autowired to remove the confusion by specifying which exact bean will be wired.
My solution, when I ran into the same problem, was to restrict the component-scan so that only a single Job bean is created in the test context.
@Configuration
@ComponentScan(basePackages={
"com.example.batch.jobs.metrics", //package where generateMetricsSnapshotJob is the only job
"com.example.batch.common",
"..."
})
public class SpringTestConfiguration
{
@Bean
public JobLauncherTestUtils jobLauncherTestUtils()
{
//generateMetricsSnapshotJob and other requirements will be autowired
return new JobLauncherTestUtils();
}
}
You might need to adjust your package structure for this to work.
The solution I came up with
@Configuration
public class SpringBatchTestConfiguration
{
@Bean
public static JobLauncherTestUtils jobLauncherTestUtilsForSnapshot()
{
return new SnapshotJobLauncherTestUtils();
}
public static class SnapshotJobLauncherTestUtils extends JobLauncherTestUtils
{
@Override
@Qualifier( "generateMetricsSnapshotJob" )
public void setJob( final Job job )
{
super.setJob( job );
}
}
}
and in the final test
@Autowired
@Qualifier( "jobLauncherTestUtilsForSnapshot" )
protected JobLauncherTestUtils jobLauncherTestUtils;
fairly confident I could just annotate my TestUtils with @Component and name it properly and do the same thing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With