Skip to content

Commit 40ab6ce

Browse files
committed
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.
1 parent cef3ffb commit 40ab6ce

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

.github/workflows/integration.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ jobs:
1010
strategy:
1111
matrix:
1212
version:
13+
- '3.1.5'
14+
- '3.1.6-SNAPSHOT'
1315
- '3.2.0-SNAPSHOT'
1416
name: Build against Boot ${{ matrix.version }}
1517
runs-on: ubuntu-latest

spring-modulith-events/spring-modulith-events-core/src/main/java/org/springframework/modulith/events/support/PersistentApplicationEventMulticaster.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.modulith.events.support;
1717

18+
import java.lang.reflect.Method;
1819
import java.time.Duration;
1920
import java.util.Collection;
2021
import java.util.List;
@@ -45,6 +46,7 @@
4546
import org.springframework.transaction.event.TransactionPhase;
4647
import org.springframework.transaction.event.TransactionalApplicationListener;
4748
import org.springframework.util.Assert;
49+
import org.springframework.util.ReflectionUtils;
4850

4951
/**
5052
* An {@link org.springframework.context.event.ApplicationEventMulticaster} to register {@link EventPublication}s in an
@@ -61,12 +63,23 @@ public class PersistentApplicationEventMulticaster extends AbstractApplicationEv
6163
implements IncompleteEventPublications, SmartInitializingSingleton {
6264

6365
private static final Logger LOGGER = LoggerFactory.getLogger(PersistentApplicationEventMulticaster.class);
66+
private static final Method LEGACY_SHOULD_HANDLE = ReflectionUtils.findMethod(ApplicationListenerMethodAdapter.class,
67+
"shouldHandle", ApplicationEvent.class, Object[].class);
68+
private static final Method SHOULD_HANDLE = ReflectionUtils.findMethod(ApplicationListenerMethodAdapter.class,
69+
"shouldHandle", ApplicationEvent.class);
6470

6571
static final String REPUBLISH_ON_RESTART = "spring.modulith.republish-outstanding-events-on-restart";
6672

6773
private final @NonNull Supplier<EventPublicationRegistry> registry;
6874
private final @NonNull Supplier<Environment> environment;
6975

76+
static {
77+
78+
if (SHOULD_HANDLE == null) {
79+
ReflectionUtils.makeAccessible(LEGACY_SHOULD_HANDLE);
80+
}
81+
}
82+
7083
/**
7184
* Creates a new {@link PersistentApplicationEventMulticaster} for the given {@link EventPublicationRegistry}.
7285
*
@@ -222,9 +235,7 @@ private static Object getEventToPersist(ApplicationEvent event) {
222235
private static boolean matches(ApplicationEvent event, Object payload, ApplicationListener<?> listener) {
223236

224237
// Verify general listener matching by eagerly evaluating the condition
225-
if (ApplicationListenerMethodAdapter.class.isInstance(listener)
226-
&& !((ApplicationListenerMethodAdapter) listener).shouldHandle(event)) {
227-
238+
if (!invokeShouldHandle(listener, event, payload)) {
228239
return false;
229240
}
230241

@@ -233,6 +244,27 @@ private static boolean matches(ApplicationEvent event, Object payload, Applicati
233244
: true;
234245
}
235246

247+
/**
248+
* Invokes {@link ApplicationListenerMethodAdapter#shouldHandle(ApplicationEvent)} in case the given candidate is one
249+
* in the first place but falls back to call {@code shouldHandle(ApplicationEvent, Object)} reflectively as fallback.
250+
*
251+
* @param candidate the listener to test, must not be {@literal null}.
252+
* @param event the event to publish, must not be {@literal null}.
253+
* @param payload the actual payload, must not be {@literal null}.
254+
* @return whether the event should be handled by the given candidate.
255+
*/
256+
@SuppressWarnings("null")
257+
private static boolean invokeShouldHandle(ApplicationListener<?> candidate, ApplicationEvent event, Object payload) {
258+
259+
if (!(candidate instanceof ApplicationListenerMethodAdapter listener)) {
260+
return true;
261+
}
262+
263+
return SHOULD_HANDLE != null
264+
? listener.shouldHandle(event)
265+
: (boolean) ReflectionUtils.invokeMethod(LEGACY_SHOULD_HANDLE, candidate, event, new Object[] { payload });
266+
}
267+
236268
private static String getConfirmationMessage(Collection<?> publications) {
237269

238270
var size = publications.size();

0 commit comments

Comments
 (0)