Suppress ClassCastException for payload type mismatch as well

Closes gh-26349
This commit is contained in:
Juergen Hoeller 2021-01-11 09:44:38 +01:00
parent b0abdee012
commit 4ac27e4dab
3 changed files with 27 additions and 10 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2002-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,8 @@
package org.springframework.context; package org.springframework.context;
import java.util.function.Consumer;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.ResolvableTypeProvider; import org.springframework.core.ResolvableTypeProvider;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -23,11 +25,12 @@ import org.springframework.util.Assert;
/** /**
* An {@link ApplicationEvent} that carries an arbitrary payload. * An {@link ApplicationEvent} that carries an arbitrary payload.
* *
* <p>Mainly intended for internal use within the framework.
*
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Juergen Hoeller
* @since 4.2 * @since 4.2
* @param <T> the payload type of the event * @param <T> the payload type of the event
* @see ApplicationEventPublisher#publishEvent(Object)
* @see ApplicationListener#forPayload(Consumer)
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class PayloadApplicationEvent<T> extends ApplicationEvent implements ResolvableTypeProvider { public class PayloadApplicationEvent<T> extends ApplicationEvent implements ResolvableTypeProvider {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.context.PayloadApplicationEvent;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.ErrorHandler; import org.springframework.util.ErrorHandler;
@ -55,6 +56,9 @@ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventM
@Nullable @Nullable
private ErrorHandler errorHandler; private ErrorHandler errorHandler;
@Nullable
private volatile Log lazyLogger;
/** /**
* Create a new SimpleApplicationEventMulticaster. * Create a new SimpleApplicationEventMulticaster.
@ -173,12 +177,18 @@ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventM
} }
catch (ClassCastException ex) { catch (ClassCastException ex) {
String msg = ex.getMessage(); String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) { if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
(event instanceof PayloadApplicationEvent &&
matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass()))) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for // Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception and just log a debug message. // -> let's suppress the exception.
Log logger = LogFactory.getLog(getClass()); Log loggerToUse = this.lazyLogger;
if (logger.isTraceEnabled()) { if (loggerToUse == null) {
logger.trace("Non-matching event type for listener: " + listener, ex); loggerToUse = LogFactory.getLog(getClass());
this.lazyLogger = loggerToUse;
}
if (loggerToUse.isTraceEnabled()) {
loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
} }
} }
else { else {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -49,9 +49,11 @@ public class PayloadApplicationEventTests {
public void testProgrammaticEventListener() { public void testProgrammaticEventListener() {
List<Auditable> events = new ArrayList<>(); List<Auditable> events = new ArrayList<>();
ApplicationListener<AuditablePayloadEvent<String>> listener = events::add; ApplicationListener<AuditablePayloadEvent<String>> listener = events::add;
ApplicationListener<AuditablePayloadEvent<Integer>> mismatch = (event -> event.getPayload().intValue());
ConfigurableApplicationContext ac = new GenericApplicationContext(); ConfigurableApplicationContext ac = new GenericApplicationContext();
ac.addApplicationListener(listener); ac.addApplicationListener(listener);
ac.addApplicationListener(mismatch);
ac.refresh(); ac.refresh();
AuditablePayloadEvent<String> event = new AuditablePayloadEvent<>(this, "xyz"); AuditablePayloadEvent<String> event = new AuditablePayloadEvent<>(this, "xyz");
@ -63,9 +65,11 @@ public class PayloadApplicationEventTests {
public void testProgrammaticPayloadListener() { public void testProgrammaticPayloadListener() {
List<String> events = new ArrayList<>(); List<String> events = new ArrayList<>();
ApplicationListener<PayloadApplicationEvent<String>> listener = ApplicationListener.forPayload(events::add); ApplicationListener<PayloadApplicationEvent<String>> listener = ApplicationListener.forPayload(events::add);
ApplicationListener<PayloadApplicationEvent<Integer>> mismatch = ApplicationListener.forPayload(payload -> payload.intValue());
ConfigurableApplicationContext ac = new GenericApplicationContext(); ConfigurableApplicationContext ac = new GenericApplicationContext();
ac.addApplicationListener(listener); ac.addApplicationListener(listener);
ac.addApplicationListener(mismatch);
ac.refresh(); ac.refresh();
AuditablePayloadEvent<String> event = new AuditablePayloadEvent<>(this, "xyz"); AuditablePayloadEvent<String> event = new AuditablePayloadEvent<>(this, "xyz");