'No qualifying bean of type 'org.springframework.batch.core.Job' available: expected single matching bean but found 2:
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.
Solution 1:[1]
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;
}
Solution 2:[2]
I had the same problem, and solved it by adding the following:
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class})
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Legna |