From 815821053bdafe0c0a27154c60e5ed2f0aa8f38a Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Thu, 10 Mar 2022 20:07:58 +0100 Subject: [PATCH] Scheduler - scheduled methods are not inherited - this is a breaking change - however, the current behavior is undocumented and inconsistent; e.g. if Scheduled#identity() is used then the build always fails - also the scope annotation is not added automatically to a subclass of a class that declares a Scheduled annotation, i.e. the class would be ignored and would result in runtime error - resolves #24212 --- .../main/asciidoc/scheduler-reference.adoc | 20 +++++++- .../deployment/SchedulerProcessor.java | 8 ---- .../ScheduledMethodNotInheritedTest.java | 47 +++++++++++++++++++ 3 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 extensions/scheduler/deployment/src/test/java/io/quarkus/scheduler/test/inheritance/ScheduledMethodNotInheritedTest.java diff --git a/docs/src/main/asciidoc/scheduler-reference.adoc b/docs/src/main/asciidoc/scheduler-reference.adoc index b34b4a0d41cc1..cb2ada2809576 100644 --- a/docs/src/main/asciidoc/scheduler-reference.adoc +++ b/docs/src/main/asciidoc/scheduler-reference.adoc @@ -33,8 +33,26 @@ Furthermore, the annotated method must return `void` and either declare no param TIP: The annotation is repeatable so a single method could be scheduled multiple times. -TIP: A CDI event of type `io.quarkus.scheduler.SuccessfulExecution` is fired synchronously and asynchronously when an execution of a scheduled method is successful. A CDI event of type `io.quarkus.scheduler.FailedExecution` is fired synchronously and asynchronously when an execution of a scheduled method throws an exception. +[WARNING] +==== +Subclasses never inherit the metadata of a `@Scheduled` method declared on a superclass. In the following example, the `everySecond()` method is only invoked upon the instance of `Jobs`. +[source,java] +---- +class Jobs { + + @Scheduled(every = "1s") + void everySecond() { + // ..do something + } +} + +@Singleton +class MyJobs extends Jobs { +} +---- +==== +A CDI event of type `io.quarkus.scheduler.SuccessfulExecution` is fired synchronously and asynchronously when an execution of a scheduled method is successful. A CDI event of type `io.quarkus.scheduler.FailedExecution` is fired synchronously and asynchronously when an execution of a scheduled method throws an exception. === Triggers diff --git a/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/SchedulerProcessor.java b/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/SchedulerProcessor.java index 72fbda6debee0..8cbbe7aa318a3 100644 --- a/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/SchedulerProcessor.java +++ b/extensions/scheduler/deployment/src/main/java/io/quarkus/scheduler/deployment/SchedulerProcessor.java @@ -178,14 +178,6 @@ private void collectScheduledMethods(IndexView index, TransformedAnnotationsBuil LOGGER.debugf("Found scheduled business method %s declared on %s", method, bean); } } - - DotName superClassName = beanClass.superName(); - if (superClassName != null) { - ClassInfo superClass = index.getClassByName(superClassName); - if (superClass != null) { - collectScheduledMethods(index, transformedAnnotations, bean, superClass, scheduledBusinessMethods); - } - } } @BuildStep diff --git a/extensions/scheduler/deployment/src/test/java/io/quarkus/scheduler/test/inheritance/ScheduledMethodNotInheritedTest.java b/extensions/scheduler/deployment/src/test/java/io/quarkus/scheduler/test/inheritance/ScheduledMethodNotInheritedTest.java new file mode 100644 index 0000000000000..5b33501cde53e --- /dev/null +++ b/extensions/scheduler/deployment/src/test/java/io/quarkus/scheduler/test/inheritance/ScheduledMethodNotInheritedTest.java @@ -0,0 +1,47 @@ +package io.quarkus.scheduler.test.inheritance; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.inject.Singleton; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.scheduler.Scheduled; +import io.quarkus.test.QuarkusUnitTest; + +public class ScheduledMethodNotInheritedTest { + + @RegisterExtension + static final QuarkusUnitTest test = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClasses(Jobs.class, MyJobs.class)); + + @Test + public void testExecution() throws InterruptedException { + assertTrue(Jobs.LATCH.await(5, TimeUnit.SECONDS)); + assertTrue(Jobs.JOB_CLASSES.stream().allMatch(s -> s.equals(Jobs.class.getName()))); + } + + @Singleton + static class MyJobs extends Jobs { + + } + + static class Jobs { + + static final CountDownLatch LATCH = new CountDownLatch(2); + static final List JOB_CLASSES = new CopyOnWriteArrayList<>(); + + @Scheduled(every = "1s", identity = "foo") + void everySecond() { + JOB_CLASSES.add(getClass().getName()); + LATCH.countDown(); + } + } +}