From a5acdc95fd5e1415c224003abe2008aea5a652b8 Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Thu, 27 May 2021 10:13:11 +0200 Subject: [PATCH] Scheduler - use an application class predicate when generating invokers - until now all invokers were considered application classes, i.e. they were always loaded by the Runtime Class Loader in the dev mode and so a package-private scheduled method defined in a dependency resulted in an IllegalAccessError - resolves #17492 --- .../deployment/SchedulerProcessor.java | 30 ++++++++++++++++--- .../java/io/quarkus/scheduler/Scheduled.java | 2 ++ 2 files changed, 28 insertions(+), 4 deletions(-) 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 5f85c176a1ab1..ad34c15f83748 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 @@ -3,6 +3,7 @@ import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT; import static io.quarkus.deployment.annotations.ExecutionTime.STATIC_INIT; +import java.lang.reflect.Modifier; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; @@ -10,6 +11,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Function; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationValue; @@ -88,6 +90,7 @@ public class SchedulerProcessor { Kind.CLASS); static final String INVOKER_SUFFIX = "_ScheduledInvoker"; + static final String NESTED_SEPARATOR = "$_"; @BuildStep void beans(Capabilities capabilities, BuildProducer additionalBeans) { @@ -159,6 +162,12 @@ void validateScheduledBusinessMethods(SchedulerConfig config, List params = method.parameters(); if (params.size() > 1 @@ -198,11 +207,24 @@ public List unremovableBeans() { @Record(RUNTIME_INIT) public FeatureBuildItem build(SchedulerConfig config, BuildProducer syntheticBeans, SchedulerRecorder recorder, List scheduledMethods, - BuildProducer generatedClass, BuildProducer reflectiveClass, + BuildProducer generatedClasses, BuildProducer reflectiveClass, AnnotationProxyBuildItem annotationProxy, ExecutorBuildItem executor) { List scheduledMetadata = new ArrayList<>(); - ClassOutput classOutput = new GeneratedClassGizmoAdaptor(generatedClass, true); + ClassOutput classOutput = new GeneratedClassGizmoAdaptor(generatedClasses, new Function() { + @Override + public String apply(String name) { + // org/acme/Foo_ScheduledInvoker_run_0000 -> org.acme.Foo + int idx = name.indexOf(INVOKER_SUFFIX); + if (idx != -1) { + name = name.substring(0, idx); + } + if (name.contains(NESTED_SEPARATOR)) { + name = name.replace(NESTED_SEPARATOR, "$"); + } + return name; + } + }); for (ScheduledBusinessMethodItem scheduledMethod : scheduledMethods) { ScheduledMethodMetadata metadata = new ScheduledMethodMetadata(); @@ -247,8 +269,8 @@ private String generateInvoker(ScheduledBusinessMethodItem scheduledMethod, Clas String baseName; if (bean.getImplClazz().enclosingClass() != null) { - baseName = DotNames.simpleName(bean.getImplClazz().enclosingClass()) + "_" - + DotNames.simpleName(bean.getImplClazz().name()); + baseName = DotNames.simpleName(bean.getImplClazz().enclosingClass()) + NESTED_SEPARATOR + + DotNames.simpleName(bean.getImplClazz()); } else { baseName = DotNames.simpleName(bean.getImplClazz().name()); } diff --git a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/Scheduled.java b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/Scheduled.java index 1bfff45c53732..e3d6873b99c1f 100644 --- a/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/Scheduled.java +++ b/extensions/scheduler/runtime/src/main/java/io/quarkus/scheduler/Scheduled.java @@ -15,6 +15,8 @@ /** * Marks a business method to be automatically scheduled and invoked by the container. *

+ * The target business method must be non-private and non-static. + *

* The schedule is defined either by {@link #cron()} or by {@link #every()} attribute. If both are specified, the cron * expression takes precedence. *