diff --git a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ObserverGenerator.java b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ObserverGenerator.java index 608e74cb56445..4700853ff10c8 100644 --- a/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ObserverGenerator.java +++ b/independent-projects/arc/processor/src/main/java/io/quarkus/arc/processor/ObserverGenerator.java @@ -226,6 +226,9 @@ Collection generate(ObserverInfo observer) { implementGetBeanClass(observerCreator, observer.getBeanClass()); implementNotify(observer, observerCreator, injectionPointToProviderField, reflectionRegistration, isApplicationClass); + if (Reception.IF_EXISTS == observer.getReception()) { + implementIfExistsGetReception(observerCreator); + } if (observer.getPriority() != ObserverMethod.DEFAULT_PRIORITY) { implementGetPriority(observerCreator, observer); } @@ -258,6 +261,12 @@ protected void initMaps(ObserverInfo observer, Map i } } + protected void implementIfExistsGetReception(ClassCreator observerCreator) { + MethodCreator getReception = observerCreator.getMethodCreator("getReception", Reception.class) + .setModifiers(ACC_PUBLIC); + getReception.returnValue(getReception.load(Reception.IF_EXISTS)); + } + protected void implementGetObservedType(ClassCreator observerCreator, FieldDescriptor observedTypeField) { MethodCreator getObservedType = observerCreator.getMethodCreator("getObservedType", Type.class) .setModifiers(ACC_PUBLIC); diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/InjectableObserverMethod.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/InjectableObserverMethod.java index 2ecc487e587c9..36780c811f856 100644 --- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/InjectableObserverMethod.java +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/InjectableObserverMethod.java @@ -6,8 +6,12 @@ import jakarta.enterprise.event.Reception; import jakarta.enterprise.event.TransactionPhase; +import jakarta.enterprise.inject.spi.Bean; import jakarta.enterprise.inject.spi.ObserverMethod; +import io.quarkus.arc.impl.EventContextImpl; +import io.quarkus.arc.impl.EventMetadataImpl; + /** * Represents an observer method. * @@ -32,6 +36,16 @@ default TransactionPhase getTransactionPhase() { return TransactionPhase.IN_PROGRESS; } + @Override + default Bean getDeclaringBean() { + return Arc.container().bean(getDeclaringBeanIdentifier()); + } + + default void notify(T event) { + notify(new EventContextImpl<>(event, + new EventMetadataImpl(getObservedQualifiers(), event.getClass()))); + } + /** * * @return the identifier or null for synthetic observers diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventContextImpl.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventContextImpl.java new file mode 100644 index 0000000000000..be52039fc0c80 --- /dev/null +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventContextImpl.java @@ -0,0 +1,28 @@ +package io.quarkus.arc.impl; + +import jakarta.enterprise.inject.spi.EventContext; +import jakarta.enterprise.inject.spi.EventMetadata; + +// this class is public because it is used in io.quarkus.arc.InjectableObserverMethod +public final class EventContextImpl implements EventContext { + + private final T payload; + + private final EventMetadata metadata; + + public EventContextImpl(T payload, EventMetadata metadata) { + this.payload = payload; + this.metadata = metadata; + } + + @Override + public T getEvent() { + return payload; + } + + @Override + public EventMetadata getMetadata() { + return metadata; + } + +} diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventImpl.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventImpl.java index 71dbb4d24d316..b35920b97c1f3 100644 --- a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventImpl.java +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventImpl.java @@ -29,7 +29,6 @@ import jakarta.enterprise.inject.Any; import jakarta.enterprise.inject.spi.EventContext; import jakarta.enterprise.inject.spi.EventMetadata; -import jakarta.enterprise.inject.spi.InjectionPoint; import jakarta.enterprise.inject.spi.ObserverMethod; import jakarta.enterprise.util.TypeLiteral; import jakarta.transaction.RollbackException; @@ -351,58 +350,6 @@ private boolean isNotTxObserver(ObserverMethod observer) { } - static class EventContextImpl implements EventContext { - - private final T payload; - - private final EventMetadata metadata; - - public EventContextImpl(T payload, EventMetadata metadata) { - this.payload = payload; - this.metadata = metadata; - } - - @Override - public T getEvent() { - return payload; - } - - @Override - public EventMetadata getMetadata() { - return metadata; - } - - } - - static class EventMetadataImpl implements EventMetadata { - - private final Set qualifiers; - - private final Type eventType; - - public EventMetadataImpl(Set qualifiers, Type eventType) { - this.qualifiers = qualifiers; - this.eventType = eventType; - } - - @Override - public Set getQualifiers() { - return qualifiers; - } - - @Override - public InjectionPoint getInjectionPoint() { - // Currently we do not support injection point of the injected Event instance which fired the event - return null; - } - - @Override - public Type getType() { - return eventType; - } - - } - static class ArcSynchronization implements Synchronization { private List> deferredEvents; diff --git a/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventMetadataImpl.java b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventMetadataImpl.java new file mode 100644 index 0000000000000..cf01e6aa0c365 --- /dev/null +++ b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/EventMetadataImpl.java @@ -0,0 +1,38 @@ +package io.quarkus.arc.impl; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.Set; + +import jakarta.enterprise.inject.spi.EventMetadata; +import jakarta.enterprise.inject.spi.InjectionPoint; + +// this class is public because it is used in io.quarkus.arc.InjectableObserverMethod +public final class EventMetadataImpl implements EventMetadata { + + private final Set qualifiers; + + private final Type eventType; + + public EventMetadataImpl(Set qualifiers, Type eventType) { + this.qualifiers = qualifiers; + this.eventType = eventType; + } + + @Override + public Set getQualifiers() { + return qualifiers; + } + + @Override + public InjectionPoint getInjectionPoint() { + // Currently we do not support injection point of the injected Event instance which fired the event + return null; + } + + @Override + public Type getType() { + return eventType; + } + +} diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/observers/SimpleObserverTest.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/observers/SimpleObserverTest.java index c9a6da10accde..aef36126df7c0 100644 --- a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/observers/SimpleObserverTest.java +++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/observers/SimpleObserverTest.java @@ -1,14 +1,18 @@ package io.quarkus.arc.test.observers; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.util.List; +import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import jakarta.annotation.PostConstruct; import jakarta.enterprise.context.Dependent; import jakarta.enterprise.event.Event; import jakarta.enterprise.event.Observes; +import jakarta.enterprise.inject.spi.Bean; +import jakarta.enterprise.inject.spi.ObserverMethod; import jakarta.inject.Inject; import jakarta.inject.Singleton; @@ -31,6 +35,15 @@ public void testObserver() { producer.produce("ping"); List events = observer.getEvents(); assertEquals(2, events.size()); + + // verify we can resolve OM and check some of its metadata + Set> foundOms = Arc.container().beanManager().resolveObserverMethods("someString"); + assertEquals(1, foundOms.size()); + ObserverMethod om = foundOms.iterator().next(); + Bean declaringBean = om.getDeclaringBean(); + assertNotNull(declaringBean); + assertEquals(StringObserver.class, declaringBean.getBeanClass()); + assertEquals(Singleton.class, declaringBean.getScope()); } @Singleton diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/observers/ifexists/ReceptionIfExistsTest.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/observers/ifexists/ReceptionIfExistsTest.java index ea270b87e83ee..99a4cd94c31dd 100644 --- a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/observers/ifexists/ReceptionIfExistsTest.java +++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/observers/ifexists/ReceptionIfExistsTest.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.List; +import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import jakarta.annotation.Priority; @@ -10,6 +11,7 @@ import jakarta.enterprise.context.RequestScoped; import jakarta.enterprise.event.Observes; import jakarta.enterprise.event.Reception; +import jakarta.enterprise.inject.spi.ObserverMethod; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -50,6 +52,16 @@ public void testObserver() { assertEquals(RequestScopedObserver.class.getName() + "foo", EVENTS.get(0)); assertEquals(DependentObserver.class.getName() + "foo", EVENTS.get(1)); container.requestContext().deactivate(); + + Set> foundOm = Arc.container().beanManager().resolveObserverMethods("eventString"); + assertEquals(2, foundOm.size()); + for (ObserverMethod om : foundOm) { + if (om.getDeclaringBean().getBeanClass().equals(RequestScopedObserver.class)) { + assertEquals(Reception.IF_EXISTS, om.getReception()); + } else { + assertEquals(Reception.ALWAYS, om.getReception()); + } + } } @RequestScoped diff --git a/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/observers/notification/ManualNotifyInvocationTest.java b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/observers/notification/ManualNotifyInvocationTest.java new file mode 100644 index 0000000000000..a60ac261dd7e2 --- /dev/null +++ b/independent-projects/arc/tests/src/test/java/io/quarkus/arc/test/observers/notification/ManualNotifyInvocationTest.java @@ -0,0 +1,43 @@ +package io.quarkus.arc.test.observers.notification; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.inject.spi.ObserverMethod; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.arc.test.ArcTestContainer; + +public class ManualNotifyInvocationTest { + + @RegisterExtension + public ArcTestContainer container = new ArcTestContainer(StringObserver.class); + + @Test + public void testManualNotifyInvocation() { + assertEquals(0, StringObserver.NOTIFIED.get()); + Arc.container().beanManager().getEvent().fire("hello"); + assertEquals(1, StringObserver.NOTIFIED.get()); + + Set> foundOM = Arc.container().beanManager().resolveObserverMethods("foo"); + assertEquals(1, foundOM.size()); + foundOM.iterator().next().notify("test"); + assertEquals(2, StringObserver.NOTIFIED.get()); + } + + @ApplicationScoped + static class StringObserver { + private static final AtomicInteger NOTIFIED = new AtomicInteger(); + + void observeString(@Observes String value) { + NOTIFIED.incrementAndGet(); + } + } +}