Skip to content

GH-1783 - Invoke listeners through SimpleApplicationEventMulticaster - #1784

Open
seonwooj0810 wants to merge 1 commit into
spring-projects:mainfrom
seonwooj0810:fix/issue-1783-lambda-listener-cce
Open

GH-1783 - Invoke listeners through SimpleApplicationEventMulticaster#1784
seonwooj0810 wants to merge 1 commit into
spring-projects:mainfrom
seonwooj0810:fix/issue-1783-lambda-listener-cce

Conversation

@seonwooj0810

Copy link
Copy Markdown
Contributor

Fixes #1783

Root cause

PersistentApplicationEventMulticaster invokes ApplicationListener.onApplicationEvent(…) directly, which bypasses the ClassCastException tolerance SimpleApplicationEventMulticaster.doInvokeListener(…) applies for lambda-defined listeners whose generic event type cannot be resolved by reflection. A listener created via ApplicationListener.forPayload(…) has no resolvable declared event type, so getApplicationListeners(…) reports it as a candidate for every event; publishing a non-payload event such as ContextRefreshedEvent then fails the lambda's implicit cast to PayloadApplicationEvent. Because the multicaster registers itself as the applicationEventMulticaster bean, merely adding event externalization to an application turns a listener that worked before into a context refresh failure.

Change

PersistentApplicationEventMulticaster now extends SimpleApplicationEventMulticaster and delegates the listener invocation to invokeListener(…). Both multicastEvent(…) overloads stay overridden, so the publication-registry logic is unchanged; the fix restores the invocation semantics of the multicaster that is being replaced and, as a side effect, honors a configured ErrorHandler.

Tests

Added PersistentApplicationEventMulticasterUnitTests.doesNotPropagateClassCastExceptionOfNonMatchingLambdaListener(), which registers an ApplicationListener.forPayload(…) listener and multicasts a plain ApplicationEvent. It fails on main with exactly the reported exception and passes with the fix.

Verification done: reproduced the reported ClassCastException with a failing test on upstream/main (same stack frame as the issue, PersistentApplicationEventMulticaster.multicastEvent); ./mvnw test -pl :spring-modulith-events-core — 49 tests, all green; ./mvnw test -pl :spring-modulith-events-tests -am — events-core, events-jpa (59) and the integration example all green. Checked that PersistentApplicationEventMulticaster is not referenced as an AbstractApplicationEventMulticaster anywhere else in the codebase.

…entMulticaster.

PersistentApplicationEventMulticaster called ApplicationListener.onApplicationEvent(…)
directly, which bypasses the ClassCastException tolerance that
SimpleApplicationEventMulticaster.doInvokeListener(…) applies for lambda-defined
listeners whose generic event type cannot be resolved.

Such a listener - e.g. one created via ApplicationListener.forPayload(…) - is
reported as a candidate for every event, so publishing a non-payload event like
ContextRefreshedEvent made the cast to PayloadApplicationEvent fail and the
application context refresh blow up as soon as event externalization was enabled.

The multicaster now extends SimpleApplicationEventMulticaster and delegates the
actual invocation to invokeListener(…), which restores the behavior of the
multicaster it replaces and additionally honors a configured ErrorHandler.

Signed-off-by: seonwoo_jung <79202163+seonwooj0810@users.noreply.github.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.

Event externalization throws ClassCastException with event listener using ApplicationListener.forPayload

1 participant