Skip to content

Commit 89d2bd9

Browse files
committed
Properly analyze Java 9 class cast messages for lambda event listeners
Issue: SPR-16435
1 parent 4f28c28 commit 89d2bd9

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

spring-context/src/main/java/org/springframework/context/event/SimpleApplicationEventMulticaster.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -173,8 +173,9 @@ private void doInvokeListener(ApplicationListener listener, ApplicationEvent eve
173173
}
174174
catch (ClassCastException ex) {
175175
String msg = ex.getMessage();
176-
if (msg == null || msg.startsWith(event.getClass().getName())) {
176+
if (msg == null || matchesClassCastMessage(msg, event.getClass().getName())) {
177177
// Possibly a lambda-defined listener which we could not resolve the generic event type for
178+
// -> let's suppress the exception and just log a debug message.
178179
Log logger = LogFactory.getLog(getClass());
179180
if (logger.isDebugEnabled()) {
180181
logger.debug("Non-matching event type for listener: " + listener, ex);
@@ -186,4 +187,18 @@ private void doInvokeListener(ApplicationListener listener, ApplicationEvent eve
186187
}
187188
}
188189

190+
private boolean matchesClassCastMessage(String classCastMessage, String eventClassName) {
191+
// On Java 8, the message simply starts with the class name: "java.lang.String cannot be cast..."
192+
if (classCastMessage.startsWith(eventClassName)) {
193+
return true;
194+
}
195+
// On Java 9, the message contains the module name: "java.base/java.lang.String cannot be cast..."
196+
int moduleSeparatorIndex = classCastMessage.indexOf('/');
197+
if (moduleSeparatorIndex != -1 && classCastMessage.startsWith(eventClassName, moduleSeparatorIndex + 1)) {
198+
return true;
199+
}
200+
// Assuming an unrelated class cast failure...
201+
return false;
202+
}
203+
189204
}

spring-context/src/test/java/org/springframework/context/event/ApplicationContextEventTests.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -472,6 +472,30 @@ public void lambdaAsListenerWithErrorHandler() {
472472
context.close();
473473
}
474474

475+
@Test
476+
public void lambdaAsListenerWithJava8StyleClassCastMessage() {
477+
StaticApplicationContext context = new StaticApplicationContext();
478+
ApplicationListener<ApplicationEvent> listener =
479+
event -> { throw new ClassCastException(event.getClass().getName()); };
480+
context.addApplicationListener(listener);
481+
context.refresh();
482+
483+
context.publishEvent(new MyEvent(context));
484+
context.close();
485+
}
486+
487+
@Test
488+
public void lambdaAsListenerWithJava9StyleClassCastMessage() {
489+
StaticApplicationContext context = new StaticApplicationContext();
490+
ApplicationListener<ApplicationEvent> listener =
491+
event -> { throw new ClassCastException("spring.context/" + event.getClass().getName()); };
492+
context.addApplicationListener(listener);
493+
context.refresh();
494+
495+
context.publishEvent(new MyEvent(context));
496+
context.close();
497+
}
498+
475499
@Test
476500
public void beanPostProcessorPublishesEvents() {
477501
GenericApplicationContext context = new GenericApplicationContext();

0 commit comments

Comments
 (0)