spring-projects / spring-projects/spring-batch

NullPointerException when closing an unopened JpaPagingItemReader

Open Beginner friendly
#5,539 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
3k
Forks
2.5k
Avg merge
6d 53m
Merged PRs (30d)
3

Description

Bug description
Closing a JpaPagingItemReader that has never been opened throws an ItemStreamException caused by a NullPointerException. Its EntityManager is assigned only in doOpen(), but doClose() calls entityManager.close() unconditionally.

This can occur at application context shutdown when an instantiated singleton reader bean has an inferred close destroy method and its step has not run.

Environment
Spring Batch main at a3028e3c8f78c0e385cb61fb800afb32b5f7846a. No database is needed to reproduce this cleanup failure.

Steps to reproduce / Minimal Complete Reproducible example
The following JUnit 5 test uses Mockito for the factory:

import jakarta.persistence.EntityManagerFactory;
import org.junit.jupiter.api.Test;
import org.springframework.batch.infrastructure.item.database.JpaPagingItemReader;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.Mockito.mock;

class JpaPagingItemReaderCloseTests {
    @Test
    void closeWithoutOpen() throws Exception {
        EntityManagerFactory factory = mock(EntityManagerFactory.class);
        JpaPagingItemReader<Object> reader = new JpaPagingItemReader<>(factory);
        reader.setQueryString("select o from Object o");
        reader.afterPropertiesSet();
        assertDoesNotThrow(reader::close);
    }
}

The close call throws ItemStreamException: Error while closing item reader, caused by NullPointerException: Cannot invoke "jakarta.persistence.EntityManager.close()" because "this.entityManager" is null in JpaPagingItemReader.doClose().

Expected behavior
Close should skip EntityManager cleanup when none has been created, while still performing superclass cleanup.

The related shutdown case for JpaCursorItemReader was addressed in #5486 / #5489. The paging reader's unguarded close predates the JSpecify migration; this report does not attribute it to that migration.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with JpaPagingItemReader.doClose() and the supplied JpaPagingItemReaderCloseTests reproduction. Run the JUnit test without a database, then verify that closing a reader before open no longer throws while superclass cleanup still occurs. Done means the regression test passes and the existing cleanup behavior remains covered.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
databases
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
86/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.