You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ja...@apache.org on 2022/10/17 06:17:42 UTC

[camel-quarkus] branch main updated (69818d7100 -> b5347a1b51)

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

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


    from 69818d7100 Updated CHANGELOG.md
     new c330078c9e Add a PackageScanClassResolver implementation that works in native mode
     new b5347a1b51 Add missing JavaDoc for componentNameResolver param

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../core/deployment/CamelContextProcessor.java     |  25 +++--
 .../quarkus/core/deployment/CamelProcessor.java    |  17 ++++
 ...em.java => CamelPackageScanClassBuildItem.java} |  22 ++--
 ...=> CamelPackageScanClassResolverBuildItem.java} |  12 +--
 .../CamelPackageScanClassResolverTest.java         | 112 +++++++++++++++++++++
 .../camel/quarkus/core/CamelContextRecorder.java   |   3 +
 .../core/CamelQuarkusPackageScanClassResolver.java |  50 +++++++++
 .../apache/camel/quarkus/core/CamelRecorder.java   |   6 ++
 .../salesforce/deployment/SalesforceProcessor.java |  11 +-
 .../component/salesforce/SalesforceTest.java       |   3 -
 10 files changed, 231 insertions(+), 30 deletions(-)
 copy extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/spi/{CamelTypeConverterLoaderBuildItem.java => CamelPackageScanClassBuildItem.java} (62%)
 copy extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/spi/{CamelContextBuildItem.java => CamelPackageScanClassResolverBuildItem.java} (69%)
 create mode 100644 extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/CamelPackageScanClassResolverTest.java
 create mode 100644 extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelQuarkusPackageScanClassResolver.java


[camel-quarkus] 02/02: Add missing JavaDoc for componentNameResolver param

Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit b5347a1b5142b44f5932e71b07bfb5ebb5e46023
Author: James Netherton <ja...@gmail.com>
AuthorDate: Fri Oct 14 07:20:28 2022 +0100

    Add missing JavaDoc for componentNameResolver param
---
 .../org/apache/camel/quarkus/core/deployment/CamelContextProcessor.java  | 1 +
 1 file changed, 1 insertion(+)

diff --git a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelContextProcessor.java b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelContextProcessor.java
index 92fab75813..a646e1a355 100644
--- a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelContextProcessor.java
+++ b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelContextProcessor.java
@@ -60,6 +60,7 @@ public class CamelContextProcessor {
      * @param  factoryFinderResolver    a list of known {@link org.apache.camel.spi.FactoryFinderResolver}.
      * @param  customizers              a list of {@link org.apache.camel.spi.CamelContextCustomizer} used to
      *                                  customize the {@link CamelContext} at {@link ExecutionTime#STATIC_INIT}.
+     * @param  componentNameResolver    a reference to a {@link org.apache.camel.spi.ComponentNameResolver}
      * @param  packageScanClassResolver a reference to a {@link org.apache.camel.spi.PackageScanClassResolver}
      * @return                          a build item holding an instance of a {@link CamelContext}
      */


[camel-quarkus] 01/02: Add a PackageScanClassResolver implementation that works in native mode

Posted by ja...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit c330078c9edad6bf173f30d22178768ed6370833
Author: James Netherton <ja...@gmail.com>
AuthorDate: Fri Oct 14 07:12:25 2022 +0100

    Add a PackageScanClassResolver implementation that works in native mode
    
    Fixes #4112
---
 .../core/deployment/CamelContextProcessor.java     |  24 +++--
 .../quarkus/core/deployment/CamelProcessor.java    |  17 ++++
 .../spi/CamelPackageScanClassBuildItem.java        |  40 ++++++++
 .../CamelPackageScanClassResolverBuildItem.java    |  36 +++++++
 .../CamelPackageScanClassResolverTest.java         | 112 +++++++++++++++++++++
 .../camel/quarkus/core/CamelContextRecorder.java   |   3 +
 .../core/CamelQuarkusPackageScanClassResolver.java |  50 +++++++++
 .../apache/camel/quarkus/core/CamelRecorder.java   |   6 ++
 .../salesforce/deployment/SalesforceProcessor.java |  11 +-
 .../component/salesforce/SalesforceTest.java       |   3 -
 10 files changed, 287 insertions(+), 15 deletions(-)

diff --git a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelContextProcessor.java b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelContextProcessor.java
index 9bcfc024c8..92fab75813 100644
--- a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelContextProcessor.java
+++ b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelContextProcessor.java
@@ -40,6 +40,7 @@ import org.apache.camel.quarkus.core.deployment.spi.CamelContextCustomizerBuildI
 import org.apache.camel.quarkus.core.deployment.spi.CamelFactoryFinderResolverBuildItem;
 import org.apache.camel.quarkus.core.deployment.spi.CamelModelJAXBContextFactoryBuildItem;
 import org.apache.camel.quarkus.core.deployment.spi.CamelModelToXMLDumperBuildItem;
+import org.apache.camel.quarkus.core.deployment.spi.CamelPackageScanClassResolverBuildItem;
 import org.apache.camel.quarkus.core.deployment.spi.CamelRegistryBuildItem;
 import org.apache.camel.quarkus.core.deployment.spi.CamelTypeConverterRegistryBuildItem;
 import org.apache.camel.quarkus.core.deployment.util.CamelSupport;
@@ -50,16 +51,17 @@ public class CamelContextProcessor {
     /**
      * This build step is responsible to assemble a {@link CamelContext} instance.
      *
-     * @param  beanContainer           a reference to a fully initialized CDI bean container
-     * @param  recorder                the recorder.
-     * @param  registry                a reference to a {@link org.apache.camel.spi.Registry}.
-     * @param  typeConverterRegistry   a reference to a {@link TypeConverterRegistry}.
-     * @param  modelJAXBContextFactory a list of known {@link ModelJAXBContextFactory}.
-     * @param  modelDumper             a list of known {@link CamelModelToXMLDumperBuildItem}.
-     * @param  factoryFinderResolver   a list of known {@link org.apache.camel.spi.FactoryFinderResolver}.
-     * @param  customizers             a list of {@link org.apache.camel.spi.CamelContextCustomizer} used to
-     *                                 customize the {@link CamelContext} at {@link ExecutionTime#STATIC_INIT}.
-     * @return                         a build item holding an instance of a {@link CamelContext}
+     * @param  beanContainer            a reference to a fully initialized CDI bean container
+     * @param  recorder                 the recorder.
+     * @param  registry                 a reference to a {@link org.apache.camel.spi.Registry}.
+     * @param  typeConverterRegistry    a reference to a {@link TypeConverterRegistry}.
+     * @param  modelJAXBContextFactory  a list of known {@link ModelJAXBContextFactory}.
+     * @param  modelDumper              a list of known {@link CamelModelToXMLDumperBuildItem}.
+     * @param  factoryFinderResolver    a list of known {@link org.apache.camel.spi.FactoryFinderResolver}.
+     * @param  customizers              a list of {@link org.apache.camel.spi.CamelContextCustomizer} used to
+     *                                  customize the {@link CamelContext} at {@link ExecutionTime#STATIC_INIT}.
+     * @param  packageScanClassResolver a reference to a {@link org.apache.camel.spi.PackageScanClassResolver}
+     * @return                          a build item holding an instance of a {@link CamelContext}
      */
     @Record(ExecutionTime.STATIC_INIT)
     @BuildStep
@@ -73,6 +75,7 @@ public class CamelContextProcessor {
             CamelFactoryFinderResolverBuildItem factoryFinderResolver,
             List<CamelContextCustomizerBuildItem> customizers,
             CamelComponentNameResolverBuildItem componentNameResolver,
+            CamelPackageScanClassResolverBuildItem packageScanClassResolver,
             CamelConfig config) {
 
         RuntimeValue<CamelContext> context = recorder.createContext(
@@ -82,6 +85,7 @@ public class CamelContextProcessor {
                 modelDumper.getValue(),
                 factoryFinderResolver.getFactoryFinderResolver(),
                 componentNameResolver.getComponentNameResolver(),
+                packageScanClassResolver.getPackageScanClassResolver(),
                 beanContainer.getValue(),
                 CamelSupport.getCamelVersion(),
                 config);
diff --git a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelProcessor.java b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelProcessor.java
index ab57746e1f..d8e06e3342 100644
--- a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelProcessor.java
+++ b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelProcessor.java
@@ -62,6 +62,8 @@ import org.apache.camel.quarkus.core.deployment.spi.CamelComponentNameResolverBu
 import org.apache.camel.quarkus.core.deployment.spi.CamelFactoryFinderResolverBuildItem;
 import org.apache.camel.quarkus.core.deployment.spi.CamelModelJAXBContextFactoryBuildItem;
 import org.apache.camel.quarkus.core.deployment.spi.CamelModelToXMLDumperBuildItem;
+import org.apache.camel.quarkus.core.deployment.spi.CamelPackageScanClassBuildItem;
+import org.apache.camel.quarkus.core.deployment.spi.CamelPackageScanClassResolverBuildItem;
 import org.apache.camel.quarkus.core.deployment.spi.CamelRoutesBuilderClassBuildItem;
 import org.apache.camel.quarkus.core.deployment.spi.CamelServiceBuildItem;
 import org.apache.camel.quarkus.core.deployment.spi.CamelServiceDestination;
@@ -423,6 +425,21 @@ class CamelProcessor {
         return new CamelComponentNameResolverBuildItem(recorder.createComponentNameResolver(componentNames));
     }
 
+    @Record(ExecutionTime.STATIC_INIT)
+    @BuildStep
+    CamelPackageScanClassResolverBuildItem packageScanClassResolver(
+            List<CamelPackageScanClassBuildItem> camelPackageScanClassBuildItems,
+            CamelRecorder recorder) {
+        Set<? extends Class<?>> packageScanClassCache = camelPackageScanClassBuildItems.stream()
+                .map(CamelPackageScanClassBuildItem::getClassNames)
+                .flatMap(Set::stream)
+                .map(className -> CamelSupport.loadClass(className, Thread.currentThread().getContextClassLoader()))
+                .collect(Collectors.toUnmodifiableSet());
+
+        return new CamelPackageScanClassResolverBuildItem(recorder.createPackageScanClassResolver(packageScanClassCache));
+
+    }
+
     @BuildStep
     NativeImageResourceBuildItem initResources() {
         return new NativeImageResourceBuildItem(
diff --git a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/spi/CamelPackageScanClassBuildItem.java b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/spi/CamelPackageScanClassBuildItem.java
new file mode 100644
index 0000000000..0039ae4db7
--- /dev/null
+++ b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/spi/CamelPackageScanClassBuildItem.java
@@ -0,0 +1,40 @@
+/*
+ * 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.quarkus.core.deployment.spi;
+
+import java.util.Set;
+
+import io.quarkus.builder.item.MultiBuildItem;
+
+/**
+ * A {@link MultiBuildItem} holding the names of a types that will be scanned by the Camel PackageScanClassResolver.
+ */
+public final class CamelPackageScanClassBuildItem extends MultiBuildItem {
+    private final Set<String> classNames;
+
+    public CamelPackageScanClassBuildItem(Set<String> classNames) {
+        this.classNames = classNames;
+    }
+
+    public CamelPackageScanClassBuildItem(String... classNames) {
+        this.classNames = Set.of(classNames);
+    }
+
+    public Set<String> getClassNames() {
+        return classNames;
+    }
+}
diff --git a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/spi/CamelPackageScanClassResolverBuildItem.java b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/spi/CamelPackageScanClassResolverBuildItem.java
new file mode 100644
index 0000000000..80cb2b3357
--- /dev/null
+++ b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/spi/CamelPackageScanClassResolverBuildItem.java
@@ -0,0 +1,36 @@
+/*
+ * 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.quarkus.core.deployment.spi;
+
+import io.quarkus.builder.item.SimpleBuildItem;
+import io.quarkus.runtime.RuntimeValue;
+import org.apache.camel.spi.PackageScanClassResolver;
+
+/**
+ * Holds the {@link PackageScanClassResolver} {@link RuntimeValue}.
+ */
+public final class CamelPackageScanClassResolverBuildItem extends SimpleBuildItem {
+    private final RuntimeValue<PackageScanClassResolver> value;
+
+    public CamelPackageScanClassResolverBuildItem(RuntimeValue<PackageScanClassResolver> value) {
+        this.value = value;
+    }
+
+    public RuntimeValue<PackageScanClassResolver> getPackageScanClassResolver() {
+        return value;
+    }
+}
diff --git a/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/CamelPackageScanClassResolverTest.java b/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/CamelPackageScanClassResolverTest.java
new file mode 100644
index 0000000000..25bc7c5b48
--- /dev/null
+++ b/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/deployment/CamelPackageScanClassResolverTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.quarkus.core.deployment;
+
+import java.util.Set;
+import java.util.function.Consumer;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import io.quarkus.builder.BuildChainBuilder;
+import io.quarkus.builder.BuildContext;
+import io.quarkus.builder.BuildStep;
+import io.quarkus.test.QuarkusUnitTest;
+import org.apache.camel.CamelContext;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.quarkus.core.deployment.spi.CamelPackageScanClassBuildItem;
+import org.apache.camel.spi.PackageScanClassResolver;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class CamelPackageScanClassResolverTest {
+
+    @RegisterExtension
+    static final QuarkusUnitTest CONFIG = new QuarkusUnitTest()
+            .addBuildChainCustomizer(new Consumer<>() {
+                @Override
+                public void accept(BuildChainBuilder buildChainBuilder) {
+                    buildChainBuilder.addBuildStep(new BuildStep() {
+                        @Override
+                        public void execute(BuildContext context) {
+                            context.produce(new CamelPackageScanClassBuildItem(Cat.class.getName()));
+                            context.produce(new CamelPackageScanClassBuildItem(Dog.class.getName()));
+                            context.produce(new CamelPackageScanClassBuildItem(Mushroom.class.getName()));
+                        }
+                    })
+                            .produces(CamelPackageScanClassBuildItem.class)
+                            .build();
+                }
+            })
+            .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class));
+
+    @Inject
+    CamelContext context;
+
+    @Test
+    public void findImplementations() {
+        ExtendedCamelContext ecc = context.adapt(ExtendedCamelContext.class);
+        PackageScanClassResolver resolver = ecc.getPackageScanClassResolver();
+        Set<Class<?>> classes = resolver.findImplementations(Animal.class, Animal.class.getPackageName());
+        assertNotNull(classes);
+        assertEquals(2, classes.size());
+        assertTrue(classes.contains(Cat.class));
+        assertTrue(classes.contains(Dog.class));
+    }
+
+    @Test
+    public void findByFilter() {
+        ExtendedCamelContext ecc = context.adapt(ExtendedCamelContext.class);
+        PackageScanClassResolver resolver = ecc.getPackageScanClassResolver();
+        Set<Class<?>> classes = resolver.findByFilter(Fungi.class::isAssignableFrom, Fungi.class.getPackageName());
+        assertNotNull(classes);
+        assertEquals(1, classes.size());
+        assertEquals(Mushroom.class, classes.iterator().next());
+    }
+
+    @Test
+    public void findAnnotated() {
+        ExtendedCamelContext ecc = context.adapt(ExtendedCamelContext.class);
+        PackageScanClassResolver resolver = ecc.getPackageScanClassResolver();
+        Set<Class<?>> classes = resolver.findAnnotated(Singleton.class, Animal.class.getPackageName());
+        assertNotNull(classes);
+        assertEquals(1, classes.size());
+        assertEquals(Cat.class, classes.iterator().next());
+    }
+
+    interface Animal {
+    }
+
+    interface Fungi {
+    }
+
+    @Singleton
+    static final class Cat implements Animal {
+    }
+
+    static final class Dog implements Animal {
+    }
+
+    static final class Mushroom implements Fungi {
+    }
+}
diff --git a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelContextRecorder.java b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelContextRecorder.java
index 989596519d..63487af35f 100644
--- a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelContextRecorder.java
+++ b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelContextRecorder.java
@@ -36,6 +36,7 @@ import org.apache.camel.spi.ComponentNameResolver;
 import org.apache.camel.spi.FactoryFinderResolver;
 import org.apache.camel.spi.ModelJAXBContextFactory;
 import org.apache.camel.spi.ModelToXMLDumper;
+import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.Registry;
 import org.apache.camel.spi.TypeConverterRegistry;
 
@@ -48,6 +49,7 @@ public class CamelContextRecorder {
             RuntimeValue<ModelToXMLDumper> xmlModelDumper,
             RuntimeValue<FactoryFinderResolver> factoryFinderResolver,
             RuntimeValue<ComponentNameResolver> componentNameResolver,
+            RuntimeValue<PackageScanClassResolver> packageScanClassResolver,
             BeanContainer beanContainer,
             String version,
             CamelConfig config) {
@@ -65,6 +67,7 @@ public class CamelContextRecorder {
         context.setTypeConverterRegistry(typeConverterRegistry.getValue());
         context.setLoadTypeConverters(false);
         context.setModelJAXBContextFactory(contextFactory.getValue());
+        context.setPackageScanClassResolver(packageScanClassResolver.getValue());
         context.build();
         context.setComponentNameResolver(componentNameResolver.getValue());
 
diff --git a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelQuarkusPackageScanClassResolver.java b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelQuarkusPackageScanClassResolver.java
new file mode 100644
index 0000000000..8d38e2c061
--- /dev/null
+++ b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelQuarkusPackageScanClassResolver.java
@@ -0,0 +1,50 @@
+/*
+ * 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.quarkus.core;
+
+import java.util.Objects;
+import java.util.Set;
+
+import org.apache.camel.impl.engine.DefaultPackageScanClassResolver;
+import org.apache.camel.spi.PackageScanClassResolver;
+import org.apache.camel.spi.PackageScanFilter;
+
+/**
+ * Custom {@link PackageScanClassResolver} where classes / packages known to be scanned can be computed at build time
+ * and cached for resolution at runtime. This is primarily needed for native mode where the default implementation
+ * reliance on ClassLoader.getResources is likely to fail due to resources not being embedded within the native image.
+ */
+public class CamelQuarkusPackageScanClassResolver extends DefaultPackageScanClassResolver {
+    private final Set<? extends Class<?>> classCache;
+
+    public CamelQuarkusPackageScanClassResolver(Set<? extends Class<?>> classCache) {
+        this.classCache = Objects.requireNonNull(classCache);
+    }
+
+    @Override
+    protected void find(PackageScanFilter test, String packageName, ClassLoader loader, Set<Class<?>> classes) {
+        classCache.stream()
+                .filter(clazz -> clazz.getPackageName().replace('.', '/').equals(packageName))
+                .filter(test::matches)
+                .forEach(classes::add);
+
+        // Try to fallback on default package scanning
+        if (classes.isEmpty()) {
+            super.find(test, packageName, loader, classes);
+        }
+    }
+}
diff --git a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelRecorder.java b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelRecorder.java
index d1217cb673..bf5d342ab7 100644
--- a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelRecorder.java
+++ b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelRecorder.java
@@ -39,6 +39,7 @@ import org.apache.camel.spi.ComponentNameResolver;
 import org.apache.camel.spi.FactoryFinderResolver;
 import org.apache.camel.spi.ModelJAXBContextFactory;
 import org.apache.camel.spi.ModelToXMLDumper;
+import org.apache.camel.spi.PackageScanClassResolver;
 import org.apache.camel.spi.ReactiveExecutor;
 import org.apache.camel.spi.Registry;
 import org.apache.camel.spi.StartupStepRecorder;
@@ -202,4 +203,9 @@ public class CamelRecorder {
     public RuntimeValue<ComponentNameResolver> createComponentNameResolver(Set<String> componentNames) {
         return new RuntimeValue<>(new FastComponentNameResolver(componentNames));
     }
+
+    public RuntimeValue<PackageScanClassResolver> createPackageScanClassResolver(
+            Set<? extends Class<?>> packageScanClassCache) {
+        return new RuntimeValue<>(new CamelQuarkusPackageScanClassResolver(packageScanClassCache));
+    }
 }
diff --git a/extensions/salesforce/deployment/src/main/java/org/apache/camel/quarkus/component/salesforce/deployment/SalesforceProcessor.java b/extensions/salesforce/deployment/src/main/java/org/apache/camel/quarkus/component/salesforce/deployment/SalesforceProcessor.java
index 23cd4c90c3..f5dca11811 100644
--- a/extensions/salesforce/deployment/src/main/java/org/apache/camel/quarkus/component/salesforce/deployment/SalesforceProcessor.java
+++ b/extensions/salesforce/deployment/src/main/java/org/apache/camel/quarkus/component/salesforce/deployment/SalesforceProcessor.java
@@ -23,6 +23,7 @@ import io.quarkus.deployment.builditem.ExtensionSslNativeSupportBuildItem;
 import io.quarkus.deployment.builditem.FeatureBuildItem;
 import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
 import org.apache.camel.component.salesforce.api.dto.AbstractDTOBase;
+import org.apache.camel.quarkus.core.deployment.spi.CamelPackageScanClassBuildItem;
 import org.apache.camel.support.jsse.KeyStoreParameters;
 import org.jboss.jandex.DotName;
 import org.jboss.jandex.IndexView;
@@ -44,7 +45,11 @@ class SalesforceProcessor {
     }
 
     @BuildStep
-    void registerForReflection(CombinedIndexBuildItem combinedIndex, BuildProducer<ReflectiveClassBuildItem> reflectiveClass) {
+    void registerForReflection(
+            CombinedIndexBuildItem combinedIndex,
+            BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
+            BuildProducer<CamelPackageScanClassBuildItem> packageScanClass) {
+
         IndexView index = combinedIndex.getIndex();
 
         // NOTE: DTO classes are registered for reflection with fields and methods due to:
@@ -69,7 +74,9 @@ class SalesforceProcessor {
                 .toArray(String[]::new);
 
         reflectiveClass.produce(new ReflectiveClassBuildItem(true, true, userDtoClasses));
-        // Register KeyStoreParameters for reflection
         reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, KeyStoreParameters.class));
+
+        // Ensure package scanning for user DTO classes can work in native mode
+        packageScanClass.produce(new CamelPackageScanClassBuildItem(userDtoClasses));
     }
 }
diff --git a/integration-tests/salesforce/src/test/java/org/apache/camel/quarkus/component/salesforce/SalesforceTest.java b/integration-tests/salesforce/src/test/java/org/apache/camel/quarkus/component/salesforce/SalesforceTest.java
index ee7e90132e..d103cf0461 100644
--- a/integration-tests/salesforce/src/test/java/org/apache/camel/quarkus/component/salesforce/SalesforceTest.java
+++ b/integration-tests/salesforce/src/test/java/org/apache/camel/quarkus/component/salesforce/SalesforceTest.java
@@ -27,7 +27,6 @@ import io.restassured.path.json.JsonPath;
 import org.apache.camel.component.salesforce.api.dto.RecentItem;
 import org.apache.camel.component.salesforce.api.dto.SObjectBasicInfo;
 import org.apache.camel.component.salesforce.api.dto.Versions;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
 import static org.hamcrest.Matchers.containsString;
@@ -53,7 +52,6 @@ class SalesforceTest {
     }
 
     @Test
-    @Disabled // https://github.com/apache/camel-quarkus/issues/4112
     public void testGetAccountDTO() {
         String accountId = null;
         String accountName = "Camel Quarkus Account Test: " + UUID.randomUUID();
@@ -186,7 +184,6 @@ class SalesforceTest {
     }
 
     @Test
-    @Disabled // https://github.com/apache/camel-quarkus/issues/4112
     void testAccountWithBasicInfo() {
         String accountId = null;
         String accountName = "Camel Quarkus Account Test: " + UUID.randomUUID();