Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

284
Views
Spring Batch WriterNotOpenException

I have created a simple single-step Spring batch job that reads items from a DB, processes them and writes the result to a csv. During runtime I end up with a

org.springframework.batch.item.WriterNotOpenException: Writer must be open before it can be written to

The relevant code:

@Configuration
@EnableBatchProcessing
@EnableAutoConfiguration
public class CleanEmailJob {

@Autowired
private JobBuilderFactory jobBuilderFactory;

@Autowired
private StepBuilderFactory stepBuilderFactory;

@Autowired
public DataSource dataSource;

@Bean
public ResourcelessTransactionManager transactionManager() {
    return new ResourcelessTransactionManager();
}

@Bean
public MapJobRepositoryFactoryBean mapJobRepositoryFactory(ResourcelessTransactionManager txManager)
        throws Exception {
    MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean(txManager);
    factory.afterPropertiesSet();
    return factory;
}

@Bean
public JobRepository jobRepository(MapJobRepositoryFactoryBean factory) throws Exception {
    return factory.getObject();
}

@Bean
public JobExplorer jobExplorer(MapJobRepositoryFactoryBean factory) {
    return new SimpleJobExplorer(factory.getJobInstanceDao(), factory.getJobExecutionDao(),
            factory.getStepExecutionDao(), factory.getExecutionContextDao());
}

@Bean
public SimpleJobLauncher jobLauncher(JobRepository jobRepository) {
    SimpleJobLauncher launcher = new SimpleJobLauncher();
    launcher.setJobRepository(jobRepository);
    return launcher;
}


@Bean
public Job cleanEmailAddressesJob() throws Exception {
    return jobBuilderFactory.get("cleanEmailAddresses")
            .incrementer(new RunIdIncrementer())
            .start(processEmailAddresses())
            .build();
}

@Bean
public Step processEmailAddresses() throws UnexpectedInputException, ParseException, Exception {
    return stepBuilderFactory.get("processAffiliates")
            .<AffiliateEmailAddress, VerifiedAffiliateEmailAddress> chunk(10)
            .reader(reader())
            .processor(processor())     
            .writer(report())
            .build();
}

@Bean
public ItemWriter<VerifiedAffiliateEmailAddress> report(){
    FlatFileItemWriter<VerifiedAffiliateEmailAddress> reportWriter = new FlatFileItemWriter<VerifiedAffiliateEmailAddress>();
    reportWriter.setResource(new ClassPathResource("report.csv"));
    DelimitedLineAggregator<VerifiedAffiliateEmailAddress> delLineAgg = new DelimitedLineAggregator<VerifiedAffiliateEmailAddress>();
    delLineAgg.setDelimiter(",");
    BeanWrapperFieldExtractor<VerifiedAffiliateEmailAddress> fieldExtractor = new BeanWrapperFieldExtractor<VerifiedAffiliateEmailAddress>();
    fieldExtractor.setNames(new String[] {"uniekNr", "reason"});
    delLineAgg.setFieldExtractor(fieldExtractor);
    reportWriter.setLineAggregator(delLineAgg);
    reportWriter.setShouldDeleteIfExists(true);
    return reportWriter;
}

As described in the documentation I would expect the lifecycle events(open, close) are automatically taken care of since I am in a single threaded and single writer job?

about 4 years ago · Santiago Trujillo
2 answers
Answer question

0

To elaborate on the comment left, Spring Batch will register any ItemStream implementations automatically when it finds them so that they will be automatically opened when the step begins. When using java config, Spring only knows what the return type is. Since you are returning ItemReader, we don't know that your implementation also implements ItemStream. When using java config, I usually recommend returning the implementation if it's known (instead of the interface). That allows Spring to introspect it fully. So in this example, returning FlatFileItemReader instead of ItemReader will fix the issue.

about 4 years ago · Santiago Trujillo Report

0

Finally it turned out to be the Spring Dev Tools interfering with my batch application. The report.csv is in my classpath, when writing to the report file, Spring Dev Tools detects a change in my classpath and triggers a reload of the application causing the report.csv resource being closed...

spring.devtools.restart.enabled=false

in my application.properties made it work again

about 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!