You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2022/04/27 09:10:02 UTC

[camel] 01/02: CAMEL-18014: camel-java-dsl - Allow to capture compiled byte code

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

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

commit e2b6a8fba07528be45025aad5bf698d4a62e6951
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Apr 27 06:20:58 2022 +0200

    CAMEL-18014: camel-java-dsl - Allow to capture compiled byte code
---
 .../camel/dsl/java/joor/CompilationUnit.java       |  8 +++-
 .../dsl/java/joor/JavaRoutesBuilderLoader.java     | 28 +++++++------
 .../apache/camel/dsl/java/joor/MultiCompile.java   |  4 ++
 .../camel/main/AnnotationDependencyInjection.java  | 11 ++++-
 .../apache/camel/main/JavaJoorPostCompiler.java    | 48 ++++++++++++++++++++++
 .../java/org/apache/camel/main/KameletMain.java    |  2 +
 6 files changed, 86 insertions(+), 15 deletions(-)

diff --git a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/CompilationUnit.java b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/CompilationUnit.java
index e6b489ad029..a9c8ccf9b1a 100644
--- a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/CompilationUnit.java
+++ b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/CompilationUnit.java
@@ -36,8 +36,12 @@ public class CompilationUnit {
         private final Map<String, byte[]> compiled = new LinkedHashMap<>();
 
         void addResult(String className, Class<?> clazz, byte[] byteCode) {
-            classes.put(className, clazz);
-            compiled.put(className, byteCode);
+            if (clazz != null && !classes.containsKey(className)) {
+                classes.put(className, clazz);
+            }
+            if (byteCode != null && !compiled.containsKey(className)) {
+                compiled.put(className, byteCode);
+            }
         }
 
         /**
diff --git a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
index 9e87733f52a..b679be54486 100644
--- a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
+++ b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
@@ -85,20 +85,24 @@ public class JavaRoutesBuilderLoader extends ExtendedRouteBuilderLoaderSupport {
         }
 
         for (String className : result.getClassNames()) {
+            Object obj = null;
+
             Class<?> clazz = result.getClass(className);
-            Object obj;
-            try {
-                // requires a default no-arg constructor otherwise we skip the class
-                obj = getCamelContext().getInjector().newInstance(clazz);
-            } catch (Exception e) {
-                LOG.debug("Compiled class: " + className + " must have a default no-arg constructor. Skipping.");
-                continue;
-            }
-            LOG.debug("Compiled: {} -> {}", className, obj);
+            if (clazz != null) {
+                try {
+                    // requires a default no-arg constructor otherwise we skip the class
+                    obj = getCamelContext().getInjector().newInstance(clazz);
+                } catch (Exception e) {
+                    LOG.debug("Compiled class: " + className + " must have a default no-arg constructor. Skipping.");
+                }
+                if (obj != null) {
+                    LOG.debug("Compiled: {} -> {}", className, obj);
 
-            // inject context and resource
-            CamelContextAware.trySetCamelContext(obj, getCamelContext());
-            ResourceAware.trySetResource(obj, nameToResource.get(className));
+                    // inject context and resource
+                    CamelContextAware.trySetCamelContext(obj, getCamelContext());
+                    ResourceAware.trySetResource(obj, nameToResource.get(className));
+                }
+            }
 
             // support custom annotation scanning post compilation
             // such as to register custom beans, type converters, etc.
diff --git a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/MultiCompile.java b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/MultiCompile.java
index b2443958a7f..a9d1ccbeca9 100644
--- a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/MultiCompile.java
+++ b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/MultiCompile.java
@@ -160,6 +160,8 @@ public final class MultiCompile {
                     if (clazz != null) {
                         result.addResult(className, clazz, byteCodes.get(className));
                     }
+                    // we may have compiled additional classes that the className is using, so add these as result as well
+                    byteCodes.forEach((cn, bc) -> result.addResult(cn, null, bc));
                 } else {
                     // Otherwise, use an arbitrary class loader. This approach doesn't allow for
                     // loading private-access interfaces in the compiled class's type hierarchy
@@ -176,6 +178,8 @@ public final class MultiCompile {
                     if (clazz != null) {
                         result.addResult(className, clazz, byteCodes.get(className));
                     }
+                    // we may have compiled additional classes that the className is using, so add these as result as well
+                    byteCodes.forEach((cn, bc) -> result.addResult(cn, null, bc));
                 }
             }
 
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/AnnotationDependencyInjection.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/AnnotationDependencyInjection.java
index 5c3d4a40199..a181c2cf5e1 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/AnnotationDependencyInjection.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/AnnotationDependencyInjection.java
@@ -100,6 +100,10 @@ public final class AnnotationDependencyInjection {
 
         @Override
         public void postCompile(CamelContext camelContext, String name, Class<?> clazz, byte[] byteCode, Object instance) throws Exception {
+            if (instance == null) {
+                return;
+            }
+
             BindToRegistry bir = instance.getClass().getAnnotation(BindToRegistry.class);
             Configuration cfg = instance.getClass().getAnnotation(Configuration.class);
             if (bir != null || cfg != null || instance instanceof CamelConfiguration) {
@@ -131,11 +135,13 @@ public final class AnnotationDependencyInjection {
 
         @Override
         public void postCompile(CamelContext camelContext, String name, Class<?> clazz, byte[] byteCode, Object instance) throws Exception {
+            if (instance == null) {
+                return;
+            }
             // @Component and @Service are the same
             Component comp = clazz.getAnnotation(Component.class);
             Service service = clazz.getAnnotation(Service.class);
             if (comp != null || service != null) {
-                CamelBeanPostProcessor bpp = camelContext.adapt(ExtendedCamelContext.class).getBeanPostProcessor();
                 if (comp != null && ObjectHelper.isNotEmpty(comp.value())) {
                     name = comp.value();
                 } else if (service != null && ObjectHelper.isNotEmpty(service.value())) {
@@ -203,6 +209,9 @@ public final class AnnotationDependencyInjection {
 
         @Override
         public void postCompile(CamelContext camelContext, String name, Class<?> clazz, byte[] byteCode, Object instance) throws Exception {
+            if (instance == null) {
+                return;
+            }
             // @ApplicationScoped and @Singleton are considered the same
             ApplicationScoped as = clazz.getAnnotation(ApplicationScoped.class);
             Singleton ss = clazz.getAnnotation(Singleton.class);
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/JavaJoorPostCompiler.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/JavaJoorPostCompiler.java
new file mode 100644
index 00000000000..606336cbe03
--- /dev/null
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/JavaJoorPostCompiler.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.main;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.dsl.support.CompilePostProcessor;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.util.IOHelper;
+
+import java.io.FileOutputStream;
+
+public class JavaJoorPostCompiler {
+
+    // TODO: add option to turn this on|off, and configure disk location
+
+    public static void initJavaJoorPostCompiler(CamelContext context) {
+        Registry registry = context.getRegistry();
+
+        registry.bind("JavaJoorPostCompiler", new ByteCodeCompilePostProcessor());
+    }
+
+    private static class ByteCodeCompilePostProcessor implements CompilePostProcessor {
+
+        @Override
+        public void postCompile(CamelContext camelContext, String name, Class<?> clazz, byte[] byteCode, Object instance) throws Exception {
+            if (byteCode != null) {
+                FileOutputStream fos = new FileOutputStream("." + name + ".class", false);
+                fos.write(byteCode);
+                IOHelper.close(fos);
+            }
+        }
+    }
+
+}
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
index be6e9247e6b..902663286ff 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
@@ -198,6 +198,8 @@ public class KameletMain extends MainCommandLineSupport {
         answer.setLoadHealthChecks(true);
         // annotation based dependency injection for camel/spring/quarkus annotations in DSLs and Java beans
         AnnotationDependencyInjection.initAnnotationBasedDependencyInjection(answer);
+        // java-dsl post compiler to save compilation to disk
+        JavaJoorPostCompiler.initJavaJoorPostCompiler(answer);
 
         // embed HTTP server if port is specified
         Object port = getInitialProperties().get("camel.jbang.platform-http.port");