GH-357 - Reinstantiate general compatibility with Boot 3.2 / Framework 6.1.

We now gracefully fall back to reflective invocation of the application event listener shouldHandle(…) method if we're not on Spring Framework 6.2. If we are, we invoke the newly introduced method directly.

This allows projects to upgrade to Spring Modulith 1.1 without necessarily upgrading to Boot 3.2.
This commit is contained in:
Oliver Drotbohm
2023-11-02 14:27:52 +01:00
parent cef3ffbe7e
commit 40ab6cecfc
2 changed files with 37 additions and 3 deletions

View File

@@ -10,6 +10,8 @@ jobs:
strategy:
matrix:
version:
- '3.1.5'
- '3.1.6-SNAPSHOT'
- '3.2.0-SNAPSHOT'
name: Build against Boot ${{ matrix.version }}
runs-on: ubuntu-latest

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.modulith.events.support;
import java.lang.reflect.Method;
import java.time.Duration;
import java.util.Collection;
import java.util.List;
@@ -45,6 +46,7 @@ import org.springframework.modulith.events.core.TargetEventPublication;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalApplicationListener;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
/**
* An {@link org.springframework.context.event.ApplicationEventMulticaster} to register {@link EventPublication}s in an
@@ -61,12 +63,23 @@ public class PersistentApplicationEventMulticaster extends AbstractApplicationEv
implements IncompleteEventPublications, SmartInitializingSingleton {
private static final Logger LOGGER = LoggerFactory.getLogger(PersistentApplicationEventMulticaster.class);
private static final Method LEGACY_SHOULD_HANDLE = ReflectionUtils.findMethod(ApplicationListenerMethodAdapter.class,
"shouldHandle", ApplicationEvent.class, Object[].class);
private static final Method SHOULD_HANDLE = ReflectionUtils.findMethod(ApplicationListenerMethodAdapter.class,
"shouldHandle", ApplicationEvent.class);
static final String REPUBLISH_ON_RESTART = "spring.modulith.republish-outstanding-events-on-restart";
private final @NonNull Supplier<EventPublicationRegistry> registry;
private final @NonNull Supplier<Environment> environment;
static {
if (SHOULD_HANDLE == null) {
ReflectionUtils.makeAccessible(LEGACY_SHOULD_HANDLE);
}
}
/**
* Creates a new {@link PersistentApplicationEventMulticaster} for the given {@link EventPublicationRegistry}.
*
@@ -222,9 +235,7 @@ public class PersistentApplicationEventMulticaster extends AbstractApplicationEv
private static boolean matches(ApplicationEvent event, Object payload, ApplicationListener<?> listener) {
// Verify general listener matching by eagerly evaluating the condition
if (ApplicationListenerMethodAdapter.class.isInstance(listener)
&& !((ApplicationListenerMethodAdapter) listener).shouldHandle(event)) {
if (!invokeShouldHandle(listener, event, payload)) {
return false;
}
@@ -233,6 +244,27 @@ public class PersistentApplicationEventMulticaster extends AbstractApplicationEv
: true;
}
/**
* Invokes {@link ApplicationListenerMethodAdapter#shouldHandle(ApplicationEvent)} in case the given candidate is one
* in the first place but falls back to call {@code shouldHandle(ApplicationEvent, Object)} reflectively as fallback.
*
* @param candidate the listener to test, must not be {@literal null}.
* @param event the event to publish, must not be {@literal null}.
* @param payload the actual payload, must not be {@literal null}.
* @return whether the event should be handled by the given candidate.
*/
@SuppressWarnings("null")
private static boolean invokeShouldHandle(ApplicationListener<?> candidate, ApplicationEvent event, Object payload) {
if (!(candidate instanceof ApplicationListenerMethodAdapter listener)) {
return true;
}
return SHOULD_HANDLE != null
? listener.shouldHandle(event)
: (boolean) ReflectionUtils.invokeMethod(LEGACY_SHOULD_HANDLE, candidate, event, new Object[] { payload });
}
private static String getConfirmationMessage(Collection<?> publications) {
var size = publications.size();