From 0aa544fc008c1324a92a11f994ae001edd3ac8e8 Mon Sep 17 00:00:00 2001 From: Matej Novotny Date: Fri, 26 Jan 2024 15:53:18 +0100 Subject: [PATCH] WELD-2775 Make sure BM#getEvent() adds @Default qualifier correctly --- .../jboss/weld/event/EventMetadataImpl.java | 4 + .../jboss/weld/event/ObserverNotifier.java | 20 ++-- .../jboss/weld/manager/BeanManagerImpl.java | 2 +- .../weld/tests/event/EventQualifierTest.java | 55 ++++++++++- .../jboss/weld/tests/event/ObservingBean.java | 92 +++++++++++++++++++ .../org/jboss/weld/tests/event/Payload.java | 5 + 6 files changed, 166 insertions(+), 12 deletions(-) create mode 100644 tests-arquillian/src/test/java/org/jboss/weld/tests/event/ObservingBean.java create mode 100644 tests-arquillian/src/test/java/org/jboss/weld/tests/event/Payload.java diff --git a/impl/src/main/java/org/jboss/weld/event/EventMetadataImpl.java b/impl/src/main/java/org/jboss/weld/event/EventMetadataImpl.java index 6af34a39db..c6d1d8c439 100644 --- a/impl/src/main/java/org/jboss/weld/event/EventMetadataImpl.java +++ b/impl/src/main/java/org/jboss/weld/event/EventMetadataImpl.java @@ -21,6 +21,7 @@ import java.util.Set; import jakarta.enterprise.inject.Any; +import jakarta.enterprise.inject.Default; import jakarta.enterprise.inject.spi.EventMetadata; import jakarta.enterprise.inject.spi.InjectionPoint; @@ -59,6 +60,9 @@ private EventMetadataImpl(Type type, InjectionPoint injectionPoint, Set getQualifiers() { ImmutableSet.Builder builder = ImmutableSet. builder(); builder.add(Any.Literal.INSTANCE); + if ((qualifiers != null && qualifiers.isEmpty()) || (qualifierArray != null && qualifierArray.length == 0)) { + builder.add(Default.Literal.INSTANCE); + } if (qualifiers != null) { return builder.addAll(qualifiers).build(); } else if (qualifierArray != null) { diff --git a/impl/src/main/java/org/jboss/weld/event/ObserverNotifier.java b/impl/src/main/java/org/jboss/weld/event/ObserverNotifier.java index 3d5cff9919..13aaff4a18 100644 --- a/impl/src/main/java/org/jboss/weld/event/ObserverNotifier.java +++ b/impl/src/main/java/org/jboss/weld/event/ObserverNotifier.java @@ -40,6 +40,7 @@ import jakarta.enterprise.event.NotificationOptions; import jakarta.enterprise.event.ObserverException; +import jakarta.enterprise.inject.Default; import jakarta.enterprise.inject.spi.EventMetadata; import jakarta.enterprise.inject.spi.ObserverMethod; @@ -120,7 +121,7 @@ protected ObserverNotifier(String contextId, TypeSafeObserverResolver resolver, * Resolves observer methods based on the given event type and qualifiers. If strict checks are enabled the given type is * verified. * - * @param event the event object + * @param eventType the event object * @param qualifiers given event qualifiers * @return resolved observer methods */ @@ -133,7 +134,7 @@ public ResolvedObservers resolveObserverMethods(Type eventType, Annotatio * Resolves observer methods based on the given event type and qualifiers. If strict checks are enabled the given type is * verified. * - * @param event the event object + * @param eventType the event object * @param qualifiers given event qualifiers * @return resolved observer methods */ @@ -200,16 +201,19 @@ public void fireEvent(Object event, Resolvable resolvable) { protected Resolvable buildEventResolvable(Type eventType, Set qualifiers) { // We can always cache as this is only ever called by Weld where we avoid non-static inner classes for annotation literals Set typeClosure = sharedObjectCache.getTypeClosureHolder(eventType).get(); - return new ResolvableBuilder(resolver.getMetaAnnotationStore()).addTypes(typeClosure).addType(Object.class) + ResolvableBuilder resolvableBuilder = new ResolvableBuilder(resolver.getMetaAnnotationStore()).addTypes(typeClosure) + .addType(Object.class) .addQualifiers(qualifiers) - .addQualifierUnchecked(QualifierInstance.ANY).create(); + .addQualifierUnchecked(QualifierInstance.ANY); + if (qualifiers.isEmpty()) { + resolvableBuilder.addQualifier(Default.Literal.INSTANCE); + } + return resolvableBuilder.create(); + } protected Resolvable buildEventResolvable(Type eventType, Annotation... qualifiers) { - // We can always cache as this is only ever called by Weld where we avoid non-static inner classes for annotation literals - return new ResolvableBuilder(resolver.getMetaAnnotationStore()) - .addTypes(sharedObjectCache.getTypeClosureHolder(eventType).get()).addType(Object.class) - .addQualifiers(qualifiers).addQualifierUnchecked(QualifierInstance.ANY).create(); + return buildEventResolvable(eventType, Set.of(qualifiers)); } /** diff --git a/impl/src/main/java/org/jboss/weld/manager/BeanManagerImpl.java b/impl/src/main/java/org/jboss/weld/manager/BeanManagerImpl.java index c7517058fd..451285d7e6 100644 --- a/impl/src/main/java/org/jboss/weld/manager/BeanManagerImpl.java +++ b/impl/src/main/java/org/jboss/weld/manager/BeanManagerImpl.java @@ -1361,7 +1361,7 @@ public Type getType() { } // there are no qualifiers by default - // ResolvableBuilder.create() takes care of adding @Default if there is no qualifier selected + // @Default and @Any are added as needed in ObserverQualifier#buildEventResolvable @Override public Set getQualifiers() { return Collections.emptySet(); diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/EventQualifierTest.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/EventQualifierTest.java index dae2c64f1a..9d58819d47 100644 --- a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/EventQualifierTest.java +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/EventQualifierTest.java @@ -16,6 +16,17 @@ */ package org.jboss.weld.tests.event; +import java.lang.annotation.Annotation; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import jakarta.enterprise.inject.Any; +import jakarta.enterprise.inject.Default; +import jakarta.enterprise.inject.spi.BeanManager; +import jakarta.inject.Inject; + import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.Archive; @@ -34,9 +45,9 @@ public static Archive deploy() { .addPackage(EventQualifierTest.class.getPackage()); } - /* - * description = "WELD-226" - */ + @Inject + BeanManager bm; + @Test public void testDefaultQualifierNotRequired(Bar bar) { bar.fireWithNoQualifiers(); @@ -60,4 +71,42 @@ public void testDefaultQualifierNotRequired(Bar bar) { Assert.assertTrue(bar.isUpdatedObserved()); } + @Test + public void testDefaultQualifierPresent(ObservingBean bean) + throws ExecutionException, InterruptedException, TimeoutException { + bean.reset(); + + Set expectedQualifiers = Set.of(Any.Literal.INSTANCE, Default.Literal.INSTANCE); + + // just get event fire right away - @Default should be included + bm.getEvent().fire(new Payload()); + Assert.assertEquals(1, bean.getDefaultObjectNotified()); + Assert.assertEquals(1, bean.getDefaultPayloadNotified()); + Assert.assertEquals(expectedQualifiers, bean.getDefaultObjectQualifiers()); + Assert.assertEquals(expectedQualifiers, bean.getDefaultPayloadQualifiers()); + + // select Payload and fire - @Default should be included + bm.getEvent().select(Payload.class).fire(new Payload()); + Assert.assertEquals(2, bean.getDefaultObjectNotified()); + Assert.assertEquals(2, bean.getDefaultPayloadNotified()); + Assert.assertEquals(expectedQualifiers, bean.getDefaultObjectQualifiers()); + Assert.assertEquals(expectedQualifiers, bean.getDefaultPayloadQualifiers()); + + // same in async variant + // just get event fire right away - @Default should be included + bm.getEvent().fireAsync(new Payload()).toCompletableFuture().get(2, TimeUnit.SECONDS); + Assert.assertEquals(1, bean.getDefaultObjectAsyncNotified()); + Assert.assertEquals(1, bean.getDefaultPayloadAsyncNotified()); + Assert.assertEquals(expectedQualifiers, bean.getDefaultObjectAsyncQualifiers()); + Assert.assertEquals(expectedQualifiers, bean.getDefaultPayloadAsyncQualifiers()); + + // select Payload and fire - @Default should be included + bm.getEvent().select(Payload.class).fireAsync(new Payload()).toCompletableFuture().get(2, TimeUnit.SECONDS); + Assert.assertEquals(2, bean.getDefaultObjectAsyncNotified()); + Assert.assertEquals(2, bean.getDefaultPayloadAsyncNotified()); + Assert.assertEquals(expectedQualifiers, bean.getDefaultObjectAsyncQualifiers()); + Assert.assertEquals(expectedQualifiers, bean.getDefaultPayloadAsyncQualifiers()); + + } + } diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/ObservingBean.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/ObservingBean.java new file mode 100644 index 0000000000..95b376ab59 --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/ObservingBean.java @@ -0,0 +1,92 @@ +package org.jboss.weld.tests.event; + +import java.lang.annotation.Annotation; +import java.util.Set; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.event.ObservesAsync; +import jakarta.enterprise.inject.Default; +import jakarta.enterprise.inject.spi.EventMetadata; + +@ApplicationScoped +public class ObservingBean { + + private volatile int defaultObjectNotified = 0; + private volatile int defaultObjectAsyncNotified = 0; + private volatile int defaultPayloadNotified = 0; + private volatile int defaultPayloadAsyncNotified = 0; + private volatile Set defaultObjectQualifiers; + private volatile Set defaultObjectAsyncQualifiers; + private volatile Set defaultPayloadQualifiers; + private volatile Set defaultPayloadAsyncQualifiers; + + public void observeDefaultObject(@Observes @Default Object payload, EventMetadata em) { + // object type is very broad, only look for Payload runtime type + if (em.getType().equals(Payload.class)) { + this.defaultObjectNotified++; + this.defaultObjectQualifiers = em.getQualifiers(); + } + } + + public void observeDefaultPayload(@Observes @Default Payload payload, EventMetadata em) { + this.defaultPayloadNotified++; + this.defaultPayloadQualifiers = em.getQualifiers(); + } + + public void observeDefaultObjectAsync(@ObservesAsync @Default Object payload, EventMetadata em) { + // object type is very broad, only look for Payload runtime type + if (em.getType().equals(Payload.class)) { + this.defaultObjectAsyncNotified++; + this.defaultObjectAsyncQualifiers = em.getQualifiers(); + } + } + + public void observeDefaultPayloadAsync(@ObservesAsync @Default Payload payload, EventMetadata em) { + this.defaultPayloadAsyncNotified++; + this.defaultPayloadAsyncQualifiers = em.getQualifiers(); + } + + public int getDefaultObjectNotified() { + return defaultObjectNotified; + } + + public int getDefaultPayloadNotified() { + return defaultPayloadNotified; + } + + public Set getDefaultObjectQualifiers() { + return defaultObjectQualifiers; + } + + public Set getDefaultPayloadQualifiers() { + return defaultPayloadQualifiers; + } + + public int getDefaultObjectAsyncNotified() { + return defaultObjectAsyncNotified; + } + + public int getDefaultPayloadAsyncNotified() { + return defaultPayloadAsyncNotified; + } + + public Set getDefaultObjectAsyncQualifiers() { + return defaultObjectAsyncQualifiers; + } + + public Set getDefaultPayloadAsyncQualifiers() { + return defaultPayloadAsyncQualifiers; + } + + public void reset() { + this.defaultPayloadNotified = 0; + this.defaultPayloadAsyncNotified = 0; + this.defaultObjectNotified = 0; + this.defaultObjectAsyncNotified = 0; + this.defaultObjectQualifiers = null; + this.defaultObjectAsyncQualifiers = null; + this.defaultPayloadQualifiers = null; + this.defaultPayloadAsyncQualifiers = null; + } +} diff --git a/tests-arquillian/src/test/java/org/jboss/weld/tests/event/Payload.java b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/Payload.java new file mode 100644 index 0000000000..7184f6be2d --- /dev/null +++ b/tests-arquillian/src/test/java/org/jboss/weld/tests/event/Payload.java @@ -0,0 +1,5 @@ +package org.jboss.weld.tests.event; + +// serves as an event payload +public class Payload { +}