I have 2 jobs running in single spring batch application based on input parameters and it is working successfully. But when i run my test case, i'm getting the below error. I'm using gradle to build my application.
No qualifying bean of type 'org.springframework.batch.core.Job' available: expected single matching bean but found 2: pureRedDataProcessingJob,pcsMasterProcessingJob
Test class:
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.ConfigFileApplicationContextInitializer;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
*
* @author
*
*/
@ContextConfiguration(classes = {UidBatchApplication.class, JobLauncherTestUtils.class},
initializers = ConfigFileApplicationContextInitializer.class)
@RunWith(SpringJUnit4ClassRunner.class)
@TestPropertySource(locations = {"classpath:application-test.properties"})
@Configuration
@ActiveProfiles("test")
@Profile("test")
@TestConfiguration
@SpringBootTest
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@EnableAutoConfiguration
public class UidBatchApplicationTest {
@Autowired
public JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void launchJob() throws Exception {
JobParameters params = new JobParametersBuilder().addString("jobName", "pcsMasterProcessingJob").toJobParameters();
jobLauncherTestUtils.launchJob(params);
}
}
Main class configuration:
/*
*/
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import javax.sql.DataSource;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.MultiResourceItemReader;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
@Configuration
@ConfigurationProperties
@EnableBatchProcessing
public class UidApplicationConfiguration{
@Autowired
private DataSource mariaDb;
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public JobExecutionListener listener() {
return new JobCompletionNotificationListener();
}
@Bean
@Qualifier("pureRedDataProcessingJob")
public Job pureRedDataProcessingJob() {
return jobBuilderFactory.get(UidConstants.PURE_RED_JOB)
.incrementer(new RunIdIncrementer()).listener(listener())
.flow(pureRedStep()).end().build();
}
@Bean
public Step pureRedStep() {
return stepBuilderFactory.get("pureRedStep").<PureRedBean, PureRedBean> chunk(1)
.reader(multiResourcePureRedReader()).processor(pureRedProcessor()).writer(pureRedWriter()).faultTolerant()
.build();
}
@Bean
public MultiResourceItemReader<PureRedBean> multiResourcePureRedReader()
{
MultiResourceItemReader<PureRedBean> resourceItemReader = new MultiResourceItemReader<>();
resourceItemReader.setResources(getPureredFilePath());
resourceItemReader.setDelegate(pureRedReader());
return resourceItemReader;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean
public FlatFileItemReader<PureRedBean> pureRedReader()
{
String[] namesArray = {"circularType","rotoKey","xyCoordinate","xyCoordinate","xyCoordinate","adPrintVerNum",
"adStartDttm","pageNum","itemWic","upc","headLineCopy","bodyCopy","xyCoordinate","pluCode",
"vendorName","xyCoordinate","xyCoordinate","xyCoordinate","imageFileName","xyCoordinate",
"offerPrice","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate",
"quantity","getFree","rewardSpend","rewardPoints","rewardQuantity","percentOff","offerLimit",
"templateName","adPriceVerbiage","rewardVerbiage","fsiVerbiage","mirVerbiage",
"ivcVerbiage","retailVerbiage","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate",
"sevenPartKey","fillerThree","largeImage","xyCoordinate","xyCoordinate","xyCoordinate","xyCoordinate",
"summary","additionalDealInfo","disclaimer","smallImage"};
PureredBeanWrapperFieldSetMapper beanWrapper = new PureredBeanWrapperFieldSetMapper();
beanWrapper.setTargetType(PureRedBean.class);
DefaultLineMapper linemapper = new DefaultLineMapper();
DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(UidConstants.CSV_DELIMITER);
tokenizer.setNames(namesArray);
linemapper.setLineTokenizer(tokenizer );
beanWrapper.setDistanceLimit(0);
linemapper.setFieldSetMapper(beanWrapper);
//Create reader instance
FlatFileItemReader<PureRedBean> reader = new FlatFileItemReader<>();
reader.setLineMapper(linemapper);
return reader;
}
@Bean
public ItemWriter<PureRedBean> pureRedWriter() {
JdbcBatchItemWriter<PureRedBean> writer = new JdbcBatchItemWriter<>();
writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<PureRedBean>());
writer.setSql(pureredInsertQuery);
writer.setDataSource(mariaDb);
return writer;
}
@Bean
public PureRedProcessor pureRedProcessor() {
return new PureRedProcessor();
}
@Bean
@Qualifier("pcsMasterProcessingJob")
public Job pcsMasterProcessingJob() {
return jobBuilderFactory.get(UidConstants.PCS_MASTER_JOB)
.incrementer(new RunIdIncrementer()).listener(listener())
.flow(masterStep()).end().build();
}
@Bean
public Step masterStep() {
return stepBuilderFactory.get("masterStep").<UniqueIdMasterBean, UniqueIdMasterBean> chunk(1)
.reader(multiResourceItemReader()).processor(masterProcessor()).writer(writer()).faultTolerant()
.build();
}
@Bean
public MultiResourceItemReader<UniqueIdMasterBean> multiResourceItemReader()
{
MultiResourceItemReader<UniqueIdMasterBean> resourceItemReader = new MultiResourceItemReader<>();
resourceItemReader.setResources(getFilePath());
resourceItemReader.setDelegate(reader());
return resourceItemReader;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean
public FlatFileItemReader<UniqueIdMasterBean> reader()
{
String[] namesArray = {"uniqueId","spotSeqNum","adTypeCd","adMarketCd","adStartDttm","adExpiryDttm",
"adEventType","adSeqNum","adVerCd","adVerSeqNum","adPrintVerNum","adLoyaltyOfferCd","adItemCouponNum",
"adItemLayoutPosNum","adItemPageNum","adItemRetailMultiple","adItemRetailPrice","adItemSingleUnitPrice",
"adItemAltPriceMult","adItemAltPrice","adItemAmtOff","adItemPercentOff","adPageTypeCd","minOrderValue",
"rewardType","offerValue","loyaltyPoints","targetedFlag","","categoryLevelTwo","adFillerOne",
"adFillerTwo","adFillerThree","statusFlagOne","statusFlagTwo"};
BeanWrapperFieldSetMapperCustom beanWrapper = new BeanWrapperFieldSetMapperCustom();
beanWrapper.setTargetType(UniqueIdMasterBean.class);
DefaultLineMapper linemapper = new DefaultLineMapper();
DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(UidConstants.CSV_DELIMITER);
tokenizer.setNames(namesArray);
linemapper.setLineTokenizer(tokenizer );
linemapper.setFieldSetMapper(beanWrapper);
//Create reader instance
FlatFileItemReader<UniqueIdMasterBean> reader = new FlatFileItemReader<>();
reader.setLineMapper(linemapper);
return reader;
}
@Bean
public ItemWriter<UniqueIdMasterBean> writer() {
JdbcBatchItemWriter<UniqueIdMasterBean> writer = new JdbcBatchItemWriter<>();
writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<UniqueIdMasterBean>());
writer.setSql(insertQuery);
writer.setDataSource(mariaDb);
return writer;
}
@Bean
public MasterProcessor masterProcessor() {
return new MasterProcessor();
}
@Value("${master.filePath}")
private Resource[] filePath;
@Value("${master.insertQuery}")
private String insertQuery;
@Value("${purered.filePath}")
private Resource[] pureredFilePath;
@Value("${purered.insertQuery}")
private String pureredInsertQuery;
@Value("${categoryList}")
private String categoryList;
private Map<String,String> categoryMap;
public Resource[] getPureredFilePath() {
return pureredFilePath;
}
public Resource[] getFilePath() {
return filePath;
}
public void setCategoryList(String categoryList) {
this.categoryList = categoryList;
}
/**
* @return the clientTagsMap
*/
public Map<String, String> getCategoryMap() {
if(null == categoryMap){
categoryMap = new HashMap<>();
int count = 0;
String current = "";
String value = null;
String key = null ;
StringTokenizer tok = new StringTokenizer(categoryList, ",=");
while (tok.hasMoreTokens()) {
current = tok.nextToken();
// the first token in the pair is the key
if (count%(PCSConstants.KEY_LENGTH)==1){
value = current;
categoryMap.put(key, value);
}else{
// the second is the value
key = current;
}
count++;
}
}
return categoryMap;
}
}
Could someone help me please.
The error is “expected at least 1 bean which qualifies as autowire candidate.” The solution is to add the injection class in the ApplicationContext using annotation @Component. The exception “NoSuchBeanDefinitionException: No qualifying bean of type” is resolved if the annotation @Component is added in the Lion class.
This is a common exception thrown by the BeanFactory when trying to resolve a bean that simply isn't defined in the Spring Context. We'll illustrate the possible causes for this problem and the available solutions.
You may need to manually configure JobLauncherTestUtils.
This looks like similar to the thread here
Spring Batch JUnit test for multiple jobs
Look into the code of JobLauncherTestUtils, which is causing the issue.
@Autowired
public void setJob(Job job) {
this.job = job;
}
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