Skip to content

Commit

Permalink
GH-357 - Reinstantiate general compatibility with Boot 3.2 / Framewor…
Browse files Browse the repository at this point in the history
…k 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.
  • Loading branch information
odrotbohm committed Nov 2, 2023
1 parent cef3ffb commit 40ab6ce
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 3 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -45,6 +46,7 @@
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
Expand All @@ -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}.
*
Expand Down Expand Up @@ -222,9 +235,7 @@ private static Object getEventToPersist(ApplicationEvent event) {
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;
}

Expand All @@ -233,6 +244,27 @@ private static boolean matches(ApplicationEvent event, Object payload, Applicati
: 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();
Expand Down

0 comments on commit 40ab6ce

Please sign in to comment.