I went through below few links already, but did not turn to be working, I'm using Spring Boot v2.7.1 and Batch and has below code and using junit 5.
Error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.batch.core.configuration.annotation.JobBuilderFactory' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1799) ~[spring-beans-5.3.20.jar:5.3.20]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1355) ~[spring-beans-5.3.20.jar:5.3.20]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1309) ~[spring-beans-5.3.20.jar:5.3.20]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:656) ~[spring-beans-5.3.20.jar:5.3.20]
... 113 common frames omitted
JUnit
@RunWith(SpringRunner.class)
@SpringBatchTest
@EnableAutoConfiguration
@ContextConfiguration(classes = { JobConfiguration.class })
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class})
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class XmlFileOutputApplicationTests {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void contextLoads() throws Exception {
JobParameters jobParameters = new JobParametersBuilder()
.addString("JobId", String.valueOf(System.currentTimeMillis())).addDate("date", new Date())
.addLong("time", System.currentTimeMillis()).toJobParameters();
JobExecution jobExecution = jobLauncherTestUtils.launchJob(jobParameters);
System.out.println(jobExecution.getExitStatus());
}
}
JobConfig.java
@Configuration
public class JobConfiguration {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private DataSource dataSource;
@Bean
public JdbcPagingItemReader<Customer> customerPagingItemReader(){
// Sort Keys
Map<String, Order> sortKeys = new HashMap<>();
sortKeys.put("id", Order.ASCENDING);
// MySQL implementation of a PagingQueryProvider using database specific features.
MySqlPagingQueryProvider queryProvider = new MySqlPagingQueryProvider();
queryProvider.setSelectClause("id, firstName, lastName, birthdate");
queryProvider.setFromClause("from customer");
queryProvider.setSortKeys(sortKeys);
return new JdbcPagingItemReaderBuilder<Customer>()
.name("customerPagingItemReader")
.dataSource(this.dataSource)
.fetchSize(1000)
.rowMapper(new CustomerRowMapper())
.queryProvider(queryProvider)
.build();
}
@Bean
public StaxEventItemWriter<Customer> customerItemWriter() throws Exception{
String customerOutputPath = File.createTempFile("customerOutput", ".out").getAbsolutePath();
System.out.println(">> Output Path = "+customerOutputPath);
Map<String, Class> aliases = new HashMap<>();
aliases.put("customer", Customer.class);
XStreamMarshaller marshaller = new XStreamMarshaller();
marshaller.setAliases(aliases);
return new StaxEventItemWriterBuilder<Customer>()
.name("customerItemWriter")
.rootTagName("customers")
.marshaller(marshaller)
.resource(new FileSystemResource(customerOutputPath))
.build();
}
@Bean
public Step step1() throws Exception {
return stepBuilderFactory.get("step1")
.<Customer, Customer>chunk(100)
.reader(customerPagingItemReader())
.writer(customerItemWriter())
.build();
}
@Bean
public Job job() throws Exception {
return jobBuilderFactory.get("job")
.start(step1())
.build();
}
}
MainApp.java
@SpringBootApplication
@EnableBatchProcessing
public class XmlFileOutputApplication implements CommandLineRunner{
@Autowired
private JobLauncher jobLauncher;
@Autowired
private Job job;
public static void main(String[] args) {
SpringApplication.run(XmlFileOutputApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
JobParameters jobParameters = new JobParametersBuilder()
.addString("JobId", String.valueOf(System.currentTimeMillis()))
.addDate("date", new Date())
.addLong("time",System.currentTimeMillis()).toJobParameters();
JobExecution execution = jobLauncher.run(job, jobParameters);
System.out.println("STATUS :: "+execution.getStatus());
}
}
Both JobBuilderFactory
and StepBuilderFactory
beans are defined by @EnableBatchProcessing
.
But now as you explicitly configure the spring test to load the context from the JobConfiguration
, the XmlFileOutputApplication
will never be picked up as the configuration class and hence the @EnableBatchProcessing
annotated on it does not have any effect.
The easy way to fix it is to make sure you include @EnableBatchProcessing
on any configuration classes that the spring test will load. You can do it by :
@ContextConfiguration(classes = { JobConfiguration.class })
@EnableBatchProcessing
public class XmlFileOutputApplicationTests {
}
or annotating @EnableBatchProcessing
on JobConfiguration
:
@ContextConfiguration(classes = { JobConfiguration.class })
public class XmlFileOutputApplicationTests {
}
@Configuration
@EnableBatchProcessing
public class JobConfiguration {
}