diff --git a/extensions/mailer/deployment/src/main/java/io/quarkus/mailer/deployment/MailerProcessor.java b/extensions/mailer/deployment/src/main/java/io/quarkus/mailer/deployment/MailerProcessor.java index a2beea53ff177..70f8bc8e54f0b 100644 --- a/extensions/mailer/deployment/src/main/java/io/quarkus/mailer/deployment/MailerProcessor.java +++ b/extensions/mailer/deployment/src/main/java/io/quarkus/mailer/deployment/MailerProcessor.java @@ -1,6 +1,8 @@ package io.quarkus.mailer.deployment; import java.io.File; +import java.lang.reflect.Modifier; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -11,8 +13,12 @@ import jakarta.inject.Singleton; import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationTarget.Kind; +import org.jboss.jandex.ClassInfo; import org.jboss.jandex.ClassType; import org.jboss.jandex.DotName; +import org.jboss.jandex.IndexView; +import org.jboss.jandex.MethodInfo; import io.quarkus.arc.deployment.AdditionalBeanBuildItem; import io.quarkus.arc.deployment.AnnotationsTransformerBuildItem; @@ -35,6 +41,7 @@ import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem; import io.quarkus.mailer.MailTemplate; +import io.quarkus.mailer.MailTemplate.MailTemplateInstance; import io.quarkus.mailer.Mailer; import io.quarkus.mailer.MailerName; import io.quarkus.mailer.MockMailbox; @@ -56,6 +63,7 @@ public class MailerProcessor { static final DotName MAIL_TEMPLATE = DotName.createSimple(MailTemplate.class.getName()); + static final DotName MAIL_TEMPLATE_INSTANCE = DotName.createSimple(MailTemplateInstance.class.getName()); static final DotName MAILER_NAME = DotName.createSimple(MailerName.class); @@ -105,7 +113,7 @@ MailersBuildItem generateMailerSupportBean(MailerRecorder recorder, .anyMatch(i -> i.hasDefaultedQualifier() || // we inject a MailTemplate and it is not named (MAIL_TEMPLATE.equals(i.getType().name()) && i.getRequiredQualifier(MAILER_NAME) == null)) - || !index.getIndex().getAnnotations(CheckedTemplate.class).isEmpty(); + || isTypeSafeMailTemplateFound(index.getIndex()); Set namedMailers = mailerInjectionPoints.stream() .map(i -> i.getRequiredQualifier(MAILER_NAME)) @@ -124,6 +132,35 @@ MailersBuildItem generateMailerSupportBean(MailerRecorder recorder, return new MailersBuildItem(hasDefaultMailer, namedMailers); } + private boolean isTypeSafeMailTemplateFound(IndexView index) { + // Find all occurences of @CheckedTemplate + Collection checkedTemplates = index.getAnnotations(CheckedTemplate.class); + for (AnnotationInstance annotation : checkedTemplates) { + if (annotation.target().kind() == Kind.CLASS) { + ClassInfo target = annotation.target().asClass(); + if (target.isRecord()) { + // Java record that most likely implements MailTemplateInstance + return true; + } + for (MethodInfo method : target.methods()) { + if (Modifier.isStatic(method.flags()) && method.returnType().name().equals(MAIL_TEMPLATE_INSTANCE)) { + // Target declares a static method that returns MailTemplateInstance + return true; + } + } + } + } + + Collection mailTemplateInstances = index.getAllKnownImplementors(MAIL_TEMPLATE_INSTANCE); + for (ClassInfo mailTemplateInstance : mailTemplateInstances) { + if (mailTemplateInstance.isRecord()) { + // Java record that implements MailTemplateInstance found + return true; + } + } + return false; + } + @Record(ExecutionTime.RUNTIME_INIT) @BuildStep void generateMailerBeans(MailerRecorder recorder, diff --git a/extensions/mailer/deployment/src/test/java/io/quarkus/mailer/MailTemplateRecordNoInjectionTest.java b/extensions/mailer/deployment/src/test/java/io/quarkus/mailer/MailTemplateRecordNoInjectionTest.java new file mode 100644 index 0000000000000..ad4dc24993143 --- /dev/null +++ b/extensions/mailer/deployment/src/test/java/io/quarkus/mailer/MailTemplateRecordNoInjectionTest.java @@ -0,0 +1,39 @@ +package io.quarkus.mailer; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.Arc; +import io.quarkus.mailer.MailTemplate.MailTemplateInstance; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.ext.mail.MailMessage; + +public class MailTemplateRecordNoInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot(root -> root + .addClasses(confirmation.class) + .addAsResource("mock-config.properties", "application.properties") + .addAsResource(new StringAsset("" + + "{name}"), "templates/MailTemplateRecordNoInjectionTest/confirmation.html")); + + @Test + public void testMailTemplateRecord() { + // Intentionally use programmatic lookup to obtain the MockMailbox + MockMailbox mockMailbox = Arc.container().instance(MockMailbox.class).get(); + new confirmation("Ondrej").to("quarkus-reactive@quarkus.io").from("from-record@quarkus.io").subject("test mailer") + .send().await().indefinitely(); + assertEquals(1, mockMailbox.getMailMessagesSentTo("quarkus-reactive@quarkus.io").size()); + MailMessage message = mockMailbox.getMailMessagesSentTo("quarkus-reactive@quarkus.io").get(0); + assertEquals("from-record@quarkus.io", message.getFrom()); + assertEquals("Ondrej", message.getHtml()); + } + + record confirmation(String name) implements MailTemplateInstance { + } + +} diff --git a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailTemplateProducer.java b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailTemplateProducer.java index f0ecc919afe7c..5073b125ad611 100644 --- a/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailTemplateProducer.java +++ b/extensions/mailer/runtime/src/main/java/io/quarkus/mailer/runtime/MailTemplateProducer.java @@ -4,9 +4,9 @@ import java.lang.reflect.Field; import jakarta.enterprise.inject.Any; +import jakarta.enterprise.inject.Default; import jakarta.enterprise.inject.Instance; import jakarta.enterprise.inject.Produces; -import jakarta.enterprise.inject.spi.Annotated; import jakarta.enterprise.inject.spi.AnnotatedParameter; import jakarta.enterprise.inject.spi.InjectionPoint; import jakarta.inject.Singleton; @@ -31,7 +31,7 @@ public class MailTemplateProducer { Instance