From 9546c7a1c83f76e61d8bd1ebcbc2a8104b557105 Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Mon, 23 Jun 2025 21:44:26 -0400 Subject: [PATCH 1/7] [events] support prototype scope now will use a supplier using `BeanScope` to inject observer beans --- .../avaje/inject/generator/MethodReader.java | 6 +++++ .../inject/generator/SimpleBeanWriter.java | 20 ++++++++++++----- .../observes/MyObserverInjectPrototype.java | 22 +++++++++++++++++++ .../example/observes/TestEventMessaging.java | 19 ++++++++++++++++ 4 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 inject-test/src/test/java/org/example/observes/MyObserverInjectPrototype.java diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java b/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java index 5b44ddc53..490e6af16 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Supplier; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; @@ -419,6 +420,11 @@ void addImports(ImportTypeMap importTypes) { if (optionalType) { importTypes.add(Constants.OPTIONAL); } + + if (observeParameter != null) { + importTypes.add(Supplier.class.getCanonicalName()); + importTypes.add(Constants.BEANSCOPE); + } conditions.addImports(importTypes); } diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java index 2b7fa0160..6740768e3 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java @@ -256,6 +256,7 @@ private void writeExtraInjection() { private void writeObserveMethods() { final var bean = "bean"; final var builder = "builder"; + final var scope = "events$$beanScope"; final var indent = " "; for (MethodReader methodReader : beanReader.observerMethods()) { @@ -264,9 +265,17 @@ private void writeObserveMethods() { final var shortWithoutAnnotations = observeUtype.shortWithoutAnnotations(); var injectParams = methodReader.params().stream().skip(1).collect(toList()); + if (!injectParams.isEmpty()) { + writer.indent(indent).append("var %s = %s.get(BeanScope.class);", scope, builder).eol(); + } + for (MethodParam param : injectParams) { - writer.indent(indent).append("var %s = ", methodReader.name() + "$" + param.simpleName()); - param.builderGetDependency(writer, builder); + writer + .indent(indent) + .append( + "Supplier<%s> %s = () -> ", + param.getFullUType().shortType(), methodReader.name() + "$" + param.simpleName()); + param.builderGetDependency(writer, scope); writer.append(";").eol(); } @@ -280,9 +289,10 @@ private void writeObserveMethods() { if (methodReader.params().size() == 1) { writer.append("%s::%s;", bean, methodReader.name()); } else { - var injectParamNames = injectParams.stream() - .map(p -> methodReader.name() + "$" + p.simpleName()) - .collect(joining(", ")); + var injectParamNames = + injectParams.stream() + .map(p -> methodReader.name() + "$" + p.simpleName() + ".get()") + .collect(joining(", ")); writer.append("e -> bean.%s(e, %s);", methodReader.name(), injectParamNames); } final var observesPrism = ObservesPrism.getInstanceOn(observeEvent.element()); diff --git a/inject-test/src/test/java/org/example/observes/MyObserverInjectPrototype.java b/inject-test/src/test/java/org/example/observes/MyObserverInjectPrototype.java new file mode 100644 index 000000000..be5d238a6 --- /dev/null +++ b/inject-test/src/test/java/org/example/observes/MyObserverInjectPrototype.java @@ -0,0 +1,22 @@ +package org.example.observes; + +import java.util.ArrayDeque; + +import org.example.coffee.prototype.MyProto; + +import io.avaje.inject.events.Observes; +import jakarta.inject.Singleton; + +@Singleton +public class MyObserverInjectPrototype { + + boolean invoked = false; + CustomEvent event; + ArrayDeque beansList = new ArrayDeque<>(); + + void observe(@Observes CustomEvent e, MyProto proto) { + invoked = true; + event = e; + beansList.add(proto); + } +} diff --git a/inject-test/src/test/java/org/example/observes/TestEventMessaging.java b/inject-test/src/test/java/org/example/observes/TestEventMessaging.java index d8603a01f..410210b8e 100644 --- a/inject-test/src/test/java/org/example/observes/TestEventMessaging.java +++ b/inject-test/src/test/java/org/example/observes/TestEventMessaging.java @@ -16,6 +16,7 @@ class TestEventMessaging { @Inject MyObserver observer; @Inject MyQualifiedObserver qualifiedObserver; @Inject MyObserverInjected observerInjected; + @Inject MyObserverInjectPrototype observerPrototype; @Inject MyStrQualifiedObserver strQualifiedObserver; @Inject Event event; @Inject EventSender2 sender2; @@ -30,6 +31,9 @@ void before() { qualifiedObserver.event = null; observerInjected.invoked= false; observerInjected.event = null; + observerPrototype.invoked = false; + observerPrototype.event = null; + observerPrototype.beansList.clear(); } @Test @@ -45,6 +49,21 @@ void test() { assertThat(observerInjected.event).isSameAs(message); } + @Test + void testProtoType() { + var message = new CustomEvent("hi"); + + event.fire(message); + + assertThat(observerPrototype.invoked).isTrue(); + assertThat(observerPrototype.event).isSameAs(message); + event.fire(message); + + assertThat(observerPrototype.invoked).isTrue(); + assertThat(observerPrototype.event).isSameAs(message); + assertThat(observerPrototype.beansList.poll()).isNotSameAs(observerPrototype.beansList.poll()); + } + @Test void testWithQualified() { var message = new CustomEvent("hi"); From f5be0fbf7336fda62f5e7b3bbb6288b008edd02a Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Mon, 23 Jun 2025 21:44:26 -0400 Subject: [PATCH 2/7] [events] support prototype scope now will use a supplier using `BeanScope` to inject observer beans --- .../avaje/inject/generator/MethodReader.java | 6 +++++ .../inject/generator/SimpleBeanWriter.java | 20 ++++++++++++----- .../observes/MyObserverInjectPrototype.java | 22 +++++++++++++++++++ .../example/observes/TestEventMessaging.java | 19 ++++++++++++++++ 4 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 inject-test/src/test/java/org/example/observes/MyObserverInjectPrototype.java diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java b/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java index 5b44ddc53..490e6af16 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Supplier; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; @@ -419,6 +420,11 @@ void addImports(ImportTypeMap importTypes) { if (optionalType) { importTypes.add(Constants.OPTIONAL); } + + if (observeParameter != null) { + importTypes.add(Supplier.class.getCanonicalName()); + importTypes.add(Constants.BEANSCOPE); + } conditions.addImports(importTypes); } diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java index 2b7fa0160..6740768e3 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java @@ -256,6 +256,7 @@ private void writeExtraInjection() { private void writeObserveMethods() { final var bean = "bean"; final var builder = "builder"; + final var scope = "events$$beanScope"; final var indent = " "; for (MethodReader methodReader : beanReader.observerMethods()) { @@ -264,9 +265,17 @@ private void writeObserveMethods() { final var shortWithoutAnnotations = observeUtype.shortWithoutAnnotations(); var injectParams = methodReader.params().stream().skip(1).collect(toList()); + if (!injectParams.isEmpty()) { + writer.indent(indent).append("var %s = %s.get(BeanScope.class);", scope, builder).eol(); + } + for (MethodParam param : injectParams) { - writer.indent(indent).append("var %s = ", methodReader.name() + "$" + param.simpleName()); - param.builderGetDependency(writer, builder); + writer + .indent(indent) + .append( + "Supplier<%s> %s = () -> ", + param.getFullUType().shortType(), methodReader.name() + "$" + param.simpleName()); + param.builderGetDependency(writer, scope); writer.append(";").eol(); } @@ -280,9 +289,10 @@ private void writeObserveMethods() { if (methodReader.params().size() == 1) { writer.append("%s::%s;", bean, methodReader.name()); } else { - var injectParamNames = injectParams.stream() - .map(p -> methodReader.name() + "$" + p.simpleName()) - .collect(joining(", ")); + var injectParamNames = + injectParams.stream() + .map(p -> methodReader.name() + "$" + p.simpleName() + ".get()") + .collect(joining(", ")); writer.append("e -> bean.%s(e, %s);", methodReader.name(), injectParamNames); } final var observesPrism = ObservesPrism.getInstanceOn(observeEvent.element()); diff --git a/inject-test/src/test/java/org/example/observes/MyObserverInjectPrototype.java b/inject-test/src/test/java/org/example/observes/MyObserverInjectPrototype.java new file mode 100644 index 000000000..be5d238a6 --- /dev/null +++ b/inject-test/src/test/java/org/example/observes/MyObserverInjectPrototype.java @@ -0,0 +1,22 @@ +package org.example.observes; + +import java.util.ArrayDeque; + +import org.example.coffee.prototype.MyProto; + +import io.avaje.inject.events.Observes; +import jakarta.inject.Singleton; + +@Singleton +public class MyObserverInjectPrototype { + + boolean invoked = false; + CustomEvent event; + ArrayDeque beansList = new ArrayDeque<>(); + + void observe(@Observes CustomEvent e, MyProto proto) { + invoked = true; + event = e; + beansList.add(proto); + } +} diff --git a/inject-test/src/test/java/org/example/observes/TestEventMessaging.java b/inject-test/src/test/java/org/example/observes/TestEventMessaging.java index d8603a01f..410210b8e 100644 --- a/inject-test/src/test/java/org/example/observes/TestEventMessaging.java +++ b/inject-test/src/test/java/org/example/observes/TestEventMessaging.java @@ -16,6 +16,7 @@ class TestEventMessaging { @Inject MyObserver observer; @Inject MyQualifiedObserver qualifiedObserver; @Inject MyObserverInjected observerInjected; + @Inject MyObserverInjectPrototype observerPrototype; @Inject MyStrQualifiedObserver strQualifiedObserver; @Inject Event event; @Inject EventSender2 sender2; @@ -30,6 +31,9 @@ void before() { qualifiedObserver.event = null; observerInjected.invoked= false; observerInjected.event = null; + observerPrototype.invoked = false; + observerPrototype.event = null; + observerPrototype.beansList.clear(); } @Test @@ -45,6 +49,21 @@ void test() { assertThat(observerInjected.event).isSameAs(message); } + @Test + void testProtoType() { + var message = new CustomEvent("hi"); + + event.fire(message); + + assertThat(observerPrototype.invoked).isTrue(); + assertThat(observerPrototype.event).isSameAs(message); + event.fire(message); + + assertThat(observerPrototype.invoked).isTrue(); + assertThat(observerPrototype.event).isSameAs(message); + assertThat(observerPrototype.beansList.poll()).isNotSameAs(observerPrototype.beansList.poll()); + } + @Test void testWithQualified() { var message = new CustomEvent("hi"); From c96bdf1a74b2f4c94083851a37b6ad6d030087c5 Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Mon, 23 Jun 2025 21:56:09 -0400 Subject: [PATCH 3/7] handle wiring beanscope --- .../java/io/avaje/inject/generator/SimpleBeanWriter.java | 9 ++++++++- .../models/valid/observes/TestObserverInjection.java | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java index 6740768e3..f9a00e447 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java @@ -270,6 +270,9 @@ private void writeObserveMethods() { } for (MethodParam param : injectParams) { + if (Constants.BEANSCOPE.equals(param.getFullUType().fullWithoutAnnotations())) { + continue; + } writer .indent(indent) .append( @@ -291,7 +294,11 @@ private void writeObserveMethods() { } else { var injectParamNames = injectParams.stream() - .map(p -> methodReader.name() + "$" + p.simpleName() + ".get()") + .map( + p -> + Constants.BEANSCOPE.equals(p.getFullUType().fullWithoutAnnotations()) + ? scope + : methodReader.name() + "$" + p.simpleName() + ".get()") .collect(joining(", ")); writer.append("e -> bean.%s(e, %s);", methodReader.name(), injectParamNames); } diff --git a/inject-generator/src/test/java/io/avaje/inject/generator/models/valid/observes/TestObserverInjection.java b/inject-generator/src/test/java/io/avaje/inject/generator/models/valid/observes/TestObserverInjection.java index 3c3a18e35..dcc88b080 100644 --- a/inject-generator/src/test/java/io/avaje/inject/generator/models/valid/observes/TestObserverInjection.java +++ b/inject-generator/src/test/java/io/avaje/inject/generator/models/valid/observes/TestObserverInjection.java @@ -1,10 +1,11 @@ package io.avaje.inject.generator.models.valid.observes; +import io.avaje.inject.BeanScope; import io.avaje.inject.events.ObservesAsync; import jakarta.inject.Singleton; @Singleton public class TestObserverInjection { - void observe(@ObservesAsync String e, TestObserver observer) {} + void observe(@ObservesAsync String e, TestObserver observer, BeanScope scope) {} } From 5fd3fde12646ad620ab0648bd155297de270a94d Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Mon, 23 Jun 2025 23:51:48 -0400 Subject: [PATCH 4/7] fix generic injection --- .../main/java/io/avaje/inject/generator/BeanReader.java | 9 +++++++++ .../java/org/example/observes/MyObserverInjected.java | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/BeanReader.java b/inject-generator/src/main/java/io/avaje/inject/generator/BeanReader.java index 5b6df4591..10113fe69 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/BeanReader.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/BeanReader.java @@ -263,6 +263,15 @@ Set allGenericTypes() { if (utype.isGeneric()) { allUTypes.add(utype); } + method.params().stream() + .filter(p -> !p.observeEvent()) + .map(MethodParam::getFullUType) + .forEach( + u -> { + if (u.isGeneric()) { + allUTypes.add(u); + } + }); } if (constructor != null) { diff --git a/inject-test/src/test/java/org/example/observes/MyObserverInjected.java b/inject-test/src/test/java/org/example/observes/MyObserverInjected.java index a1a4c96c8..0ee4d3795 100644 --- a/inject-test/src/test/java/org/example/observes/MyObserverInjected.java +++ b/inject-test/src/test/java/org/example/observes/MyObserverInjected.java @@ -1,5 +1,6 @@ package org.example.observes; +import io.avaje.inject.events.Event; import io.avaje.inject.events.Observes; import jakarta.inject.Singleton; @@ -9,7 +10,10 @@ public class MyObserverInjected { boolean invoked = false; CustomEvent event; - void observe(@Observes CustomEvent e, MyObserver observer) { + void observe( + @Observes CustomEvent e, + MyObserver observer, + @StrQualifier(value = "foo") Event publisher) { invoked = true; event = e; } From e4ee4b0d4636c3e64489c23806b6e784571418ee Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Mon, 23 Jun 2025 23:56:03 -0400 Subject: [PATCH 5/7] Update MethodReader.java --- .../src/main/java/io/avaje/inject/generator/MethodReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java b/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java index 490e6af16..d5a6f7b89 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java @@ -421,7 +421,7 @@ void addImports(ImportTypeMap importTypes) { importTypes.add(Constants.OPTIONAL); } - if (observeParameter != null) { + if (observeParameter != null && params.size() > 1) { importTypes.add(Supplier.class.getCanonicalName()); importTypes.add(Constants.BEANSCOPE); } From 3dbe8f11bdbc8aa3aaeccd77ae2714d065a950cf Mon Sep 17 00:00:00 2001 From: Josiah Noel <32279667+SentryMan@users.noreply.github.com> Date: Tue, 24 Jun 2025 00:07:10 -0400 Subject: [PATCH 6/7] Update SimpleBeanWriter.java --- .../main/java/io/avaje/inject/generator/SimpleBeanWriter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java index f9a00e447..4962090e2 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java @@ -256,7 +256,7 @@ private void writeExtraInjection() { private void writeObserveMethods() { final var bean = "bean"; final var builder = "builder"; - final var scope = "events$$beanScope"; + final var scope = "beanScope"; final var indent = " "; for (MethodReader methodReader : beanReader.observerMethods()) { From ef9715c892dde59113cd6d2df90ae6453ab5fedb Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 24 Jun 2025 18:30:51 +1200 Subject: [PATCH 7/7] Format only --- .../io/avaje/inject/generator/BeanReader.java | 15 ++++++------- .../inject/generator/SimpleBeanWriter.java | 22 ++++++++----------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/BeanReader.java b/inject-generator/src/main/java/io/avaje/inject/generator/BeanReader.java index 10113fe69..0193faec6 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/BeanReader.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/BeanReader.java @@ -264,14 +264,13 @@ Set allGenericTypes() { allUTypes.add(utype); } method.params().stream() - .filter(p -> !p.observeEvent()) - .map(MethodParam::getFullUType) - .forEach( - u -> { - if (u.isGeneric()) { - allUTypes.add(u); - } - }); + .filter(p -> !p.observeEvent()) + .map(MethodParam::getFullUType) + .forEach(u -> { + if (u.isGeneric()) { + allUTypes.add(u); + } + }); } if (constructor != null) { diff --git a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java index 4962090e2..4095ecd5e 100644 --- a/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java +++ b/inject-generator/src/main/java/io/avaje/inject/generator/SimpleBeanWriter.java @@ -273,11 +273,9 @@ private void writeObserveMethods() { if (Constants.BEANSCOPE.equals(param.getFullUType().fullWithoutAnnotations())) { continue; } - writer - .indent(indent) - .append( - "Supplier<%s> %s = () -> ", - param.getFullUType().shortType(), methodReader.name() + "$" + param.simpleName()); + writer.indent(indent).append("Supplier<%s> %s = () -> ", + param.getFullUType().shortType(), + methodReader.name() + "$" + param.simpleName()); param.builderGetDependency(writer, scope); writer.append(";").eol(); } @@ -292,14 +290,12 @@ private void writeObserveMethods() { if (methodReader.params().size() == 1) { writer.append("%s::%s;", bean, methodReader.name()); } else { - var injectParamNames = - injectParams.stream() - .map( - p -> - Constants.BEANSCOPE.equals(p.getFullUType().fullWithoutAnnotations()) - ? scope - : methodReader.name() + "$" + p.simpleName() + ".get()") - .collect(joining(", ")); + var injectParamNames = injectParams.stream() + .map(p -> + Constants.BEANSCOPE.equals(p.getFullUType().fullWithoutAnnotations()) + ? scope + : methodReader.name() + "$" + p.simpleName() + ".get()") + .collect(joining(", ")); writer.append("e -> bean.%s(e, %s);", methodReader.name(), injectParamNames); } final var observesPrism = ObservesPrism.getInstanceOn(observeEvent.element());