diff --git a/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/SmallRyeFaultToleranceProcessor.java b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/SmallRyeFaultToleranceProcessor.java index f6c4778e6f508f..d38ad7e100c021 100644 --- a/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/SmallRyeFaultToleranceProcessor.java +++ b/extensions/smallrye-fault-tolerance/deployment/src/main/java/io/quarkus/smallrye/faulttolerance/deployment/SmallRyeFaultToleranceProcessor.java @@ -88,7 +88,6 @@ public void build(BuildProducer annotationsTran BuildProducer systemProperty, CombinedIndexBuildItem combinedIndexBuildItem, BuildProducer reflectiveClass, - BuildProducer reflectiveMethod, BuildProducer config, BuildProducer runtimeInitializedClassBuildItems) { @@ -120,43 +119,6 @@ public void build(BuildProducer annotationsTran } beans.produce(handlerBeans.build()); } - // Add reflective access to fallback methods - for (AnnotationInstance annotation : index.getAnnotations(DotNames.FALLBACK)) { - AnnotationValue fallbackMethodValue = annotation.value("fallbackMethod"); - if (fallbackMethodValue == null) { - continue; - } - String fallbackMethod = fallbackMethodValue.asString(); - - Queue classesToScan = new ArrayDeque<>(); // work queue - - // @Fallback can only be present on methods, so this is just future-proofing - AnnotationTarget target = annotation.target(); - if (target.kind() == Kind.METHOD) { - classesToScan.add(target.asMethod().declaringClass().name()); - } - - while (!classesToScan.isEmpty()) { - DotName name = classesToScan.poll(); - ClassInfo clazz = index.getClassByName(name); - if (clazz == null) { - continue; - } - - // we could further restrict the set of registered methods based on matching parameter types, - // but that's relatively complex and SmallRye Fault Tolerance has to do it anyway - clazz.methods() - .stream() - .filter(it -> fallbackMethod.equals(it.name())) - .forEach(it -> reflectiveMethod.produce(new ReflectiveMethodBuildItem(it))); - - DotName superClass = clazz.superName(); - if (superClass != null && !DotNames.OBJECT.equals(superClass)) { - classesToScan.add(superClass); - } - classesToScan.addAll(clazz.interfaceNames()); - } - } // Add reflective access to custom backoff strategies for (ClassInfo strategy : index.getAllKnownImplementors(DotNames.CUSTOM_BACKOFF_STRATEGY)) { reflectiveClass.produce(ReflectiveClassBuildItem.builder(strategy.name().toString()).methods().build()); @@ -270,6 +232,7 @@ void processFaultToleranceAnnotations(SmallRyeFaultToleranceRecorder recorder, AnnotationProxyBuildItem annotationProxy, BuildProducer generatedClasses, BuildProducer reflectiveClass, + BuildProducer reflectiveMethod, BuildProducer errors, BuildProducer faultToleranceInfo) { @@ -287,6 +250,49 @@ void processFaultToleranceAnnotations(SmallRyeFaultToleranceRecorder recorder, AnnotationStore annotationStore = validationPhase.getContext().get(BuildExtension.Key.ANNOTATION_STORE); IndexView index = beanArchiveIndexBuildItem.getIndex(); + + // Add reflective access to fallback methods + for (AnnotationInstance annotation : index.getAnnotations(DotNames.FALLBACK)) { + AnnotationValue fallbackMethodValue = annotation.value("fallbackMethod"); + if (fallbackMethodValue == null) { + continue; + } + String fallbackMethod = fallbackMethodValue.asString(); + + System.out.println("Looking for fallback method: " + fallbackMethod); + + Queue classesToScan = new ArrayDeque<>(); // work queue + + // @Fallback can only be present on methods, so this is just future-proofing + AnnotationTarget target = annotation.target(); + if (target.kind() == Kind.METHOD) { + classesToScan.add(target.asMethod().declaringClass().name()); + } + + while (!classesToScan.isEmpty()) { + DotName name = classesToScan.poll(); + ClassInfo clazz = index.getClassByName(name); + if (clazz == null) { + continue; + } + + System.out.println("Looking into class: " + clazz); + + // we could further restrict the set of registered methods based on matching parameter types, + // but that's relatively complex and SmallRye Fault Tolerance has to do it anyway + clazz.methods() + .stream() + .filter(it -> fallbackMethod.equals(it.name())) + .forEach(it -> reflectiveMethod.produce(new ReflectiveMethodBuildItem(it))); + + DotName superClass = clazz.superName(); + if (superClass != null && !DotNames.OBJECT.equals(superClass)) { + classesToScan.add(superClass); + } + classesToScan.addAll(clazz.interfaceNames()); + } + } + // only generating annotation literal classes for MicroProfile/SmallRye Fault Tolerance annotations, // none of them are application classes ClassOutput classOutput = new GeneratedClassGizmoAdaptor(generatedClasses, false); @@ -313,6 +319,9 @@ void processFaultToleranceAnnotations(SmallRyeFaultToleranceRecorder recorder, } } + // io.smallrye.faulttolerance.internal.SecurityActions.findDeclaredMethodNames accesses class' methods + reflectiveClass.produce(ReflectiveClassBuildItem.builder(beanClass.name().toString()).queryMethods().build()); + scanner.forEachMethod(beanClass, method -> { FaultToleranceMethod ftMethod = scanner.createFaultToleranceMethod(beanClass, method); if (ftMethod.isLegitimate()) { diff --git a/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/VertxProcessor.java b/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/VertxProcessor.java index 1c3d7fb2e99159..438add51a2f58d 100644 --- a/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/VertxProcessor.java +++ b/extensions/vertx/deployment/src/main/java/io/quarkus/vertx/deployment/VertxProcessor.java @@ -54,7 +54,9 @@ import io.quarkus.deployment.builditem.ServiceStartBuildItem; import io.quarkus.deployment.builditem.ShutdownContextBuildItem; import io.quarkus.deployment.builditem.nativeimage.NativeImageConfigBuildItem; +import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; +import io.quarkus.deployment.builditem.nativeimage.ReflectiveMethodBuildItem; import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem; import io.quarkus.deployment.recording.RecorderContext; import io.quarkus.gizmo.ClassOutput; @@ -274,4 +276,20 @@ private Class tryLoad(String name, ClassLoader tccl) { throw new IllegalStateException("Unable to load type: " + name, e); } } + + @BuildStep + void registerNativeImageResources(BuildProducer resources) { + // Accessed by io.vertx.core.impl.VertxBuilder. + resources.produce(new NativeImageResourceBuildItem("META-INF/services/io.vertx.core.spi.VertxServiceProvider")); + // Accessed by io.vertx.core.impl.VertxImpl. + resources.produce(new NativeImageResourceBuildItem("META-INF/services/io.vertx.core.spi.VerticleFactory")); + } + + @BuildStep + void registerReflectivelyAccessedMethods(BuildProducer reflectiveMethods) { + // Accessed by io.vertx.core.impl.VertxImpl. + reflectiveMethods.produce(new ReflectiveMethodBuildItem("java.lang.Thread$Builder$OfVirtual", "name", + String.class, long.class)); + reflectiveMethods.produce(new ReflectiveMethodBuildItem("java.lang.Thread$Builder", "factory", new Class[0])); + } }