New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong detection of event type on ApplicationListener<> when using lambdas (ClassCast Exception) [SPR-14109] #18681

Closed
spring-issuemaster opened this Issue Apr 4, 2016 · 7 comments

Comments

Projects
None yet
2 participants
@spring-issuemaster
Copy link
Collaborator

spring-issuemaster commented Apr 4, 2016

Michael Simons opened SPR-14109 and commented

Hello there,

i hope this is indeed a Spring Framework and not a Spring Boot bug. If not, please excuse and move it to the right place.

In my application i have a WebSocketMessageBroker (enabled through @EnableWebSocketMessageBroker) as well as a HttpSessionEventPublisher (enabled via @Bean) and a ApplicationListener<HttpSessionCreatedEvent>.

If i use an anonymous inner class for the ApplicationListener, everything works fine.

If i use a lambda like so

public ApplicationListener<HttpSessionCreatedEvent> httpSessionCreatedEventListener() {
  return (HttpSessionCreatedEvent event) -> {
    LoggerFactory.getLogger(ClasscastApplication.class).info("Session created...");
  };
}

the generic type of my listener is incorrectly identified and a BrokerAvailabilityEvent is passed to it leading to:

Caused by: java.lang.ClassCastException: org.springframework.messaging.simp.broker.BrokerAvailabilityEvent cannot be cast to org.springframework.security.web.session.HttpSessionCreatedEvent
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:163) ~[spring-context-4.2.5.RELEASE.jar:4.2.5.RELEASE]
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:136) ~[spring-context-4.2.5.RELEASE.jar:4.2.5.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:381) ~[spring-context-4.2.5.RELEASE.jar:4.2.5.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:335) ~[spring-context-4.2.5.RELEASE.jar:4.2.5.RELEASE]
	at org.springframework.messaging.simp.broker.AbstractBrokerMessageHandler.publishBrokerAvailableEvent(AbstractBrokerMessageHandler.java:262) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
	at org.springframework.messaging.simp.broker.SimpleBrokerMessageHandler.startInternal(SimpleBrokerMessageHandler.java:178) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
	at org.springframework.messaging.simp.broker.AbstractBrokerMessageHandler.start(AbstractBrokerMessageHandler.java:164) ~[spring-messaging-4.2.5.RELEASE.jar:4.2.5.RELEASE]
	at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:173) ~[spring-context-4.2.5.RELEASE.jar:4.2.5.RELEASE]
	... 14 common frames omitted

I guess that might happen with other events, too, but i noticed it in context of messaging.

I have attached a demo application that reproduces that bug.


Affects: 4.2.5

Attachments:

Issue Links:

  • #17130 GenericTypeResolver should be able to introspect generic arguments from lambdas
  • #20393 SimpleApplicationEventMulticaster does not deal with lambda-defined listeners when ErrorHandler is set
  • #19412 SimpleApplicationEventMulticaster should not generally suppress ClassCastException
@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Apr 4, 2016

Juergen Hoeller commented

This is unfortunately a known limitation with lambda-defined callbacks: We cannot reliably introspect generic type declarations there upfront. That said, we should at least make our event processing defensive enough: catching ClassCastException and simply skipping the listener if the event doesn't match... I'll try that right away.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Apr 4, 2016

Michael Simons commented

Hello Juergen,
thanks for looking into it so quickly.

Sorry, didn't find the other ticket.

If you skip the listener, a big warning is need, i think.
Or: Throw a custom exception with the reason and explanation.

Just for your interest: We've been using TypeTools which are linked in the SO question in #17130 for detecting generic types of Lambdas successfully.

Thanks again,
Michael.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Apr 4, 2016

Juergen Hoeller commented

Skipping the listener in case of a ClassCastException should actually be reasonably safe: It just means that we were trying to invoke it with a non-matching event type which, if known upfront, would have to led to the listener getting skipped in any case...

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Apr 4, 2016

Michael Simons commented

Thanks for clarifying, now i understand, i thought you meant skipping that listener from being registered at all.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Aug 4, 2016

Hans-Peter Werner commented

Hello Juergen,

I try to catch and log exceptions at the site where an event is fired. When a listener is throwing a ClassCastException, this happens without being noticed (provided the log-level is not debug) because of that exception being catched within the SimpleApplicationEventMulticaster. I don't know a perfect solution for that problem, but I would rather have too much exceptions than too few :)

Cheers
hp

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Oct 27, 2016

Juergen Hoeller commented

As of 4.3.4 / 4.2.9, we're now just swallowing a ClassCastException if it affects the passed-in event class directly (as in the case of a lambda-defined listener for a specific event type).

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

spring-issuemaster commented Oct 27, 2016

Michael Simons commented

Thanks Jürgen for the update. Good to know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment