This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch camel-4.22.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-4.22.x by this push:
new 33bdd76dfbf5 [backport camel-4.22.x] CAMEL-25239: camel-kamelet-main -
an import of any class of a Camel component downloads the component (#27293)
33bdd76dfbf5 is described below
commit 33bdd76dfbf529f22893b611767e191260bf41fc
Author: Salvatore Mongiardo <[email protected]>
AuthorDate: Mon Oct 5 12:28:56 2026 +0200
[backport camel-4.22.x] CAMEL-25239: camel-kamelet-main - an import of any
class of a Camel component downloads the component (#27293)
Cherry-pick of a58aee231a38 (#27283) onto camel-4.22.x. An import in a Java
or Groovy source now resolves any class of a Camel component by its package,
not only the component class itself, so importing e.g. AWS2S3Constants
downloads camel-aws2-s3 before the route is compiled. Runtime class lookups
still need the component class, so probing does not download a component.
4.22.x-specific adjustments, as the third-party mapping work of CAMEL-24809
is not on this branch:
- KnownDependenciesResolver does not load
camel-thirdparty-known-dependencies.properties
- the jackson-annotations mapping is added to
camel-main-known-dependencies.properties
- only the component-import test and the 7-line doc paragraph are backported
- the test accepts ${...} version placeholders, which
KnownDependenciesVersionResolver
resolves when the dependency is downloaded
Co-Authored-By: Claus Ibsen <[email protected]>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Signed-off-by: Claus Ibsen <[email protected]>
---
.../modules/ROOT/pages/camel-jbang-running.adoc | 7 +++
.../main/download/JavaKnownImportsDownloader.java | 2 +-
.../main/download/KnownDependenciesResolver.java | 61 +++++++++++++++++++---
.../camel-main-known-dependencies.properties | 1 +
.../download/KnownDependenciesResolverTest.java | 44 ++++++++++++++++
5 files changed, 108 insertions(+), 7 deletions(-)
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-running.adoc
b/docs/user-manual/modules/ROOT/pages/camel-jbang-running.adoc
index 4d56d7565df9..d561f88dd6fb 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-running.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-running.adoc
@@ -224,6 +224,13 @@ To disable automatic downloading:
camel run foo.java --download=false
----
+For an `import` in a Java or Groovy source, a Camel component is also found by
its package, so
+importing any class of a component downloads it, not only the component class
itself. For
+example, a route that imports
`org.apache.camel.component.aws2.s3.AWS2S3Constants` for the
+headers of the `aws-s3-source` Kamelet gets `camel-aws2-s3` before the route
is compiled. A class
+that is only looked up while running still needs the component class itself,
so probing whether
+a class is present does not download a component.
+
== Running with Spring Boot or Quarkus
Camel CLI can run integrations using Spring Boot or Quarkus runtimes:
diff --git
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/JavaKnownImportsDownloader.java
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/JavaKnownImportsDownloader.java
index d2a949333f29..e0af6b1849c1 100644
---
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/JavaKnownImportsDownloader.java
+++
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/JavaKnownImportsDownloader.java
@@ -51,7 +51,7 @@ public class JavaKnownImportsDownloader implements
CompilePreProcessor {
List<String> imports = determineImports(code);
for (String imp : imports) {
// attempt known dependency resolver first
- MavenGav gav = knownDependenciesResolver.mavenGavForClass(imp);
+ MavenGav gav = knownDependenciesResolver.mavenGavForImport(imp);
if (gav != null) {
downloadLoader(gav.getGroupId(), gav.getArtifactId(),
gav.getVersion());
} else {
diff --git
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/KnownDependenciesResolver.java
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/KnownDependenciesResolver.java
index cae1d090987a..248579988aa7 100644
---
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/KnownDependenciesResolver.java
+++
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/KnownDependenciesResolver.java
@@ -20,8 +20,10 @@ import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
+import java.util.Set;
import org.apache.camel.CamelContext;
import org.apache.camel.tooling.maven.MavenGav;
@@ -29,6 +31,8 @@ import org.apache.camel.tooling.maven.MavenGav;
public final class KnownDependenciesResolver {
private final Map<String, String> mappings = new HashMap<>();
+ // the package of each component, only used for the imports of a source
(see mavenGavForImport)
+ private final Map<String, String> componentPackages = new HashMap<>();
private final CamelContext camelContext;
private final String springBootVersion;
private final String quarkusVersion;
@@ -40,15 +44,15 @@ public final class KnownDependenciesResolver {
}
public void loadKnownDependencies() {
- doLoadKnownDependencies("camel-main-known-dependencies.properties");
-
doLoadKnownDependencies("camel-component-known-dependencies.properties");
+ doLoadKnownDependencies("camel-main-known-dependencies.properties",
false);
+
doLoadKnownDependencies("camel-component-known-dependencies.properties", true);
}
public void loadKnownFactoryFinderDependencies() {
-
doLoadKnownDependencies("camel-factoryfinder-known-dependencies.properties");
+
doLoadKnownDependencies("camel-factoryfinder-known-dependencies.properties",
false);
}
- private void doLoadKnownDependencies(String name) {
+ private void doLoadKnownDependencies(String name, boolean byPackage) {
try {
Enumeration<URL> resources =
getClass().getClassLoader().getResources(name);
while (resources.hasMoreElements()) {
@@ -61,6 +65,9 @@ public final class KnownDependenciesResolver {
String value = prop.getProperty(key);
map.put(key, value);
}
+ if (byPackage) {
+ addPackageMappings(map, componentPackages);
+ }
addMappings(map);
}
}
@@ -69,13 +76,55 @@ public final class KnownDependenciesResolver {
}
}
+ /**
+ * The package of each class, unless the package is shared by classes of
different dependencies, or is a base
+ * package such as <tt>org.apache.camel</tt> that would match every Camel
class.
+ */
+ private static void addPackageMappings(Map<String, String> classes,
Map<String, String> packages) {
+ Set<String> shared = new HashSet<>();
+ for (Map.Entry<String, String> entry : classes.entrySet()) {
+ String key = entry.getKey();
+ int pos = key.lastIndexOf('.');
+ if (pos == -1) {
+ continue;
+ }
+ String pkg = key.substring(0, pos);
+ if (pkg.chars().filter(ch -> ch == '.').count() < 3) {
+ continue;
+ }
+ String existing = packages.putIfAbsent(pkg, entry.getValue());
+ if (existing != null && !existing.equals(entry.getValue())) {
+ shared.add(pkg);
+ }
+ }
+ shared.forEach(packages::remove);
+ }
+
public void addMappings(Map<String, String> mappings) {
this.mappings.putAll(mappings);
}
public MavenGav mavenGavForClass(String className) {
+ return toMavenGav(findGav(mappings, className));
+ }
+
+ /**
+ * The dependency of a class a source imports: as {@link
#mavenGavForClass(String)}, and also any class of a Camel
+ * component (such as the constants of its headers), not only the
component class itself.
+ * <p/>
+ * Only for imports: a class that is looked up at runtime is often only
probed for, which must not download a
+ * component.
+ */
+ public MavenGav mavenGavForImport(String className) {
+ String gav = findGav(mappings, className);
+ if (gav == null) {
+ gav = findGav(componentPackages, className);
+ }
+ return toMavenGav(gav);
+ }
+
+ private MavenGav toMavenGav(String gav) {
MavenGav answer = null;
- String gav = findGav(className);
if (gav != null) {
answer = MavenGav.parseGav(gav, camelContext.getVersion());
}
@@ -90,7 +139,7 @@ public final class KnownDependenciesResolver {
return answer;
}
- private String findGav(String prefix) {
+ private static String findGav(Map<String, String> mappings, String prefix)
{
String gav = mappings.get(prefix);
while (gav == null && prefix.lastIndexOf(".") != -1) {
prefix = prefix.substring(0, prefix.lastIndexOf("."));
diff --git
a/dsl/camel-kamelet-main/src/main/resources/camel-main-known-dependencies.properties
b/dsl/camel-kamelet-main/src/main/resources/camel-main-known-dependencies.properties
index 4f98022c4f35..9b1946ae1f53 100644
---
a/dsl/camel-kamelet-main/src/main/resources/camel-main-known-dependencies.properties
+++
b/dsl/camel-kamelet-main/src/main/resources/camel-main-known-dependencies.properties
@@ -73,3 +73,4 @@ org.apache.qpid.jms.JmsConnectionFactory =
org.apache.qpid:qpid-jms-client:${qpi
org.messaginghub.pooled.jms.JmsPoolConnectionFactory =
org.messaginghub:pooled-jms:${pooled-jms-version}
org.postgresql.Driver = org.postgresql:postgresql:${pgjdbc-driver-version}
org.postgresql.ds.PGSimpleDataSource =
org.postgresql:postgresql:${pgjdbc-driver-version}
+com.fasterxml.jackson.annotation =
com.fasterxml.jackson.core:jackson-annotations:${jackson2-annotations-version}
diff --git
a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/download/KnownDependenciesResolverTest.java
b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/download/KnownDependenciesResolverTest.java
index 3eba6ffc2f58..8b3594ca7e21 100644
---
a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/download/KnownDependenciesResolverTest.java
+++
b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/download/KnownDependenciesResolverTest.java
@@ -22,6 +22,7 @@ import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
public class KnownDependenciesResolverTest {
@@ -53,4 +54,47 @@ public class KnownDependenciesResolverTest {
public static class SomeClass {
}
+
+ @Test
+ void anImportResolvesAnyClassOfAComponent() {
+ // CAMEL-25239: any class of a component a source imports, not only
the component class itself, such as the
+ // constants of the headers of a component that a kamelet uses
+ KnownDependenciesResolver resolver = new KnownDependenciesResolver(new
SimpleCamelContext(), null, null);
+ resolver.loadKnownDependencies();
+
+ assertImport(resolver,
"org.apache.camel.component.aws2.s3.AWS2S3Component", "camel-aws2-s3");
+ assertImport(resolver,
"org.apache.camel.component.aws2.s3.AWS2S3Constants", "camel-aws2-s3");
+ assertImport(resolver,
"org.apache.camel.component.aws2.s3.utils.AWS2S3Utils", "camel-aws2-s3");
+ // a sibling package of another component is not mistaken for it
+ assertImport(resolver,
"org.apache.camel.component.aws2.s3vectors.AWS2S3VectorsConstants",
"camel-aws2-s3-vectors");
+ // a sub package of another component's package wins for its own
classes
+ assertImport(resolver,
"org.apache.camel.component.file.remote.SftpConstants", "camel-ftp");
+ assertImport(resolver, "org.apache.camel.component.file.GenericFile",
"camel-file");
+ // the libraries still resolve as before
+ assertGav(resolver, "com.fasterxml.jackson.annotation.JsonProperty",
"com.fasterxml.jackson.core",
+ "jackson-annotations");
+ // a component in a base package does not claim every class in it
+ assertNull(resolver.mavenGavForImport("org.apache.camel.Exchange"));
+
assertNull(resolver.mavenGavForImport("org.apache.camel.component.Anything"));
+ // a class looked up at runtime (often only probed for) still needs
the component class itself
+
assertNull(resolver.mavenGavForClass("org.apache.camel.component.aws2.s3.AWS2S3Constants"));
+ assertGav(resolver,
"org.apache.camel.component.aws2.s3.AWS2S3Component", "org.apache.camel",
"camel-aws2-s3");
+ }
+
+ private static void assertImport(KnownDependenciesResolver resolver,
String className, String artifactId) {
+ MavenGav gav = resolver.mavenGavForImport(className);
+ assertNotNull(gav, className);
+ assertEquals("org.apache.camel", gav.getGroupId(), className);
+ assertEquals(artifactId, gav.getArtifactId(), className);
+ assertNotNull(gav.getVersion(), className + " version is null");
+ }
+
+ private static void assertGav(KnownDependenciesResolver resolver, String
className, String groupId, String artifactId) {
+ MavenGav gav = resolver.mavenGavForClass(className);
+ assertNotNull(gav, className);
+ assertEquals(groupId, gav.getGroupId(), className);
+ assertEquals(artifactId, gav.getArtifactId(), className);
+ // on this branch a library version can be a ${...} placeholder,
resolved when the dependency is downloaded
+ assertNotNull(gav.getVersion(), className + " version is null");
+ }
}