You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by nf...@apache.org on 2023/04/03 06:06:34 UTC

[camel-quarkus] branch main updated: Ref #4716: java-joor-dsl - Add RegisterForReflection support (#4726)

This is an automated email from the ASF dual-hosted git repository.

nfilotto pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git


The following commit(s) were added to refs/heads/main by this push:
     new bdaf2fabcc Ref #4716: java-joor-dsl - Add RegisterForReflection support (#4726)
bdaf2fabcc is described below

commit bdaf2fabccb3ccda39fcbc4397b59280e520a2ea
Author: Nicolas Filotto <es...@users.noreply.github.com>
AuthorDate: Mon Apr 3 08:06:28 2023 +0200

    Ref #4716: java-joor-dsl - Add RegisterForReflection support (#4726)
    
    ## Motivation
    
    All the annotations added to a class managed by the extension `java-joor-dsl` are not considered by Quarkus since it is not part of the Jandex index.
    
    This change aims to support the annotation `RegisterForReflection` to easily configure the reflection in Camel-K.
    
    ## Modifications:
    
    * Produce the corresponding `ReflectiveClassBuildItem` and  `LambdaCapturingTypeBuildItem` if a `RouteBuilder` is annotated with `RegisterForReflection`.
    * Add some doc to explain the limitations
    * Add a unit test to ensure that it works as expected
---
 .../pages/reference/extensions/java-joor-dsl.adoc  |  8 +++
 .../java/joor/deployment/JavaJoorDslProcessor.java | 63 +++++++++++++++++++++-
 .../runtime/src/main/doc/limitations.adoc          |  3 ++
 .../quarkus/dsl/java/joor/JavaJoorDslBean.java}    | 20 ++++---
 .../quarkus/dsl/java/joor/JavaJoorDslResource.java | 10 +++-
 .../src/main/resources/routes/MyRoutes.java        | 14 ++++-
 .../quarkus/dsl/java/joor/JavaJoorDslTest.java     | 12 ++++-
 7 files changed, 119 insertions(+), 11 deletions(-)

diff --git a/docs/modules/ROOT/pages/reference/extensions/java-joor-dsl.adoc b/docs/modules/ROOT/pages/reference/extensions/java-joor-dsl.adoc
index 2461a370a6..edbf914728 100644
--- a/docs/modules/ROOT/pages/reference/extensions/java-joor-dsl.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/java-joor-dsl.adoc
@@ -43,3 +43,11 @@ Or add the coordinates to your existing project:
 ifeval::[{doc-show-user-guide-link} == true]
 Check the xref:user-guide/index.adoc[User guide] for more information about writing Camel Quarkus applications.
 endif::[]
+
+[id="extensions-java-joor-dsl-camel-quarkus-limitations"]
+== Camel Quarkus limitations
+
+The annotations added to the classes to be compiled by the component are ignored by Quarkus. The only annotation that is
+partially supported by the extension is the annotation `RegisterForReflection` to ease the configuration of the reflection
+for the native mode however please note that the element `registerFullHierarchy` is not supported.
+
diff --git a/extensions/java-joor-dsl/deployment/src/main/java/org/apache/camel/quarkus/dsl/java/joor/deployment/JavaJoorDslProcessor.java b/extensions/java-joor-dsl/deployment/src/main/java/org/apache/camel/quarkus/dsl/java/joor/deployment/JavaJoorDslProcessor.java
index e556b46b99..fa42fe2a3c 100644
--- a/extensions/java-joor-dsl/deployment/src/main/java/org/apache/camel/quarkus/dsl/java/joor/deployment/JavaJoorDslProcessor.java
+++ b/extensions/java-joor-dsl/deployment/src/main/java/org/apache/camel/quarkus/dsl/java/joor/deployment/JavaJoorDslProcessor.java
@@ -31,12 +31,14 @@ import io.quarkus.deployment.annotations.ExecutionTime;
 import io.quarkus.deployment.annotations.Record;
 import io.quarkus.deployment.builditem.FeatureBuildItem;
 import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.LambdaCapturingTypeBuildItem;
 import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
 import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem;
 import io.quarkus.deployment.pkg.steps.NativeBuild;
 import io.quarkus.maven.dependency.ResolvedDependency;
 import io.quarkus.paths.PathCollection;
 import io.quarkus.runtime.RuntimeValue;
+import io.quarkus.runtime.annotations.RegisterForReflection;
 import org.apache.camel.CamelContext;
 import org.apache.camel.dsl.java.joor.CompilationUnit;
 import org.apache.camel.dsl.java.joor.Helper;
@@ -61,6 +63,8 @@ public class JavaJoorDslProcessor {
 
     @BuildStep(onlyIf = NativeBuild.class)
     void compileClassesAOT(BuildProducer<JavaJoorGeneratedClassBuildItem> generatedClass,
+            BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
+            BuildProducer<LambdaCapturingTypeBuildItem> lambdaCapturingTypeProducer,
             CurateOutcomeBuildItem curateOutcomeBuildItem) throws Exception {
         Map<String, Resource> nameToResource = new HashMap<>();
         LOG.debug("Loading .java resources");
@@ -96,6 +100,62 @@ public class JavaJoorDslProcessor {
             generatedClass
                     .produce(new JavaJoorGeneratedClassBuildItem(className, nameToResource.get(className).getLocation(),
                             result.getByteCode(className)));
+            registerForReflection(reflectiveClass, lambdaCapturingTypeProducer,
+                    result.getClass(className).getAnnotation(RegisterForReflection.class));
+        }
+    }
+
+    private void registerForReflection(BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
+            BuildProducer<LambdaCapturingTypeBuildItem> lambdaCapturingTypeProducer,
+            RegisterForReflection annotation) {
+        if (annotation == null) {
+            return;
+        }
+
+        for (String lambdaCapturingType : annotation.lambdaCapturingTypes()) {
+            lambdaCapturingTypeProducer.produce(new LambdaCapturingTypeBuildItem(lambdaCapturingType));
+        }
+        boolean methods = annotation.methods();
+        boolean fields = annotation.fields();
+        boolean ignoreNested = annotation.ignoreNested();
+        boolean serialization = annotation.serialization();
+        boolean unsafeAllocated = annotation.unsafeAllocated();
+
+        if (annotation.registerFullHierarchy()) {
+            LOG.warn(
+                    "The element 'registerFullHierarchy' of the annotation 'RegisterForReflection' is not supported by the extension Camel Java jOOR DSL");
+        }
+        for (Class<?> type : annotation.targets()) {
+            registerClass(type.getName(), methods, fields, ignoreNested, serialization,
+                    unsafeAllocated, reflectiveClass);
+        }
+
+        for (String className : annotation.classNames()) {
+            registerClass(className, methods, fields, ignoreNested, serialization, unsafeAllocated,
+                    reflectiveClass);
+        }
+    }
+
+    private void registerClass(String className, boolean methods, boolean fields, boolean ignoreNested, boolean serialization,
+            boolean unsafeAllocated, BuildProducer<ReflectiveClassBuildItem> reflectiveClass) {
+        reflectiveClass.produce(serialization
+                ? ReflectiveClassBuildItem.builder(className).serialization().unsafeAllocated(unsafeAllocated).build()
+                : ReflectiveClassBuildItem.builder(className).constructors().methods(methods).fields(fields)
+                        .unsafeAllocated(unsafeAllocated).build());
+
+        if (ignoreNested) {
+            return;
+        }
+
+        try {
+            Class<?>[] declaredClasses = Thread.currentThread().getContextClassLoader().loadClass(className)
+                    .getDeclaredClasses();
+            for (Class<?> clazz : declaredClasses) {
+                registerClass(clazz.getName(), methods, fields, false, serialization, unsafeAllocated,
+                        reflectiveClass);
+            }
+        } catch (ClassNotFoundException e) {
+            LOG.warn("Failed to load Class {}", className, e);
         }
     }
 
@@ -106,8 +166,9 @@ public class JavaJoorDslProcessor {
 
         for (JavaJoorGeneratedClassBuildItem clazz : classes) {
             generatedClass.produce(new GeneratedClassBuildItem(true, clazz.getName(), clazz.getClassData()));
-            reflectiveClass.produce(ReflectiveClassBuildItem.builder(clazz.getName()).build());
         }
+        reflectiveClass.produce(ReflectiveClassBuildItem
+                .builder(classes.stream().map(JavaJoorGeneratedClassBuildItem::getName).toArray(String[]::new)).build());
     }
 
     @BuildStep(onlyIf = NativeBuild.class)
diff --git a/extensions/java-joor-dsl/runtime/src/main/doc/limitations.adoc b/extensions/java-joor-dsl/runtime/src/main/doc/limitations.adoc
new file mode 100644
index 0000000000..a818c7f8a9
--- /dev/null
+++ b/extensions/java-joor-dsl/runtime/src/main/doc/limitations.adoc
@@ -0,0 +1,3 @@
+The annotations added to the classes to be compiled by the component are ignored by Quarkus. The only annotation that is
+partially supported by the extension is the annotation `RegisterForReflection` to ease the configuration of the reflection
+for the native mode however please note that the element `registerFullHierarchy` is not supported.
\ No newline at end of file
diff --git a/integration-tests/java-joor-dsl/src/main/resources/routes/MyRoutes.java b/integration-tests/java-joor-dsl/src/main/java/org/apache/camel/quarkus/dsl/java/joor/JavaJoorDslBean.java
similarity index 70%
copy from integration-tests/java-joor-dsl/src/main/resources/routes/MyRoutes.java
copy to integration-tests/java-joor-dsl/src/main/java/org/apache/camel/quarkus/dsl/java/joor/JavaJoorDslBean.java
index 590dfe1d97..cea1834ff0 100644
--- a/integration-tests/java-joor-dsl/src/main/resources/routes/MyRoutes.java
+++ b/integration-tests/java-joor-dsl/src/main/java/org/apache/camel/quarkus/dsl/java/joor/JavaJoorDslBean.java
@@ -14,11 +14,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-public class MyRoutes extends org.apache.camel.builder.RouteBuilder {
-    @Override
-    public void configure() throws Exception {
-        from("direct:joorHello")
-            .id("my-java-route")
-            .setBody(exchange -> "Hello " + exchange.getMessage().getBody()  + " from jOOR!");
+package org.apache.camel.quarkus.dsl.java.joor;
+
+public class JavaJoorDslBean {
+
+    public static String hi(String name) {
+        return String.format("Hi %s", name);
     }
-}
\ No newline at end of file
+
+    public static class Inner {
+        public static String addSource(String value) {
+            return String.format("%s from jOOR!", value);
+        }
+    }
+}
diff --git a/integration-tests/java-joor-dsl/src/main/java/org/apache/camel/quarkus/dsl/java/joor/JavaJoorDslResource.java b/integration-tests/java-joor-dsl/src/main/java/org/apache/camel/quarkus/dsl/java/joor/JavaJoorDslResource.java
index f1b3c1e596..797bd27b6f 100644
--- a/integration-tests/java-joor-dsl/src/main/java/org/apache/camel/quarkus/dsl/java/joor/JavaJoorDslResource.java
+++ b/integration-tests/java-joor-dsl/src/main/java/org/apache/camel/quarkus/dsl/java/joor/JavaJoorDslResource.java
@@ -75,8 +75,16 @@ public class JavaJoorDslResource {
     @Path("/hello")
     @Consumes(MediaType.TEXT_PLAIN)
     @Produces(MediaType.TEXT_PLAIN)
-    public String hello(String message) throws Exception {
+    public String hello(String message) {
         return producerTemplate.requestBody("direct:joorHello", message, String.class);
     }
 
+    @POST
+    @Path("/hi")
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.TEXT_PLAIN)
+    public String hi(String name) {
+        return producerTemplate.requestBody("direct:joorHi", name, String.class);
+    }
+
 }
diff --git a/integration-tests/java-joor-dsl/src/main/resources/routes/MyRoutes.java b/integration-tests/java-joor-dsl/src/main/resources/routes/MyRoutes.java
index 590dfe1d97..fdcfa82266 100644
--- a/integration-tests/java-joor-dsl/src/main/resources/routes/MyRoutes.java
+++ b/integration-tests/java-joor-dsl/src/main/resources/routes/MyRoutes.java
@@ -14,11 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-public class MyRoutes extends org.apache.camel.builder.RouteBuilder {
+import io.quarkus.runtime.annotations.RegisterForReflection;
+import org.apache.camel.builder.RouteBuilder;
+
+@RegisterForReflection(classNames = "org.apache.camel.quarkus.dsl.java.joor.JavaJoorDslBean", ignoreNested = false)
+public class MyRoutes extends RouteBuilder {
     @Override
     public void configure() throws Exception {
         from("direct:joorHello")
             .id("my-java-route")
             .setBody(exchange -> "Hello " + exchange.getMessage().getBody()  + " from jOOR!");
+        from("direct:joorHi")
+            .id("reflection-route")
+            .process(exchange -> {
+                Class<?> c = Thread.currentThread().getContextClassLoader().loadClass("org.apache.camel.quarkus.dsl.java.joor.JavaJoorDslBean");
+                Object hi = c.getMethod("hi", String.class).invoke(null, exchange.getMessage().getBody());
+                Class<?> c2 = Thread.currentThread().getContextClassLoader().loadClass("org.apache.camel.quarkus.dsl.java.joor.JavaJoorDslBean$Inner");
+                exchange.getMessage().setBody(c2.getMethod("addSource", String.class).invoke(null, hi));
+            });
     }
 }
\ No newline at end of file
diff --git a/integration-tests/java-joor-dsl/src/test/java/org/apache/camel/quarkus/dsl/java/joor/JavaJoorDslTest.java b/integration-tests/java-joor-dsl/src/test/java/org/apache/camel/quarkus/dsl/java/joor/JavaJoorDslTest.java
index 3fbf057b98..56862ea213 100644
--- a/integration-tests/java-joor-dsl/src/test/java/org/apache/camel/quarkus/dsl/java/joor/JavaJoorDslTest.java
+++ b/integration-tests/java-joor-dsl/src/test/java/org/apache/camel/quarkus/dsl/java/joor/JavaJoorDslTest.java
@@ -35,6 +35,16 @@ class JavaJoorDslTest {
                 .body(CoreMatchers.is("Hello Camelus bactrianus from jOOR!"));
     }
 
+    @Test
+    void joorHi() {
+        RestAssured.given()
+                .body("Will Smith")
+                .post("/java-joor-dsl/hi")
+                .then()
+                .statusCode(200)
+                .body(CoreMatchers.is("Hi Will Smith from jOOR!"));
+    }
+
     @Test
     void testMainInstanceWithJavaRoutes() {
         RestAssured.given()
@@ -53,6 +63,6 @@ class JavaJoorDslTest {
                 .get("/java-joor-dsl/main/routes")
                 .then()
                 .statusCode(200)
-                .body(CoreMatchers.is("my-java-route"));
+                .body(CoreMatchers.is("my-java-route,reflection-route"));
     }
 }