No qualifying bean of type 'org.springframework.batch.core.Job' available: expected single matching bean but found 2:

13,409

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;
    }
Share:
13,409
Parthiban
Author by

Parthiban

Updated on July 07, 2022

Comments

  • Parthiban
    Parthiban almost 2 years

    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.

  • Parthiban
    Parthiban over 5 years
    Thanks everyone. I fixed this issue by following the above steps and adding @Primary to one of my bean method.