Skip to content

Fix duplicate listener registration in ChunkOrientedStepBuilder - #5467

Open
benelog wants to merge 1 commit into
spring-projects:mainfrom
benelog:GH-5466
Open

Fix duplicate listener registration in ChunkOrientedStepBuilder#5467
benelog wants to merge 1 commit into
spring-projects:mainfrom
benelog:GH-5466

Conversation

@benelog

@benelog benelog commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Resolves #5466

ChunkOrientedStepBuilder#addAsStreamAndListener registered an item handler as a listener in two non-exclusive branches: once as the raw object (instanceof StepListener) and once as a StepListenerFactoryBean proxy (isListener(...)). Since AbstractListenerFactoryBean#getObject resolves callbacks by interface as well as by annotation, an item handler that implements a listener interface and has a listener-annotated method was registered twice, and every interface callback fired twice per item.

This change registers through StepListenerFactoryBean only, restoring the 5.2.x behavior of SimpleStepBuilder#registerAsStreamsAndListeners:

  • isListener(...) already returns true for interface-only implementations, and
  • getObject() returns the delegate unchanged when no annotated methods are present (synthetic == false), so interface-only handlers are still registered as before.

The added integration test fails on main with expected: <1> but was: <2> for beforeProcess/afterProcess counts and passes with this fix.

An item reader/processor/writer that implements a StepListener
sub-interface and also has a listener-annotated method was added to
stepListeners twice: once as the raw object and once as a
StepListenerFactoryBean proxy. Since the proxy resolves callbacks by
interface as well as by annotation, every interface callback was
invoked twice per item.

Register through StepListenerFactoryBean only, as in 5.2.x: the factory
already covers interface-only implementations and returns the delegate
unchanged when no annotated methods are present.

The added integration tests cover the failing case and the control case
of an item handler that implements the listener interface without any
listener annotation, which must keep being registered exactly once.

Resolves spring-projects#5466

Signed-off-by: Sanghyuk Jung <sanghyuk.jung@navercorp.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Interface listener callbacks are invoked twice when an item handler also has a listener annotation

1 participant