From 4a6cc2ce4e950842c813c087362c3fd896e73960 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Tue, 16 Dec 2025 12:24:04 +0100
Subject: [PATCH 01/41] feat(QTDI-2134): initial commit
---
... => DynamicDependenciesConfiguration.java} | 6 +--
.../runtime/manager/ComponentManager.java | 13 +++---
.../runtime/manager/ComponentManagerTest.java | 5 ++-
.../classloader/ConfigurableClassLoader.java | 12 +++++
.../sdk/component/container/Container.java | 4 ++
.../component/container/ContainerManager.java | 44 ++++++++++++++++---
.../config/DynamicDependenciesConf.java | 4 +-
7 files changed, 69 insertions(+), 19 deletions(-)
rename component-api/src/main/java/org/talend/sdk/component/api/configuration/type/{DynamicDependenciesServiceConfiguration.java => DynamicDependenciesConfiguration.java} (85%)
diff --git a/component-api/src/main/java/org/talend/sdk/component/api/configuration/type/DynamicDependenciesServiceConfiguration.java b/component-api/src/main/java/org/talend/sdk/component/api/configuration/type/DynamicDependenciesConfiguration.java
similarity index 85%
rename from component-api/src/main/java/org/talend/sdk/component/api/configuration/type/DynamicDependenciesServiceConfiguration.java
rename to component-api/src/main/java/org/talend/sdk/component/api/configuration/type/DynamicDependenciesConfiguration.java
index d367dce515f68..f7f01ec74d5b3 100644
--- a/component-api/src/main/java/org/talend/sdk/component/api/configuration/type/DynamicDependenciesServiceConfiguration.java
+++ b/component-api/src/main/java/org/talend/sdk/component/api/configuration/type/DynamicDependenciesConfiguration.java
@@ -26,9 +26,9 @@
@Target(TYPE)
@Retention(RUNTIME)
-@ConfigurationType("dynamicDependenciesServiceConfiguration")
-@Documentation("Mark a model (complex object) as being the configuration used in services annotated with @DynamicDependencies.")
-public @interface DynamicDependenciesServiceConfiguration {
+@ConfigurationType("dynamicDependenciesConfiguration")
+@Documentation("Mark a model (complex object) as being the configuration expected to compute dynamic dependencies.")
+public @interface DynamicDependenciesConfiguration {
String value() default "default";
}
\ No newline at end of file
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
index 56957e149196f..446b262fd3ebd 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
@@ -211,11 +211,14 @@ private static ComponentManager buildNewComponentManager() {
{
info("ComponentManager version: " + ComponentManagerVersion.VERSION);
info("Creating the contextual ComponentManager instance " + getIdentifiers());
-
- parallelIf(Boolean.getBoolean("talend.component.manager.plugins.parallel"),
- container.getDefinedNestedPlugin().stream().filter(p -> !hasPlugin(p)))
- .forEach(this::addPlugin);
- info("Components: " + availablePlugins());
+ try {
+ parallelIf(Boolean.getBoolean("talend.component.manager.plugins.parallel"),
+ container.getDefinedNestedPlugin().stream().filter(p -> !hasPlugin(p)))
+ .forEach(this::addPlugin);
+ info("Components: " + availablePlugins());
+ } catch (Exception e) {
+ info("Failed to load plugins from plugins.properties: " + e.getMessage());
+ }
}
@Override
diff --git a/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/ComponentManagerTest.java b/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/ComponentManagerTest.java
index 1441c9e7088e9..e9934f20b71f0 100644
--- a/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/ComponentManagerTest.java
+++ b/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/ComponentManagerTest.java
@@ -441,8 +441,9 @@ void extendFamilyInNestedRepo(@TempDir final File temporaryFolder) throws Except
.map(File::getName)
.sorted()
.toArray(String[]::new);
- assertEquals(1, dependencies.length); // ignored transitive deps, enables the new root to control it
- assertEquals("main.jar", dependencies[0]); // transitive-1.0.0.jar is nested
+ assertEquals(2, dependencies.length); // ignored transitive deps, enables the new root to control it
+ assertEquals("fatjar.jar", dependencies[0]);
+ assertEquals("main.jar", dependencies[1]); // transitive-1.0.0.jar is nested
} finally {
if (!transitive.delete()) {
transitive.deleteOnExit();
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
index 3ded8250b3ccd..5e75d9ebdf5fa 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
@@ -111,6 +111,8 @@ public class ConfigurableClassLoader extends URLClassLoader {
@Getter
private final List cacheableClasses;
+ private List nestedURLs = new ArrayList<>();
+
public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent,
final Predicate parentFilter, final Predicate childFirstFilter,
final String[] nestedDependencies, final String[] jvmPrefixes) {
@@ -155,6 +157,7 @@ private void loadNestedDependencies(final ClassLoader parent, final String[] nes
if (url == null) {
throw new IllegalArgumentException("Didn't find " + resource + " in " + asList(nestedDependencies));
}
+ nestedURLs.add(url);
final Map resources = new HashMap<>();
final URLConnection urlConnection;
final Manifest manifest;
@@ -458,6 +461,15 @@ public Enumeration findResources(final String name) throws IOException {
return enumeration(aggregated);
}
+ @Override
+ public URL[] getURLs() {
+ final List urls = new ArrayList<>(Arrays.asList(super.getURLs()));
+ if (!nestedURLs.isEmpty()) {
+ urls.addAll(nestedURLs);
+ }
+ return urls.toArray(new URL[0]);
+ }
+
private boolean isNestedDependencyResource(final String name) {
return name != null && name.startsWith(NESTED_MAVEN_REPOSITORY);
}
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java b/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java
index 67e33c498479a..287e580ae72ad 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java
@@ -307,6 +307,10 @@ public Date getCreated() {
return created.get();
}
+ public boolean hasNestedRepository() {
+ return hasNestedRepository;
+ }
+
public void registerTransformer(final ClassFileTransformer transformer) {
transformers.add(transformer);
}
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index ac3ed4fbdfa37..b5579f3ecfa67 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -29,6 +29,9 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -111,8 +114,11 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe
this.containerInitializer = containerInitializer;
this.resolver = dependenciesResolutionConfiguration.getResolver();
this.rootRepositoryLocation = dependenciesResolutionConfiguration.getRootRepositoryLocation();
-
info("Using root repository: " + this.rootRepositoryLocation.toAbsolutePath());
+ if (log.isDebugEnabled()) {
+ getSystemInformations();
+ }
+
final String nestedPluginMappingResource = ofNullable(classLoaderConfiguration.getNestedPluginMappingResource())
.orElse("TALEND-INF/plugins.properties");
this.classLoaderConfiguration = new ClassLoaderConfiguration(
@@ -124,6 +130,12 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe
try (final InputStream mappingStream =
classLoaderConfiguration.getParent().getResourceAsStream(nestedPluginMappingResource)) {
if (mappingStream != null) {
+ if (log.isDebugEnabled()) {
+ final URL plug = classLoaderConfiguration.getParent().getResource(nestedPluginMappingResource);
+ if (plug != null) {
+ log.debug("[sysinfo] plugins mapping " + plug.toString());
+ }
+ }
final Properties properties = new Properties() {
{
@@ -150,10 +162,13 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe
this.jvmMarkers = Stream
.concat(Stream.concat(Stream.of(getJre()), getComponentModules()), getCustomJvmMarkers())
.toArray(String[]::new);
- this.hasNestedRepository =
- this.classLoaderConfiguration.isSupportsResourceDependencies() && this.classLoaderConfiguration
- .getParent()
- .getResource(ConfigurableClassLoader.NESTED_MAVEN_REPOSITORY) != null;
+ final URL nestedMvn = this.classLoaderConfiguration
+ .getParent()
+ .getResource(ConfigurableClassLoader.NESTED_MAVEN_REPOSITORY);
+ this.hasNestedRepository = this.classLoaderConfiguration.isSupportsResourceDependencies() && nestedMvn != null;
+ if (log.isDebugEnabled() && hasNestedRepository) {
+ log.debug("[sysinfo] nested maven repository: " + nestedMvn);
+ }
}
public File getRootRepositoryLocation() {
@@ -389,6 +404,21 @@ private String getJre() {
.orElseThrow(IllegalArgumentException::new);
}
+ private void getSystemInformations() {
+ try {
+ final RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
+ log.debug("[sysinfo] JVM arguments: " + rt.getInputArguments());
+ try {
+ log.debug("[sysinfo] Boot classpath: " + rt.getBootClassPath());
+ } catch (Exception e) {
+ }
+ log.debug("[sysinfo] Runtime classpath: " + rt.getClassPath());
+ log.debug("[sysinfo] Runtime arguments: " + System.getProperty("sun.java.command"));
+ } catch (Exception e) {
+ log.debug("Unable to get JVM information: " + e.getMessage(), e);
+ }
+ }
+
@Override
public void close() {
lifecycle.closeIfNeeded(() -> {
@@ -472,8 +502,8 @@ public Container create() {
? nestedContainerMapping.getOrDefault(module, module)
: module;
final Path resolved = resolve(moduleLocation);
- info("Creating module " + moduleLocation + " (from " + module
- + (Files.exists(resolved) ? ", location=" + resolved.toAbsolutePath().toString() : "") + ")");
+ info(String.format("Creating module %s (from %s, location=%s)", moduleLocation, module,
+ resolved.toAbsolutePath()));
final Stream classpath = Stream
.concat(getBuiltInClasspath(moduleLocation),
additionalClasspath == null ? Stream.empty() : additionalClasspath.stream());
diff --git a/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/DynamicDependenciesConf.java b/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/DynamicDependenciesConf.java
index 22258c28bebca..4d182f743ac96 100644
--- a/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/DynamicDependenciesConf.java
+++ b/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/DynamicDependenciesConf.java
@@ -18,14 +18,14 @@
import java.io.Serializable;
import org.talend.sdk.component.api.configuration.Option;
-import org.talend.sdk.component.api.configuration.type.DynamicDependenciesServiceConfiguration;
+import org.talend.sdk.component.api.configuration.type.DynamicDependenciesConfiguration;
import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
import org.talend.sdk.component.api.meta.Documentation;
import lombok.Data;
@Data
-@DynamicDependenciesServiceConfiguration
+@DynamicDependenciesConfiguration
@GridLayout({
@GridLayout.Row({ "group" }),
@GridLayout.Row({ "artifact" })
From 83505e1d25c7a3e92ceb693431cf9434bac07c42 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Mon, 22 Dec 2025 19:00:57 +0100
Subject: [PATCH 02/41] feat(QTDI-2134): parent resources filtering
---
.../runtime/manager/ComponentManager.java | 33 +++++++++++++++++++
.../classloader/ConfigurableClassLoader.java | 26 +++++++++++++--
.../sdk/component/container/Container.java | 3 +-
.../component/container/ContainerManager.java | 3 ++
...DependencyListLocalRepositoryResolver.java | 26 +++++++++++++--
5 files changed, 84 insertions(+), 7 deletions(-)
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
index 446b262fd3ebd..14f14b4a4febb 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
@@ -113,6 +113,7 @@
import org.apache.xbean.finder.archive.FileArchive;
import org.apache.xbean.finder.archive.FilteredArchive;
import org.apache.xbean.finder.archive.JarArchive;
+import org.apache.xbean.finder.filter.ContainsFilter;
import org.apache.xbean.finder.filter.ExcludeIncludeFilter;
import org.apache.xbean.finder.filter.Filter;
import org.apache.xbean.finder.filter.FilterList;
@@ -315,6 +316,8 @@ public String[] categories() {
// + tcomp "runtime" indeed (invisible from the components but required for the runtime
private final Filter classesFilter;
+ private final Filter resourcesFilter;
+
private final ParameterModelService parameterModelService;
private final InternationalizationServiceFactory internationalizationServiceFactory;
@@ -430,6 +433,13 @@ public ComponentManager(final Path m2, final String dependenciesResource, final
.map(PrefixFilter::new)
.toArray(Filter[]::new));
+ resourcesFilter = new FilterList(Stream.concat(
+ Stream.of("META-INF/services/"),
+ additionalParentResources())
+ .distinct()
+ .map(ContainsFilter::new)
+ .toArray(Filter[]::new));
+
jsonpProvider = loadJsonProvider();
jsonbProvider = loadJsonbProvider();
// these factories have memory caches so ensure we reuse them properly
@@ -463,6 +473,7 @@ public ComponentManager(final Path m2, final String dependenciesResource, final
migrationHandlerFactory = new MigrationHandlerFactory(reflections);
final Predicate isContainerClass = name -> isContainerClass(classesFilter, name);
+ final Predicate isParentResource = name -> isContainerResource(resourcesFilter, name);
final ContainerManager.ClassLoaderConfiguration defaultClassLoaderConfiguration =
ContainerManager.ClassLoaderConfiguration
.builder()
@@ -470,6 +481,7 @@ public ComponentManager(final Path m2, final String dependenciesResource, final
.parentClassesFilter(isContainerClass)
.classesFilter(isContainerClass.negate())
.supportsResourceDependencies(true)
+ .parentResourcesFilter(isParentResource)
.create();
this.container = new ContainerManager(ContainerManager.DependenciesResolutionConfiguration
.builder()
@@ -614,6 +626,16 @@ private Stream additionalContainerClasses() {
.orElseGet(Stream::empty));
}
+ private Stream additionalParentResources() {
+ return Stream
+ .concat(customizers.stream().flatMap(Customizer::parentResources),
+ ofNullable(
+ System.getProperty("talend.component.manager.classloader.container.parentResources"))
+ .map(s -> s.split(","))
+ .map(Stream::of)
+ .orElseGet(Stream::empty));
+ }
+
public static Path findM2() {
return new MavenRepositoryDefaultResolver().discover();
}
@@ -1048,6 +1070,10 @@ protected boolean isContainerClass(final Filter filter, final String name) {
return name != null && filter.accept(name);
}
+ protected boolean isContainerResource(final Filter filter, final String name) {
+ return name != null && filter.accept(name);
+ }
+
@Override
public void close() {
container.close();
@@ -2210,6 +2236,13 @@ public interface Customizer {
*/
Stream containerClassesAndPackages();
+ /**
+ * @return
+ */
+ default Stream parentResources() {
+ return Stream.empty();
+ }
+
/**
* @return advanced toggle to ignore built-in beam exclusions and let this customizer override them.
*/
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
index 5e75d9ebdf5fa..e62328e557796 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
@@ -92,6 +92,9 @@ public class ConfigurableClassLoader extends URLClassLoader {
@Getter
private final Predicate childFirstFilter;
+ @Getter
+ private final Predicate resourcesFilter;
+
private final Map> resources = new HashMap<>();
private final Collection transformers = new ArrayList<>();
@@ -116,7 +119,16 @@ public class ConfigurableClassLoader extends URLClassLoader {
public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent,
final Predicate parentFilter, final Predicate childFirstFilter,
final String[] nestedDependencies, final String[] jvmPrefixes) {
- this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes);
+ this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes, (name) -> false);
+ if (nestedDependencies != null) {
+ loadNestedDependencies(parent, nestedDependencies);
+ }
+ }
+
+ public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent,
+ final Predicate parentFilter, final Predicate childFirstFilter,
+ final String[] nestedDependencies, final String[] jvmPrefixes, final Predicate resourcesFilter) {
+ this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes, resourcesFilter);
if (nestedDependencies != null) {
loadNestedDependencies(parent, nestedDependencies);
}
@@ -124,12 +136,14 @@ public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoa
private ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent,
final Predicate parentFilter, final Predicate childFirstFilter,
- final Map> resources, final String[] jvmPrefixes) {
+ final Map> resources, final String[] jvmPrefixes,
+ final Predicate resourcesFilter) {
super(urls, parent);
this.id = id;
this.creationUrls = urls;
this.parentFilter = parentFilter;
this.childFirstFilter = childFirstFilter;
+ this.resourcesFilter = resourcesFilter;
this.resources.putAll(resources);
this.fullPathJvmPrefixes =
@@ -232,7 +246,7 @@ public void registerTransformer(final ClassFileTransformer transformer) {
public synchronized URLClassLoader createTemporaryCopy() {
final ConfigurableClassLoader self = this;
return temporaryCopy == null ? temporaryCopy = new ConfigurableClassLoader(id, creationUrls, getParent(),
- parentFilter, childFirstFilter, resources, fullPathJvmPrefixes) {
+ parentFilter, childFirstFilter, resources, fullPathJvmPrefixes, resourcesFilter) {
@Override
public synchronized void close() throws IOException {
@@ -475,6 +489,12 @@ private boolean isNestedDependencyResource(final String name) {
}
private boolean isInJvm(final URL resource) {
+ // Services and parent allowed resources that should always be found by top level classloader.
+ // By default, META-INF/services/ is always allowed otherwise SPI won't work properly in nested environments.
+ // Warning: selection shouldn't be too generic! Use very specific paths only like jndi.properties.
+ if (resourcesFilter.test(resource.getFile())) {
+ return true;
+ }
final Path path = toPath(resource);
if (path == null) {
return false;
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java b/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java
index 287e580ae72ad..8990bfbe45030 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java
@@ -145,7 +145,8 @@ public Container(final String id, final String rootModule, final Artifact[] depe
: null;
final ConfigurableClassLoader loader = new ConfigurableClassLoader(id, urls,
overrideClassLoaderConfig.getParent(), overrideClassLoaderConfig.getParentClassesFilter(),
- overrideClassLoaderConfig.getClassesFilter(), rawNestedDependencies, jvmMarkers);
+ overrideClassLoaderConfig.getClassesFilter(), rawNestedDependencies, jvmMarkers,
+ overrideClassLoaderConfig.getParentResourcesFilter());
transformers.forEach(loader::registerTransformer);
activeSpecificTransformers(loader);
return loader;
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index b5579f3ecfa67..9995b12da2932 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -125,6 +125,7 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe
ofNullable(classLoaderConfiguration.getParent()).orElseGet(ContainerManager.class::getClassLoader),
ofNullable(classLoaderConfiguration.getClassesFilter()).orElseGet(() -> name -> true),
ofNullable(classLoaderConfiguration.getParentClassesFilter()).orElseGet(() -> name -> true),
+ ofNullable(classLoaderConfiguration.getParentResourcesFilter()).orElseGet(() -> name -> true),
classLoaderConfiguration.isSupportsResourceDependencies(), nestedPluginMappingResource);
if (classLoaderConfiguration.isSupportsResourceDependencies()) {
try (final InputStream mappingStream =
@@ -451,6 +452,8 @@ public static class ClassLoaderConfiguration {
private final Predicate parentClassesFilter;
+ private final Predicate parentResourcesFilter;
+
// is nested jar in jar supported (1 level only)
private final boolean supportsResourceDependencies;
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
index c061f2d95caec..70d0fe75f0416 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
@@ -32,6 +32,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
+import java.util.Properties;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.jar.JarFile;
@@ -61,8 +62,8 @@ public class MvnDependencyListLocalRepositoryResolver implements Resolver {
@Override
public Stream resolve(final ClassLoader rootLoader, final String artifact) {
- return Stream
- .of(readDependencies(ofNullable(getJar(artifact))
+ return Stream.of(
+ readDependencies(ofNullable(getJar(artifact))
.filter(Files::exists)
.map(this::findDependenciesFile)
.orElseGet(() -> {
@@ -98,7 +99,26 @@ public Stream resolve(final ClassLoader rootLoader, final String artif
}
return "";
- })));
+ })), readDynamicDependencies(rootLoader, artifact));
+ }
+
+ private String readDynamicDependencies(ClassLoader rootLoader, String artifact) {
+ try (final InputStream stream = rootLoader.getResourceAsStream("TALEND-INF/dynamic-dependencies.properties")) {
+ if (stream == null) {
+ return "";
+ }
+ final Properties properties = new Properties() {
+
+ {
+ load(stream);
+ }
+ };
+ final String dyndeps = properties.getProperty(artifact, "");
+ return dyndeps.replaceAll(",", System.lineSeparator());
+ } catch (final IOException e) {
+ log.debug(e.getMessage(), e);
+ return "";
+ }
}
private Path getJar(final String artifact) {
From 921e7fec4fe592ff0918f50f61cba8a9af4ac56f Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Mon, 22 Dec 2025 19:04:00 +0100
Subject: [PATCH 03/41] Revert "feat(QTDI-2134): parent resources filtering"
This reverts commit 83505e1d25c7a3e92ceb693431cf9434bac07c42.
---
.../runtime/manager/ComponentManager.java | 33 -------------------
.../classloader/ConfigurableClassLoader.java | 26 ++-------------
.../sdk/component/container/Container.java | 3 +-
.../component/container/ContainerManager.java | 3 --
...DependencyListLocalRepositoryResolver.java | 26 ++-------------
5 files changed, 7 insertions(+), 84 deletions(-)
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
index 14f14b4a4febb..446b262fd3ebd 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
@@ -113,7 +113,6 @@
import org.apache.xbean.finder.archive.FileArchive;
import org.apache.xbean.finder.archive.FilteredArchive;
import org.apache.xbean.finder.archive.JarArchive;
-import org.apache.xbean.finder.filter.ContainsFilter;
import org.apache.xbean.finder.filter.ExcludeIncludeFilter;
import org.apache.xbean.finder.filter.Filter;
import org.apache.xbean.finder.filter.FilterList;
@@ -316,8 +315,6 @@ public String[] categories() {
// + tcomp "runtime" indeed (invisible from the components but required for the runtime
private final Filter classesFilter;
- private final Filter resourcesFilter;
-
private final ParameterModelService parameterModelService;
private final InternationalizationServiceFactory internationalizationServiceFactory;
@@ -433,13 +430,6 @@ public ComponentManager(final Path m2, final String dependenciesResource, final
.map(PrefixFilter::new)
.toArray(Filter[]::new));
- resourcesFilter = new FilterList(Stream.concat(
- Stream.of("META-INF/services/"),
- additionalParentResources())
- .distinct()
- .map(ContainsFilter::new)
- .toArray(Filter[]::new));
-
jsonpProvider = loadJsonProvider();
jsonbProvider = loadJsonbProvider();
// these factories have memory caches so ensure we reuse them properly
@@ -473,7 +463,6 @@ public ComponentManager(final Path m2, final String dependenciesResource, final
migrationHandlerFactory = new MigrationHandlerFactory(reflections);
final Predicate isContainerClass = name -> isContainerClass(classesFilter, name);
- final Predicate isParentResource = name -> isContainerResource(resourcesFilter, name);
final ContainerManager.ClassLoaderConfiguration defaultClassLoaderConfiguration =
ContainerManager.ClassLoaderConfiguration
.builder()
@@ -481,7 +470,6 @@ public ComponentManager(final Path m2, final String dependenciesResource, final
.parentClassesFilter(isContainerClass)
.classesFilter(isContainerClass.negate())
.supportsResourceDependencies(true)
- .parentResourcesFilter(isParentResource)
.create();
this.container = new ContainerManager(ContainerManager.DependenciesResolutionConfiguration
.builder()
@@ -626,16 +614,6 @@ private Stream additionalContainerClasses() {
.orElseGet(Stream::empty));
}
- private Stream additionalParentResources() {
- return Stream
- .concat(customizers.stream().flatMap(Customizer::parentResources),
- ofNullable(
- System.getProperty("talend.component.manager.classloader.container.parentResources"))
- .map(s -> s.split(","))
- .map(Stream::of)
- .orElseGet(Stream::empty));
- }
-
public static Path findM2() {
return new MavenRepositoryDefaultResolver().discover();
}
@@ -1070,10 +1048,6 @@ protected boolean isContainerClass(final Filter filter, final String name) {
return name != null && filter.accept(name);
}
- protected boolean isContainerResource(final Filter filter, final String name) {
- return name != null && filter.accept(name);
- }
-
@Override
public void close() {
container.close();
@@ -2236,13 +2210,6 @@ public interface Customizer {
*/
Stream containerClassesAndPackages();
- /**
- * @return
- */
- default Stream parentResources() {
- return Stream.empty();
- }
-
/**
* @return advanced toggle to ignore built-in beam exclusions and let this customizer override them.
*/
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
index e62328e557796..5e75d9ebdf5fa 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
@@ -92,9 +92,6 @@ public class ConfigurableClassLoader extends URLClassLoader {
@Getter
private final Predicate childFirstFilter;
- @Getter
- private final Predicate resourcesFilter;
-
private final Map> resources = new HashMap<>();
private final Collection transformers = new ArrayList<>();
@@ -119,16 +116,7 @@ public class ConfigurableClassLoader extends URLClassLoader {
public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent,
final Predicate parentFilter, final Predicate childFirstFilter,
final String[] nestedDependencies, final String[] jvmPrefixes) {
- this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes, (name) -> false);
- if (nestedDependencies != null) {
- loadNestedDependencies(parent, nestedDependencies);
- }
- }
-
- public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent,
- final Predicate parentFilter, final Predicate childFirstFilter,
- final String[] nestedDependencies, final String[] jvmPrefixes, final Predicate resourcesFilter) {
- this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes, resourcesFilter);
+ this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes);
if (nestedDependencies != null) {
loadNestedDependencies(parent, nestedDependencies);
}
@@ -136,14 +124,12 @@ public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoa
private ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent,
final Predicate parentFilter, final Predicate childFirstFilter,
- final Map> resources, final String[] jvmPrefixes,
- final Predicate resourcesFilter) {
+ final Map> resources, final String[] jvmPrefixes) {
super(urls, parent);
this.id = id;
this.creationUrls = urls;
this.parentFilter = parentFilter;
this.childFirstFilter = childFirstFilter;
- this.resourcesFilter = resourcesFilter;
this.resources.putAll(resources);
this.fullPathJvmPrefixes =
@@ -246,7 +232,7 @@ public void registerTransformer(final ClassFileTransformer transformer) {
public synchronized URLClassLoader createTemporaryCopy() {
final ConfigurableClassLoader self = this;
return temporaryCopy == null ? temporaryCopy = new ConfigurableClassLoader(id, creationUrls, getParent(),
- parentFilter, childFirstFilter, resources, fullPathJvmPrefixes, resourcesFilter) {
+ parentFilter, childFirstFilter, resources, fullPathJvmPrefixes) {
@Override
public synchronized void close() throws IOException {
@@ -489,12 +475,6 @@ private boolean isNestedDependencyResource(final String name) {
}
private boolean isInJvm(final URL resource) {
- // Services and parent allowed resources that should always be found by top level classloader.
- // By default, META-INF/services/ is always allowed otherwise SPI won't work properly in nested environments.
- // Warning: selection shouldn't be too generic! Use very specific paths only like jndi.properties.
- if (resourcesFilter.test(resource.getFile())) {
- return true;
- }
final Path path = toPath(resource);
if (path == null) {
return false;
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java b/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java
index 8990bfbe45030..287e580ae72ad 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java
@@ -145,8 +145,7 @@ public Container(final String id, final String rootModule, final Artifact[] depe
: null;
final ConfigurableClassLoader loader = new ConfigurableClassLoader(id, urls,
overrideClassLoaderConfig.getParent(), overrideClassLoaderConfig.getParentClassesFilter(),
- overrideClassLoaderConfig.getClassesFilter(), rawNestedDependencies, jvmMarkers,
- overrideClassLoaderConfig.getParentResourcesFilter());
+ overrideClassLoaderConfig.getClassesFilter(), rawNestedDependencies, jvmMarkers);
transformers.forEach(loader::registerTransformer);
activeSpecificTransformers(loader);
return loader;
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index 9995b12da2932..b5579f3ecfa67 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -125,7 +125,6 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe
ofNullable(classLoaderConfiguration.getParent()).orElseGet(ContainerManager.class::getClassLoader),
ofNullable(classLoaderConfiguration.getClassesFilter()).orElseGet(() -> name -> true),
ofNullable(classLoaderConfiguration.getParentClassesFilter()).orElseGet(() -> name -> true),
- ofNullable(classLoaderConfiguration.getParentResourcesFilter()).orElseGet(() -> name -> true),
classLoaderConfiguration.isSupportsResourceDependencies(), nestedPluginMappingResource);
if (classLoaderConfiguration.isSupportsResourceDependencies()) {
try (final InputStream mappingStream =
@@ -452,8 +451,6 @@ public static class ClassLoaderConfiguration {
private final Predicate parentClassesFilter;
- private final Predicate parentResourcesFilter;
-
// is nested jar in jar supported (1 level only)
private final boolean supportsResourceDependencies;
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
index 70d0fe75f0416..c061f2d95caec 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
@@ -32,7 +32,6 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
-import java.util.Properties;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.jar.JarFile;
@@ -62,8 +61,8 @@ public class MvnDependencyListLocalRepositoryResolver implements Resolver {
@Override
public Stream resolve(final ClassLoader rootLoader, final String artifact) {
- return Stream.of(
- readDependencies(ofNullable(getJar(artifact))
+ return Stream
+ .of(readDependencies(ofNullable(getJar(artifact))
.filter(Files::exists)
.map(this::findDependenciesFile)
.orElseGet(() -> {
@@ -99,26 +98,7 @@ public Stream resolve(final ClassLoader rootLoader, final String artif
}
return "";
- })), readDynamicDependencies(rootLoader, artifact));
- }
-
- private String readDynamicDependencies(ClassLoader rootLoader, String artifact) {
- try (final InputStream stream = rootLoader.getResourceAsStream("TALEND-INF/dynamic-dependencies.properties")) {
- if (stream == null) {
- return "";
- }
- final Properties properties = new Properties() {
-
- {
- load(stream);
- }
- };
- final String dyndeps = properties.getProperty(artifact, "");
- return dyndeps.replaceAll(",", System.lineSeparator());
- } catch (final IOException e) {
- log.debug(e.getMessage(), e);
- return "";
- }
+ })));
}
private Path getJar(final String artifact) {
From f92f29dde20031c34abcefab87e349e622d969ca Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Mon, 22 Dec 2025 19:04:57 +0100
Subject: [PATCH 04/41] feat(QTDI-2134): parent resources filtering
---
.../classloader/ConfigurableClassLoader.java | 26 ++++++++++++++++---
.../sdk/component/container/Container.java | 3 ++-
.../component/container/ContainerManager.java | 3 +++
3 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
index 5e75d9ebdf5fa..e62328e557796 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
@@ -92,6 +92,9 @@ public class ConfigurableClassLoader extends URLClassLoader {
@Getter
private final Predicate childFirstFilter;
+ @Getter
+ private final Predicate resourcesFilter;
+
private final Map> resources = new HashMap<>();
private final Collection transformers = new ArrayList<>();
@@ -116,7 +119,16 @@ public class ConfigurableClassLoader extends URLClassLoader {
public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent,
final Predicate parentFilter, final Predicate childFirstFilter,
final String[] nestedDependencies, final String[] jvmPrefixes) {
- this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes);
+ this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes, (name) -> false);
+ if (nestedDependencies != null) {
+ loadNestedDependencies(parent, nestedDependencies);
+ }
+ }
+
+ public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent,
+ final Predicate parentFilter, final Predicate childFirstFilter,
+ final String[] nestedDependencies, final String[] jvmPrefixes, final Predicate resourcesFilter) {
+ this(id, urls, parent, parentFilter, childFirstFilter, emptyMap(), jvmPrefixes, resourcesFilter);
if (nestedDependencies != null) {
loadNestedDependencies(parent, nestedDependencies);
}
@@ -124,12 +136,14 @@ public ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoa
private ConfigurableClassLoader(final String id, final URL[] urls, final ClassLoader parent,
final Predicate parentFilter, final Predicate childFirstFilter,
- final Map> resources, final String[] jvmPrefixes) {
+ final Map> resources, final String[] jvmPrefixes,
+ final Predicate resourcesFilter) {
super(urls, parent);
this.id = id;
this.creationUrls = urls;
this.parentFilter = parentFilter;
this.childFirstFilter = childFirstFilter;
+ this.resourcesFilter = resourcesFilter;
this.resources.putAll(resources);
this.fullPathJvmPrefixes =
@@ -232,7 +246,7 @@ public void registerTransformer(final ClassFileTransformer transformer) {
public synchronized URLClassLoader createTemporaryCopy() {
final ConfigurableClassLoader self = this;
return temporaryCopy == null ? temporaryCopy = new ConfigurableClassLoader(id, creationUrls, getParent(),
- parentFilter, childFirstFilter, resources, fullPathJvmPrefixes) {
+ parentFilter, childFirstFilter, resources, fullPathJvmPrefixes, resourcesFilter) {
@Override
public synchronized void close() throws IOException {
@@ -475,6 +489,12 @@ private boolean isNestedDependencyResource(final String name) {
}
private boolean isInJvm(final URL resource) {
+ // Services and parent allowed resources that should always be found by top level classloader.
+ // By default, META-INF/services/ is always allowed otherwise SPI won't work properly in nested environments.
+ // Warning: selection shouldn't be too generic! Use very specific paths only like jndi.properties.
+ if (resourcesFilter.test(resource.getFile())) {
+ return true;
+ }
final Path path = toPath(resource);
if (path == null) {
return false;
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java b/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java
index 287e580ae72ad..8990bfbe45030 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/Container.java
@@ -145,7 +145,8 @@ public Container(final String id, final String rootModule, final Artifact[] depe
: null;
final ConfigurableClassLoader loader = new ConfigurableClassLoader(id, urls,
overrideClassLoaderConfig.getParent(), overrideClassLoaderConfig.getParentClassesFilter(),
- overrideClassLoaderConfig.getClassesFilter(), rawNestedDependencies, jvmMarkers);
+ overrideClassLoaderConfig.getClassesFilter(), rawNestedDependencies, jvmMarkers,
+ overrideClassLoaderConfig.getParentResourcesFilter());
transformers.forEach(loader::registerTransformer);
activeSpecificTransformers(loader);
return loader;
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index b5579f3ecfa67..9995b12da2932 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -125,6 +125,7 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe
ofNullable(classLoaderConfiguration.getParent()).orElseGet(ContainerManager.class::getClassLoader),
ofNullable(classLoaderConfiguration.getClassesFilter()).orElseGet(() -> name -> true),
ofNullable(classLoaderConfiguration.getParentClassesFilter()).orElseGet(() -> name -> true),
+ ofNullable(classLoaderConfiguration.getParentResourcesFilter()).orElseGet(() -> name -> true),
classLoaderConfiguration.isSupportsResourceDependencies(), nestedPluginMappingResource);
if (classLoaderConfiguration.isSupportsResourceDependencies()) {
try (final InputStream mappingStream =
@@ -451,6 +452,8 @@ public static class ClassLoaderConfiguration {
private final Predicate parentClassesFilter;
+ private final Predicate parentResourcesFilter;
+
// is nested jar in jar supported (1 level only)
private final boolean supportsResourceDependencies;
From 26a5079a456672d581339ea430f3b69cc762f3d0 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Mon, 5 Jan 2026 16:32:31 +0100
Subject: [PATCH 05/41] feat(QTDI-2134): reintroduce MAVEN-INF resolve
---
...DependencyListLocalRepositoryResolver.java | 93 ++++++++++++-------
1 file changed, 59 insertions(+), 34 deletions(-)
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
index c061f2d95caec..34687b5e82505 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
@@ -32,6 +32,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
+import java.util.Properties;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.jar.JarFile;
@@ -61,44 +62,68 @@ public class MvnDependencyListLocalRepositoryResolver implements Resolver {
@Override
public Stream resolve(final ClassLoader rootLoader, final String artifact) {
- return Stream
- .of(readDependencies(ofNullable(getJar(artifact))
- .filter(Files::exists)
- .map(this::findDependenciesFile)
- .orElseGet(() -> {
- final boolean isNested;
- try (final InputStream stream = rootLoader
- .getResourceAsStream(ConfigurableClassLoader.NESTED_MAVEN_REPOSITORY + artifact)) {
- isNested = stream != null;
- } catch (final IOException e) {
- log.debug(e.getMessage(), e);
- return "";
- }
+ final String standardDeps = ofNullable(getJar(artifact))
+ .filter(Files::exists)
+ .map(this::findDependenciesFile)
+ .orElseGet(() -> {
+ final boolean isNested;
+ try (final InputStream stream = rootLoader
+ .getResourceAsStream(ConfigurableClassLoader.NESTED_MAVEN_REPOSITORY + artifact)) {
+ isNested = stream != null;
+ } catch (final IOException e) {
+ log.debug(e.getMessage(), e);
+ return "";
+ }
- if (isNested) { // we reuse ConfigurableClassLoader just to not
- // rewrite the logic but it is NOT a plugin!
- try (final ConfigurableClassLoader configurableClassLoader =
- new ConfigurableClassLoader("", new URL[0], rootLoader, name -> true,
- name -> true, new String[] { artifact }, new String[0])) {
- try (final InputStream deps =
- configurableClassLoader.getResourceAsStream(dependenciesListFile)) {
- return ofNullable(deps).map(s -> {
- try {
- return slurp(s);
- } catch (final IOException e) {
- log.debug(e.getMessage(), e);
- return "";
- }
- }).orElse("");
+ if (isNested) { // we reuse ConfigurableClassLoader just to not
+ // rewrite the logic but it is NOT a plugin!
+ try (final ConfigurableClassLoader configurableClassLoader =
+ new ConfigurableClassLoader("", new URL[0], rootLoader, name -> true,
+ name -> true, new String[] { artifact }, new String[0])) {
+ try (final InputStream deps =
+ configurableClassLoader.getResourceAsStream(dependenciesListFile)) {
+ return ofNullable(deps).map(s -> {
+ try {
+ return slurp(s);
+ } catch (final IOException e) {
+ log.debug(e.getMessage(), e);
+ return "";
}
- } catch (final IOException e) {
- log.debug(e.getMessage(), e);
- return "";
- }
+ }).orElse("");
}
-
+ } catch (final IOException e) {
+ log.debug(e.getMessage(), e);
return "";
- })));
+ }
+ }
+
+ return "";
+ });
+ final String dynamicDeps = findDynamicDependencies(rootLoader, artifact);
+ final String allDeps = Stream.of(standardDeps, dynamicDeps)
+ .filter(s -> !s.isEmpty())
+ .collect(joining(System.lineSeparator()));
+
+ return Stream.of(readDependencies(allDeps));
+ }
+
+ private String findDynamicDependencies(final ClassLoader rootLoader, final String artifact) {
+ try (final InputStream stream = rootLoader.getResourceAsStream("TALEND-INF/dynamic-dependencies.properties")) {
+ if (stream == null) {
+ return "";
+ }
+ final Properties properties = new Properties() {
+
+ {
+ load(stream);
+ }
+ };
+ final String dyndeps = properties.getProperty(artifact, "");
+ return dyndeps.replaceAll(",", System.lineSeparator());
+ } catch (final IOException e) {
+ log.debug(e.getMessage(), e);
+ return "";
+ }
}
private Path getJar(final String artifact) {
From 9589b3c29911252466220b0030054f17f6353d36 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Tue, 6 Jan 2026 18:52:06 +0100
Subject: [PATCH 06/41] feat(QTDI-2134): parentFilterResource configuration
---
.../runtime/manager/ComponentManager.java | 33 ++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
index 446b262fd3ebd..7f6843def8670 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
@@ -113,6 +113,7 @@
import org.apache.xbean.finder.archive.FileArchive;
import org.apache.xbean.finder.archive.FilteredArchive;
import org.apache.xbean.finder.archive.JarArchive;
+import org.apache.xbean.finder.filter.ContainsFilter;
import org.apache.xbean.finder.filter.ExcludeIncludeFilter;
import org.apache.xbean.finder.filter.Filter;
import org.apache.xbean.finder.filter.FilterList;
@@ -315,6 +316,8 @@ public String[] categories() {
// + tcomp "runtime" indeed (invisible from the components but required for the runtime
private final Filter classesFilter;
+ private final Filter resourcesFilter;
+
private final ParameterModelService parameterModelService;
private final InternationalizationServiceFactory internationalizationServiceFactory;
@@ -429,7 +432,12 @@ public ComponentManager(final Path m2, final String dependenciesResource, final
.distinct()
.map(PrefixFilter::new)
.toArray(Filter[]::new));
-
+ resourcesFilter = new FilterList(Stream.concat(
+ Stream.of("META-INF/services/"),
+ additionalParentResources())
+ .distinct()
+ .map(ContainsFilter::new)
+ .toArray(Filter[]::new));
jsonpProvider = loadJsonProvider();
jsonbProvider = loadJsonbProvider();
// these factories have memory caches so ensure we reuse them properly
@@ -463,6 +471,7 @@ public ComponentManager(final Path m2, final String dependenciesResource, final
migrationHandlerFactory = new MigrationHandlerFactory(reflections);
final Predicate isContainerClass = name -> isContainerClass(classesFilter, name);
+ final Predicate isParentResource = name -> isParentResource(resourcesFilter, name);
final ContainerManager.ClassLoaderConfiguration defaultClassLoaderConfiguration =
ContainerManager.ClassLoaderConfiguration
.builder()
@@ -470,6 +479,7 @@ public ComponentManager(final Path m2, final String dependenciesResource, final
.parentClassesFilter(isContainerClass)
.classesFilter(isContainerClass.negate())
.supportsResourceDependencies(true)
+ .parentResourcesFilter(isParentResource)
.create();
this.container = new ContainerManager(ContainerManager.DependenciesResolutionConfiguration
.builder()
@@ -614,6 +624,16 @@ private Stream additionalContainerClasses() {
.orElseGet(Stream::empty));
}
+ private Stream additionalParentResources() {
+ return Stream
+ .concat(customizers.stream().flatMap(Customizer::parentResources),
+ ofNullable(
+ System.getProperty("talend.component.manager.classloader.container.parentResources"))
+ .map(s -> s.split(","))
+ .map(Stream::of)
+ .orElseGet(Stream::empty));
+ }
+
public static Path findM2() {
return new MavenRepositoryDefaultResolver().discover();
}
@@ -1048,6 +1068,10 @@ protected boolean isContainerClass(final Filter filter, final String name) {
return name != null && filter.accept(name);
}
+ protected boolean isParentResource(final Filter filter, final String name) {
+ return name != null && filter.accept(name);
+ }
+
@Override
public void close() {
container.close();
@@ -2210,6 +2234,13 @@ public interface Customizer {
*/
Stream containerClassesAndPackages();
+ /**
+ * @return
+ */
+ default Stream parentResources() {
+ return Stream.empty();
+ }
+
/**
* @return advanced toggle to ignore built-in beam exclusions and let this customizer override them.
*/
From 82d0275a72abe6070b3804d4e28974a667a0a599 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Thu, 8 Jan 2026 11:01:16 +0100
Subject: [PATCH 07/41] feat(QTDI-2134): doc for configuration type
---
.../pages/_partials/generated_configuration-types.adoc | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/documentation/src/main/antora/modules/ROOT/pages/_partials/generated_configuration-types.adoc b/documentation/src/main/antora/modules/ROOT/pages/_partials/generated_configuration-types.adoc
index 3fa442503bb76..00241ce1bc0c3 100644
--- a/documentation/src/main/antora/modules/ROOT/pages/_partials/generated_configuration-types.adoc
+++ b/documentation/src/main/antora/modules/ROOT/pages/_partials/generated_configuration-types.adoc
@@ -47,18 +47,18 @@ Mark a model (complex object) as being a dataset discovery configuration.
----
-= DynamicDependenciesServiceConfiguration
+= DynamicDependenciesConfiguration
-Mark a model (complex object) as being the configuration used in services annotated with @DynamicDependencies.
+Mark a model (complex object) as being the configuration expected to compute dynamic dependencies.
-- API: @org.talend.sdk.component.api.configuration.type.DynamicDependenciesServiceConfiguration
+- API: @org.talend.sdk.component.api.configuration.type.DynamicDependenciesConfiguration
- Sample:
[source,js]
----
{
"tcomp::configurationtype::name":"test",
- "tcomp::configurationtype::type":"dynamicDependenciesServiceConfiguration"
+ "tcomp::configurationtype::type":"dynamicDependenciesConfiguration"
}
----
From 7abd065f806060aaaf8dd00042fefc77a96f2165 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Mon, 12 Jan 2026 11:28:19 +0100
Subject: [PATCH 08/41] feat(QTDI-2134): fix module lookup in
dynamic-dependencies.properties
---
.../sdk/component/container/ContainerManager.java | 10 +++-------
.../MvnDependencyListLocalRepositoryResolver.java | 4 +++-
2 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index 9995b12da2932..96ab203d34d22 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -103,10 +103,6 @@ public class ContainerManager implements Lifecycle {
private final boolean hasNestedRepository;
- private final Pattern versionWithJiraIssue = Pattern.compile("-[A-Z]{2,}-\\d+$");
-
- private final Pattern versionWithMilestone = Pattern.compile("M\\d+$");
-
public ContainerManager(final DependenciesResolutionConfiguration dependenciesResolutionConfiguration,
final ClassLoaderConfiguration classLoaderConfiguration, final Consumer containerInitializer,
final Level logInfoLevelMapping) {
@@ -265,7 +261,7 @@ public ContainerBuilder builder(final String module) {
return builder(buildAutoIdFromName(module), module);
}
- public String buildAutoIdFromName(final String module) {
+ public static String buildAutoIdFromName(final String module) {
final String[] segments = module.split(":");
if (segments.length > 2) { // == 2 can be a windows path so enforce > 2 but then
// assume it is mvn GAV
@@ -281,11 +277,11 @@ public String buildAutoIdFromName(final String module) {
if (autoId.endsWith("-SNAPSHOT")) {
autoId = autoId.substring(0, autoId.length() - "-SNAPSHOT".length());
}
- final Matcher jiraTicket = versionWithJiraIssue.matcher(autoId);
+ final Matcher jiraTicket = Pattern.compile("-[A-Z]{2,}-\\d+$").matcher(autoId);
if (jiraTicket.find()) {
autoId = autoId.substring(0, jiraTicket.start());
}
- final Matcher milestone = versionWithMilestone.matcher(autoId);
+ final Matcher milestone = Pattern.compile("M\\d+$").matcher(autoId);
if (milestone.find()) {
autoId = autoId.substring(0, milestone.start());
}
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
index 34687b5e82505..901e4caa69001 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
@@ -40,6 +40,7 @@
import java.util.zip.ZipEntry;
import org.talend.sdk.component.classloader.ConfigurableClassLoader;
+import org.talend.sdk.component.container.ContainerManager;
import org.talend.sdk.component.dependencies.Resolver;
import org.talend.sdk.component.path.PathFactory;
@@ -118,7 +119,8 @@ private String findDynamicDependencies(final ClassLoader rootLoader, final Strin
load(stream);
}
};
- final String dyndeps = properties.getProperty(artifact, "");
+ final String module = ContainerManager.buildAutoIdFromName(artifact);
+ final String dyndeps = properties.getProperty(module, "");
return dyndeps.replaceAll(",", System.lineSeparator());
} catch (final IOException e) {
log.debug(e.getMessage(), e);
From 0c0de56eebd51174fb9c55625d0b445ddc5bd3b9 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Mon, 12 Jan 2026 16:40:39 +0100
Subject: [PATCH 09/41] feat(QTDI-2134): fix NestedJarArchive in OSGI env
---
.../runtime/manager/ComponentManager.java | 29 ++++++++++++++-----
1 file changed, 21 insertions(+), 8 deletions(-)
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
index 7f6843def8670..4df946448951e 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
@@ -925,13 +925,26 @@ private void autoDiscoverPlugins0(final boolean callers, final boolean classpath
final Enumeration componentMarkers =
Thread.currentThread().getContextClassLoader().getResources("TALEND-INF/dependencies.txt");
while (componentMarkers.hasMoreElements()) {
- File file = Files.toFile(componentMarkers.nextElement());
- if (file.getName().equals("dependencies.txt") && file.getParentFile() != null
- && file.getParentFile().getName().equals("TALEND-INF")) {
- file = file.getParentFile().getParentFile();
- }
- if (!hasPlugin(container.buildAutoIdFromName(file.getName()))) {
- addPlugin(file.getAbsolutePath());
+ final URL marker = componentMarkers.nextElement();
+ File file = Files.toFile(marker);
+ if (file != null) {
+ if (file.getName().equals("dependencies.txt") && file.getParentFile() != null
+ && file.getParentFile().getName().equals("TALEND-INF")) {
+ file = file.getParentFile().getParentFile();
+ }
+ if (!hasPlugin(container.buildAutoIdFromName(file.getName()))) {
+ addPlugin(file.getAbsolutePath());
+ }
+ } else {
+ // lookup nested jar
+ if (marker != null && "jar".equals(marker.getProtocol())) {
+ final String urlFile = marker.getFile();
+ final String jarPath = urlFile.substring(0, urlFile.lastIndexOf("!"));
+ final String jarFilePath = jarPath.substring(jarPath.lastIndexOf("/") + 1);
+ if (!hasPlugin(container.buildAutoIdFromName(jarFilePath))) {
+ addPlugin(jarPath);
+ }
+ }
}
}
} catch (final IOException e) {
@@ -1749,7 +1762,7 @@ private Archive toArchive(final String module, final OriginalId originalId,
return true;
}).map(nested -> {
if ("nested".equals(nested.getProtocol())
- || (nested.getPath() != null && nested.getPath().contains("!/MAVEN-INF/repository/"))) {
+ || (nested.getPath() != null && nested.getPath().contains(NESTED_MAVEN_REPOSITORY))) {
JarInputStream jarStream = null;
try {
jarStream = new JarInputStream(nested.openStream());
From d68b742d17157cad536d3d7c3d8d059541b9361f Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Tue, 3 Feb 2026 15:57:02 +0100
Subject: [PATCH 10/41] feat(QTDI-2134): remove "META-INF/services" from
default parent resources
---
.../sdk/component/runtime/manager/ComponentManager.java | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
index 4df946448951e..4c3cbe0aa0cfa 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
@@ -432,9 +432,7 @@ public ComponentManager(final Path m2, final String dependenciesResource, final
.distinct()
.map(PrefixFilter::new)
.toArray(Filter[]::new));
- resourcesFilter = new FilterList(Stream.concat(
- Stream.of("META-INF/services/"),
- additionalParentResources())
+ resourcesFilter = new FilterList(additionalParentResources()
.distinct()
.map(ContainsFilter::new)
.toArray(Filter[]::new));
From a27725a6c22cdb57f19b944215a497321f7669af Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Mon, 9 Feb 2026 11:42:08 +0100
Subject: [PATCH 11/41] feat(QTDI-2134): analyse classpath and use it for
resolve
---
.../component/container/ContainerManager.java | 67 ++++++++++++++++++-
1 file changed, 65 insertions(+), 2 deletions(-)
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index 19d920a3e0107..979dc6d22c68e 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -103,6 +103,8 @@ public class ContainerManager implements Lifecycle {
private final boolean hasNestedRepository;
+ private final List runtimeClasspath = new ArrayList<>();
+
public ContainerManager(final DependenciesResolutionConfiguration dependenciesResolutionConfiguration,
final ClassLoaderConfiguration classLoaderConfiguration, final Consumer containerInitializer,
final Level logInfoLevelMapping) {
@@ -114,7 +116,7 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe
if (log.isDebugEnabled()) {
getSystemInformations();
}
-
+ readRuntimeClasspath();
final String nestedPluginMappingResource = ofNullable(classLoaderConfiguration.getNestedPluginMappingResource())
.orElse("TALEND-INF/plugins.properties");
this.classLoaderConfiguration = new ClassLoaderConfiguration(
@@ -168,6 +170,55 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe
}
}
+ /**
+ * Catch the runtime classpath to be able to resolve plugins from it if needed.
+ * This may be useful in case of running in an environment like jobServer where
+ * the classpath is not linked to a single directory like `../lib` but scattered
+ * through cache dirs.
+ */
+ private void readRuntimeClasspath() {
+ try {
+ final RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
+ final String classpath = rt.getClassPath();
+ if ("classpath.jar".equals(classpath)) {
+ // read MANIFEST.MF in "classpath.jar" to get classpath jars' list
+ final Path cpJar = PathFactory.get("classpath.jar");
+ if (Files.exists(cpJar)) {
+ try (InputStream is = Files.newInputStream(cpJar)) {
+ final java.util.jar.JarInputStream jarStream = new java.util.jar.JarInputStream(is);
+ final java.util.jar.Manifest manifest = jarStream.getManifest();
+ if (manifest != null) {
+ final String cp = manifest.getMainAttributes().getValue("Class-Path");
+ if (cp != null) {
+ Stream.of(cp.split(" "))
+ .filter(c -> !c.equals(".") || !c.trim().isEmpty())
+ .map(PathFactory::get)
+ .filter(Files::exists)
+ .forEach(p -> {
+ runtimeClasspath.add(p.toAbsolutePath().toString());
+ log.debug("[sysinfo] Runtime classpath entry (manifest): "
+ + p.toAbsolutePath());
+ });
+ }
+ }
+ } catch (IOException e) {
+ info("Unable to read classpath.jar manifest: " + e.getMessage());
+ }
+ }
+ } else {
+ Stream.of(classpath.split(File.pathSeparator))
+ .map(PathFactory::get)
+ .filter(Files::exists)
+ .forEach(p -> {
+ runtimeClasspath.add(p.toAbsolutePath().toString());
+ log.debug("[sysinfo] Runtime classpath entry: " + p.toAbsolutePath());
+ });
+ }
+ } catch (Exception e) {
+ info("Unable to get runtime classpath: " + e.getMessage());
+ }
+ }
+
public File getRootRepositoryLocation() {
return rootRepositoryLocation.toFile();
}
@@ -247,12 +298,24 @@ public Path resolve(final String path) {
return file;
}
+ final String artifactName = path.substring(path.lastIndexOf('/') + 1);
// from job lib folder
- final Path libFile = rootRepositoryLocation.resolve(path.substring(path.lastIndexOf('/') + 1));
+ final Path libFile = rootRepositoryLocation.resolve(artifactName);
if (Files.exists(libFile)) {
return libFile;
}
+ // try to find it in the runtime classpath
+ final Optional rtcpFile = runtimeClasspath.stream()
+ .filter(p -> p.endsWith(artifactName) && p.contains(File.separator + artifactName))
+ .findFirst();
+ if (rtcpFile.isPresent()) {
+ final Path cpFile = PathFactory.get(rtcpFile.get());
+ if (Files.exists(cpFile)) {
+ return cpFile;
+ }
+ }
+
// will be filtered later
return file;
}
From 238294cee300bf5fa745e4b69c317198c07654d6 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Tue, 10 Feb 2026 14:16:47 +0100
Subject: [PATCH 12/41] feat(QTDI-2134): improve classpath feed for resolve
---
.../component/container/ContainerManager.java | 115 ++++++++++--------
1 file changed, 66 insertions(+), 49 deletions(-)
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index 979dc6d22c68e..c77125fc768f9 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -15,6 +15,7 @@
*/
package org.talend.sdk.component.container;
+import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
import static java.util.Collections.list;
import static java.util.Optional.of;
@@ -103,6 +104,7 @@ public class ContainerManager implements Lifecycle {
private final boolean hasNestedRepository;
+ @Getter
private final List runtimeClasspath = new ArrayList<>();
public ContainerManager(final DependenciesResolutionConfiguration dependenciesResolutionConfiguration,
@@ -170,55 +172,6 @@ public ContainerManager(final DependenciesResolutionConfiguration dependenciesRe
}
}
- /**
- * Catch the runtime classpath to be able to resolve plugins from it if needed.
- * This may be useful in case of running in an environment like jobServer where
- * the classpath is not linked to a single directory like `../lib` but scattered
- * through cache dirs.
- */
- private void readRuntimeClasspath() {
- try {
- final RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
- final String classpath = rt.getClassPath();
- if ("classpath.jar".equals(classpath)) {
- // read MANIFEST.MF in "classpath.jar" to get classpath jars' list
- final Path cpJar = PathFactory.get("classpath.jar");
- if (Files.exists(cpJar)) {
- try (InputStream is = Files.newInputStream(cpJar)) {
- final java.util.jar.JarInputStream jarStream = new java.util.jar.JarInputStream(is);
- final java.util.jar.Manifest manifest = jarStream.getManifest();
- if (manifest != null) {
- final String cp = manifest.getMainAttributes().getValue("Class-Path");
- if (cp != null) {
- Stream.of(cp.split(" "))
- .filter(c -> !c.equals(".") || !c.trim().isEmpty())
- .map(PathFactory::get)
- .filter(Files::exists)
- .forEach(p -> {
- runtimeClasspath.add(p.toAbsolutePath().toString());
- log.debug("[sysinfo] Runtime classpath entry (manifest): "
- + p.toAbsolutePath());
- });
- }
- }
- } catch (IOException e) {
- info("Unable to read classpath.jar manifest: " + e.getMessage());
- }
- }
- } else {
- Stream.of(classpath.split(File.pathSeparator))
- .map(PathFactory::get)
- .filter(Files::exists)
- .forEach(p -> {
- runtimeClasspath.add(p.toAbsolutePath().toString());
- log.debug("[sysinfo] Runtime classpath entry: " + p.toAbsolutePath());
- });
- }
- } catch (Exception e) {
- info("Unable to get runtime classpath: " + e.getMessage());
- }
- }
-
public File getRootRepositoryLocation() {
return rootRepositoryLocation.toFile();
}
@@ -479,6 +432,70 @@ private void getSystemInformations() {
}
}
+ /**
+ * Catch the runtime classpath to be able to resolve plugins from it if needed.
+ * This may be useful in case of running in an environment like jobServer where
+ * the classpath is not linked to a single directory like `../lib` but scattered
+ * through cache dirs.
+ */
+ private void readRuntimeClasspath() {
+ try {
+ final RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
+ final String classpath = rt.getClassPath();
+ Stream.of(classpath.split(File.pathSeparator))
+ .filter(p -> p.endsWith(".jar"))
+ .map(PathFactory::get)
+ .filter(Files::exists)
+ .forEach(p -> {
+ if ("classpath.jar".equals(p.getFileName().toString())) {
+ runtimeClasspath.addAll(getClasspathFromJar(p));
+ } else {
+ runtimeClasspath.add(p.toAbsolutePath().toString());
+ log.debug("[sysinfo] Runtime classpath entry: " + p.toAbsolutePath());
+ }
+ });
+ // cleanup the classpath from entries that are known as framework artifacts
+ final Predicate frameworkFilter = p -> p.matches(".*" + File.separatorChar +
+ "(container-core|component-api|component-spi|component-runtime-impl|component-runtime-manager|" +
+ "component-spi|component-runtime-design-extension|component-runtime-di|geronimo|johnzon|xbean|slf4j|log4j|log4j2)"
+ + "-.*jar$");
+ runtimeClasspath.removeIf(p -> frameworkFilter.test(p));
+ } catch (Exception e) {
+ info("Unable to get runtime classpath: " + e.getMessage());
+ }
+ }
+
+ /**
+ * In some environments like jobServer, the classpath can be set to a single "classpath.jar" file containing in its
+ * manifest the list of real classpath entries.
+ * In this case we need to read MANIFEST.MF in "classpath.jar" to get classpath jars' list
+ *
+ * @param jar
+ * @return classpath entries defined in the manifest of the given jar, or an empty list if the manifest can't be
+ * read or doesn't contain a Class-Path entry
+ */
+ private List getClasspathFromJar(final Path jar) {
+ try (final java.util.jar.JarFile jarFile = new java.util.jar.JarFile(jar.toFile())) {
+ final java.util.jar.Manifest manifest = jarFile.getManifest();
+ if (manifest != null) {
+ final String cp = manifest.getMainAttributes().getValue("Class-Path");
+ if (cp != null) {
+ return Stream.of(cp.split(" "))
+ .filter(c -> !c.equals(".") || !c.trim().isEmpty())
+ .filter(c -> c.endsWith(".jar"))
+ .map(PathFactory::get)
+ .filter(Files::exists)
+ .map(p -> p.toAbsolutePath().toString())
+ .peek(p -> log.debug("[sysinfo] Runtime classpath entry from manifest: " + p))
+ .collect(toList());
+ }
+ }
+ } catch (IOException e) {
+ info("Unable to read " + jar + " manifest: " + e.getMessage());
+ }
+ return emptyList();
+ }
+
@Override
public void close() {
lifecycle.closeIfNeeded(() -> {
From db4dd22f3f107a61feb834a050a13d6d3db6ce25 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Tue, 10 Feb 2026 15:17:26 +0100
Subject: [PATCH 13/41] feat(QTDI-2134): fix framework filter
---
.../talend/sdk/component/container/ContainerManager.java | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index c77125fc768f9..ba238dd2419be 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -456,8 +456,10 @@ private void readRuntimeClasspath() {
});
// cleanup the classpath from entries that are known as framework artifacts
final Predicate frameworkFilter = p -> p.matches(".*" + File.separatorChar +
- "(container-core|component-api|component-spi|component-runtime-impl|component-runtime-manager|" +
- "component-spi|component-runtime-design-extension|component-runtime-di|geronimo|johnzon|xbean|slf4j|log4j|log4j2)"
+ "(component-api|component-runtime-design-extension|component-runtime-di|component-runtime-impl|" +
+ "component-runtime-manager|component-spi|container-core|geronimo-annotation_1.3_spec|" +
+ "geronimo-json_1.1_spec|geronimo-jsonb_1.0_spec|johnzon-core|johnzon-jsonb|johnzon-mapper|" +
+ "slf4j-api|slf4j-log4j12|slf4j-reload4j|xbean-asm9-shaded|xbean-finder-shaded|xbean-reflect-)"
+ "-.*jar$");
runtimeClasspath.removeIf(p -> frameworkFilter.test(p));
} catch (Exception e) {
From 146a4689fd3f32bedffdc160b869e47156abb27d Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Tue, 10 Feb 2026 15:53:23 +0100
Subject: [PATCH 14/41] feat(QTDI-2134): fix framework filter xbean + rhino
---
.../org/talend/sdk/component/container/ContainerManager.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index ba238dd2419be..de12cf9651967 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -459,7 +459,7 @@ private void readRuntimeClasspath() {
"(component-api|component-runtime-design-extension|component-runtime-di|component-runtime-impl|" +
"component-runtime-manager|component-spi|container-core|geronimo-annotation_1.3_spec|" +
"geronimo-json_1.1_spec|geronimo-jsonb_1.0_spec|johnzon-core|johnzon-jsonb|johnzon-mapper|" +
- "slf4j-api|slf4j-log4j12|slf4j-reload4j|xbean-asm9-shaded|xbean-finder-shaded|xbean-reflect-)"
+ "rhino|slf4j-api|slf4j-log4j12|slf4j-reload4j|xbean-asm9-shaded|xbean-finder-shaded|xbean-reflect)"
+ "-.*jar$");
runtimeClasspath.removeIf(p -> frameworkFilter.test(p));
} catch (Exception e) {
From 60bedfcdba6dc92937d7d2538c6d117fbdc90939 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Thu, 26 Feb 2026 17:45:39 +0100
Subject: [PATCH 15/41] feat(QTDI-2134): add interface javadoc
---
.../talend/sdk/component/runtime/manager/ComponentManager.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
index ffc740fd8d580..968a11df65593 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
@@ -2246,7 +2246,8 @@ public interface Customizer {
Stream containerClassesAndPackages();
/**
- * @return
+ * @return a stream of string representing resources. They will be considered
+ * as loaded from the "container" (ComponentManager loader) and not the components classloaders.
*/
default Stream parentResources() {
return Stream.empty();
From 28c4dd1d8d2c30184222f755cb6ce5acab21dc0e Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Thu, 26 Feb 2026 17:45:57 +0100
Subject: [PATCH 16/41] feat(QTDI-2134): change visibility for testing
---
.../org/talend/sdk/component/container/ContainerManager.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index de12cf9651967..6bbf41839a188 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -476,7 +476,7 @@ private void readRuntimeClasspath() {
* @return classpath entries defined in the manifest of the given jar, or an empty list if the manifest can't be
* read or doesn't contain a Class-Path entry
*/
- private List getClasspathFromJar(final Path jar) {
+ public List getClasspathFromJar(final Path jar) {
try (final java.util.jar.JarFile jarFile = new java.util.jar.JarFile(jar.toFile())) {
final java.util.jar.Manifest manifest = jarFile.getManifest();
if (manifest != null) {
From 62ce939e16ccfceaadf9962cfb39aaacdc6a17ec Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Thu, 26 Feb 2026 17:46:35 +0100
Subject: [PATCH 17/41] feat(QTDI-2134): add some container-core tests
---
.../sdk/component/ContainerManagerTest.java | 73 +++++++++++++++++++
.../ConfigurableClassLoaderTest.java | 31 ++++++++
...ndencyListLocalRepositoryResolverTest.java | 25 +++++++
3 files changed, 129 insertions(+)
diff --git a/container/container-core/src/test/java/org/talend/sdk/component/ContainerManagerTest.java b/container/container-core/src/test/java/org/talend/sdk/component/ContainerManagerTest.java
index bd96c1d5ef643..8287d9da6c766 100644
--- a/container/container-core/src/test/java/org/talend/sdk/component/ContainerManagerTest.java
+++ b/container/container-core/src/test/java/org/talend/sdk/component/ContainerManagerTest.java
@@ -23,16 +23,25 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.io.TempDir;
import org.talend.sdk.component.container.Container;
import org.talend.sdk.component.container.ContainerListener;
import org.talend.sdk.component.container.ContainerManager;
@@ -151,6 +160,70 @@ void close(final TempJars jars) {
});
}
+ @Test
+ void getClasspathFromJarWithValidManifestClassPath(@TempDir final Path tempDir) throws Exception {
+ final File jar1 = createJarFile(tempDir, "lib1.jar");
+ final File jar2 = createJarFile(tempDir, "lib2.jar");
+ final File mainJar = createJarWithManifest(tempDir, "main.jar",
+ jar1.getAbsolutePath() + " " + jar2.getAbsolutePath());
+
+ try (final ContainerManager containerManager = createDefaultManager()) {
+ final List result = containerManager.getClasspathFromJar(mainJar.toPath());
+
+ assertEquals(2, result.size());
+ assertTrue(result.contains(jar1.getAbsolutePath()));
+ assertTrue(result.contains(jar2.getAbsolutePath()));
+ }
+ }
+
+ @Test
+ void getClasspathFromJarWithNoManifest(@TempDir final Path tempDir) throws Exception {
+ final File jar = createJarFile(tempDir, "noManifest.jar");
+
+ try (final ContainerManager containerManager = createDefaultManager()) {
+ final List result = containerManager.getClasspathFromJar(jar.toPath());
+
+ assertTrue(result.isEmpty());
+ }
+ }
+
+ @Test
+ void getClasspathFromJarWithEmptyClassPath(@TempDir final Path tempDir) throws Exception {
+ final File jar = createJarWithManifest(tempDir, "emptyCP.jar", "");
+
+ try (final ContainerManager containerManager = createDefaultManager()) {
+ final List result = containerManager.getClasspathFromJar(jar.toPath());
+
+ assertTrue(result.isEmpty());
+ }
+ }
+
+ private static File createJarFile(final Path tempDir, final String fileName) throws IOException {
+ final File jar = new File(tempDir.toFile(), fileName);
+ try (final JarOutputStream jos = new JarOutputStream(new FileOutputStream(jar))) {
+ jos.putNextEntry(new ZipEntry("dummy.txt"));
+ jos.write("dummy content".getBytes(StandardCharsets.UTF_8));
+ jos.closeEntry();
+ }
+ return jar;
+ }
+
+ private static File createJarWithManifest(final Path tempDir, final String fileName, final String classPath)
+ throws IOException {
+ final File jar = new File(tempDir.toFile(), fileName);
+ final Manifest manifest = new Manifest();
+ manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
+ if (classPath != null && !classPath.isEmpty()) {
+ manifest.getMainAttributes().put(Attributes.Name.CLASS_PATH, classPath);
+ }
+ try (final JarOutputStream jos = new JarOutputStream(new FileOutputStream(jar), manifest)) {
+ jos.putNextEntry(new ZipEntry("dummy.txt"));
+ jos.write("dummy content".getBytes(StandardCharsets.UTF_8));
+ jos.closeEntry();
+ }
+ return jar;
+ }
+
private File createZiplockJar(final TempJars jars) {
return jars.create("org.apache.tomee:ziplock:jar:" +
"8.0.14");
diff --git a/container/container-core/src/test/java/org/talend/sdk/component/classloader/ConfigurableClassLoaderTest.java b/container/container-core/src/test/java/org/talend/sdk/component/classloader/ConfigurableClassLoaderTest.java
index 3eca4c0a51ee3..20800a7e4ec02 100644
--- a/container/container-core/src/test/java/org/talend/sdk/component/classloader/ConfigurableClassLoaderTest.java
+++ b/container/container-core/src/test/java/org/talend/sdk/component/classloader/ConfigurableClassLoaderTest.java
@@ -20,6 +20,7 @@
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
@@ -344,6 +345,36 @@ void cacheableClasses(@TempDir final File temporaryFolder) throws Exception {
}
}
+ @Test
+ void parentResourceFiltering(@TempDir final File temporaryFolder) throws IOException {
+ final File parentJar = new File(temporaryFolder, "multipleResourceFiltering.jar");
+ temporaryFolder.mkdirs();
+ try (final JarOutputStream outputStream = new JarOutputStream(new FileOutputStream(parentJar))) {
+ outputStream.putNextEntry(new JarEntry("META-INF/services/allowed.Service"));
+ outputStream.write("impl.AllowedService".getBytes(StandardCharsets.UTF_8));
+ outputStream.closeEntry();
+
+ outputStream.putNextEntry(new JarEntry("META-INF/services/filtered.Service"));
+ outputStream.write("impl.FilteredService".getBytes(StandardCharsets.UTF_8));
+ outputStream.closeEntry();
+ }
+
+ try (final URLClassLoader parent =
+ new URLClassLoader(new URL[] { parentJar.toURI().toURL() },
+ Thread.currentThread().getContextClassLoader());
+ final ConfigurableClassLoader loader =
+ new ConfigurableClassLoader("", new URL[0], parent,
+ name -> true, name -> false, new String[0], new String[0],
+ name -> name.contains("allowed"))) {
+ // Allowed service should be found via getResources
+ final Enumeration allowedResources = loader.getResources("META-INF/services/allowed.Service");
+ assertTrue(allowedResources.hasMoreElements());
+ // Filtered service is NOT accessible via getResources (filtered out by resourcesFilter)
+ final Enumeration filteredResources = loader.getResources("META-INF/services/filtered.Service");
+ assertFalse(filteredResources.hasMoreElements());
+ }
+ }
+
private void assertXmlReader() throws SAXException {
final XMLReader xmlReader = XMLReaderFactory.createXMLReader();
final Class extends XMLReader> clazz = xmlReader.getClass();
diff --git a/container/container-core/src/test/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolverTest.java b/container/container-core/src/test/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolverTest.java
index f3c66f6cd71ca..24dc8e15ac050 100644
--- a/container/container-core/src/test/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolverTest.java
+++ b/container/container-core/src/test/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolverTest.java
@@ -33,6 +33,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
+import org.talend.sdk.component.container.ContainerManager;
import org.talend.sdk.component.test.dependencies.DependenciesTxtBuilder;
class MvnDependencyListLocalRepositoryResolverTest {
@@ -95,4 +96,28 @@ void nestedDependencyWithJira(@TempDir final File temporaryFolder) throws IOExce
"org/apache/tomee/javaee-api/7.0-1/javaee-api-7.0-1.jar"), toResolve);
}
}
+
+ @Test
+ void resolveWithDynamicDependencies(@TempDir final File temporaryFolder) throws Exception {
+ final File file = new File(temporaryFolder, UUID.randomUUID().toString() + ".jar");
+ file.getParentFile().mkdirs();
+ final String module = ContainerManager.buildAutoIdFromName("dummy-1.0.0.jar");
+ final String deps = "org.apache.tomee:ziplock:jar:8.0.14:runtime,org.apache.tomee:javaee-api:jar:7.0-1:compile";
+ try (final JarOutputStream jar = new JarOutputStream(new FileOutputStream(file))) {
+ jar.putNextEntry(new ZipEntry("TALEND-INF/dynamic-dependencies.properties"));
+ jar.write((module + "=" + deps).getBytes(StandardCharsets.UTF_8));
+ jar.closeEntry();
+ }
+
+ try (final URLClassLoader tempLoader =
+ new URLClassLoader(new URL[] { file.toURI().toURL() }, getSystemClassLoader())) {
+ final List toResolve =
+ new MvnDependencyListLocalRepositoryResolver("TALEND-INF/dependencies.txt", d -> null)
+ .resolve(tempLoader, "foo/bar/dummy/1.0.0/dummy-1.0.0.jar")
+ .map(Artifact::toPath)
+ .collect(toList());
+ assertEquals(asList("org/apache/tomee/ziplock/8.0.14/ziplock-8.0.14.jar",
+ "org/apache/tomee/javaee-api/7.0-1/javaee-api-7.0-1.jar"), toResolve);
+ }
+ }
}
From 24999a3a00c1970e08c96aeac5f35f3880dfc3de Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Thu, 26 Feb 2026 18:32:10 +0100
Subject: [PATCH 18/41] feat(QTDI-2134): add some optimizations from pr comment
---
.../sdk/component/container/ContainerManager.java | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index 6bbf41839a188..5d84a0e8daacd 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -78,6 +78,10 @@ public class ContainerManager implements Lifecycle {
private static final Consumer NOOP_CUSTOMIZER = c -> {
};
+ private static final Pattern JIRA_TICKET_PATTERN = Pattern.compile("-[A-Z]{2,}-\\d+$");
+
+ private static final Pattern MILESTONE_PATTERN = Pattern.compile("M\\d+$");
+
private final ConcurrentMap containers = new ConcurrentHashMap<>();
private final ClassLoaderConfiguration classLoaderConfiguration;
@@ -293,11 +297,11 @@ public static String buildAutoIdFromName(final String module) {
if (autoId.endsWith("-SNAPSHOT")) {
autoId = autoId.substring(0, autoId.length() - "-SNAPSHOT".length());
}
- final Matcher jiraTicket = Pattern.compile("-[A-Z]{2,}-\\d+$").matcher(autoId);
+ final Matcher jiraTicket = JIRA_TICKET_PATTERN.matcher(autoId);
if (jiraTicket.find()) {
autoId = autoId.substring(0, jiraTicket.start());
}
- final Matcher milestone = Pattern.compile("M\\d+$").matcher(autoId);
+ final Matcher milestone = MILESTONE_PATTERN.matcher(autoId);
if (milestone.find()) {
autoId = autoId.substring(0, milestone.start());
}
@@ -652,4 +656,4 @@ private Stream getBuiltInClasspath(final String moduleLocation) {
return resolver.resolve(classLoaderConfiguration.getParent(), moduleLocation);
}
}
-}
\ No newline at end of file
+}
From cb48ba7f7a3750643415de4ffdcc36184e8b1979 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Thu, 26 Feb 2026 18:50:04 +0100
Subject: [PATCH 19/41] feat(QTDI-2134): fix wrong stream filter
---
.../org/talend/sdk/component/container/ContainerManager.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index 5d84a0e8daacd..844c8c9d71077 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -487,7 +487,7 @@ public List getClasspathFromJar(final Path jar) {
final String cp = manifest.getMainAttributes().getValue("Class-Path");
if (cp != null) {
return Stream.of(cp.split(" "))
- .filter(c -> !c.equals(".") || !c.trim().isEmpty())
+ .filter(c -> !c.equals(".") && !c.trim().isEmpty())
.filter(c -> c.endsWith(".jar"))
.map(PathFactory::get)
.filter(Files::exists)
From 4e612ee93af9254f572f6a574fae2fce4d03439f Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Fri, 27 Feb 2026 10:09:13 +0100
Subject: [PATCH 20/41] feat(QTDI-2134): pr comments flow
---
.../runtime/manager/ComponentManager.java | 4 ++--
.../classloader/ConfigurableClassLoader.java | 1 -
.../component/container/ContainerManager.java | 19 ++++++++++++-------
...DependencyListLocalRepositoryResolver.java | 2 +-
4 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
index 968a11df65593..0cefc2a72e366 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
@@ -930,7 +930,7 @@ private void autoDiscoverPlugins0(final boolean callers, final boolean classpath
&& file.getParentFile().getName().equals("TALEND-INF")) {
file = file.getParentFile().getParentFile();
}
- if (!hasPlugin(container.buildAutoIdFromName(file.getName()))) {
+ if (!hasPlugin(ContainerManager.buildAutoIdFromName(file.getName()))) {
addPlugin(file.getAbsolutePath());
}
} else {
@@ -939,7 +939,7 @@ private void autoDiscoverPlugins0(final boolean callers, final boolean classpath
final String urlFile = marker.getFile();
final String jarPath = urlFile.substring(0, urlFile.lastIndexOf("!"));
final String jarFilePath = jarPath.substring(jarPath.lastIndexOf("/") + 1);
- if (!hasPlugin(container.buildAutoIdFromName(jarFilePath))) {
+ if (!hasPlugin(ContainerManager.buildAutoIdFromName(jarFilePath))) {
addPlugin(jarPath);
}
}
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
index f86c2acfe5256..a084ea937c293 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
@@ -490,7 +490,6 @@ private boolean isNestedDependencyResource(final String name) {
private boolean isInJvm(final URL resource) {
// Services and parent allowed resources that should always be found by top level classloader.
- // By default, META-INF/services/ is always allowed otherwise SPI won't work properly in nested environments.
// Warning: selection shouldn't be too generic! Use very specific paths only like jndi.properties.
if (resourcesFilter.test(resource.getFile())) {
return true;
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index 844c8c9d71077..ee3db90a79219 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -78,6 +78,13 @@ public class ContainerManager implements Lifecycle {
private static final Consumer NOOP_CUSTOMIZER = c -> {
};
+ private static final Pattern FRAMEWORK_JAR_PATTERN = Pattern.compile(".*" + File.separatorChar +
+ "(component-api|component-runtime-design-extension|component-runtime-di|component-runtime-impl|" +
+ "component-runtime-manager|component-spi|container-core|geronimo-annotation_1.3_spec|" +
+ "geronimo-json_1.1_spec|geronimo-jsonb_1.0_spec|johnzon-core|johnzon-jsonb|johnzon-mapper|" +
+ "rhino|slf4j-api|slf4j-log4j12|slf4j-reload4j|xbean-asm9-shaded|xbean-finder-shaded|xbean-reflect)" +
+ "-.*jar$");
+
private static final Pattern JIRA_TICKET_PATTERN = Pattern.compile("-[A-Z]{2,}-\\d+$");
private static final Pattern MILESTONE_PATTERN = Pattern.compile("M\\d+$");
@@ -108,7 +115,6 @@ public class ContainerManager implements Lifecycle {
private final boolean hasNestedRepository;
- @Getter
private final List runtimeClasspath = new ArrayList<>();
public ContainerManager(final DependenciesResolutionConfiguration dependenciesResolutionConfiguration,
@@ -421,6 +427,10 @@ private String getJre() {
.orElseThrow(IllegalArgumentException::new);
}
+ public List getRuntimeClasspath() {
+ return Collections.unmodifiableList(runtimeClasspath);
+ }
+
private void getSystemInformations() {
try {
final RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
@@ -459,12 +469,7 @@ private void readRuntimeClasspath() {
}
});
// cleanup the classpath from entries that are known as framework artifacts
- final Predicate frameworkFilter = p -> p.matches(".*" + File.separatorChar +
- "(component-api|component-runtime-design-extension|component-runtime-di|component-runtime-impl|" +
- "component-runtime-manager|component-spi|container-core|geronimo-annotation_1.3_spec|" +
- "geronimo-json_1.1_spec|geronimo-jsonb_1.0_spec|johnzon-core|johnzon-jsonb|johnzon-mapper|" +
- "rhino|slf4j-api|slf4j-log4j12|slf4j-reload4j|xbean-asm9-shaded|xbean-finder-shaded|xbean-reflect)"
- + "-.*jar$");
+ final Predicate frameworkFilter = p -> FRAMEWORK_JAR_PATTERN.matcher(p).matches();
runtimeClasspath.removeIf(p -> frameworkFilter.test(p));
} catch (Exception e) {
info("Unable to get runtime classpath: " + e.getMessage());
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
index 100560695739f..68c3d14ba2679 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
@@ -121,7 +121,7 @@ private String findDynamicDependencies(final ClassLoader rootLoader, final Strin
};
final String module = ContainerManager.buildAutoIdFromName(artifact);
final String dyndeps = properties.getProperty(module, "");
- return dyndeps.replaceAll(",", System.lineSeparator());
+ return dyndeps.replace(",", System.lineSeparator());
} catch (final IOException e) {
log.debug(e.getMessage(), e);
return "";
From 6a4caf179ec38ebd4fa0f062962fb045d95554f0 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Mon, 16 Mar 2026 16:27:27 +0100
Subject: [PATCH 21/41] feat(QTDI-2134): fix platform specific regexp
---
.../org/talend/sdk/component/container/ContainerManager.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index ee3db90a79219..b0320cf3a9097 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -78,7 +78,8 @@ public class ContainerManager implements Lifecycle {
private static final Consumer NOOP_CUSTOMIZER = c -> {
};
- private static final Pattern FRAMEWORK_JAR_PATTERN = Pattern.compile(".*" + File.separatorChar +
+ private static final Pattern FRAMEWORK_JAR_PATTERN = Pattern.compile(".*" +
+ Matcher.quoteReplacement(File.separator) +
"(component-api|component-runtime-design-extension|component-runtime-di|component-runtime-impl|" +
"component-runtime-manager|component-spi|container-core|geronimo-annotation_1.3_spec|" +
"geronimo-json_1.1_spec|geronimo-jsonb_1.0_spec|johnzon-core|johnzon-jsonb|johnzon-mapper|" +
From 326dd2b66ffb7c4ec017b602d7785c6ebaf776f5 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Mon, 16 Mar 2026 17:07:40 +0100
Subject: [PATCH 22/41] feat(QTDI-2134): fix platform specific regexp (fmt
space)
---
.../org/talend/sdk/component/container/ContainerManager.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index b0320cf3a9097..d63d0624c2236 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -79,7 +79,7 @@ public class ContainerManager implements Lifecycle {
};
private static final Pattern FRAMEWORK_JAR_PATTERN = Pattern.compile(".*" +
- Matcher.quoteReplacement(File.separator) +
+ Matcher.quoteReplacement(File.separator) +
"(component-api|component-runtime-design-extension|component-runtime-di|component-runtime-impl|" +
"component-runtime-manager|component-spi|container-core|geronimo-annotation_1.3_spec|" +
"geronimo-json_1.1_spec|geronimo-jsonb_1.0_spec|johnzon-core|johnzon-jsonb|johnzon-mapper|" +
From 44a6bf643df9c0df99faadfb84efa12feaf80b4b Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Fri, 20 Mar 2026 11:44:13 +0100
Subject: [PATCH 23/41] feat(QTDI-2134): Improve resolver to customize the
volatile classloader
---
.../dependency/ClassLoaderDefinition.java | 63 +++++++++
.../api/service/dependency/Resolver.java | 18 +++
component-runtime-manager/pom.xml | 10 ++
.../runtime/manager/service/ResolverImpl.java | 26 +++-
.../manager/service/ResolverImplTest.java | 125 +++++++++++++++++-
container/container-core/pom.xml | 5 +
.../component/container/ContainerManager.java | 3 +-
7 files changed, 239 insertions(+), 11 deletions(-)
create mode 100644 component-api/src/main/java/org/talend/sdk/component/api/service/dependency/ClassLoaderDefinition.java
diff --git a/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/ClassLoaderDefinition.java b/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/ClassLoaderDefinition.java
new file mode 100644
index 0000000000000..53ef315022cdb
--- /dev/null
+++ b/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/ClassLoaderDefinition.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.api.service.dependency;
+
+import java.util.function.Predicate;
+
+public interface ClassLoaderDefinition {
+
+ /**
+ *
+ * @return the parent classloader to use for the classloader to create.
+ */
+ ClassLoader getParent();
+
+ /**
+ *
+ * @return a filter to apply on the classes to load from the classloader to create. If the filter returns false for
+ * a class, the classloader to create will try to load it from its parent.
+ */
+ Predicate getClassesFilter();
+
+ /**
+ *
+ * @return a filter to apply on the classes to load from the parent classloader. If the filter returns false for a
+ * class, the classloader to create will try to load it by itself instead of delegating to its parent.
+ */
+ Predicate getParentClassesFilter();
+
+ /**
+ *
+ * @return a filter to apply on the resources to load from the parent classloader. If the filter returns false for a
+ * resource, the classloader to create will try to load it by itself instead of delegating to its parent.
+ */
+ Predicate getParentResourcesFilter();
+
+ /**
+ *
+ * @return true if the classloader to create should support resource dependencies (i.e. the dependencies.txt can
+ * also list resources to load and not only classes). Note that if this is true, the classloader to create will try
+ * to load resources by itself instead of delegating to its parent.
+ *
+ */
+ boolean isSupportsResourceDependencies();
+
+ /**
+ *
+ * @return the resource path to the plugins mapping file ("TALEND-INF/plugins.properties").
+ */
+ String getNestedPluginMappingResource();
+}
diff --git a/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java b/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java
index 71211111fddd1..03f6ca21d07f7 100644
--- a/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java
+++ b/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java
@@ -46,6 +46,24 @@ default ClassLoaderDescriptor mapDescriptorToClassLoader(final List gavs
new ByteArrayInputStream(String.join("\n", gavs).getBytes(StandardCharsets.UTF_8)));
}
+ /**
+ * Creates a classloader from the passed classloader configuration and descriptor (dependencies.txt).
+ *
+ * WARNING: note it is very important to close the descriptor once no more used otherwise
+ * you can leak memory.
+ *
+ * @param descriptor the dependencies.txt InputStream.
+ * @param configuration
+ * @return the classloader initialized with the configuration provided and the resolved dependencies.
+ */
+ ClassLoaderDescriptor mapDescriptorToClassLoader(InputStream descriptor, final ClassLoaderDefinition configuration);
+
+ default ClassLoaderDescriptor mapDescriptorToClassLoader(final List gavs,
+ final ClassLoaderDefinition configuration) {
+ return mapDescriptorToClassLoader(
+ new ByteArrayInputStream(String.join("\n", gavs).getBytes(StandardCharsets.UTF_8)), configuration);
+ }
+
/**
* Resolves the dependencies from the descriptor passed as an InputStream.
*
diff --git a/component-runtime-manager/pom.xml b/component-runtime-manager/pom.xml
index 844be9df2df8c..73b8286fb3e71 100644
--- a/component-runtime-manager/pom.xml
+++ b/component-runtime-manager/pom.xml
@@ -145,6 +145,7 @@
${project.build.directory}/test-dependencies/org/apache/tomee/openejb-itests-beans/${ziplock.test.version}openejb-itests-beans-${ziplock.test.version}.jar
+
org.apache.tomeearquillian-tomee-codi-tests
@@ -154,6 +155,15 @@
${project.build.directory}/test-dependencies/org/apache/tomee/arquillian-tomee-codi-tests/8.0.9arquillian-tomee-codi-tests-8.0.9.jar
+
+ org.apache.poi
+ poi-ooxml
+ 5.4.1
+ jar
+ true
+ ${project.build.directory}/test-dependencies/org/apache/poi/poi-ooxml/5.4.1
+ poi-ooxml-5.4.1.jar
+
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java
index 4f0d48b785bf5..3b94753405432 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java
@@ -31,8 +31,10 @@
import java.util.Collection;
import java.util.function.Function;
+import org.talend.sdk.component.api.service.dependency.ClassLoaderDefinition;
import org.talend.sdk.component.api.service.dependency.Resolver;
import org.talend.sdk.component.classloader.ConfigurableClassLoader;
+import org.talend.sdk.component.container.ContainerManager.ClassLoaderConfiguration;
import org.talend.sdk.component.dependencies.maven.Artifact;
import org.talend.sdk.component.dependencies.maven.MvnDependencyListLocalRepositoryResolver;
import org.talend.sdk.component.runtime.serialization.SerializableService;
@@ -48,6 +50,19 @@ public class ResolverImpl implements Resolver, Serializable {
@Override
public ClassLoaderDescriptor mapDescriptorToClassLoader(final InputStream descriptor) {
+ return mapDescriptorToClassLoader(descriptor,
+ ClassLoaderConfiguration.builder()
+ .parent(Thread.currentThread().getContextClassLoader())
+ .classesFilter(it -> true)
+ .parentClassesFilter(it -> false)
+ .supportsResourceDependencies(true)
+ .parentResourcesFilter(it -> true)
+ .create());
+ }
+
+ @Override
+ public ClassLoaderDescriptor mapDescriptorToClassLoader(final InputStream descriptor,
+ final ClassLoaderDefinition configuration) {
final Collection urls = new ArrayList<>();
final Collection nested = new ArrayList<>();
final Collection resolved = new ArrayList<>();
@@ -72,10 +87,15 @@ public ClassLoaderDescriptor mapDescriptorToClassLoader(final InputStream descri
resolved.add(artifact.toCoordinate());
} // else will be missing
});
+ final ClassLoader parent = configuration.getParent();
final ConfigurableClassLoader volatileLoader = new ConfigurableClassLoader(plugin + "#volatile-resolver",
- urls.toArray(new URL[0]), classLoader, it -> false, it -> true, nested.toArray(new String[0]),
- ConfigurableClassLoader.class.isInstance(classLoader)
- ? ConfigurableClassLoader.class.cast(classLoader).getJvmMarkers()
+ urls.toArray(new URL[0]),
+ parent,
+ configuration.getParentClassesFilter(),
+ configuration.getClassesFilter(),
+ nested.toArray(new String[0]),
+ ConfigurableClassLoader.class.isInstance(parent)
+ ? ConfigurableClassLoader.class.cast(parent).getJvmMarkers()
: new String[] { "" });
return new ClassLoaderDescriptorImpl(volatileLoader, resolved);
} catch (final IOException e) {
diff --git a/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/service/ResolverImplTest.java b/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/service/ResolverImplTest.java
index 2d6519bf6f3b9..5b1f12702158f 100644
--- a/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/service/ResolverImplTest.java
+++ b/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/service/ResolverImplTest.java
@@ -18,6 +18,8 @@
import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.ByteArrayInputStream;
@@ -30,25 +32,46 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import java.util.Properties;
import java.util.UUID;
+import java.util.function.Function;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
+import org.talend.sdk.component.api.service.dependency.ClassLoaderDefinition;
import org.talend.sdk.component.api.service.dependency.Resolver;
import org.talend.sdk.component.classloader.ConfigurableClassLoader;
+import org.talend.sdk.component.container.ContainerManager;
import org.talend.sdk.component.path.PathFactory;
class ResolverImplTest {
+ public final String ARTIFACT_ID = "artifactId";
+
+ public final String EXPECTED_ARTIFACT_ID = "arquillian-tomee-codi-tests";
+
+ public final String GAV_CODI_TESTS = "org.apache.tomee:arquillian-tomee-codi-tests:jar:8.0.9";
+
+ public final String GAV_OPENEJB = "org.apache.tomee:openejb-itests-beans:jar:8.0.14";
+
+ public final String POM_PROPS_TOMEE = "META-INF/maven/org.apache.tomee/arquillian-tomee-codi-tests/pom.properties";
+
+ public final String CLASS_OPENEJB = "org.apache.openejb.test.ApplicationException";
+
+ public final String CLASS_POIXML = "org.apache.poi.ooxml.POIXMLException";
+
+ public final String POI_PATH = "target/test-dependencies/org/apache/poi/poi-ooxml/5.4.1/poi-ooxml-5.4.1.jar";
+
@Test
void createClassLoader(@TempDir final Path temporaryFolder) throws Exception {
final File root = temporaryFolder.toFile();
root.mkdirs();
- final String dep = "org.apache.tomee:arquillian-tomee-codi-tests:jar:8.0.9";
+ final String dep = GAV_CODI_TESTS;
final File nestedJar = new File(root, UUID.randomUUID().toString() + ".jar");
try (final JarOutputStream out = new JarOutputStream(new FileOutputStream(nestedJar))) {
addDepToJar(dep, out);
@@ -70,14 +93,11 @@ void createClassLoader(@TempDir final Path temporaryFolder) throws Exception {
assertNotNull(desc.asClassLoader());
assertEquals(singletonList(dep), desc.resolvedDependencies());
final Properties props = new Properties();
- try (final InputStream in = desc
- .asClassLoader()
- .getResourceAsStream(
- "META-INF/maven/org.apache.tomee/arquillian-tomee-codi-tests/pom.properties")) {
+ try (final InputStream in = desc.asClassLoader().getResourceAsStream(POM_PROPS_TOMEE)) {
assertNotNull(in);
props.load(in);
}
- assertEquals("arquillian-tomee-codi-tests", props.getProperty("artifactId"));
+ assertEquals(EXPECTED_ARTIFACT_ID, props.getProperty(ARTIFACT_ID));
} finally {
thread.setContextClassLoader(contextClassLoader);
appLoader.close();
@@ -97,6 +117,95 @@ void resolvefromDescriptor() throws IOException {
}
}
+ @Test
+ void createBareConfigurableClassLoader(@TempDir final Path temporaryFolder) throws Exception {
+ createConfigurableClassLoader(temporaryFolder, true, false);
+ }
+
+ @Test
+ void createConfigurableClassLoaderWithParentLoading(@TempDir final Path temporaryFolder) throws Exception {
+ createConfigurableClassLoader(temporaryFolder, false, true);
+ }
+
+ @Test
+ void createConfigurableClassLoaderWithoutParentLoading(@TempDir final Path temporaryFolder) throws Exception {
+ createConfigurableClassLoader(temporaryFolder, false, false);
+ }
+
+ private void createConfigurableClassLoader(final Path temporaryFolder, final boolean bare,
+ final boolean parentLoading)
+ throws Exception {
+ final File root = temporaryFolder.toFile();
+ root.mkdirs();
+ final List deps = Arrays.asList(GAV_CODI_TESTS, GAV_OPENEJB);
+ final File nestedJar = new File(root, UUID.randomUUID().toString() + ".jar");
+ try (final JarOutputStream out = new JarOutputStream(new FileOutputStream(nestedJar))) {
+ deps.forEach(d -> addDepToJar(d, out));
+ }
+
+ final Thread thread = Thread.currentThread();
+ final ClassLoader contextCl = thread.getContextClassLoader();
+ // component loader simulation which is always the parent of that
+ // here the parent of the component is the jar containing the nested repo
+ final URLClassLoader appLoader = new URLClassLoader(new URL[] { nestedJar.toURI().toURL() }, contextCl);
+ final File poiJar = new File(POI_PATH);
+ assertTrue(Files.exists(poiJar.toPath()));
+ final ConfigurableClassLoader componentLoader =
+ new ConfigurableClassLoader("test", new URL[] { poiJar.toURI().toURL() }, appLoader,
+ it -> true, it -> true, new String[0], new String[0]);
+ // force loading of a class from the future parent for the created classloader with no parent loading allowed.
+ final Class poiClazz = componentLoader.loadClass(CLASS_POIXML, true);
+ assertEquals(componentLoader, poiClazz.getClassLoader());
+
+ thread.setContextClassLoader(componentLoader);
+ final ClassLoaderDefinition classLoaderDefinition = ContainerManager.ClassLoaderConfiguration.builder()
+ .parent(componentLoader)
+ .classesFilter(it -> true)
+ .parentClassesFilter(it -> parentLoading)
+ .supportsResourceDependencies(true)
+ .parentResourcesFilter(it -> true)
+ .create();
+
+ final Function fileResolver = coord -> PathFactory.get("maven2").resolve(coord);
+ try (final Resolver.ClassLoaderDescriptor desc = bare
+ ? new ResolverImpl(null, fileResolver).mapDescriptorToClassLoader(deps)
+ : new ResolverImpl(null, fileResolver).mapDescriptorToClassLoader(deps, classLoaderDefinition)) {
+ assertNotNull(desc);
+ final ClassLoader dumbCl = desc.asClassLoader();
+ assertNotNull(dumbCl);
+ // the classloader should be a child of the component loader and a ConfigurableClassLoader
+ assertTrue(dumbCl.getParent() == componentLoader);
+ assertTrue(dumbCl instanceof ConfigurableClassLoader);
+ final ConfigurableClassLoader ccl = (ConfigurableClassLoader) dumbCl;
+ // class loading should work and be done by the created classloader
+ Class clazz = ccl.loadClass(CLASS_OPENEJB, true);
+ assertNotNull(clazz);
+ assertEquals(ccl, clazz.getClassLoader());
+ // check that parent loading is or not allowed
+ if (parentLoading) {
+ Class clzz = ccl.loadClass(CLASS_POIXML, true);
+ assertNotNull(clzz);
+ assertEquals(poiClazz, clzz);
+ } else {
+ assertThrows(ClassNotFoundException.class, () -> ccl.loadClass(CLASS_POIXML, true));
+ }
+ // checks dependencies and resources
+ assertEquals(deps, desc.resolvedDependencies());
+ final Properties props = new Properties();
+ try (final InputStream in = desc.asClassLoader().getResourceAsStream(POM_PROPS_TOMEE)) {
+ assertNotNull(in);
+ props.load(in);
+ }
+ assertEquals(EXPECTED_ARTIFACT_ID, props.getProperty(ARTIFACT_ID));
+ //
+ // TODO: check parent loading of resources is allowed or not depending on the configuration.
+ //
+ } finally {
+ thread.setContextClassLoader(contextCl);
+ appLoader.close(); // cascade close the classloaders
+ }
+ }
+
private void addDepToJar(final String dep, final JarOutputStream out) {
final String[] segments = dep.split(":");
final String path = "MAVEN-INF/repository/" + segments[0].replace(".", "/") + "/" + segments[1] + "/"
@@ -110,7 +219,9 @@ private void addDepToJar(final String dep, final JarOutputStream out) {
try {
out.putNextEntry(new ZipEntry(current.toString()));
} catch (final IOException e) {
- fail(e.getMessage());
+ if (!e.getMessage().contains("duplicate entry")) {
+ fail(e.getMessage());
+ }
}
}
// add the dep
diff --git a/container/container-core/pom.xml b/container/container-core/pom.xml
index b8e227c1ef2e1..418f3a3b0018e 100644
--- a/container/container-core/pom.xml
+++ b/container/container-core/pom.xml
@@ -32,6 +32,11 @@
+
+ org.talend.sdk.component
+ component-api
+
+
org.slf4jslf4j-api
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index d63d0624c2236..f0edb421dc47c 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -59,6 +59,7 @@
import java.util.regex.Pattern;
import java.util.stream.Stream;
+import org.talend.sdk.component.api.service.dependency.ClassLoaderDefinition;
import org.talend.sdk.component.classloader.ConfigurableClassLoader;
import org.talend.sdk.component.dependencies.Resolver;
import org.talend.sdk.component.dependencies.maven.Artifact;
@@ -532,7 +533,7 @@ public static class DependenciesResolutionConfiguration {
@Getter
@Builder(buildMethodName = "create")
- public static class ClassLoaderConfiguration {
+ public static class ClassLoaderConfiguration implements ClassLoaderDefinition {
private final ClassLoader parent;
From 7eddd30f9b3b8c99c8b2151d677b3e13b75e38fc Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Fri, 20 Mar 2026 14:25:05 +0100
Subject: [PATCH 24/41] feat(QTDI-2134): fixes pr comments
---
.../api/service/dependency/Resolver.java | 6 ++++-
.../runtime/manager/service/ResolverImpl.java | 9 +++++--
.../component/container/ContainerManager.java | 9 +++----
...DependencyListLocalRepositoryResolver.java | 8 ++----
.../sdk/component/ContainerManagerTest.java | 27 +++++++++++++++++++
5 files changed, 45 insertions(+), 14 deletions(-)
diff --git a/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java b/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java
index 03f6ca21d07f7..9383c8471f26e 100644
--- a/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java
+++ b/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java
@@ -56,7 +56,11 @@ default ClassLoaderDescriptor mapDescriptorToClassLoader(final List gavs
* @param configuration
* @return the classloader initialized with the configuration provided and the resolved dependencies.
*/
- ClassLoaderDescriptor mapDescriptorToClassLoader(InputStream descriptor, final ClassLoaderDefinition configuration);
+ default ClassLoaderDescriptor mapDescriptorToClassLoader(InputStream descriptor,
+ final ClassLoaderDefinition configuration) {
+ throw new UnsupportedOperationException(
+ "This method is not implemented yet, please use the mapDescriptorToClassLoader(InputStream) method instead");
+ }
default ClassLoaderDescriptor mapDescriptorToClassLoader(final List gavs,
final ClassLoaderDefinition configuration) {
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java
index 3b94753405432..34e13e25fe38d 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java
@@ -50,9 +50,13 @@ public class ResolverImpl implements Resolver, Serializable {
@Override
public ClassLoaderDescriptor mapDescriptorToClassLoader(final InputStream descriptor) {
+ final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ final ClassLoader loader =
+ ofNullable(classLoader).map(ClassLoader::getParent).orElseGet(ClassLoader::getSystemClassLoader);
+
return mapDescriptorToClassLoader(descriptor,
ClassLoaderConfiguration.builder()
- .parent(Thread.currentThread().getContextClassLoader())
+ .parent(loader)
.classesFilter(it -> true)
.parentClassesFilter(it -> false)
.supportsResourceDependencies(true)
@@ -96,7 +100,8 @@ public ClassLoaderDescriptor mapDescriptorToClassLoader(final InputStream descri
nested.toArray(new String[0]),
ConfigurableClassLoader.class.isInstance(parent)
? ConfigurableClassLoader.class.cast(parent).getJvmMarkers()
- : new String[] { "" });
+ : new String[] { "" },
+ configuration.getParentResourcesFilter());
return new ClassLoaderDescriptorImpl(volatileLoader, resolved);
} catch (final IOException e) {
throw new IllegalArgumentException(e);
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index f0edb421dc47c..950782ee6e877 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -76,17 +76,16 @@
@Slf4j
public class ContainerManager implements Lifecycle {
- private static final Consumer NOOP_CUSTOMIZER = c -> {
- };
-
- private static final Pattern FRAMEWORK_JAR_PATTERN = Pattern.compile(".*" +
- Matcher.quoteReplacement(File.separator) +
+ public static final Pattern FRAMEWORK_JAR_PATTERN = Pattern.compile("(.*[\\\\/])?" + // Optional path with separator
"(component-api|component-runtime-design-extension|component-runtime-di|component-runtime-impl|" +
"component-runtime-manager|component-spi|container-core|geronimo-annotation_1.3_spec|" +
"geronimo-json_1.1_spec|geronimo-jsonb_1.0_spec|johnzon-core|johnzon-jsonb|johnzon-mapper|" +
"rhino|slf4j-api|slf4j-log4j12|slf4j-reload4j|xbean-asm9-shaded|xbean-finder-shaded|xbean-reflect)" +
"-.*jar$");
+ private static final Consumer NOOP_CUSTOMIZER = c -> {
+ };
+
private static final Pattern JIRA_TICKET_PATTERN = Pattern.compile("-[A-Z]{2,}-\\d+$");
private static final Pattern MILESTONE_PATTERN = Pattern.compile("M\\d+$");
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
index 68c3d14ba2679..46809803e656a 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/dependencies/maven/MvnDependencyListLocalRepositoryResolver.java
@@ -113,12 +113,8 @@ private String findDynamicDependencies(final ClassLoader rootLoader, final Strin
if (stream == null) {
return "";
}
- final Properties properties = new Properties() {
-
- {
- load(stream);
- }
- };
+ final Properties properties = new Properties();
+ properties.load(stream);
final String module = ContainerManager.buildAutoIdFromName(artifact);
final String dyndeps = properties.getProperty(module, "");
return dyndeps.replace(",", System.lineSeparator());
diff --git a/container/container-core/src/test/java/org/talend/sdk/component/ContainerManagerTest.java b/container/container-core/src/test/java/org/talend/sdk/component/ContainerManagerTest.java
index 8287d9da6c766..12555e0060620 100644
--- a/container/container-core/src/test/java/org/talend/sdk/component/ContainerManagerTest.java
+++ b/container/container-core/src/test/java/org/talend/sdk/component/ContainerManagerTest.java
@@ -18,9 +18,11 @@
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.talend.sdk.component.container.ContainerManager.FRAMEWORK_JAR_PATTERN;
import java.io.File;
import java.io.FileOutputStream;
@@ -160,6 +162,31 @@ void close(final TempJars jars) {
});
}
+ @Test
+ void frameworkJarPatternShouldMatchBothUnixAndWindowsPaths() {
+ // Basic filename tests
+ assertTrue(FRAMEWORK_JAR_PATTERN.matcher("component-api-1.2.3.jar").matches());
+ assertFalse(FRAMEWORK_JAR_PATTERN.matcher("component-api-1.2.3.txt").matches());
+ // Unix-style paths
+ assertTrue(FRAMEWORK_JAR_PATTERN.matcher("/usr/lib/component-api-1.2.3.jar").matches());
+ assertTrue(FRAMEWORK_JAR_PATTERN.matcher("/opt/talend/lib/slf4j-api-1.7.30.jar").matches());
+ assertTrue(FRAMEWORK_JAR_PATTERN.matcher("lib/johnzon-mapper-1.2.18.jar").matches());
+ // Windows-style paths
+ assertTrue(FRAMEWORK_JAR_PATTERN.matcher("lib\\component-api-1.2.3.jar").matches());
+ assertTrue(FRAMEWORK_JAR_PATTERN.matcher("C:\\Program Files\\Talend\\lib\\component-api-1.2.3.jar").matches());
+ assertTrue(FRAMEWORK_JAR_PATTERN.matcher("D:\\workspace\\lib\\slf4j-api-1.7.30.jar").matches());
+ assertTrue(FRAMEWORK_JAR_PATTERN.matcher("lib\\johnzon-mapper-1.2.18.jar").matches());
+ // Edge cases: paths with multiple separators
+ assertTrue(FRAMEWORK_JAR_PATTERN.matcher("foo/bar/baz/component-spi-2.0.0.jar").matches());
+ assertTrue(FRAMEWORK_JAR_PATTERN.matcher("foo\\bar\\baz\\container-core-1.0.0.jar").matches());
+ // Should NOT match non-framework jars
+ assertFalse(FRAMEWORK_JAR_PATTERN.matcher("/usr/lib/my-custom-component-1.0.0.jar").matches());
+ assertFalse(FRAMEWORK_JAR_PATTERN.matcher("C:\\libs\\other-library-2.0.jar").matches());
+ // Edge case: filename that starts with framework name but isn't a framework jar
+ assertFalse(FRAMEWORK_JAR_PATTERN.matcher("/usr/lib/component-api.txt").matches());
+ assertFalse(FRAMEWORK_JAR_PATTERN.matcher("/usr/lib/component-api").matches());
+ }
+
@Test
void getClasspathFromJarWithValidManifestClassPath(@TempDir final Path tempDir) throws Exception {
final File jar1 = createJarFile(tempDir, "lib1.jar");
From c9efe1b3f672ded9e7ea1c996e5e6ccc539d9cd3 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Fri, 20 Mar 2026 14:34:55 +0100
Subject: [PATCH 25/41] feat(QTDI-2134): fix classloader's parent test
---
.../sdk/component/runtime/manager/service/ResolverImplTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/service/ResolverImplTest.java b/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/service/ResolverImplTest.java
index 5b1f12702158f..1550a98d856e3 100644
--- a/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/service/ResolverImplTest.java
+++ b/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/service/ResolverImplTest.java
@@ -173,8 +173,8 @@ private void createConfigurableClassLoader(final Path temporaryFolder, final boo
assertNotNull(desc);
final ClassLoader dumbCl = desc.asClassLoader();
assertNotNull(dumbCl);
+ assertTrue(dumbCl.getParent() == (bare ? appLoader : componentLoader));
// the classloader should be a child of the component loader and a ConfigurableClassLoader
- assertTrue(dumbCl.getParent() == componentLoader);
assertTrue(dumbCl instanceof ConfigurableClassLoader);
final ConfigurableClassLoader ccl = (ConfigurableClassLoader) dumbCl;
// class loading should work and be done by the created classloader
From c8c6aa14ba1189432e6692781c19699bead54dcf Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Fri, 20 Mar 2026 15:26:33 +0100
Subject: [PATCH 26/41] feat(QTDI-2134): rename isInJvm method
---
.../component/classloader/ConfigurableClassLoader.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
index a084ea937c293..53059eda1eef1 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
@@ -389,10 +389,10 @@ public Enumeration getResources(final String name) throws IOException {
return selfResources;
}
if (!selfResources.hasMoreElements()) {
- return new FilteringUrlEnum(parentResources, this::isInJvm);
+ return new FilteringUrlEnum(parentResources, this::shouldLoadFromParent);
}
return new ChainedEnumerations(
- asList(selfResources, new FilteringUrlEnum(parentResources, this::isInJvm)).iterator());
+ asList(selfResources, new FilteringUrlEnum(parentResources, this::shouldLoadFromParent)).iterator());
}
@Override
@@ -403,7 +403,7 @@ public URL getResource(final String name) {
}
if (!isBlacklistedFromParent(name)) {
resource = getParent().getResource(name);
- if (resource != null && (isNestedDependencyResource(name) || isInJvm(resource))) {
+ if (resource != null && (isNestedDependencyResource(name) || shouldLoadFromParent(resource))) {
return resource;
}
}
@@ -488,7 +488,7 @@ private boolean isNestedDependencyResource(final String name) {
return name != null && name.startsWith(NESTED_MAVEN_REPOSITORY);
}
- private boolean isInJvm(final URL resource) {
+ private boolean shouldLoadFromParent(final URL resource) {
// Services and parent allowed resources that should always be found by top level classloader.
// Warning: selection shouldn't be too generic! Use very specific paths only like jndi.properties.
if (resourcesFilter.test(resource.getFile())) {
From b54e276d6ad057845455579668bdf4ffd0e6e459 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Fri, 20 Mar 2026 15:40:01 +0100
Subject: [PATCH 27/41] Update
component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/service/ResolverImplTest.java
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../manager/service/ResolverImplTest.java | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/service/ResolverImplTest.java b/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/service/ResolverImplTest.java
index 1550a98d856e3..5084441279b69 100644
--- a/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/service/ResolverImplTest.java
+++ b/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/service/ResolverImplTest.java
@@ -51,21 +51,23 @@
class ResolverImplTest {
- public final String ARTIFACT_ID = "artifactId";
+ private static final String ARTIFACT_ID = "artifactId";
- public final String EXPECTED_ARTIFACT_ID = "arquillian-tomee-codi-tests";
+ private static final String EXPECTED_ARTIFACT_ID = "arquillian-tomee-codi-tests";
- public final String GAV_CODI_TESTS = "org.apache.tomee:arquillian-tomee-codi-tests:jar:8.0.9";
+ private static final String GAV_CODI_TESTS = "org.apache.tomee:arquillian-tomee-codi-tests:jar:8.0.9";
- public final String GAV_OPENEJB = "org.apache.tomee:openejb-itests-beans:jar:8.0.14";
+ private static final String GAV_OPENEJB = "org.apache.tomee:openejb-itests-beans:jar:8.0.14";
- public final String POM_PROPS_TOMEE = "META-INF/maven/org.apache.tomee/arquillian-tomee-codi-tests/pom.properties";
+ private static final String POM_PROPS_TOMEE =
+ "META-INF/maven/org.apache.tomee/arquillian-tomee-codi-tests/pom.properties";
- public final String CLASS_OPENEJB = "org.apache.openejb.test.ApplicationException";
+ private static final String CLASS_OPENEJB = "org.apache.openejb.test.ApplicationException";
- public final String CLASS_POIXML = "org.apache.poi.ooxml.POIXMLException";
+ private static final String CLASS_POIXML = "org.apache.poi.ooxml.POIXMLException";
- public final String POI_PATH = "target/test-dependencies/org/apache/poi/poi-ooxml/5.4.1/poi-ooxml-5.4.1.jar";
+ private static final String POI_PATH =
+ "target/test-dependencies/org/apache/poi/poi-ooxml/5.4.1/poi-ooxml-5.4.1.jar";
@Test
void createClassLoader(@TempDir final Path temporaryFolder) throws Exception {
From bf5dea75200ffc5a2dcf232aaa78a0e1e52c082e Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Fri, 20 Mar 2026 16:01:59 +0100
Subject: [PATCH 28/41] feat(QTDI-2134): fix loader (pr comment)
---
.../component/runtime/manager/service/ResolverImpl.java | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java
index 34e13e25fe38d..d7f7817a71ba8 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java
@@ -70,9 +70,9 @@ public ClassLoaderDescriptor mapDescriptorToClassLoader(final InputStream descri
final Collection urls = new ArrayList<>();
final Collection nested = new ArrayList<>();
final Collection resolved = new ArrayList<>();
- final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
- final ClassLoader loader =
- ofNullable(classLoader).map(ClassLoader::getParent).orElseGet(ClassLoader::getSystemClassLoader);
+ final ClassLoader parent = configuration.getParent() != null ? configuration.getParent()
+ : ofNullable(Thread.currentThread().getContextClassLoader()).map(ClassLoader::getParent)
+ .orElseGet(ClassLoader::getSystemClassLoader);
try {
new MvnDependencyListLocalRepositoryResolver(null, fileResolver)
.resolveFromDescriptor(descriptor)
@@ -86,12 +86,11 @@ public ClassLoaderDescriptor mapDescriptorToClassLoader(final InputStream descri
} catch (final MalformedURLException e) {
throw new IllegalStateException(e);
}
- } else if (loader.getResource("MAVEN-INF/repository/" + path) != null) {
+ } else if (parent.getResource("MAVEN-INF/repository/" + path) != null) {
nested.add(path);
resolved.add(artifact.toCoordinate());
} // else will be missing
});
- final ClassLoader parent = configuration.getParent();
final ConfigurableClassLoader volatileLoader = new ConfigurableClassLoader(plugin + "#volatile-resolver",
urls.toArray(new URL[0]),
parent,
From 5b21af17d00c1c48f0cacbbd86b0b3eb1a357dca Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Fri, 20 Mar 2026 16:16:35 +0100
Subject: [PATCH 29/41] feat(QTDI-2134): fix debug (pr comment)
---
.../org/talend/sdk/component/container/ContainerManager.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index 950782ee6e877..d137831baaef8 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -466,7 +466,7 @@ private void readRuntimeClasspath() {
runtimeClasspath.addAll(getClasspathFromJar(p));
} else {
runtimeClasspath.add(p.toAbsolutePath().toString());
- log.debug("[sysinfo] Runtime classpath entry: " + p.toAbsolutePath());
+ log.debug("[sysinfo] Runtime classpath entry: {}", p.toAbsolutePath());
}
});
// cleanup the classpath from entries that are known as framework artifacts
From ab9ae4fc6cb55457e1f6232915925ccb519a0058 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Fri, 20 Mar 2026 16:18:12 +0100
Subject: [PATCH 30/41] Update
component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../talend/sdk/component/runtime/manager/ComponentManager.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
index 0cefc2a72e366..cd893347a28e5 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
@@ -219,6 +219,7 @@ private static ComponentManager buildNewComponentManager() {
info("Components: " + availablePlugins());
} catch (Exception e) {
info("Failed to load plugins from plugins.properties: " + e.getMessage());
+ log.debug("Failed to load plugins from plugins.properties.", e);
}
}
From f7b1f6afbd9093d4b919f7268361911cdc5591df Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Fri, 20 Mar 2026 16:19:36 +0100
Subject: [PATCH 31/41] Update
component-api/src/main/java/org/talend/sdk/component/api/service/dependency/ClassLoaderDefinition.java
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../api/service/dependency/ClassLoaderDefinition.java | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/ClassLoaderDefinition.java b/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/ClassLoaderDefinition.java
index 53ef315022cdb..4bc3a76eec709 100644
--- a/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/ClassLoaderDefinition.java
+++ b/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/ClassLoaderDefinition.java
@@ -41,8 +41,11 @@ public interface ClassLoaderDefinition {
/**
*
- * @return a filter to apply on the resources to load from the parent classloader. If the filter returns false for a
- * resource, the classloader to create will try to load it by itself instead of delegating to its parent.
+ * @return a filter to apply on the resources to load from the parent classloader. The {@link String} argument of
+ * the predicate is the path of the resource as obtained from {@code URL#getFile()} (i.e. the full URL/file path),
+ * not the logical resource name used in {@link ClassLoader#getResource(String)}. If the filter returns
+ * {@code false} for a resource, the classloader to create will try to load it by itself instead of delegating to
+ * its parent.
*/
Predicate getParentResourcesFilter();
From 3c2845443542078e100ee8cfc92e0b1810d178bf Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Fri, 20 Mar 2026 16:40:12 +0100
Subject: [PATCH 32/41] Update
component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../component/api/service/dependency/Resolver.java | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java b/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java
index 9383c8471f26e..b7908fd6583b4 100644
--- a/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java
+++ b/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java
@@ -52,14 +52,21 @@ default ClassLoaderDescriptor mapDescriptorToClassLoader(final List gavs
* WARNING: note it is very important to close the descriptor once no more used otherwise
* you can leak memory.
*
+ *
The default implementation of this method is unsupported and will always throw
+ * {@link UnsupportedOperationException}. Implementations that support configurable
+ * classloader creation must override this method.
+ *
* @param descriptor the dependencies.txt InputStream.
- * @param configuration
+ * @param configuration the classloader configuration to apply when creating the classloader.
* @return the classloader initialized with the configuration provided and the resolved dependencies.
+ * @throws UnsupportedOperationException if this implementation does not support configurable
+ * classloader creation.
*/
default ClassLoaderDescriptor mapDescriptorToClassLoader(InputStream descriptor,
final ClassLoaderDefinition configuration) {
throw new UnsupportedOperationException(
- "This method is not implemented yet, please use the mapDescriptorToClassLoader(InputStream) method instead");
+ "ClassLoader configuration is not supported by this implementation; "
+ + "override mapDescriptorToClassLoader(InputStream, ClassLoaderDefinition) to provide an implementation");
}
default ClassLoaderDescriptor mapDescriptorToClassLoader(final List gavs,
From d11f4dea5187f5524000524c5659889ef4bbb125 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Wed, 25 Mar 2026 16:10:32 +0100
Subject: [PATCH 33/41] feat(QTDI-2134): fix parametrize for log.debug
---
.../talend/sdk/component/runtime/manager/ComponentManager.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
index cd893347a28e5..d56beeafa6b45 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
@@ -1765,7 +1765,7 @@ private Archive toArchive(final String module, final OriginalId originalId,
JarInputStream jarStream = null;
try {
jarStream = new JarInputStream(nested.openStream());
- log.debug("Found a nested resource for " + nested);
+ log.debug("Found a nested resource for {}", nested);
return new NestedJarArchive(nested, jarStream, loader);
} catch (final IOException e) {
if (jarStream != null) {
From 40e6c786acfd1134b594ac07d3ed3836961173fd Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Wed, 25 Mar 2026 18:07:36 +0100
Subject: [PATCH 34/41] feat(QTDI-2134): apply parent restrictions to
resourceAsStream
---
.../sdk/component/classloader/ConfigurableClassLoader.java | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
index 53059eda1eef1..ee4a5987c168c 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/classloader/ConfigurableClassLoader.java
@@ -429,7 +429,10 @@ private InputStream doGetResourceAsStream(final String name) {
try {
if (resource == null && !isBlacklistedFromParent(name)) {
final URL url = getParent().getResource(name);
- return url != null ? getInputStream(url) : null;
+ if (url != null && shouldLoadFromParent(url)) {
+ return getInputStream(url);
+ }
+ return null;
}
if (resource == null) {
return null;
From 85e779507f5e6885ad4d14adeb0e4cd2751e1ec0 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Wed, 25 Mar 2026 18:31:28 +0100
Subject: [PATCH 35/41] Update
component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../sdk/component/runtime/manager/service/ResolverImpl.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java
index d7f7817a71ba8..822916b66ffa0 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/service/ResolverImpl.java
@@ -94,13 +94,13 @@ public ClassLoaderDescriptor mapDescriptorToClassLoader(final InputStream descri
final ConfigurableClassLoader volatileLoader = new ConfigurableClassLoader(plugin + "#volatile-resolver",
urls.toArray(new URL[0]),
parent,
- configuration.getParentClassesFilter(),
- configuration.getClassesFilter(),
+ ofNullable(configuration.getParentClassesFilter()).orElse(it -> false),
+ ofNullable(configuration.getClassesFilter()).orElse(it -> true),
nested.toArray(new String[0]),
ConfigurableClassLoader.class.isInstance(parent)
? ConfigurableClassLoader.class.cast(parent).getJvmMarkers()
: new String[] { "" },
- configuration.getParentResourcesFilter());
+ ofNullable(configuration.getParentResourcesFilter()).orElse(it -> true));
return new ClassLoaderDescriptorImpl(volatileLoader, resolved);
} catch (final IOException e) {
throw new IllegalArgumentException(e);
From e6edd39365d30bb6018065e4b5775b09a37432d4 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Wed, 25 Mar 2026 18:48:20 +0100
Subject: [PATCH 36/41] feat(QTDI-2134): fix failing test
---
.../sdk/component/api/service/dependency/Resolver.java | 6 ++++--
.../runtime/manager/xbean/NestedJarArchiveTest.java | 2 +-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java b/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java
index b7908fd6583b4..447350586b015 100644
--- a/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java
+++ b/component-api/src/main/java/org/talend/sdk/component/api/service/dependency/Resolver.java
@@ -52,9 +52,11 @@ default ClassLoaderDescriptor mapDescriptorToClassLoader(final List gavs
* WARNING: note it is very important to close the descriptor once no more used otherwise
* you can leak memory.
*
- *
The default implementation of this method is unsupported and will always throw
+ *
+ * The default implementation of this method is unsupported and will always throw
* {@link UnsupportedOperationException}. Implementations that support configurable
- * classloader creation must override this method.
+ * classloader creation must override this method.
+ *
*
* @param descriptor the dependencies.txt InputStream.
* @param configuration the classloader configuration to apply when creating the classloader.
diff --git a/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/xbean/NestedJarArchiveTest.java b/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/xbean/NestedJarArchiveTest.java
index 983081616ef06..f8081252fdc00 100644
--- a/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/xbean/NestedJarArchiveTest.java
+++ b/component-runtime-manager/src/test/java/org/talend/sdk/component/runtime/manager/xbean/NestedJarArchiveTest.java
@@ -53,7 +53,7 @@ void xbeanNestedScanning(final TestInfo info, @TempDir final File temporaryFolde
final File jar = createPlugin(temporaryFolder, info.getTestMethod().get().getName());
final ConfigurableClassLoader configurableClassLoader = new ConfigurableClassLoader("", new URL[0],
new URLClassLoader(new URL[] { jar.toURI().toURL() }, Thread.currentThread().getContextClassLoader()),
- n -> true, n -> true, new String[] { "com/foo/bar/1.0/bar-1.0.jar" }, new String[0]);
+ n -> true, n -> true, new String[] { "com/foo/bar/1.0/bar-1.0.jar" }, new String[0], n -> true);
try (final JarInputStream jis = new JarInputStream(
configurableClassLoader.getResourceAsStream("MAVEN-INF/repository/com/foo/bar/1.0/bar-1.0.jar"))) {
assertNotNull(jis, "test is wrongly setup, no nested jar, fix the createPlugin() method please");
From deecff7deab9ef550587851bbf49413690d1cc71 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Thu, 7 May 2026 17:58:38 +0200
Subject: [PATCH 37/41] feat(QTDI-2134): fix RegExp loading via SPI
---
.../form/internal/validation/JavascriptRegex.java | 12 ++++++++++++
.../runtime/manager/reflect/ReflectionService.java | 13 +++++++++++++
2 files changed, 25 insertions(+)
diff --git a/component-form/component-form-core/src/main/java/org/talend/sdk/component/form/internal/validation/JavascriptRegex.java b/component-form/component-form-core/src/main/java/org/talend/sdk/component/form/internal/validation/JavascriptRegex.java
index 4eff67920014b..66839b8b4750a 100644
--- a/component-form/component-form-core/src/main/java/org/talend/sdk/component/form/internal/validation/JavascriptRegex.java
+++ b/component-form/component-form-core/src/main/java/org/talend/sdk/component/form/internal/validation/JavascriptRegex.java
@@ -15,9 +15,12 @@
*/
package org.talend.sdk.component.form.internal.validation;
+import java.util.ServiceLoader;
import java.util.function.Predicate;
import org.mozilla.javascript.Context;
+import org.mozilla.javascript.RegExpLoader;
+import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
public class JavascriptRegex implements Predicate {
@@ -47,6 +50,15 @@ public boolean test(final CharSequence text) {
final String script = "new RegExp(regex, indicators).test(text)";
final Context context = Context.enter();
try {
+ // Rhino 1.9.0+: RegExp is registered via ServiceLoader.
+ // The ServiceLoader uses Thread.currentThread().getContextClassLoader() by default,
+ // which may not find the service in an isolated classloader context.
+ // Explicitly register RegExpProxy using Rhino's own classloader as fallback.
+ if (ScriptRuntime.getRegExpProxy(context) == null) {
+ ServiceLoader.load(RegExpLoader.class, context.getClass().getClassLoader())
+ .findFirst()
+ .ifPresent(loader -> ScriptRuntime.setRegExpProxy(context, loader.newProxy()));
+ }
final Scriptable scope = context.initStandardObjects();
scope.put("text", scope, text);
scope.put("regex", scope, regex);
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/reflect/ReflectionService.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/reflect/ReflectionService.java
index cb8b313a95757..cbc46f55ad124 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/reflect/ReflectionService.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/reflect/ReflectionService.java
@@ -44,6 +44,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@@ -69,6 +70,8 @@
import org.apache.xbean.recipe.ObjectRecipe;
import org.apache.xbean.recipe.UnsetPropertiesRecipe;
import org.mozilla.javascript.Context;
+import org.mozilla.javascript.RegExpLoader;
+import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.talend.sdk.component.api.record.Schema;
import org.talend.sdk.component.api.service.configuration.Configuration;
@@ -855,6 +858,16 @@ public boolean test(final CharSequence text) {
final String script = "new RegExp(regex, indicators).test(text)";
final Context context = Context.enter();
try {
+ // Rhino 1.9.0+: RegExp is registered via ServiceLoader.
+ // The ServiceLoader uses Thread.currentThread().getContextClassLoader() by default,
+ // which may not find the service in an isolated classloader context.
+ // Explicitly register RegExpProxy using Rhino's own classloader as fallback.
+ if (ScriptRuntime.getRegExpProxy(context) == null) {
+ ServiceLoader
+ .load(RegExpLoader.class, context.getClass().getClassLoader())
+ .findFirst()
+ .ifPresent(loader -> ScriptRuntime.setRegExpProxy(context, loader.newProxy()));
+ }
final Scriptable scope = context.initStandardObjects();
scope.put("text", scope, text);
scope.put("regex", scope, regex);
From 040860a254f5194b69e8cce50a4d6284d100540e Mon Sep 17 00:00:00 2001
From: ypiel
Date: Wed, 13 May 2026 11:41:52 +0200
Subject: [PATCH 38/41] feat(QTDI-1914): TCK connectors loading
deps/SPI/resources (#1178)
---
.../runtime/manager/ComponentManager.java | 4 +-
.../config/SimpleInputConfiguration.java | 46 ++
.../connectors/config/SimpleInputDataset.java | 50 +++
.../config/SimpleInputDatastore.java | 52 +++
.../connectors/simpleinput/SimpleInput.java | 64 +++
.../test/connectors/Messages.properties | 6 +-
.../connectors/config/Messages.properties | 13 +-
.../simpleinput/Messages.properties | 17 +
.../loading-analysis/README.md | 317 +++++++++++++
.../loading-dependencies-common/pom.xml | 127 ++++++
.../loadinganalysis/config/Connector.java | 69 +++
.../loadinganalysis/config/Dependency.java | 52 +++
.../config/DynamicDependencyConfig.java | 26 ++
.../AbstractDynamicDependenciesService.java | 417 ++++++++++++++++++
...bstractDynamicDependenciesServiceTest.java | 219 +++++++++
.../src/test/resources/version.properties | 17 +
.../pom.xml | 80 ++++
.../DynamicDependencySupported.java | 36 ++
.../config/Config.java | 66 +++
.../config/Dataset.java | 36 ++
.../config/Datastore.java | 30 ++
.../config/SubConfig.java | 45 ++
...denciesWithDataprepRunAnnotationInput.java | 66 +++
.../package-info.java | 23 +
...endenciesDataprepRunAnnotationService.java | 51 +++
.../src/main/resources/icons/dark/icon.svg | 64 +++
.../src/main/resources/icons/light/icon.svg | 64 +++
.../Messages.properties | 18 +
.../config/Messages.properties | 24 +
.../input/Messages.properties | 17 +
...nciesDataprepRunAnnotationServiceTest.java | 62 +++
.../dynamic-dependencies.properties | 18 +
.../loading-dependencies-with-dataset/pom.xml | 71 +++
.../withdataset/config/Config.java | 53 +++
.../withdataset/config/Dataset.java | 52 +++
.../withdataset/config/Datastore.java | 30 ++
.../DynamicDependenciesWithDatasetInput.java | 64 +++
.../withdataset/package-info.java | 23 +
...DynamicDependenciesWithDatasetService.java | 51 +++
.../src/main/resources/icons/dark/icon.svg | 67 +++
.../src/main/resources/icons/light/icon.svg | 67 +++
.../withdataset/Messages.properties | 18 +
.../withdataset/config/Messages.properties | 20 +
.../withdataset/input/Messages.properties | 17 +
...micDependenciesWithDatasetServiceTest.java | 67 +++
.../pom.xml | 72 +++
.../withdatastore/config/Config.java | 51 +++
.../withdatastore/config/Dataset.java | 36 ++
.../withdatastore/config/Datastore.java | 47 ++
...DynamicDependenciesWithDatastoreInput.java | 64 +++
.../withdatastore/package-info.java | 23 +
...namicDependenciesWithDatastoreService.java | 52 +++
.../src/main/resources/icons/dark/icon.svg | 64 +++
.../src/main/resources/icons/light/icon.svg | 64 +++
.../withdatastore/Messages.properties | 18 +
.../withdatastore/config/Messages.properties | 20 +
.../withdatastore/input/Messages.properties | 17 +
...cDependenciesWithDatastoreServiceTest.java | 55 +++
.../pom.xml | 71 +++
.../config/Config.java | 58 +++
.../config/Dataset.java | 36 ++
.../config/Datastore.java | 30 ++
.../config/SubConfig.java | 47 ++
...DynamicDependenciesConfigurationInput.java | 66 +++
.../package-info.java | 23 +
...namicDependenciesConfigurationService.java | 53 +++
.../src/main/resources/icons/dark/icon.svg | 64 +++
.../src/main/resources/icons/light/icon.svg | 64 +++
.../Messages.properties | 18 +
.../config/Messages.properties | 21 +
.../input/Messages.properties | 17 +
...cDependenciesConfigurationServiceTest.java | 57 +++
.../pom.xml | 87 ++++
.../StringProviderFromExternalSPI.java | 22 +
.../StringProviderSPIAsDependency.java | 22 +
.../StringProviderSPIAsDynamicDependency.java | 22 +
.../spiConsumers/AbstractSPIConsumer.java | 73 +++
.../spiConsumers/DependencySPIConsumer.java | 35 ++
.../DynamicDependencySPIConsumer.java | 35 ++
.../ExternalDependencySPIConsumer.java | 35 ++
.../resource.properties | 16 +
.../MULTIPLE_RESOURCE/common.properties | 16 +
.../loading-services-and-resources/pom.xml | 81 ++++
.../withspi/config/Config.java | 41 ++
.../withspi/config/Dataset.java | 40 ++
.../withspi/config/Datastore.java | 36 ++
.../DynamicDependenciesWithSPIInput.java | 64 +++
.../loadinganalysis/withspi/package-info.java | 23 +
.../withspi/service/CustomizeClassLoader.java | 107 +++++
.../DynamicDependenciesWithSPIService.java | 279 ++++++++++++
...untime.manager.ComponentManager$Customizer | 1 +
.../src/main/resources/icons/dark/icon.svg | 65 +++
.../src/main/resources/icons/light/icon.svg | 65 +++
.../withspi/Messages.properties | 19 +
.../withspi/config/Messages.properties | 25 ++
.../withspi/input/Messages.properties | 17 +
.../src/main/resources/version.properties | 17 +
.../DynamicDependenciesWithSPIInputTest.java | 110 +++++
.../loading-with-specific-isolation/pom.xml | 53 +++
.../specificisolation/config/Config.java | 41 ++
.../specificisolation/config/Dataset.java | 40 ++
.../specificisolation/config/Datastore.java | 111 +++++
.../input/SpecificIsolationInput.java | 56 +++
.../specificisolation/package-info.java | 23 +
.../service/SpecificIsolationService.java | 119 +++++
.../src/main/resources/icons/dark/icon.svg | 65 +++
.../src/main/resources/icons/light/icon.svg | 65 +++
.../specificisolation/Messages.properties | 18 +
.../config/Messages.properties | 43 ++
.../input/Messages.properties | 17 +
.../service/SpecificIsolationServiceTest.java | 22 +
.../sample-features/loading-analysis/pom.xml | 57 +++
.../service-provider-from-dependency/pom.xml | 95 ++++
.../ServiceProviderFromDependency.java | 27 ++
.../FROM_DEPENDENCY/resource.properties | 16 +
...ceInterfaces.StringProviderSPIAsDependency | 16 +
.../resources/MULTIPLE_RESOURCE/content.txt | 16 +
.../ServiceProviderFromDependencyTest.java | 32 ++
.../pom.xml | 95 ++++
.../ServiceProviderFromDynamicDependency.java | 26 ++
.../resource.properties | 16 +
...faces.StringProviderSPIAsDynamicDependency | 16 +
.../resources/MULTIPLE_RESOURCE/content.txt | 16 +
.../ServiceProviderFromDependencyTest.java | 33 ++
.../pom.xml | 95 ++++
...ServiceProviderFromExternalDependency.java | 27 ++
.../resource.properties | 16 +
...ceInterfaces.StringProviderFromExternalSPI | 16 +
.../resources/MULTIPLE_RESOURCE/content.txt | 16 +
...iceProviderFromExternalDependencyTest.java | 31 ++
.../loading-analysis/suppressions.xml | 23 +
sample-parent/sample-features/pom.xml | 12 +-
132 files changed, 6722 insertions(+), 5 deletions(-)
create mode 100644 sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/SimpleInputConfiguration.java
create mode 100644 sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/SimpleInputDataset.java
create mode 100644 sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/SimpleInputDatastore.java
create mode 100644 sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/simpleinput/SimpleInput.java
create mode 100644 sample-parent/sample-connector/src/main/resources/org/talend/sdk/component/test/connectors/simpleinput/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/README.md
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-common/pom.xml
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/config/Connector.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/config/Dependency.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/config/DynamicDependencyConfig.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/service/AbstractDynamicDependenciesService.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/AbstractDynamicDependenciesServiceTest.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/test/resources/version.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/pom.xml
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/annotation/DynamicDependencySupported.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Config.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Dataset.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Datastore.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/SubConfig.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/input/DynamicDependenciesWithDataprepRunAnnotationInput.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/package-info.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/service/DynamicDependenciesDataprepRunAnnotationService.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/icons/dark/icon.svg
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/icons/light/icon.svg
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/input/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/service/DynamicDependenciesDataprepRunAnnotationServiceTest.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/test/resources/TALEND-INF/dynamic-dependencies.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/pom.xml
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Config.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Dataset.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Datastore.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/input/DynamicDependenciesWithDatasetInput.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/package-info.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/service/DynamicDependenciesWithDatasetService.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/icons/dark/icon.svg
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/icons/light/icon.svg
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/input/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/service/DynamicDependenciesWithDatasetServiceTest.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/pom.xml
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Config.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Dataset.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Datastore.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/input/DynamicDependenciesWithDatastoreInput.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/package-info.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/service/DynamicDependenciesWithDatastoreService.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/icons/dark/icon.svg
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/icons/light/icon.svg
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/input/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/service/DynamicDependenciesWithDatastoreServiceTest.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/pom.xml
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Config.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Dataset.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Datastore.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/SubConfig.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/input/DynamicDependenciesWithDynamicDependenciesConfigurationInput.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/package-info.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/service/DynamicDependenciesWithDynamicDependenciesConfigurationService.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/icons/dark/icon.svg
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/icons/light/icon.svg
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/input/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/service/DynamicDependenciesWithDynamicDependenciesConfigurationServiceTest.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/pom.xml
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/serviceInterfaces/StringProviderFromExternalSPI.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/serviceInterfaces/StringProviderSPIAsDependency.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/serviceInterfaces/StringProviderSPIAsDynamicDependency.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/AbstractSPIConsumer.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/DependencySPIConsumer.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/DynamicDependencySPIConsumer.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/ExternalDependencySPIConsumer.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/resources/CLASSLOADER-TEST-LIBRARY/resource.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/resources/MULTIPLE_RESOURCE/common.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/pom.xml
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Config.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Dataset.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Datastore.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/input/DynamicDependenciesWithSPIInput.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/package-info.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/service/CustomizeClassLoader.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/service/DynamicDependenciesWithSPIService.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/META-INF/services/org.talend.sdk.component.runtime.manager.ComponentManager$Customizer
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/icons/dark/icon.svg
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/icons/light/icon.svg
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/input/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/version.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/input/DynamicDependenciesWithSPIInputTest.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/pom.xml
create mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Config.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Dataset.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Datastore.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/SpecificIsolationInput.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/package-info.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationService.java
create mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/dark/icon.svg
create mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/light/icon.svg
create mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/Messages.properties
create mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationServiceTest.java
create mode 100644 sample-parent/sample-features/loading-analysis/pom.xml
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-dependency/pom.xml
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdependency/ServiceProviderFromDependency.java
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/resources/FROM_DEPENDENCY/resource.properties
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/resources/META-INF/services/org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDependency
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/resources/MULTIPLE_RESOURCE/content.txt
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdependency/ServiceProviderFromDependencyTest.java
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/pom.xml
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdynamicdependency/ServiceProviderFromDynamicDependency.java
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/resources/FROM_DYNAMIC_DEPENDENCY/resource.properties
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/resources/META-INF/services/org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDynamicDependency
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/resources/MULTIPLE_RESOURCE/content.txt
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdynamicdependency/ServiceProviderFromDependencyTest.java
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/pom.xml
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromexternaldependency/ServiceProviderFromExternalDependency.java
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/resources/FROM_EXTERNAL_DEPENDENCY/resource.properties
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/resources/META-INF/services/org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderFromExternalSPI
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/resources/MULTIPLE_RESOURCE/content.txt
create mode 100644 sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromexternaldependency/ServiceProviderFromExternalDependencyTest.java
create mode 100644 sample-parent/sample-features/loading-analysis/suppressions.xml
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
index d56beeafa6b45..d2f80c4f1c8e7 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
@@ -2262,7 +2262,7 @@ default boolean ignoreBeamClassLoaderExclusions() {
}
/**
- * Disable default built-in component classpath building mecanism. This is useful when relying on
+ * Disable default built-in component classpath building mechanism. This is useful when relying on
* a custom {@link ContainerClasspathContributor} handling it.
*
* @return true if the default dependencies descriptor (TALEND-INF/dependencies.txt) must be ignored.
@@ -2295,4 +2295,4 @@ public interface ContainerClasspathContributor {
Path resolve(String path);
}
-}
+}
\ No newline at end of file
diff --git a/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/SimpleInputConfiguration.java b/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/SimpleInputConfiguration.java
new file mode 100644
index 0000000000000..888e7286b02e5
--- /dev/null
+++ b/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/SimpleInputConfiguration.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.test.connectors.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@GridLayout({
+ @GridLayout.Row({ "dataset" }),
+ @GridLayout.Row({ "debug" })
+})
+@Documentation("Configuration used by the simple input emitter.")
+public class SimpleInputConfiguration implements Serializable {
+
+ @Option
+ @Documentation("The simple input dataset.")
+ private SimpleInputDataset dataset;
+
+ @Option
+ @Documentation("Is it in debug mode.")
+ private boolean debug;
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/SimpleInputDataset.java b/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/SimpleInputDataset.java
new file mode 100644
index 0000000000000..d8eb8f2d37395
--- /dev/null
+++ b/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/SimpleInputDataset.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.test.connectors.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.type.DataSet;
+import org.talend.sdk.component.api.configuration.ui.DefaultValue;
+import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@DataSet("dataset")
+@GridLayout({
+ @GridLayout.Row({ "datastore" }),
+ @GridLayout.Row({ "resource" })
+})
+@Documentation("Dataset selecting a simple resource.")
+public class SimpleInputDataset implements Serializable {
+
+ @Option
+ @Documentation("The Simple input datastore.")
+ private SimpleInputDatastore datastore;
+
+ @Option
+ @DefaultValue("default")
+ @Documentation("The resource to process.")
+ private String resource;
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/SimpleInputDatastore.java b/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/SimpleInputDatastore.java
new file mode 100644
index 0000000000000..23001fbad3805
--- /dev/null
+++ b/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/config/SimpleInputDatastore.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.test.connectors.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.type.DataStore;
+import org.talend.sdk.component.api.configuration.ui.DefaultValue;
+import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
+import org.talend.sdk.component.api.configuration.ui.widget.Credential;
+import org.talend.sdk.component.api.meta.Documentation;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@DataStore("simpleDSO")
+@GridLayout({
+ @GridLayout.Row({ "url" }),
+ @GridLayout.Row({ "token" })
+})
+@Documentation("Datastore for simple input.")
+public class SimpleInputDatastore implements Serializable {
+
+ @Option
+ @DefaultValue("http://localhost")
+ @Documentation("The url to call.")
+ private String url;
+
+ @Option
+ @Credential
+ @Documentation("The token to use.")
+ private String token;
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/simpleinput/SimpleInput.java b/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/simpleinput/SimpleInput.java
new file mode 100644
index 0000000000000..0e7651906e3f3
--- /dev/null
+++ b/sample-parent/sample-connector/src/main/java/org/talend/sdk/component/test/connectors/simpleinput/SimpleInput.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.test.connectors.simpleinput;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.component.Icon;
+import org.talend.sdk.component.api.component.Version;
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.input.Emitter;
+import org.talend.sdk.component.api.input.Producer;
+import org.talend.sdk.component.api.meta.Documentation;
+import org.talend.sdk.component.api.record.Record;
+import org.talend.sdk.component.api.service.record.RecordBuilderFactory;
+import org.talend.sdk.component.test.connectors.config.SimpleInputConfiguration;
+
+@Version
+@Icon(value = Icon.IconType.CUSTOM, custom = "mapper")
+@Emitter(name = "simple-input")
+@Documentation("A simple emitter that doesn't expect dynamic dependencies and generated few records.")
+public class SimpleInput implements Serializable {
+
+ private RecordBuilderFactory recordBuilderFactory;
+
+ private final SimpleInputConfiguration configuration;
+
+ private boolean done = false;
+
+ public SimpleInput(@Option("configuration") final SimpleInputConfiguration configuration,
+ final RecordBuilderFactory recordBuilderFactory) {
+ this.configuration = configuration;
+ this.recordBuilderFactory = recordBuilderFactory;
+ }
+
+ @Producer
+ public Record next() {
+ if (done) {
+ return null;
+ }
+
+ done = true;
+
+ return recordBuilderFactory.newRecordBuilder()
+ .withString("url", configuration.getDataset().getDatastore().getUrl())
+ .withString("token", configuration.getDataset().getDatastore().getToken())
+ .withString("resource", configuration.getDataset().getResource())
+ .withBoolean("debug", configuration.isDebug())
+ .build();
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-connector/src/main/resources/org/talend/sdk/component/test/connectors/Messages.properties b/sample-parent/sample-connector/src/main/resources/org/talend/sdk/component/test/connectors/Messages.properties
index 1c613dc2a322f..38a9bd0f1ff5a 100644
--- a/sample-parent/sample-connector/src/main/resources/org/talend/sdk/component/test/connectors/Messages.properties
+++ b/sample-parent/sample-connector/src/main/resources/org/talend/sdk/component/test/connectors/Messages.properties
@@ -36,4 +36,8 @@ the_family.actions.connection.action_CREATE_CONNECTION_ERROR._displayName = Name
the_family.actions.user.action_USER._displayName = Name: Extension point for custom UI integrations and custom actions
the_family.actions.dataset.action_DISCOVER_DATASET._displayName = Name: Discover the datasets
the_family.actions.connection.action_BUILTIN_SUGGESTABLE._displayName = Name: BuiltInSuggestable
-the_family.actions.dynamic_values.action_DYNAMIC_VALUES._displayName = Name: DynamicValues
\ No newline at end of file
+the_family.actions.dynamic_values.action_DYNAMIC_VALUES._displayName = Name: DynamicValues
+
+# Simple input
+the_family.datastore.simpleDSO._displayName = Simple input datastore
+the_family.dataset.dataset._displayName = Simple input dataset
diff --git a/sample-parent/sample-connector/src/main/resources/org/talend/sdk/component/test/connectors/config/Messages.properties b/sample-parent/sample-connector/src/main/resources/org/talend/sdk/component/test/connectors/config/Messages.properties
index 8612eb9608bb2..23ace3a466692 100644
--- a/sample-parent/sample-connector/src/main/resources/org/talend/sdk/component/test/connectors/config/Messages.properties
+++ b/sample-parent/sample-connector/src/main/resources/org/talend/sdk/component/test/connectors/config/Messages.properties
@@ -93,4 +93,15 @@ NestedConfig.stringOption2._documentation = Doc: string option 2
Auth.nbAuthRetry._placeholder =
TheDatastore.timeout._placeholder =
-InputConfig.date._placeholder =
\ No newline at end of file
+InputConfig.date._placeholder =
+
+# The simpleInput connector configuration
+SimpleInputDatastore.url._displayName = URL
+SimpleInputDatastore.token._displayName = Token
+SimpleInputDataset.datastore._displayName =
+SimpleInputDataset.resource._displayName = Resource
+SimpleInputConfiguration.dataset._displayName =
+SimpleInputConfiguration.debug._displayName = Debug
+SimpleInputDatastore.url._placeholder =
+SimpleInputDatastore.token._placeholder =
+SimpleInputDataset.resource._placeholder =
diff --git a/sample-parent/sample-connector/src/main/resources/org/talend/sdk/component/test/connectors/simpleinput/Messages.properties b/sample-parent/sample-connector/src/main/resources/org/talend/sdk/component/test/connectors/simpleinput/Messages.properties
new file mode 100644
index 0000000000000..033c5195b4c96
--- /dev/null
+++ b/sample-parent/sample-connector/src/main/resources/org/talend/sdk/component/test/connectors/simpleinput/Messages.properties
@@ -0,0 +1,17 @@
+# Copyright (C) 2006-2025 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+the_family.simple-input._displayName = Simple Input
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/README.md b/sample-parent/sample-features/loading-analysis/README.md
new file mode 100644
index 0000000000000..3fd0c0861230a
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/README.md
@@ -0,0 +1,317 @@
+# Loading Analysis Module
+
+## Overview
+
+The `loading-analysis` module provides several TCK connector plugins designed to validate the `@DynamicDependencies` feature integration, at design time and runtime. It contains several connectors organized into two categories:
+
+- First are connectors with a service that inherits `AbstractDynamicDependenciesService` and that check:
+ - All supported ways to call `@DynamicDependencies` annotated services, according to expected configuration types
+ - Loading of static, dynamic and provided dependencies
+ - Load a TCK connectors as dynamic dependencies and retrieve data from them
+- The other one is `DynamicDependenciesWithSPIInput`, and it checks:
+ - `Service Provider Interface` (_SPI_) loading from different dependency scopes:
+ - Standard dependency
+ - Dynamic dependency
+ - Provided by the runtime
+ - Loading of resources from those dependencies
+ - Loading a single resource as stream
+ - Loading multiple resources at once
+
+## Check dynamic dependencies loading
+When TCK connectors are built, a file `TALEND-INF/dependencies.txt` is generated in the `jar`, that contains all its dependencies as a list of maven coordinates (_group:artifactId:version:scope_):
+
+**dependencies.txt**
+```
+net.datafaker:datafaker:jar:2.4.2:compile
+org.yaml:snakeyaml:jar:2.4:compile
+com.github.curious-odd-man:rgxgen:jar:2.0:compile
+com.googlecode.libphonenumber:libphonenumber:jar:8.13.50:compile
+org.talend.components.extension:polling:jar:1.2512.0:compile
+```
+
+It happens that some dependencies can only be computed at design time, because, it depends on the connector's configuration. To support this, TCK provides the `@DynamicDependencies` annotation that can be used on a service. The annotated service should return a list of maven coordinates as strings:
+```java
+ @DynamicDependencies()
+ public List getDynamicDependencies(@Option("theDataset") final Dataset dataset) {
+ List dynamicDependencies = new ArrayList<>();
+ if(dataset.hasASpecialOption()){
+ dynamicDependencies.add("org.company:special-dependency:1.0.0");
+ dynamicDependencies.add("org.company:another-special-dependency:2.1.0");
+ }
+ return dynamicDependencies;
+ }
+```
+Then, the final application that integrates TCK, call the service with the configuration the user set, load those dependencies and provide them for the runtime.
+
+### Connectors in this module
+As you can see in the previous example, the annotated `@DynamicDependencies` service expect a parameter. This parameter can be of 3 different types:
+- A datastore
+- A dataset
+- Any configuration annotated with `DynamicDependenciesConfiguration`
+
+(_This documentation will not mention the deprecated `DynamicDependencySupported` provided by the `tDataprepRun` connector._)
+
+So, 3 TCK modules have been designed, each one provide a service with one of those parameter types:
+- loading-dependencies-with-datastore
+- loading-dependencies-with-dataset
+- loading-dependencies-with-dynamicDependenciesConfiguration
+Those 3 modules has the module `loading-dependencies-common` as dependency. They all have a service that inherits `AbstractDynamicDependenciesService`, that implements the `@DynamicDependencies` annotated method.
+
+#### How to configure them?
+Each of those TCK modules provide an input connector in which you can configure:
+- A list of maven coordinate that will be returned as dynamic dependencies.
+ - The user has to set the maven coordinate and a class to load coming from this dependency. If the class is successfully loaded, it means that the dependency is well loaded.
+ - The coordinate `org.apache.maven.resolver:maven-resolver-api:2.0.14` is also returned by the `@DynamicDependencies`, the class to load is `org.eclipse.aether.artifact.DefaultArtifact`.
+- A list of maven coordinates that references a TCK connector.
+ - For each of them, the user has to set the connector's family, its name, its version and the configuration to use to retrieve data from it.
+ - A boolean option `useDynamicDependencyLoading` is also provided to indicate that we also want to load dependencies coming from the configured connector.
+
+Here is an example of connector's configuration:
+```
+- groupId: org.talend.components
+- artifactId: data-generator
+- version: 1.2512.0
+- connector's family: DataGenerator
+- connector's name: DataGeneratorInput
+- Connector's version: 1
+- load transitive dependencies: true
+- connector's configuration:
+ {
+ "configuration.minimumRows": "1000",
+ "configuration.maximumRows": "10000",
+ "configuration.dataset.seed": "123456",
+ "configuration.dataset.customLocale": "false",
+ "configuration.dataset.customSeed": "false",
+ "configuration.dataset.rows": "10000",
+ "configuration.dataset.fields[0].name": "name",
+ "configuration.dataset.fields[0].type": "LASTNAME",
+ "configuration.dataset.fields[0].$type_name": "Last name",
+ "configuration.dataset.fields[0].blank": "0",
+ "configuration.randomRows": "false"
+ }
+```
+
+#### Output of those connectors
+All of those connectors generate the same output. Only the configuration type of the `@DynamicDependencies` annotated service is different.
+
+It will generate TCK/records containing those fields:
+- `maven`: the maven coordinate of the dependency
+- `clazz`: the class that we tried to load from this dependency
+- `is_loaded`: a boolean indicating if the class has been successfully loaded
+- `connector_classloader`: the classloader name of the dynamic dependency connector
+- `clazz_classloader`: the classloader name of the loaded class
+- `from_location`: the location from which the class has been loaded
+- `is_tck_container`: a boolean indicating if the dependency is a standard dependency or a TCK plugin
+- `first_record`: if the dependency is a TCK plugin, this is the first record retrieve from the loaded connector
+- `root_repository`: The value of the property `talend.component.manager.m2.repository`
+- `runtime_classpath`: the value of the property `java.class.path`
+- `working_directory`: the value of the property `user.dir`
+- `comment`: a comment
+
+##### The first record is the result of the class loading from a static dependency, the generated record should be something like:
+```
++-----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| key | value |
++-----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| maven | org.talend.sdk.component.loading-analysis:loading-dependencies-common:N/A |
+| clazz | org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency |
+| is_loaded | true |
+| connector_classloader | org.talend.sdk.component.classloader.ConfigurableClassLoader@9ebe38b |
+| clazz_classloader | org.talend.sdk.component.classloader.ConfigurableClassLoader@9ebe38b |
+| from_location | jar:file:/C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository/org/talend/sdk/component/loading-analysis/loading-dependencies-common/1.90.0-SNAPSHOT/loading-dependencies-common-1.90.0-SNAPSHOT.jar!/org/talend/sdk/component/sample/feature/loadinganalysis/config/Dependency.class |
+| is_tck_container | false |
+| first_record | null |
+| root_repository | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository |
+| runtime_classpath | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/workspace/AAAA/poms/jobs/process/qtdi2134_dyndeps_0.1/target/classpath.jar;/C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.jar; |
+| working_directory | C:\tmp\202601_dyndeps_exports\Talend-Studio-20260121_1719-V8.0.1 |
+| comment | Check static dependency. |
++-----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+```
+In this example we can see that we try to load the class `org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency` from the dependency `org.talend.sdk.component.loading-analysis:loading-dependencies-common`.
+The version is `N/A` since it is not needed, the dependency is a static one and is loaded at build time.
+The `DynamicDependencyWithXxxInput` is well loaded from `org.talend.sdk.component.classloader.ConfigurableClassLoader` as the class to test.
+
+##### The second record is the result when it tries to load a class from the runtime. It tries to load `org.talend.sdk.component.api.service.asyncvalidation.ValidationResult` that is provided by TCK:
+```
++-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| key | value |
++-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| maven | org.talend.sdk.component:component-runtime:N/A |
+| clazz | org.talend.sdk.component.api.service.asyncvalidation.ValidationResult |
+| is_loaded | true |
+| connector_classloader | org.talend.sdk.component.classloader.ConfigurableClassLoader@9ebe38b |
+| clazz_classloader | jdk.internal.loader.ClassLoaders$AppClassLoader@73d16e93 |
+| from_location | jar:file:/C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository/org/talend/sdk/component/component-api/1.89.0-QTDI-2134-YPL-SNAPSHOT/component-api-1.89.0-QTDI-2134-YPL-SNAPSHOT.jar!/org/talend/sdk/component/api/service/asyncvalidation/ValidationResult.class |
+| is_tck_container | false |
+| first_record | null |
+| root_repository | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository |
+| runtime_classpath | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/workspace/AAAA/poms/jobs/process/qtdi2134_dyndeps_0.1/target/classpath.jar;/C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.jar; |
+| working_directory | C:\tmp\202601_dyndeps_exports\Talend-Studio-20260121_1719-V8.0.1 |
+| comment | Check provided dependency. |
++-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+```
+In this example, we can see that the class `org.talend.sdk.component.api.service.asyncvalidation.ValidationResult` is loaded from the `AppClassLoader`, meaning that it is provided by the runtime and not loaded from the `ConfigurableClassLoader` of the TCK container.
+
+##### The third record is the result of loading a class from a dynamic dependency:
+```
++-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| key | value |
++-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| maven | org.apache.maven.resolver:maven-resolver-api:2.0.14 |
+| clazz | org.eclipse.aether.artifact.DefaultArtifact |
+| is_loaded | true |
+| connector_classloader | org.talend.sdk.component.classloader.ConfigurableClassLoader@9ebe38b |
+| clazz_classloader | jdk.internal.loader.ClassLoaders$AppClassLoader@73d16e93 |
+| from_location | jar:file:/C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository/org/apache/maven/resolver/maven-resolver-api/2.0.14/maven-resolver-api-2.0.14.jar!/org/eclipse/aether/artifact/DefaultArtifact.class |
+| is_tck_container | false |
+| first_record | null |
+| root_repository | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository |
+| runtime_classpath | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/workspace/AAAA/poms/jobs/process/qtdi2134_dyndeps_0.1/target/classpath.jar;/C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.jar; |
+| working_directory | C:\tmp\202601_dyndeps_exports\Talend-Studio-20260121_1719-V8.0.1 |
+| comment | An instance has been instantiated and assigned. |
++-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+```
+This is the result of the default dynamic dependency loading. We can see that the class `org.eclipse.aether.artifact.DefaultArtifact` has been successfully loaded from the dynamic dependency `org.apache.maven.resolver:maven-resolver-api:2.0.14`.
+In this environment, it has been loaded from the `AppClassLoader`. It happens when all dependencies are flatten in single folder, and not organized as a maven repository.
+
+##### Example of a record when loading a TCK connector as dynamic dependency
+```
++-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| key | value |
++-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| maven | org.talend.components:data-generator:1.2512.0 |
+| clazz | N/A |
+| is_loaded | true |
+| connector_classloader | org.talend.sdk.component.classloader.ConfigurableClassLoader@9ebe38b |
+| clazz_classloader | N/A |
+| from_location | N/A |
+| is_tck_container | true |
+| first_record | {"name":"Rogahn"} |
+| root_repository | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository |
+| runtime_classpath | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/workspace/AAAA/poms/jobs/process/qtdi2134_dyndeps_0.1/target/classpath.jar;/C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.jar; |
+| working_directory | C:\tmp\202601_dyndeps_exports\Talend-Studio-20260121_1719-V8.0.1 |
+| comment | |
++-----------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+```
+In that example, we can see that we don't try to load a class, `clazz: N/A`, but TCK plugin, `is_tck_container: true`. It has been well loaded since we retrieve some data from it:
+```
+| first_record | {"name":"Rogahn"}
+```
+
+## Check SPI and resource loading
+The `loading-services-and-resources` provides an input connector that will try to load:
+- The SPI implementation from a static dependency
+- The SPI implementation from a dynamic dependency
+- The SPI implementation provided by the runtime
+- A resource as stream from a static dependency
+- A resource as stream from a dynamic dependency
+- A resource as stream provided by the runtime
+- Multiple resources at once from a static, dynamic and provided dependencies
+
+There is no configuration to set in that connector.
+
+It generates TCK records containing those fields:
+- `value`: a string value returned by the loaded SPI implementation or values from resources forthe last record
+- `SPI_Interface`: the SPI interface class name
+- `SPI_Interface_classloader`: the classloader name that loaded the SPI interface
+- `SPI_Impl`: the SPI implementation class name
+- `SPI_Impl_classloader`: the classloader name that loaded the SPI implementation
+- `comment`: a comment
+- `rootRepository`: The value of the property `talend.component.manager.m2.repository`
+- `classpath`: the value of the property `java.class.path`
+- `workingDirectory`: the value of the property `user.dir`
+
+### The first record checks SPI implementation provided by a static dependency
+The SPI implementation is provided by the dependency `org.talend.sdk.component.loading-analysis:service-provider-from-dependency`.
+```
++---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| key | value |
++---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| value | ServiceProviderFromDependency value |
+| SPI_Interface | interface org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDependency |
+| SPI_Interface_classloader | org.talend.sdk.component.classloader.ConfigurableClassLoader@6457a08f |
+| SPI_Impl | class org.talend.sdk.component.sample.feature.loadinganalysis.serviceproviderfromdependency.ServiceProviderFromDependency |
+| SPI_Impl_classloader | org.talend.sdk.component.classloader.ConfigurableClassLoader@6457a08f |
+| comment | SPI implementation loaded from a dependency. |
+| rootRepository | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository |
+| classpath | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/workspace/AAAA/poms/jobs/process/qtdi2134_dyndeps_withspi_service_0.1/target/classpath.jar;/C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.jar; |
+| workingDirectory | C:\tmp\202601_dyndeps_exports\Talend-Studio-20260121_1719-V8.0.1 |
++---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+```
+We can see that the SPI implementation has been well loaded, since the value is retrieved, and has been loaded by the container classloader `ConfigurableClassLoader` as expected.
+
+### The second record checks SPI implementation provided by a dynamic dependency
+The spi implementation is provided by the dependency `org.talend.sdk.component.loading-analysis:service-provider-from-dynamic-dependency`. It is returned by the `@DynamicDependency` service.
+```
++---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| key | value |
++---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| value | ServiceProviderFromDynamicDependency value |
+| SPI_Interface | interface org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDynamicDependency |
+| SPI_Interface_classloader | org.talend.sdk.component.classloader.ConfigurableClassLoader@6457a08f |
+| SPI_Impl | class org.talend.sdk.component.sample.feature.loadinganalysis.serviceproviderfromdynamicdependency.ServiceProviderFromDynamicDependency |
+| SPI_Impl_classloader | org.talend.sdk.component.classloader.ConfigurableClassLoader@6457a08f |
+| comment | SPI implementation loaded from a dynamic dependency. |
+| rootRepository | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository |
+| classpath | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/workspace/AAAA/poms/jobs/process/qtdi2134_dyndeps_withspi_service_0.1/target/classpath.jar;/C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.jar; |
+| workingDirectory | C:\tmp\202601_dyndeps_exports\Talend-Studio-20260121_1719-V8.0.1 |
++---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+```
+In this second record, we see that the SPI implementation has been loaded from the `ConfigurableClassLoader`.
+
+### The third record checks SPI implementation provided by the runtime
+The spi implementation is provided by the dependency `org.talend.sdk.component.loading-analysis:service-provider-from-external-dependency`. In the studio, we can add this library using the `tLibraryLoad` connector.
+```
++---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| key | value |
++---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| value | [ERROR] StringProviderFromExternalSPI not loaded! |
+| SPI_Interface | interface org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderFromExternalSPI |
+| SPI_Interface_classloader | org.talend.sdk.component.classloader.ConfigurableClassLoader@6457a08f |
+| SPI_Impl | Not found |
+| SPI_Impl_classloader | Not found |
+| comment | SPI implementation loaded from a runtime/provided dependency. |
+| rootRepository | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository |
+| classpath | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/workspace/AAAA/poms/jobs/process/qtdi2134_dyndeps_withspi_service_0.1/target/classpath.jar;/C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.jar; |
+| workingDirectory | C:\tmp\202601_dyndeps_exports\Talend-Studio-20260121_1719-V8.0.1 |
++---------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+```
+In this thirds record, we can see that the connector were not able to find implementation for this SPI whereas it should be available in the runtime.
+
+### The fourth record checks resource loading from dependencies
+The last record is quite different. Only the `value` field is interesting. It contains a json document with resources loading results:
+```
++---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| key | value |
++---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+| value | {"contentFromResourceDependency":"Message from a dependency resource.","contentFromResourceDynamicDependency":"Message from a dynamic dependency resource.","contentFromResourceExternalDependency":"Message from an external dependency resource.","contentFromMultipleResources":"There should be 3 different values:\nContent from static dependency\nContent from dynamic dependency\nContent from static dependency\nContent from dynamic dependency"} |
+| SPI_Interface | N/A |
+| SPI_Interface_classloader | N/A |
+| SPI_Impl | N/A |
+| SPI_Impl_classloader | N/A |
+| comment | Resources loading. |
+| rootRepository | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository |
+| classpath | C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/workspace/AAAA/poms/jobs/process/qtdi2134_dyndeps_withspi_service_0.1/target/classpath.jar;/C:/tmp/202601_dyndeps_exports/Talend-Studio-20260121_1719-V8.0.1/configuration/.m2/repository/org/apache/commons/commons-lang3/3.18.0/commons-lang3-3.18.0.jar; |
+| workingDirectory | C:\tmp\202601_dyndeps_exports\Talend-Studio-20260121_1719-V8.0.1 |
++---------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
+```
+Here is the json documentation contained in the `value` field:
+```
+{
+ "contentFromResourceDependency": "Message from a dependency resource.",
+ "contentFromResourceDynamicDependency": "Message from a dynamic dependency resource.",
+ "contentFromResourceExternalDependency": "Message from an external dependency resource.",
+ "contentFromMultipleResources": "There should be 3 different values:\nContent from static dependency\nContent from dynamic dependency\nContent from static dependency\nContent from dynamic dependency"
+}
+```
+The `DynamicDependenciesWithSPIInput` connector tries to load some resources using `DynamicDependenciesWithSPIService.class.getClassLoader().getResourceAsStream(resource)`:
+- `FROM_DEPENDENCY/resource.properties`: this resource exists only in `org.talend.sdk.component.loading-analysis:service-provider-from-dependency` module. The resource value is copied in the `contentFromResourceDependency` field of the record.
+- `FROM_DYNAMIC_DEPENDENCY/resource.properties`: this resource exists only in `org.talend.sdk.component.loading-analysis:service-provider-from-dynamic-dependency` module. The resource value is copied in the `contentFromResourceDynamicDependency` field of the record.
+- `FROM_EXTERNAL_DEPENDENCY/resource.properties`: this resource exists only in `org.talend.sdk.component.loading-analysis:service-provider-from-external-dependency` module. The resource value is copied in the `contentFromResourceExternalDependency` field of the record.
+
+All those three resources are successfully loaded in this example.
+
+The last field, `contentFromMultipleResources` contain the result of loading multiple resources at once using `DynamicDependenciesWithSPIService.class.getClassLoader().getResources(resource)` for the resource path `FROM_MULTIPLE/resource.txt`.
+This resource exists in all the three modules `org.talend.sdk.component.loading-analysis:service-provider-from-dependency`, `org.talend.sdk.component.loading-analysis:service-provider-from-dynamic-dependency`, `org.talend.sdk.component.loading-analysis:service-provider-from-external-dependency`.
+So, 3 values should be concatenated in this field if everything were loaded. In the example, the content of this resource is successfully loaded from static and dynamic dependencies, but twice for each! And, the `FROM_MULTIPLE/resource.txt`
+in `org.talend.sdk.component.loading-analysis:service-provider-from-external-dependency` is not found.
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-common/pom.xml b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/pom.xml
new file mode 100644
index 0000000000000..a3d37787e4ecd
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/pom.xml
@@ -0,0 +1,127 @@
+
+
+
+ 4.0.0
+
+ org.talend.sdk.component.loading-analysis
+ loading-analysis
+ 1.91.0-SNAPSHOT
+
+
+
+
+ loading-dependencies-common
+ jar
+ Component Runtime :: Sample Features :: Loading Analysis :: Loading Dependencies Common
+
+
+
+ org.talend.sdk.component
+ component-runtime-manager
+ ${project.version}
+ provided
+
+
+ org.apache.maven.resolver
+ maven-resolver-api
+ 2.0.14
+
+ provided
+
+
+
+
+
+
+
+
+ src/test/resources
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ loading.dependencies.common
+
+
+
+
+
+
+ test-jar
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ create-TALEND-INF/dependencies.txt
+
+ list
+
+ none
+
+
+
+
+ org.talend.sdk.component
+ talend-component-maven-plugin
+ ${project.version}
+
+
+ talend-component-validate
+
+ false
+ false
+ false
+
+
+
+ talend-dependencies
+
+ dependencies
+
+ none
+
+
+ talend-component-bundle
+
+ car
+
+ none
+
+
+ talend-scan-descriptor
+
+ scan-descriptor
+
+ none
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/config/Connector.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/config/Connector.java
new file mode 100644
index 0000000000000..0292029770d12
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/config/Connector.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@GridLayout(value = {
+ @GridLayout.Row({ "groupId", "artifactId", "version", "connectorFamily", "connectorName", "connectorVersion",
+ "loadTransitiveDependencies", "connectorConfiguration" })
+})
+@NoArgsConstructor
+@AllArgsConstructor
+public class Connector implements Serializable {
+
+ @Option
+ @Documentation("The connector's group id.")
+ private String groupId;
+
+ @Option
+ @Documentation("The connector's artifact id.")
+ private String artifactId;
+
+ @Option
+ @Documentation("The connector's artifact version.")
+ private String version;
+
+ @Option
+ @Documentation("The connector's family.")
+ private String connectorFamily;
+
+ @Option
+ @Documentation("The connector's name.")
+ private String connectorName;
+
+ @Option
+ @Documentation("The connector's version.")
+ private int connectorVersion;
+
+ @Option
+ @Documentation("Load transitive dependencies from TALEND-INF/dependencies.txt.")
+ private boolean loadTransitiveDependencies;
+
+ @Option
+ @Documentation("The connector's configuration.")
+ private String connectorConfiguration;
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/config/Dependency.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/config/Dependency.java
new file mode 100644
index 0000000000000..a8d61c85e3def
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/config/Dependency.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@GridLayout(value = {
+ @GridLayout.Row({ "groupId", "artifactId", "version", "clazz" })
+})
+public class Dependency implements Serializable {
+
+ @Option
+ @Documentation("The groupId of the dependency.")
+ private String groupId;
+
+ @Option
+ @Documentation("The artifactId of the dependency.")
+ private String artifactId;
+
+ @Option
+ @Documentation("The version of the dependency.")
+ private String version;
+
+ @Option
+ @Documentation("The class to try to load from this dependency.")
+ private String clazz;
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/config/DynamicDependencyConfig.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/config/DynamicDependencyConfig.java
new file mode 100644
index 0000000000000..2414f75916cbe
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/config/DynamicDependencyConfig.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.config;
+
+import java.util.List;
+
+public interface DynamicDependencyConfig {
+
+ List getDependencies();
+
+ List getConnectors();
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/service/AbstractDynamicDependenciesService.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/service/AbstractDynamicDependenciesService.java
new file mode 100644
index 0000000000000..7fc3959f91499
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/service/AbstractDynamicDependenciesService.java
@@ -0,0 +1,417 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.service;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Serializable;
+import java.io.StringReader;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.talend.sdk.component.api.exception.ComponentException;
+import org.talend.sdk.component.api.record.Record;
+import org.talend.sdk.component.api.record.Record.Builder;
+import org.talend.sdk.component.api.record.Schema;
+import org.talend.sdk.component.api.record.Schema.Type;
+import org.talend.sdk.component.api.service.Service;
+import org.talend.sdk.component.api.service.dependency.Resolver;
+import org.talend.sdk.component.api.service.record.RecordBuilderFactory;
+import org.talend.sdk.component.api.service.source.ProducerFinder;
+import org.talend.sdk.component.runtime.manager.ComponentManager;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Connector;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.DynamicDependencyConfig;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public abstract class AbstractDynamicDependenciesService implements Serializable {
+
+ public static final String ENTRY_MAVEN = "maven";
+
+ public static final String ENTRY_CLASS = "clazz";
+
+ public static final String ENTRY_IS_LOADED = "is_loaded";
+
+ public static final String ENTRY_CONNECTOR_CLASSLOADER = "connector_classloader";
+
+ public static final String ENTRY_CLAZZ_CLASSLOADER = "clazz_classloader";
+
+ public static final String ENTRY_FROM_LOCATION = "from_location";
+
+ public static final String ENTRY_IS_TCK_CONTAINER = "is_tck_container";
+
+ public static final String ENTRY_FIRST_RECORD = "first_record";
+
+ public static final String ENTRY_ROOT_REPOSITORY = "root_repository";
+
+ public static final String ENTRY_RUNTIME_CLASSPATH = "runtime_classpath";
+
+ public static final String ENTRY_WORKING_DIRECTORY = "working_directory";
+
+ public static final String ENTRY_COMMENT = "comment";
+
+ @Service
+ private RecordBuilderFactory factory;
+
+ @Service
+ private ProducerFinder finder;
+
+ @Service
+ private Resolver resolver;
+
+ public Iterator loadIterator(final DynamicDependencyConfig dynamicDependencyConfig) {
+ Schema schema = buildSchema();
+
+ List standardDependencies = loadStandardDependencies(dynamicDependencyConfig, schema);
+ List additionalConnectors = loadConnectors(dynamicDependencyConfig, schema);
+
+ return Stream.concat(standardDependencies.stream(), additionalConnectors.stream()).iterator();
+ }
+
+ private List loadStandardDependencies(final DynamicDependencyConfig dynamicDependencyConfig,
+ final Schema schema) {
+ List records = new ArrayList<>();
+
+ List dependencies = new ArrayList<>();
+
+ // Hardcoded dependency to check that 'static' dependencies from configuration are well loaded and assigned
+ dependencies.add(new Dependency("org.talend.sdk.component.loading-analysis",
+ "loading-dependencies-common",
+ "N/A",
+ "org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency"));
+
+ // Hardcoded dependency to check that 'provided' dependencies are well loaded and assigned
+ dependencies.add(new Dependency("org.talend.sdk.component",
+ "component-runtime",
+ "N/A",
+ "org.talend.sdk.component.api.service.asyncvalidation.ValidationResult"));
+
+ dependencies.addAll(additionalDependencies());
+
+ dependencies.addAll(dynamicDependencyConfig.getDependencies());
+ for (Dependency dependency : dependencies) {
+ String comment = "";
+ String maven = String.format("%s:%s:%s", dependency.getGroupId(), dependency.getArtifactId(),
+ dependency.getVersion());
+
+ boolean isLoaded = false;
+ String connectorClassLoaderId = this.getClass().getClassLoader().toString();
+ String clazzClassLoaderId = "N/A";
+ String fromLocation = "N/A";
+ try {
+ Class> clazz = Class.forName(dependency.getClazz());
+ isLoaded = true;
+ clazzClassLoaderId = clazz.getClassLoader().toString();
+
+ // This way to retrieve the location works even if the jar from where clazz comes from
+ // is nested into another jar (uber jar scenario)
+ String classPath = clazz.getName().replace('.', '/') + ".class";
+ URL url = clazz.getClassLoader().getResource(classPath);
+ fromLocation = String.valueOf(url);
+
+ if ("maven-resolver-api".equals(dependency.getArtifactId())) {
+ // This dependency is automatically added by additionalDependencies()
+ checkAssignmentFromDynamicDependency();
+ comment = "Hardcoded dynamic dependency test. The instantiated object has been assigned.";
+ } else if ("loading-dependencies-common".equals(dependency.getArtifactId())) {
+ comment = "Hardcoded 'static' dependency test.";
+ } else if ("component-runtime".equals(dependency.getArtifactId())) {
+ comment = "Hardcoded provided dependency test.";
+ }
+
+ } catch (ClassNotFoundException e) {
+ logError("Cannot load class %s from system classloader".formatted(dependency.getClazz()), e);
+ }
+
+ Record record = buildRecord(schema,
+ dynamicDependencyConfig,
+ maven,
+ dependency.getClazz(),
+ isLoaded,
+ connectorClassLoaderId,
+ clazzClassLoaderId,
+ fromLocation,
+ false,
+ Optional.empty(),
+ comment);
+ records.add(record);
+ }
+
+ return records;
+ }
+
+ private List loadConnectors(final DynamicDependencyConfig dynamicDependencyConfig, final Schema schema) {
+ List records = new ArrayList<>();
+ for (Connector connector : dynamicDependencyConfig.getConnectors()) {
+
+ String maven = String.format("%s:%s:%s", connector.getGroupId(), connector.getArtifactId(),
+ connector.getVersion());
+
+ String connectorClassLoaderId = this.getClass().getClassLoader().toString();
+ String clazzClassLoaderId = "N/A";
+ String fromLocation = "N/A";
+ Optional optionalRecord = testLoadingData(connector);
+ boolean isLoaded = optionalRecord.isPresent();
+
+ Record record = buildRecord(schema,
+ dynamicDependencyConfig,
+ maven,
+ "N/A",
+ isLoaded,
+ connectorClassLoaderId,
+ clazzClassLoaderId,
+ fromLocation,
+ true,
+ optionalRecord,
+ "");
+ records.add(record);
+ }
+
+ return records;
+
+ }
+
+ // Checkstyle off to let have 11 parameters to this method (normally 10 max)
+ // CHECKSTYLE:OFF
+ private Record buildRecord(final Schema schema,
+ final DynamicDependencyConfig dynamicDependencyConfig,
+ final String maven,
+ final String clazz,
+ final boolean isLoaded,
+ final String connectorClassLoaderId,
+ final String clazzClassLoaderId,
+ final String fromLocation,
+ final boolean isTckContainer,
+ final Optional firstRecord,
+ final String comment) {
+
+ Builder builder = factory.newRecordBuilder(schema);
+ Builder recordBuilder = builder
+ .withString(ENTRY_MAVEN, maven)
+ .withString(ENTRY_CLASS, clazz)
+ .withBoolean(ENTRY_IS_LOADED, isLoaded)
+ .withString(ENTRY_CONNECTOR_CLASSLOADER, connectorClassLoaderId)
+ .withString(ENTRY_CLAZZ_CLASSLOADER, clazzClassLoaderId)
+ .withString(ENTRY_FROM_LOCATION, fromLocation)
+ .withBoolean(ENTRY_IS_TCK_CONTAINER, isTckContainer)
+ .withString(ENTRY_COMMENT, comment);
+
+ firstRecord.ifPresent(record -> builder.withRecord(ENTRY_FIRST_RECORD, record));
+
+ String rootRepository =
+ String.valueOf(ComponentManager.instance().getContainer().getRootRepositoryLocationPath());
+ String runtimeClasspath = System.getProperty("java.class.path");
+ String workDirectory = System.getProperty("user.dir");
+
+ recordBuilder = recordBuilder
+ .withString(ENTRY_ROOT_REPOSITORY, rootRepository)
+ .withString(ENTRY_RUNTIME_CLASSPATH, runtimeClasspath)
+ .withString(ENTRY_WORKING_DIRECTORY, workDirectory);
+
+ return recordBuilder.build();
+ }
+ // CHECKSTYLE:ON
+
+ private Optional testLoadingData(final Connector connector) {
+ Iterator recordIterator = this.loadData(connector.getConnectorFamily(), connector.getConnectorName(),
+ connector.getConnectorVersion(), json2Map(connector.getConnectorConfiguration()));
+ return Optional.ofNullable(
+ recordIterator.hasNext() ? recordIterator.next() : null);
+ }
+
+ private Map json2Map(final String json) {
+ // Transform the given json to map
+ if (json == null || json.isBlank()) {
+ return Collections.emptyMap();
+ }
+ try (JsonReader reader = Json.createReader(new StringReader(json))) {
+ JsonObject jsonObject = reader.readObject();
+ Map map = new HashMap<>();
+ for (String key : jsonObject.keySet()) {
+ map.put(key, jsonObject.getString(key, null));
+ }
+ return map;
+ } catch (Exception e) {
+ log.error("conversion JSON: {}", e.getMessage(), e);
+ return Collections.emptyMap();
+ }
+ }
+
+ public Schema buildSchema() {
+ Schema.Builder builder = factory.newSchemaBuilder(Type.RECORD)
+ .withEntry(factory.newEntryBuilder().withName(ENTRY_MAVEN).withType(Type.STRING).build())
+ .withEntry(factory.newEntryBuilder().withName(ENTRY_CLASS).withType(Type.STRING).build())
+ .withEntry(factory.newEntryBuilder().withName(ENTRY_IS_LOADED).withType(Type.BOOLEAN).build())
+ .withEntry(
+ factory.newEntryBuilder().withName(ENTRY_CONNECTOR_CLASSLOADER).withType(Type.STRING).build())
+ .withEntry(factory.newEntryBuilder().withName(ENTRY_CLAZZ_CLASSLOADER).withType(Type.STRING).build())
+ .withEntry(factory.newEntryBuilder().withName(ENTRY_FROM_LOCATION).withType(Type.STRING).build())
+ .withEntry(factory.newEntryBuilder().withName(ENTRY_IS_TCK_CONTAINER).withType(Type.BOOLEAN).build())
+ .withEntry(factory.newEntryBuilder()
+ .withName(ENTRY_FIRST_RECORD)
+ .withType(Type.RECORD)
+ .withNullable(true)
+ .build());
+
+ builder = builder
+ .withEntry(factory.newEntryBuilder().withName(ENTRY_ROOT_REPOSITORY).withType(Type.STRING).build())
+ .withEntry(
+ factory.newEntryBuilder().withName(ENTRY_RUNTIME_CLASSPATH).withType(Type.STRING).build())
+ .withEntry(
+ factory.newEntryBuilder().withName(ENTRY_WORKING_DIRECTORY).withType(Type.STRING).build());
+
+ builder = builder.withEntry(factory.newEntryBuilder().withName(ENTRY_COMMENT).withType(Type.STRING).build());
+
+ return builder.build();
+ }
+
+ protected Iterator loadData(final String family, final String name, final int version,
+ final Map parameters) {
+ return finder.find(family, name, version, parameters);
+ }
+
+ private void logError(final String message, final Exception e) {
+ String msg = "Dynamic dependencies connector raised an exception: %s : %s".formatted(message, e.getMessage());
+ log.error(msg, e);
+ }
+
+ private List additionalDependencies() {
+ List additionalDependencies = new ArrayList<>();
+
+ // This dynamic dependency is hardcoded since we test assignment in checkAssignmentFromDynamicDependency
+ // It is a dependency without any transitive dependency
+ additionalDependencies.add(new Dependency("org.apache.maven.resolver",
+ "maven-resolver-api",
+ "2.0.14",
+ "org.eclipse.aether.artifact.DefaultArtifact"));
+
+ return additionalDependencies;
+ }
+
+ protected List getDynamicDependencies(final List dependenciesFromConfiguration,
+ final List connectors) {
+
+ List dependencies = new ArrayList<>();
+ dependencies.addAll(dependenciesFromConfiguration);
+ dependencies.addAll(additionalDependencies());
+
+ List standardDependencies = dependencies
+ .stream()
+ .map(d -> String.format("%s:%s:%s", d.getGroupId(), d.getArtifactId(), d.getVersion()))
+ .toList();
+
+ List additionalConnectors = connectors
+ .stream()
+ .map(c -> String.format("%s:%s:%s", c.getGroupId(), c.getArtifactId(), c.getVersion()))
+ .toList();
+
+ List connectorsDependencies = connectors
+ .stream()
+ .flatMap(this::getConnectorDependencies)
+ .toList();
+ List all = Stream.of(standardDependencies, additionalConnectors, connectorsDependencies)
+ .flatMap(Collection::stream)
+ .toList();
+
+ if (log.isInfoEnabled()) {
+ String collect = all.stream().collect(Collectors.joining("\n- ", "- ", ""));
+ log.info("All identified dependencies:\n" + collect);
+ }
+
+ return all;
+ }
+
+ private Stream getConnectorDependencies(final Connector connector) {
+ if (!connector.isLoadTransitiveDependencies()) {
+ return Stream.empty();
+ }
+
+ List result;
+
+ String gav = String.format("%s:%s:%s", connector.getGroupId(),
+ connector.getArtifactId(),
+ connector.getVersion());
+ Collection jarFiles = resolver.resolveFromDescriptor(
+ Collections.singletonList(gav));
+
+ if (jarFiles == null || jarFiles.size() <= 0) {
+ throw new ComponentException("Can't find additional connector '%s'.".formatted(gav));
+ }
+ if (jarFiles.size() > 1) {
+ String join = jarFiles.stream().map(File::getAbsolutePath).collect(Collectors.joining(","));
+ throw new ComponentException("Several files have been found to resolve '%s': %s".formatted(gav, join));
+ }
+
+ File jarFile = jarFiles.iterator().next();
+
+ if (!Files.exists(jarFile.toPath())) {
+ log.warn("Can't find the dynamic loaded connector jar {}.", jarFile.getAbsolutePath());
+ return Stream.empty();
+ }
+
+ try (JarFile jar = new JarFile(jarFile)) {
+ JarEntry entry = jar.getJarEntry("TALEND-INF/dependencies.txt");
+ if (entry == null) {
+ throw new ComponentException("TALEND-INF/dependencies.txt not found in JAR");
+ }
+
+ try (InputStream is = jar.getInputStream(entry);
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
+
+ result = reader.lines()
+ .filter(line -> !line.isBlank()) // skip empty lines
+ .map(line -> line.substring(0, line.lastIndexOf(":"))) // remove last ':xxx'
+ .collect(Collectors.toList());
+ }
+
+ } catch (IOException e) {
+ throw new ComponentException("Can't load dependencies for %s: %s".formatted(gav, e.getMessage()), e);
+ }
+ return result.stream();
+ }
+
+ private void checkAssignmentFromDynamicDependency() {
+ DefaultArtifact defaultArtifact = new DefaultArtifact("g:a:v");
+ // Do nothing, just check assignment
+ // commons-net should be provided by a dynamic dependency
+ // to validate the test.
+ log.info("Successful assignment from a class loaded from a dynamic dependency.");
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/AbstractDynamicDependenciesServiceTest.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/AbstractDynamicDependenciesServiceTest.java
new file mode 100644
index 0000000000000..0555b0777e040
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/AbstractDynamicDependenciesServiceTest.java
@@ -0,0 +1,219 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis;
+
+import static org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService.ENTRY_CLASS;
+import static org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService.ENTRY_CLAZZ_CLASSLOADER;
+import static org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService.ENTRY_CONNECTOR_CLASSLOADER;
+import static org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService.ENTRY_FROM_LOCATION;
+import static org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService.ENTRY_IS_LOADED;
+import static org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService.ENTRY_IS_TCK_CONTAINER;
+import static org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService.ENTRY_MAVEN;
+import static org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService.ENTRY_RUNTIME_CLASSPATH;
+import static org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService.ENTRY_WORKING_DIRECTORY;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.stream.Collectors;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.talend.sdk.component.api.exception.ComponentException;
+import org.talend.sdk.component.api.record.Record;
+import org.talend.sdk.component.api.record.Schema;
+import org.talend.sdk.component.api.record.Schema.Entry;
+import org.talend.sdk.component.api.record.Schema.Type;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Connector;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.DynamicDependencyConfig;
+import org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService;
+
+import lombok.Getter;
+
+public abstract class AbstractDynamicDependenciesServiceTest {
+
+ @Getter
+ private C config;
+
+ protected abstract C buildConfig();
+
+ protected abstract S getService();
+
+ @BeforeEach
+ void setUp() {
+ this.config = this.buildConfig();
+ }
+
+ @Test
+ void testLoadIterator() {
+ final Iterator result = getService().loadIterator(config);
+
+ List records = new ArrayList<>();
+ result.forEachRemaining(records::add);
+ Assertions.assertEquals(4, records.size());
+
+ Record record = records.get(0);
+ ResultDetails expected = new ResultDetails(
+ false,
+ "jdk.internal.loader.ClassLoaders$AppClassLoader",
+ "jdk.internal.loader.ClassLoaders$AppClassLoader",
+ "org.talend.sdk.component.loading-analysis:loading-dependencies-common:N/A",
+ System.getProperty("user.dir"),
+ true,
+ "org/talend/sdk/component/sample/feature/loadinganalysis/config/Dependency.class",
+ "Hardcoded 'static' dependency test.",
+ "org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency",
+ "commons-numbers-primes-1.2.jar");
+ this.assertRecord(record, expected);
+
+ record = records.get(1);
+ expected = new ResultDetails(
+ false,
+ "jdk.internal.loader.ClassLoaders$AppClassLoader",
+ "jdk.internal.loader.ClassLoaders$AppClassLoader",
+ "org.talend.sdk.component:component-runtime:N/A",
+ System.getProperty("user.dir"),
+ true,
+ "org/talend/sdk/component/api/service/asyncvalidation/ValidationResult.class",
+ "Hardcoded provided dependency test.",
+ "org.talend.sdk.component.api.service.asyncvalidation.ValidationResult",
+ "component-runtime-impl");
+ this.assertRecord(record, expected);
+
+ record = records.get(2);
+ expected = new ResultDetails(
+ false,
+ "jdk.internal.loader.ClassLoaders$AppClassLoader",
+ "jdk.internal.loader.ClassLoaders$AppClassLoader",
+ "org.apache.maven.resolver:maven-resolver-api:2.0.14",
+ System.getProperty("user.dir"),
+ true,
+ "org/eclipse/aether/artifact/DefaultArtifact.class",
+ "Hardcoded dynamic dependency test. The instantiated object has been assigned.",
+ "org.eclipse.aether.artifact.DefaultArtifact",
+ "maven-resolver-api-2.0.14.jar");
+ this.assertRecord(record, expected);
+
+ record = records.get(3);
+ expected = new ResultDetails(
+ false,
+ "jdk.internal.loader.ClassLoaders$AppClassLoader",
+ "jdk.internal.loader.ClassLoaders$AppClassLoader",
+ "org.apache.commons:commons-numbers-primes:1.2",
+ System.getProperty("user.dir"),
+ true,
+ "org/apache/commons/commons-numbers-primes/1.2/commons-numbers-primes-1.2.jar!/org/apache/commons/numbers/primes/SmallPrimes.class",
+ null,
+ "org.apache.commons.numbers.primes.SmallPrimes",
+ "commons-numbers-primes-1.2.jar");
+ this.assertRecord(record, expected);
+ }
+
+ @Test
+ void testGuessSchema4Input() {
+ Schema schema = this.getService().buildSchema();
+ Map entries = schema.getAllEntries().collect(Collectors.toMap(Entry::getName, e -> e));
+ Assertions.assertEquals(12, entries.size());
+ Assertions.assertEquals(Type.BOOLEAN, entries.get("is_tck_container").getType());
+ Assertions.assertEquals(Type.STRING, entries.get("root_repository").getType());
+ Assertions.assertEquals(Type.STRING, entries.get("clazz_classloader").getType());
+ Assertions.assertEquals(Type.STRING, entries.get("maven").getType());
+ Assertions.assertEquals(Type.RECORD, entries.get("first_record").getType());
+ Assertions.assertEquals(Type.BOOLEAN, entries.get("is_loaded").getType());
+ Assertions.assertEquals(Type.STRING, entries.get("from_location").getType());
+ Assertions.assertEquals(Type.STRING, entries.get("working_directory").getType());
+ Assertions.assertEquals(Type.STRING, entries.get("comment").getType());
+ Assertions.assertEquals(Type.STRING, entries.get("connector_classloader").getType());
+ Assertions.assertEquals(Type.STRING, entries.get("clazz").getType());
+ Assertions.assertEquals(Type.STRING, entries.get("runtime_classpath").getType());
+ }
+
+ protected List getDynamicDependenciesConfigurationList() {
+ // This dependency is added in dynamic dependencies list
+ List depends = new ArrayList<>();
+ Dependency depend = new Dependency();
+ depend.setArtifactId("commons-numbers-primes");
+ depend.setVersion("1.2");
+ depend.setGroupId("org.apache.commons");
+ depend.setClazz("org.apache.commons.numbers.primes.SmallPrimes");
+ depends.add(depend);
+ return depends;
+ }
+
+ protected List getDynamicDependenciesConnectorsConfigurationList() {
+ // Return an empty list since currently this is not supported at unit test time.
+ // It is not possible to load another connector in unit test.
+ return Collections.emptyList();
+ }
+
+ private void assertRecord(Record record, ResultDetails expected) {
+ Assertions.assertNotNull(record);
+
+ Assertions.assertEquals(expected.isTckContainer(), record.getBoolean(ENTRY_IS_TCK_CONTAINER));
+ Assertions.assertTrue(record.getString(ENTRY_CONNECTOR_CLASSLOADER)
+ .startsWith(expected.connectorClassloader()));
+ Assertions.assertTrue(record.getString(ENTRY_CLAZZ_CLASSLOADER).startsWith(expected.clazzClassloader()));
+ Assertions.assertEquals(expected.maven(), record.getString(ENTRY_MAVEN));
+ Assertions.assertEquals(expected.workingDirectory(), record.getString(ENTRY_WORKING_DIRECTORY));
+ Assertions.assertEquals(expected.isLoaded(), record.getBoolean(ENTRY_IS_LOADED));
+ Assertions.assertTrue(record.getString(ENTRY_FROM_LOCATION).endsWith(expected.fromLocation()));
+ Assertions.assertEquals(expected.clazz(), record.getString(ENTRY_CLASS));
+ Assertions.assertTrue(record.getString(ENTRY_RUNTIME_CLASSPATH).contains(expected.runtimeClasspath()));
+
+ }
+
+ /**
+ * rootRepository is present for debugging information, there is no need to check its value in unit test.
+ * Moreover, its value can be different on different machines, so it is not possible to set a fixed value for it in
+ * the expected result.
+ */
+ public record ResultDetails(
+ boolean isTckContainer,
+ String connectorClassloader,
+ String clazzClassloader,
+ String maven,
+ String workingDirectory,
+ boolean isLoaded,
+ String fromLocation,
+ String comment,
+ String clazz,
+ String runtimeClasspath
+ ) {
+ }
+
+ protected static String getVersion() {
+ String version;
+ try (InputStream is = AbstractDynamicDependenciesServiceTest.class.getClassLoader()
+ .getResourceAsStream("version.properties")) {
+ if (is == null) {
+ throw new ComponentException("Can't retrieve version.properties resource.");
+ }
+ Properties props = new Properties();
+ props.load(is);
+ version = props.getProperty("version");
+ } catch (IOException e) {
+ throw new ComponentException("Unable to load project version", e);
+ }
+ return version;
+ }
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/test/resources/version.properties b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/test/resources/version.properties
new file mode 100644
index 0000000000000..bbe2f4191301e
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/src/test/resources/version.properties
@@ -0,0 +1,17 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+version=${project.version}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/pom.xml b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/pom.xml
new file mode 100644
index 0000000000000..8c7a20e2b8268
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/pom.xml
@@ -0,0 +1,80 @@
+
+
+
+ 4.0.0
+
+
+ org.talend.sdk.component.loading-analysis
+ loading-analysis
+ 1.91.0-SNAPSHOT
+
+
+ loading-dependencies-with-dataprepRunAnnotation
+ jar
+ Component Runtime :: Sample Features :: Loading Analysis :: Loading Dependencies with DataprepRun Annotation
+
+
+
+ org.talend.sdk.component.loading-analysis
+ loading-dependencies-common
+ ${project.version}
+
+
+
+ org.talend.sdk.component.loading-analysis
+ loading-dependencies-common
+ ${project.version}
+ test-jar
+ test
+
+
+ org.apache.commons
+ commons-numbers-primes
+ 1.2
+ test
+
+
+ org.apache.maven.resolver
+ maven-resolver-api
+ 2.0.14
+ test
+
+
+
+
+
+
+
+ src/test/resources
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ loading.dependencies.with.datapreprunannotation
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/annotation/DynamicDependencySupported.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/annotation/DynamicDependencySupported.java
new file mode 100644
index 0000000000000..d5a4664c65e84
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/annotation/DynamicDependencySupported.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.annotation;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import org.talend.sdk.component.api.configuration.type.meta.ConfigurationType;
+import org.talend.sdk.component.api.meta.Documentation;
+
+@Target(TYPE)
+@Retention(RUNTIME)
+@ConfigurationType("configuration")
+@Documentation("Copy/paste of the annotation from tDataprepRun." +
+ "It should be removed soon and replaced by the 'DynamicDependenciesConfiguration' provided by the framework.")
+@Deprecated
+public @interface DynamicDependencySupported {
+
+ String value() default "default";
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Config.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Config.java
new file mode 100644
index 0000000000000..47651f7a44487
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Config.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.config;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Connector;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.DynamicDependencyConfig;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.annotation.DynamicDependencySupported;
+
+import lombok.Data;
+
+/**
+ * For this sample, the same configuration is used for all connectors input/processor/output.
+ */
+@Data
+@DynamicDependencySupported
+@GridLayout({
+ @GridLayout.Row({ "dse" }),
+ @GridLayout.Row({ "subConfig" }),
+ @GridLayout.Row({ "notUsed" })
+})
+public class Config implements DynamicDependencyConfig, Serializable {
+
+ @Option
+ @Documentation("The dataset configuration.")
+ private Dataset dse = new Dataset();
+
+ @Option
+ @Documentation("Sub-configuration that contains the DynamicDependenciesConfiguration.")
+ private SubConfig subConfig = new SubConfig();
+
+ @Option
+ @Documentation("Unused configuration field required as a workaround for the DynamicDependency service.")
+ private String notUsed;
+
+ @Override
+ public List getDependencies() {
+ return new ArrayList<>(this.getSubConfig().getDependencies());
+ }
+
+ @Override
+ public List getConnectors() {
+ return new ArrayList<>(this.getSubConfig().getConnectors());
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Dataset.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Dataset.java
new file mode 100644
index 0000000000000..9e9152ce78972
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Dataset.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.type.DataSet;
+import org.talend.sdk.component.api.configuration.ui.layout.AutoLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+
+import lombok.Data;
+
+@Data
+@DataSet("dyndepsdse")
+@AutoLayout
+public class Dataset implements Serializable {
+
+ @Option
+ @Documentation("A datastore.")
+ private Datastore dso = new Datastore();
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Datastore.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Datastore.java
new file mode 100644
index 0000000000000..3ba4834dfdcfa
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Datastore.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.type.DataStore;
+import org.talend.sdk.component.api.configuration.ui.layout.AutoLayout;
+
+import lombok.Data;
+
+@Data
+@DataStore("dyndepsdso")
+@AutoLayout
+public class Datastore implements Serializable {
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/SubConfig.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/SubConfig.java
new file mode 100644
index 0000000000000..31ca9e985a314
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/SubConfig.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.config;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Connector;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency;
+
+import lombok.Data;
+
+@Data
+@GridLayout({
+ @GridLayout.Row({ "dependencies" }),
+ @GridLayout.Row({ "connectors" })
+})
+public class SubConfig implements Serializable {
+
+ @Option
+ @Documentation("The dependencies to load dynamically.")
+ private List dependencies = new ArrayList<>();
+
+ @Option
+ @Documentation("The connectors to load dynamically.")
+ private List connectors = new ArrayList<>();
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/input/DynamicDependenciesWithDataprepRunAnnotationInput.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/input/DynamicDependenciesWithDataprepRunAnnotationInput.java
new file mode 100644
index 0000000000000..2d27fa459e6d3
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/input/DynamicDependenciesWithDataprepRunAnnotationInput.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.input;
+
+import java.io.Serializable;
+import java.util.Iterator;
+
+import javax.annotation.PostConstruct;
+
+import org.talend.sdk.component.api.component.Icon;
+import org.talend.sdk.component.api.component.Version;
+import org.talend.sdk.component.api.input.Emitter;
+import org.talend.sdk.component.api.input.Producer;
+import org.talend.sdk.component.api.meta.Documentation;
+import org.talend.sdk.component.api.record.Record;
+import org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.config.Config;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.service.DynamicDependenciesDataprepRunAnnotationService;
+
+@Version
+@Icon(value = Icon.IconType.CUSTOM, custom = "icon")
+@Emitter(name = "Input")
+@Documentation("Dynamic dependencies sample input connector.")
+public class DynamicDependenciesWithDataprepRunAnnotationInput extends AbstractDynamicDependenciesService
+ implements Serializable {
+
+ private final Config config;
+
+ private final DynamicDependenciesDataprepRunAnnotationService service;
+
+ private Iterator recordIterator;
+
+ public DynamicDependenciesWithDataprepRunAnnotationInput(final Config config,
+ final DynamicDependenciesDataprepRunAnnotationService service) {
+ this.config = config;
+ this.service = service;
+ }
+
+ @PostConstruct
+ public void init() {
+ this.recordIterator = this.service.loadIterator(this.config);
+ }
+
+ @Producer
+ public Record next() {
+ if (recordIterator == null || !recordIterator.hasNext()) {
+ return null;
+ }
+
+ return recordIterator.next();
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/package-info.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/package-info.java
new file mode 100644
index 0000000000000..5d8e5e6624c9f
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.
+ */
+@Components(
+ family = "LoadingDependenciesWithDataprepAnnotation",
+ categories = "sample")
+@Icon(value = Icon.IconType.CUSTOM, custom = "icon")
+package org.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation;
+
+import org.talend.sdk.component.api.component.Components;
+import org.talend.sdk.component.api.component.Icon;
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/service/DynamicDependenciesDataprepRunAnnotationService.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/service/DynamicDependenciesDataprepRunAnnotationService.java
new file mode 100644
index 0000000000000..9005304baaddd
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/service/DynamicDependenciesDataprepRunAnnotationService.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.service;
+
+import java.io.Serializable;
+import java.util.List;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.record.Schema;
+import org.talend.sdk.component.api.service.Service;
+import org.talend.sdk.component.api.service.dependency.DynamicDependencies;
+import org.talend.sdk.component.api.service.schema.DiscoverSchemaExtended;
+import org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.config.Config;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Service
+public class DynamicDependenciesDataprepRunAnnotationService extends AbstractDynamicDependenciesService
+ implements Serializable {
+
+ public final static String DEPENDENCY_WITHDATAPREPRUN_ACTION = "DEPENDENCY_WITHDATAPREPRUN_ACTION";
+
+ @DynamicDependencies
+ public List getDynamicDependencies(@Option("theConfig") final Config config) {
+ List dynamicDependencies = super.getDynamicDependencies(config.getDependencies(),
+ config.getConnectors());
+ log.info("Dynamic dependencies with DataprepRunAnnotation: {}", String.join(";", dynamicDependencies));
+ return dynamicDependencies;
+ }
+
+ @DiscoverSchemaExtended(DEPENDENCY_WITHDATAPREPRUN_ACTION)
+ public Schema guessSchema4Input(final @Option("configuration") Config config) {
+ return super.buildSchema();
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/icons/dark/icon.svg b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/icons/dark/icon.svg
new file mode 100644
index 0000000000000..07c7f2c71c358
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/icons/dark/icon.svg
@@ -0,0 +1,64 @@
+
+
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/icons/light/icon.svg b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/icons/light/icon.svg
new file mode 100644
index 0000000000000..07c7f2c71c358
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/icons/light/icon.svg
@@ -0,0 +1,64 @@
+
+
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/Messages.properties
new file mode 100644
index 0000000000000..ed2b3fe23423d
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/Messages.properties
@@ -0,0 +1,18 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+LoadingDependenciesWithDataprepAnnotation.datastore.dyndepsdso._displayName = Datastore for loading dependencies with datapreprun
+LoadingDependenciesWithDataprepAnnotation.dataset.dyndepsdse._displayName = Dataset for loading dependencies with datapreprun
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Messages.properties
new file mode 100644
index 0000000000000..21f12ed2f2959
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/config/Messages.properties
@@ -0,0 +1,24 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+Dataset.dso._displayName =
+Dataset.dependencies._displayName = Dynamic dependencies
+Config.dse._displayName =
+Config.subConfig._displayName =
+SubConfig.dependencies._displayName = Dependencies
+SubConfig.connectors._displayName = Connectors dynamically loaded
+Config.notUsed._displayName = Not used
+Config.notUsed._placeholder =
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/input/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/input/Messages.properties
new file mode 100644
index 0000000000000..93959ee5ced3e
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/input/Messages.properties
@@ -0,0 +1,17 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+LoadingDependenciesWithDataprepAnnotation.Input._displayName = Loading Dependencies With DataprepRun annotation Input
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/service/DynamicDependenciesDataprepRunAnnotationServiceTest.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/service/DynamicDependenciesDataprepRunAnnotationServiceTest.java
new file mode 100644
index 0000000000000..710bfb9b58441
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/service/DynamicDependenciesDataprepRunAnnotationServiceTest.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.talend.sdk.component.api.service.Service;
+import org.talend.sdk.component.junit5.WithComponents;
+import org.talend.sdk.component.sample.feature.loadinganalysis.AbstractDynamicDependenciesServiceTest;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.config.Config;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.config.Dataset;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.config.Datastore;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@WithComponents(value = "org.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation")
+public class DynamicDependenciesDataprepRunAnnotationServiceTest
+ extends AbstractDynamicDependenciesServiceTest {
+
+ @Service
+ DynamicDependenciesDataprepRunAnnotationService dynamicDependenciesServiceService;
+
+ @Override
+ protected Config buildConfig() {
+ Config config = new Config();
+ Dataset dse = new Dataset();
+ Datastore dso = new Datastore();
+ config.getSubConfig().setDependencies(this.getDynamicDependenciesConfigurationList());
+ config.getSubConfig().setConnectors(this.getDynamicDependenciesConnectorsConfigurationList());
+ dse.setDso(dso);
+ config.setDse(dse);
+
+ return config;
+ }
+
+ @Override
+ protected DynamicDependenciesDataprepRunAnnotationService getService() {
+ return dynamicDependenciesServiceService;
+ }
+
+ @Test
+ void getDynamicDependenciesTest() {
+ List dynamicDependencies = this.dynamicDependenciesServiceService.getDynamicDependencies(buildConfig());
+ List expectedDynamicDependencies = new ArrayList<>();
+ }
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/test/resources/TALEND-INF/dynamic-dependencies.properties b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/test/resources/TALEND-INF/dynamic-dependencies.properties
new file mode 100644
index 0000000000000..2daa7b7b557e5
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/test/resources/TALEND-INF/dynamic-dependencies.properties
@@ -0,0 +1,18 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+loading-dependencies-with-dataprepRunAnnotation = org.talend.sdk.component:sample-connector:${project.version},org.apache.commons:commons-numbers-primes:1.2,org.apache.maven.resolver:maven-resolver-api:2.0.14
+classes = org.talend.sdk.component:sample-connector:${project.version},org.apache.commons:commons-numbers-primes:1.2,org.apache.maven.resolver:maven-resolver-api:2.0.14
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/pom.xml b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/pom.xml
new file mode 100644
index 0000000000000..d814ac0db2e99
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/pom.xml
@@ -0,0 +1,71 @@
+
+
+
+ 4.0.0
+
+ org.talend.sdk.component.loading-analysis
+ loading-analysis
+ 1.91.0-SNAPSHOT
+
+
+ loading-dependencies-with-dataset
+ jar
+ Component Runtime :: Sample Features :: Loading Analysis :: Loading Dependencies with Dataset
+
+
+
+ org.talend.sdk.component.loading-analysis
+ loading-dependencies-common
+ ${project.version}
+
+
+
+ org.talend.sdk.component.loading-analysis
+ loading-dependencies-common
+ ${project.version}
+ test-jar
+ test
+
+
+ org.apache.commons
+ commons-numbers-primes
+ 1.2
+ test
+
+
+ org.apache.maven.resolver
+ maven-resolver-api
+ 2.0.14
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ loading.dependencies.with.dataset
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Config.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Config.java
new file mode 100644
index 0000000000000..98c7609be4a23
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Config.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withdataset.config;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Connector;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.DynamicDependencyConfig;
+
+import lombok.Data;
+
+/**
+ * For this sample, the same configuration is used for all connectors input/processor/output.
+ */
+@Data
+@GridLayout({
+ @GridLayout.Row({ "dse" })
+})
+public class Config implements DynamicDependencyConfig, Serializable {
+
+ @Option
+ @Documentation("The dataset configuration.")
+ private Dataset dse = new Dataset();
+
+ @Override
+ public List getDependencies() {
+ return new ArrayList<>(this.getDse().getDependencies());
+ }
+
+ public List getConnectors() {
+ return new ArrayList<>(this.getDse().getConnectors());
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Dataset.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Dataset.java
new file mode 100644
index 0000000000000..1a60a21d64c2e
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Dataset.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withdataset.config;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.type.DataSet;
+import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Connector;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency;
+
+import lombok.Data;
+
+@Data
+@DataSet("dyndepsdse")
+@GridLayout(value = {
+ @GridLayout.Row({ "dso" }),
+ @GridLayout.Row({ "dependencies" }),
+ @GridLayout.Row({ "connectors" })
+})
+public class Dataset implements Serializable {
+
+ @Option
+ @Documentation("A datastore.")
+ private Datastore dso = new Datastore();
+
+ @Option
+ @Documentation("The dependencies to load dynamically.")
+ private List dependencies = new ArrayList<>();
+
+ @Option
+ @Documentation("The connectors to load dynamically.")
+ private List connectors = new ArrayList<>();
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Datastore.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Datastore.java
new file mode 100644
index 0000000000000..28324574b61bd
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Datastore.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withdataset.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.type.DataStore;
+import org.talend.sdk.component.api.configuration.ui.layout.AutoLayout;
+
+import lombok.Data;
+
+@Data
+@DataStore("dyndepsdso")
+@AutoLayout
+public class Datastore implements Serializable {
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/input/DynamicDependenciesWithDatasetInput.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/input/DynamicDependenciesWithDatasetInput.java
new file mode 100644
index 0000000000000..4717c52fba97b
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/input/DynamicDependenciesWithDatasetInput.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withdataset.input;
+
+import java.io.Serializable;
+import java.util.Iterator;
+
+import javax.annotation.PostConstruct;
+
+import org.talend.sdk.component.api.component.Icon;
+import org.talend.sdk.component.api.component.Version;
+import org.talend.sdk.component.api.input.Emitter;
+import org.talend.sdk.component.api.input.Producer;
+import org.talend.sdk.component.api.meta.Documentation;
+import org.talend.sdk.component.api.record.Record;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withdataset.config.Config;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withdataset.service.DynamicDependenciesWithDatasetService;
+
+@Version
+@Icon(value = Icon.IconType.CUSTOM, custom = "icon")
+@Emitter(name = "Input")
+@Documentation("Dynamic dependencies sample input connector.")
+public class DynamicDependenciesWithDatasetInput implements Serializable {
+
+ private final Config config;
+
+ private final DynamicDependenciesWithDatasetService service;
+
+ private Iterator recordIterator;
+
+ public DynamicDependenciesWithDatasetInput(final Config config,
+ final DynamicDependenciesWithDatasetService service) {
+ this.config = config;
+ this.service = service;
+ }
+
+ @PostConstruct
+ public void init() {
+ this.recordIterator = this.service.loadIterator(this.config);
+ }
+
+ @Producer
+ public Record next() {
+ if (recordIterator == null || !recordIterator.hasNext()) {
+ return null;
+ }
+
+ return recordIterator.next();
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/package-info.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/package-info.java
new file mode 100644
index 0000000000000..c1fdf7112d18a
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.
+ */
+@Components(
+ family = "LoadingDependenciesWithDataset",
+ categories = "sample")
+@Icon(value = Icon.IconType.CUSTOM, custom = "icon")
+package org.talend.sdk.component.sample.feature.loadinganalysis.withdataset;
+
+import org.talend.sdk.component.api.component.Components;
+import org.talend.sdk.component.api.component.Icon;
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/service/DynamicDependenciesWithDatasetService.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/service/DynamicDependenciesWithDatasetService.java
new file mode 100644
index 0000000000000..c7b968773cb62
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/service/DynamicDependenciesWithDatasetService.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withdataset.service;
+
+import java.io.Serializable;
+import java.util.List;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.record.Schema;
+import org.talend.sdk.component.api.service.Service;
+import org.talend.sdk.component.api.service.dependency.DynamicDependencies;
+import org.talend.sdk.component.api.service.schema.DiscoverSchemaExtended;
+import org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withdataset.config.Config;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withdataset.config.Dataset;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Service
+public class DynamicDependenciesWithDatasetService extends AbstractDynamicDependenciesService implements Serializable {
+
+ public final static String DEPENDENCY_WITHDATASET_ACTION = "DEPENDENCY_WITHDATASET_ACTION";
+
+ @DynamicDependencies
+ public List getDynamicDependencies(@Option("theDataset") final Dataset dataset) {
+ List dynamicDependencies =
+ super.getDynamicDependencies(dataset.getDependencies(), dataset.getConnectors());
+ log.info("Dynamic dependencies with dataset: {}", String.join(";", dynamicDependencies));
+ return dynamicDependencies;
+ }
+
+ @DiscoverSchemaExtended(DEPENDENCY_WITHDATASET_ACTION)
+ public Schema guessSchema4Input(final @Option("configuration") Config config) {
+ return super.buildSchema();
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/icons/dark/icon.svg b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/icons/dark/icon.svg
new file mode 100644
index 0000000000000..6138ac205b130
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/icons/dark/icon.svg
@@ -0,0 +1,67 @@
+
+
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/icons/light/icon.svg b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/icons/light/icon.svg
new file mode 100644
index 0000000000000..6138ac205b130
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/icons/light/icon.svg
@@ -0,0 +1,67 @@
+
+
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/Messages.properties
new file mode 100644
index 0000000000000..10d399f7e916d
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/Messages.properties
@@ -0,0 +1,18 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+LoadingDependenciesWithDataset.datastore.dyndepsdso._displayName = Datastore for loading dependencies with dataset
+LoadingDependenciesWithDataset.dataset.dyndepsdse._displayName = Dataset for loading dependencies with dataset
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Messages.properties
new file mode 100644
index 0000000000000..5adf99f8356e2
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/config/Messages.properties
@@ -0,0 +1,20 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+Dataset.dso._displayName =
+Dataset.dependencies._displayName = Dynamic dependencies
+Config.dse._displayName =
+Dataset.connectors._displayName = Connectors dynamically loaded
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/input/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/input/Messages.properties
new file mode 100644
index 0000000000000..a0e8fe90ab84c
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/input/Messages.properties
@@ -0,0 +1,17 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+LoadingDependenciesWithDataset.Input._displayName = Loading Dependencies With Dataset Input
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/service/DynamicDependenciesWithDatasetServiceTest.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/service/DynamicDependenciesWithDatasetServiceTest.java
new file mode 100644
index 0000000000000..eb68544380918
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdataset/service/DynamicDependenciesWithDatasetServiceTest.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withdataset.service;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.talend.sdk.component.api.service.Service;
+import org.talend.sdk.component.junit5.WithComponents;
+import org.talend.sdk.component.sample.feature.loadinganalysis.AbstractDynamicDependenciesServiceTest;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withdataset.config.Config;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withdataset.config.Dataset;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withdataset.config.Datastore;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@WithComponents(value = "org.talend.sdk.component.sample.feature.loadinganalysis.withdataset")
+public class DynamicDependenciesWithDatasetServiceTest
+ extends AbstractDynamicDependenciesServiceTest {
+
+ @Service
+ private DynamicDependenciesWithDatasetService dynamicDependenciesServiceService;
+
+ @Override
+ protected Config buildConfig() {
+ Config config = new Config();
+ Dataset dse = new Dataset();
+ Datastore dso = new Datastore();
+ List depends = this.getDynamicDependenciesConfigurationList();
+ dse.setDependencies(depends);
+ dse.setDso(dso);
+ config.setDse(dse);
+
+ return config;
+ }
+
+ @Override
+ protected DynamicDependenciesWithDatasetService getService() {
+ return dynamicDependenciesServiceService;
+ }
+
+ @Test
+ void testDynamicDependencies() {
+ List dynamicDependencies = this.getService().getDynamicDependencies(this.getConfig().getDse());
+ Assertions.assertEquals(2, dynamicDependencies.size());
+ Assertions.assertEquals("org.apache.commons:commons-numbers-primes:1.2", dynamicDependencies.get(0));
+ Assertions.assertEquals("org.apache.maven.resolver:maven-resolver-api:2.0.14",
+ dynamicDependencies.get(1));
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/pom.xml b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/pom.xml
new file mode 100644
index 0000000000000..885c45b726ed5
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/pom.xml
@@ -0,0 +1,72 @@
+
+
+
+ 4.0.0
+
+ org.talend.sdk.component.loading-analysis
+ loading-analysis
+ 1.91.0-SNAPSHOT
+
+
+ loading-dependencies-with-datastore
+ jar
+ Component Runtime :: Sample Features :: Loading Analysis :: Loading Dependencies with Datastore
+
+
+
+ org.talend.sdk.component.loading-analysis
+ loading-dependencies-common
+ ${project.version}
+
+
+
+ org.talend.sdk.component.loading-analysis
+ loading-dependencies-common
+ ${project.version}
+ test-jar
+ test
+
+
+ org.apache.commons
+ commons-numbers-primes
+ 1.2
+ test
+
+
+ org.apache.maven.resolver
+ maven-resolver-api
+ 2.0.14
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ loading.dependencies.with.datastore
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Config.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Config.java
new file mode 100644
index 0000000000000..b6f07273d6c54
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Config.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withdatastore.config;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.ui.layout.AutoLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Connector;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.DynamicDependencyConfig;
+
+import lombok.Data;
+
+/**
+ * For this sample, the same configuration is used for all connectors input/processor/output.
+ */
+@Data
+@AutoLayout
+public class Config implements DynamicDependencyConfig, Serializable {
+
+ @Option
+ @Documentation("The dataset configuration.")
+ private Dataset dse = new Dataset();
+
+ @Override
+ public List getDependencies() {
+ return new ArrayList<>(this.getDse().getDso().getDependencies());
+ }
+
+ public List getConnectors() {
+ return new ArrayList<>(this.getDse().getDso().getConnectors());
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Dataset.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Dataset.java
new file mode 100644
index 0000000000000..19b6b90c1c768
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Dataset.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withdatastore.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.type.DataSet;
+import org.talend.sdk.component.api.configuration.ui.layout.AutoLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+
+import lombok.Data;
+
+@Data
+@DataSet("dyndepsdse")
+@AutoLayout
+public class Dataset implements Serializable {
+
+ @Option
+ @Documentation("A datastore.")
+ private Datastore dso = new Datastore();
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Datastore.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Datastore.java
new file mode 100644
index 0000000000000..068028aa672c6
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Datastore.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withdatastore.config;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.type.DataStore;
+import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Connector;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency;
+
+import lombok.Data;
+
+@Data
+@DataStore("dyndepsdso")
+@GridLayout({
+ @GridLayout.Row({ "dependencies" }),
+ @GridLayout.Row({ "connectors" })
+})
+public class Datastore implements Serializable {
+
+ @Option
+ @Documentation("The dependencies to load dynamically.")
+ private List dependencies = new ArrayList<>();
+
+ @Option
+ @Documentation("The connectors to load dynamically.")
+ private List connectors = new ArrayList<>();
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/input/DynamicDependenciesWithDatastoreInput.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/input/DynamicDependenciesWithDatastoreInput.java
new file mode 100644
index 0000000000000..cbb8522ae112e
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/input/DynamicDependenciesWithDatastoreInput.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withdatastore.input;
+
+import java.io.Serializable;
+import java.util.Iterator;
+
+import javax.annotation.PostConstruct;
+
+import org.talend.sdk.component.api.component.Icon;
+import org.talend.sdk.component.api.component.Version;
+import org.talend.sdk.component.api.input.Emitter;
+import org.talend.sdk.component.api.input.Producer;
+import org.talend.sdk.component.api.meta.Documentation;
+import org.talend.sdk.component.api.record.Record;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withdatastore.config.Config;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withdatastore.service.DynamicDependenciesWithDatastoreService;
+
+@Version
+@Icon(value = Icon.IconType.CUSTOM, custom = "icon")
+@Emitter(name = "Input")
+@Documentation("Dynamic dependencies sample input connector.")
+public class DynamicDependenciesWithDatastoreInput implements Serializable {
+
+ private final Config config;
+
+ private final DynamicDependenciesWithDatastoreService service;
+
+ private Iterator recordIterator;
+
+ public DynamicDependenciesWithDatastoreInput(final Config config,
+ final DynamicDependenciesWithDatastoreService service) {
+ this.config = config;
+ this.service = service;
+ }
+
+ @PostConstruct
+ public void init() {
+ this.recordIterator = this.service.loadIterator(this.config);
+ }
+
+ @Producer
+ public Record next() {
+ if (recordIterator == null || !recordIterator.hasNext()) {
+ return null;
+ }
+
+ return recordIterator.next();
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/package-info.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/package-info.java
new file mode 100644
index 0000000000000..78ad63ebe1bc6
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.
+ */
+@Components(
+ family = "LoadingDependenciesWithDatastore",
+ categories = "sample")
+@Icon(value = Icon.IconType.CUSTOM, custom = "icon")
+package org.talend.sdk.component.sample.feature.loadinganalysis.withdatastore;
+
+import org.talend.sdk.component.api.component.Components;
+import org.talend.sdk.component.api.component.Icon;
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/service/DynamicDependenciesWithDatastoreService.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/service/DynamicDependenciesWithDatastoreService.java
new file mode 100644
index 0000000000000..28da8b8609789
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/service/DynamicDependenciesWithDatastoreService.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withdatastore.service;
+
+import java.io.Serializable;
+import java.util.List;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.record.Schema;
+import org.talend.sdk.component.api.service.Service;
+import org.talend.sdk.component.api.service.dependency.DynamicDependencies;
+import org.talend.sdk.component.api.service.schema.DiscoverSchemaExtended;
+import org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withdatastore.config.Config;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withdatastore.config.Datastore;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Service
+public class DynamicDependenciesWithDatastoreService extends AbstractDynamicDependenciesService
+ implements Serializable {
+
+ public final static String DEPENDENCY_WITHDATASTORE_ACTION = "DEPENDENCY_WITHDATASTORE_ACTION";
+
+ @DynamicDependencies
+ public List getDynamicDependencies(@Option("theDatastore") final Datastore datastore) {
+ List dynamicDependencies =
+ super.getDynamicDependencies(datastore.getDependencies(), datastore.getConnectors());
+ log.info("Dynamic dependencies with datastore: {}", String.join(";", dynamicDependencies));
+ return dynamicDependencies;
+ }
+
+ @DiscoverSchemaExtended(DEPENDENCY_WITHDATASTORE_ACTION)
+ public Schema guessSchema4Input(final @Option("configuration") Config config) {
+ return super.buildSchema();
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/icons/dark/icon.svg b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/icons/dark/icon.svg
new file mode 100644
index 0000000000000..65cc253cb8b26
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/icons/dark/icon.svg
@@ -0,0 +1,64 @@
+
+
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/icons/light/icon.svg b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/icons/light/icon.svg
new file mode 100644
index 0000000000000..65cc253cb8b26
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/icons/light/icon.svg
@@ -0,0 +1,64 @@
+
+
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/Messages.properties
new file mode 100644
index 0000000000000..765dc0af9123f
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/Messages.properties
@@ -0,0 +1,18 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+LoadingDependenciesWithDatastore.datastore.dyndepsdso._displayName = Datastore for loading dependencies with datastore
+LoadingDependenciesWithDatastore.dataset.dyndepsdse._displayName = Dataset for loading dependencies with datastore
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Messages.properties
new file mode 100644
index 0000000000000..4d2a76d000a1b
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/config/Messages.properties
@@ -0,0 +1,20 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+Datastore.dependencies._displayName = Dynamic dependencies
+Dataset.dso._displayName =
+Config.dse._displayName =
+Datastore.connectors._displayName = Connectors dynamically loaded
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/input/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/input/Messages.properties
new file mode 100644
index 0000000000000..62cccc687013e
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/input/Messages.properties
@@ -0,0 +1,17 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+LoadingDependenciesWithDatastore.Input._displayName = Loading Dependencies With Datastore Input
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/service/DynamicDependenciesWithDatastoreServiceTest.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/service/DynamicDependenciesWithDatastoreServiceTest.java
new file mode 100644
index 0000000000000..277c6f0e65c2b
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withdatastore/service/DynamicDependenciesWithDatastoreServiceTest.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withdatastore.service;
+
+import java.util.List;
+
+import org.talend.sdk.component.api.service.Service;
+import org.talend.sdk.component.junit5.WithComponents;
+import org.talend.sdk.component.sample.feature.loadinganalysis.AbstractDynamicDependenciesServiceTest;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withdatastore.config.Config;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withdatastore.config.Dataset;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withdatastore.config.Datastore;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@WithComponents(value = "org.talend.sdk.component.sample.feature.loadinganalysis.withdatastore")
+public class DynamicDependenciesWithDatastoreServiceTest
+ extends AbstractDynamicDependenciesServiceTest {
+
+ @Service
+ DynamicDependenciesWithDatastoreService dynamicDependenciesServiceService;
+
+ @Override
+ protected Config buildConfig() {
+ Config config = new Config();
+ Dataset dse = new Dataset();
+ Datastore dso = new Datastore();
+ List depends = this.getDynamicDependenciesConfigurationList();
+ dso.setDependencies(depends);
+ dse.setDso(dso);
+ config.setDse(dse);
+
+ return config;
+ }
+
+ @Override
+ protected DynamicDependenciesWithDatastoreService getService() {
+ return dynamicDependenciesServiceService;
+ }
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/pom.xml b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/pom.xml
new file mode 100644
index 0000000000000..c47b9fd46c69e
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/pom.xml
@@ -0,0 +1,71 @@
+
+
+
+ 4.0.0
+
+ org.talend.sdk.component.loading-analysis
+ loading-analysis
+ 1.91.0-SNAPSHOT
+
+
+ loading-dependencies-with-dynamicDependenciesConfiguration
+ jar
+ Component Runtime :: Sample Features :: Loading Analysis :: Loading Dependencies with DynamicDependenciesConfiguration
+
+
+
+ org.talend.sdk.component.loading-analysis
+ loading-dependencies-common
+ ${project.version}
+
+
+
+ org.talend.sdk.component.loading-analysis
+ loading-dependencies-common
+ ${project.version}
+ test-jar
+ test
+
+
+ org.apache.commons
+ commons-numbers-primes
+ 1.2
+ test
+
+
+ org.apache.maven.resolver
+ maven-resolver-api
+ 2.0.14
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ loading.dependencies.with.dynamicdependenciesconfiguration
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Config.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Config.java
new file mode 100644
index 0000000000000..9d43d43965da6
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Config.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration.config;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Connector;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.DynamicDependencyConfig;
+
+import lombok.Data;
+
+/**
+ * For this sample, the same configuration is used for all connectors input/processor/output.
+ */
+@Data
+@GridLayout({
+ @GridLayout.Row({ "dse" }),
+ @GridLayout.Row({ "subConfig" })
+})
+public class Config implements DynamicDependencyConfig, Serializable {
+
+ @Option
+ @Documentation("The dataset configuration.")
+ private Dataset dse = new Dataset();
+
+ @Option
+ @Documentation("Sub-configuration that contains the DynamicDependenciesConfiguration.")
+ private SubConfig subConfig = new SubConfig();
+
+ @Override
+ public List getDependencies() {
+ return new ArrayList<>(this.getSubConfig().getDependencies());
+ }
+
+ public List getConnectors() {
+ return new ArrayList<>(this.getSubConfig().getConnectors());
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Dataset.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Dataset.java
new file mode 100644
index 0000000000000..ea89ecac24b3c
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Dataset.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.type.DataSet;
+import org.talend.sdk.component.api.configuration.ui.layout.AutoLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+
+import lombok.Data;
+
+@Data
+@DataSet("dyndepsdse")
+@AutoLayout
+public class Dataset implements Serializable {
+
+ @Option
+ @Documentation("A datastore.")
+ private Datastore dso = new Datastore();
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Datastore.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Datastore.java
new file mode 100644
index 0000000000000..48e7f29af362b
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Datastore.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.type.DataStore;
+import org.talend.sdk.component.api.configuration.ui.layout.AutoLayout;
+
+import lombok.Data;
+
+@Data
+@DataStore("dyndepsdso")
+@AutoLayout
+public class Datastore implements Serializable {
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/SubConfig.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/SubConfig.java
new file mode 100644
index 0000000000000..a66d153a193be
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/SubConfig.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration.config;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.type.DynamicDependenciesConfiguration;
+import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Connector;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency;
+
+import lombok.Data;
+
+@Data
+@DynamicDependenciesConfiguration
+@GridLayout({
+ @GridLayout.Row({ "dependencies" }),
+ @GridLayout.Row({ "connectors" })
+})
+public class SubConfig implements Serializable {
+
+ @Option
+ @Documentation("The dependencies to load dynamically.")
+ private List dependencies = new ArrayList<>();
+
+ @Option
+ @Documentation("The connectors to load dynamically.")
+ private List connectors = new ArrayList<>();
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/input/DynamicDependenciesWithDynamicDependenciesConfigurationInput.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/input/DynamicDependenciesWithDynamicDependenciesConfigurationInput.java
new file mode 100644
index 0000000000000..7eeeb24d54b6d
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/input/DynamicDependenciesWithDynamicDependenciesConfigurationInput.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration.input;
+
+import java.io.Serializable;
+import java.util.Iterator;
+
+import javax.annotation.PostConstruct;
+
+import org.talend.sdk.component.api.component.Icon;
+import org.talend.sdk.component.api.component.Version;
+import org.talend.sdk.component.api.input.Emitter;
+import org.talend.sdk.component.api.input.Producer;
+import org.talend.sdk.component.api.meta.Documentation;
+import org.talend.sdk.component.api.record.Record;
+import org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration.config.Config;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration.service.DynamicDependenciesWithDynamicDependenciesConfigurationService;
+
+@Version
+@Icon(value = Icon.IconType.CUSTOM, custom = "icon")
+@Emitter(name = "Input")
+@Documentation("Dynamic dependencies sample input connector.")
+public class DynamicDependenciesWithDynamicDependenciesConfigurationInput extends AbstractDynamicDependenciesService
+ implements Serializable {
+
+ private final Config config;
+
+ private final DynamicDependenciesWithDynamicDependenciesConfigurationService service;
+
+ private Iterator recordIterator;
+
+ public DynamicDependenciesWithDynamicDependenciesConfigurationInput(final Config config,
+ final DynamicDependenciesWithDynamicDependenciesConfigurationService service) {
+ this.config = config;
+ this.service = service;
+ }
+
+ @PostConstruct
+ public void init() {
+ this.recordIterator = this.service.loadIterator(this.config);
+ }
+
+ @Producer
+ public Record next() {
+ if (recordIterator == null || !recordIterator.hasNext()) {
+ return null;
+ }
+
+ return recordIterator.next();
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/package-info.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/package-info.java
new file mode 100644
index 0000000000000..2e6731cb5deb4
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.
+ */
+@Components(
+ family = "LoadingDependenciesWithDynamicDependenciesConfiguration",
+ categories = "sample")
+@Icon(value = Icon.IconType.CUSTOM, custom = "icon")
+package org.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration;
+
+import org.talend.sdk.component.api.component.Components;
+import org.talend.sdk.component.api.component.Icon;
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/service/DynamicDependenciesWithDynamicDependenciesConfigurationService.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/service/DynamicDependenciesWithDynamicDependenciesConfigurationService.java
new file mode 100644
index 0000000000000..504ac787b2b61
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/service/DynamicDependenciesWithDynamicDependenciesConfigurationService.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration.service;
+
+import java.io.Serializable;
+import java.util.List;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.record.Schema;
+import org.talend.sdk.component.api.service.Service;
+import org.talend.sdk.component.api.service.dependency.DynamicDependencies;
+import org.talend.sdk.component.api.service.schema.DiscoverSchemaExtended;
+import org.talend.sdk.component.sample.feature.loadinganalysis.service.AbstractDynamicDependenciesService;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration.config.Config;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration.config.SubConfig;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Service
+public class DynamicDependenciesWithDynamicDependenciesConfigurationService extends AbstractDynamicDependenciesService
+ implements Serializable {
+
+ public final static String DEPENDENCY_WITHDYNDEPSCONFIG_ACTION = "DEPENDENCY_WITHDYNDEPSCONFIG_ACTION";
+
+ @DynamicDependencies
+ public List getDynamicDependencies(@Option("theSubConfig") final SubConfig subConfig) {
+ List dynamicDependencies = super.getDynamicDependencies(subConfig.getDependencies(),
+ subConfig.getConnectors());
+ log.info("Dynamic dependencies with DynamicDependenciesConfiguration: {}",
+ String.join(";", dynamicDependencies));
+ return dynamicDependencies;
+ }
+
+ @DiscoverSchemaExtended(DEPENDENCY_WITHDYNDEPSCONFIG_ACTION)
+ public Schema guessSchema4Input(final @Option("configuration") Config config) {
+ return super.buildSchema();
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/icons/dark/icon.svg b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/icons/dark/icon.svg
new file mode 100644
index 0000000000000..95722d546500e
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/icons/dark/icon.svg
@@ -0,0 +1,64 @@
+
+
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/icons/light/icon.svg b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/icons/light/icon.svg
new file mode 100644
index 0000000000000..95722d546500e
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/icons/light/icon.svg
@@ -0,0 +1,64 @@
+
+
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/Messages.properties
new file mode 100644
index 0000000000000..3626d1c25aa82
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/Messages.properties
@@ -0,0 +1,18 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+LoadingDependenciesWithDynamicDependenciesConfiguration.datastore.dyndepsdso._displayName = Datastore for loading dependencies With DynamicDependenciesConfiguration
+LoadingDependenciesWithDynamicDependenciesConfiguration.dataset.dyndepsdse._displayName = Dataset for loading dependencies With DynamicDependenciesConfiguration
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Messages.properties
new file mode 100644
index 0000000000000..78375b6691435
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/config/Messages.properties
@@ -0,0 +1,21 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+Dataset.dso._displayName =
+Config.dse._displayName =
+Config.subConfig._displayName =
+SubConfig.dependencies._displayName = Dynamic dependencies
+SubConfig.connectors._displayName = Connectors dynamically loaded
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/input/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/input/Messages.properties
new file mode 100644
index 0000000000000..07acac8f9bd8e
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/input/Messages.properties
@@ -0,0 +1,17 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+LoadingDependenciesWithDynamicDependenciesConfiguration.Input._displayName = Dynamic Dependencies With DynamicDependenciesConfiguration Input
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/service/DynamicDependenciesWithDynamicDependenciesConfigurationServiceTest.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/service/DynamicDependenciesWithDynamicDependenciesConfigurationServiceTest.java
new file mode 100644
index 0000000000000..30a1064abddd6
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDynamicDependenciesConfiguration/service/DynamicDependenciesWithDynamicDependenciesConfigurationServiceTest.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration.service;
+
+import java.util.List;
+
+import org.talend.sdk.component.api.service.Service;
+import org.talend.sdk.component.junit5.WithComponents;
+import org.talend.sdk.component.sample.feature.loadinganalysis.AbstractDynamicDependenciesServiceTest;
+import org.talend.sdk.component.sample.feature.loadinganalysis.config.Dependency;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration.config.Config;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration.config.Dataset;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration.config.Datastore;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@WithComponents(
+ value = "org.talend.sdk.component.sample.feature.loadinganalysis.withDynamicDependenciesConfiguration")
+public class DynamicDependenciesWithDynamicDependenciesConfigurationServiceTest
+ extends
+ AbstractDynamicDependenciesServiceTest {
+
+ @Service
+ DynamicDependenciesWithDynamicDependenciesConfigurationService dynamicDependenciesServiceService;
+
+ @Override
+ protected Config buildConfig() {
+ Config config = new Config();
+ Dataset dse = new Dataset();
+ Datastore dso = new Datastore();
+ List depends = this.getDynamicDependenciesConfigurationList();
+ config.getSubConfig().setDependencies(depends);
+ dse.setDso(dso);
+ config.setDse(dse);
+
+ return config;
+ }
+
+ @Override
+ protected DynamicDependenciesWithDynamicDependenciesConfigurationService getService() {
+ return dynamicDependenciesServiceService;
+ }
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/pom.xml b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/pom.xml
new file mode 100644
index 0000000000000..ad9c66d3022eb
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/pom.xml
@@ -0,0 +1,87 @@
+
+
+
+ 4.0.0
+
+ org.talend.sdk.component.loading-analysis
+ loading-analysis
+ 1.91.0-SNAPSHOT
+
+
+ loading-services-and-resources-lib
+
+ jar
+ Component Runtime :: Sample Features :: Loading Analysis :: Loading Services and Resources Lib
+
+
+ true
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ service.provider.from.dependency.lib
+
+
+
+
+
+ org.talend.sdk.component
+ talend-component-maven-plugin
+ ${project.version}
+
+
+ talend-component-validate
+
+ false
+ false
+ false
+
+
+
+ talend-dependencies
+
+ dependencies
+
+ none
+
+
+ talend-component-bundle
+
+ car
+
+ none
+
+
+ talend-scan-descriptor
+
+ scan-descriptor
+
+ none
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/serviceInterfaces/StringProviderFromExternalSPI.java b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/serviceInterfaces/StringProviderFromExternalSPI.java
new file mode 100644
index 0000000000000..8a6a8cc79c518
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/serviceInterfaces/StringProviderFromExternalSPI.java
@@ -0,0 +1,22 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces;
+
+public interface StringProviderFromExternalSPI {
+
+ String getValueFromExternalSPI();
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/serviceInterfaces/StringProviderSPIAsDependency.java b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/serviceInterfaces/StringProviderSPIAsDependency.java
new file mode 100644
index 0000000000000..51cd4f1b46c89
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/serviceInterfaces/StringProviderSPIAsDependency.java
@@ -0,0 +1,22 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces;
+
+public interface StringProviderSPIAsDependency {
+
+ String getValueFromDependency();
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/serviceInterfaces/StringProviderSPIAsDynamicDependency.java b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/serviceInterfaces/StringProviderSPIAsDynamicDependency.java
new file mode 100644
index 0000000000000..f5e4d3f4bb36f
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/serviceInterfaces/StringProviderSPIAsDynamicDependency.java
@@ -0,0 +1,22 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces;
+
+public interface StringProviderSPIAsDynamicDependency {
+
+ String getValueFromASPIAsDynamicDependency();
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/AbstractSPIConsumer.java b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/AbstractSPIConsumer.java
new file mode 100644
index 0000000000000..aa985f0fcdb15
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/AbstractSPIConsumer.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.spiConsumers;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.ServiceLoader;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public abstract class AbstractSPIConsumer {
+
+ private final Optional spiImpl;
+
+ protected AbstractSPIConsumer(final Class clazz) {
+ ServiceLoader serviceLoader = ServiceLoader.load(clazz, AbstractSPIConsumer.class.getClassLoader());
+
+ List implProvider = new ArrayList<>();
+
+ try {
+ serviceLoader.iterator().forEachRemaining(implProvider::add);
+ } catch (Throwable e) {
+ log.error("Can't load %s spi implementation: %s.".formatted(clazz, e.getMessage()), e);
+ }
+
+ if (implProvider.size() <= 0) {
+ log.error("No SPI service found for %s.".formatted(clazz));
+ spiImpl = Optional.empty();
+ return;
+ }
+
+ if (implProvider.size() > 1) {
+ String join = implProvider.stream()
+ .map(m -> m.getClass().getName())
+ .collect(Collectors.joining("\n"));
+ log.error("More than one %s service has been found: %s.".formatted(clazz, join));
+ // For testing purpose (the goal of this connector), better to fail in that case.
+ spiImpl = Optional.empty();
+ return;
+ }
+
+ this.spiImpl = Optional.of(implProvider.get(0));
+ }
+
+ public abstract String getValue();
+
+ public T transform(final Function function) {
+ String value = this.getValue();
+ return function.apply(value);
+ }
+
+ public Optional getSPIImpl() {
+ return this.spiImpl;
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/DependencySPIConsumer.java b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/DependencySPIConsumer.java
new file mode 100644
index 0000000000000..4e987c500a1e2
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/DependencySPIConsumer.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.spiConsumers;
+
+import org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDependency;
+
+public class DependencySPIConsumer extends AbstractSPIConsumer {
+
+ public DependencySPIConsumer() {
+ super(StringProviderSPIAsDependency.class);
+ }
+
+ public String getValue() {
+ if (this.getSPIImpl().isPresent()) {
+ StringProviderSPIAsDependency impl = this.getSPIImpl().get();
+ return impl.getValueFromDependency();
+ } else {
+ return "[ERROR] StringProviderSPIAsDependency not loaded!";
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/DynamicDependencySPIConsumer.java b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/DynamicDependencySPIConsumer.java
new file mode 100644
index 0000000000000..4977b5c3209c3
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/DynamicDependencySPIConsumer.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.spiConsumers;
+
+import org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDynamicDependency;
+
+public class DynamicDependencySPIConsumer extends AbstractSPIConsumer {
+
+ public DynamicDependencySPIConsumer() {
+ super(StringProviderSPIAsDynamicDependency.class);
+ }
+
+ public String getValue() {
+ if (this.getSPIImpl().isPresent()) {
+ StringProviderSPIAsDynamicDependency impl = this.getSPIImpl().get();
+ return impl.getValueFromASPIAsDynamicDependency();
+ } else {
+ return "[ERROR] StringProviderSPIAsDynamicDependency not loaded!";
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/ExternalDependencySPIConsumer.java b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/ExternalDependencySPIConsumer.java
new file mode 100644
index 0000000000000..befb50583cbe4
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/classloadertestlibrary/spiConsumers/ExternalDependencySPIConsumer.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.spiConsumers;
+
+import org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderFromExternalSPI;
+
+public class ExternalDependencySPIConsumer extends AbstractSPIConsumer {
+
+ public ExternalDependencySPIConsumer() {
+ super(StringProviderFromExternalSPI.class);
+ }
+
+ public String getValue() {
+ if (this.getSPIImpl().isPresent()) {
+ StringProviderFromExternalSPI impl = this.getSPIImpl().get();
+ return impl.getValueFromExternalSPI();
+ } else {
+ return "[ERROR] StringProviderFromExternalSPI not loaded!";
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/resources/CLASSLOADER-TEST-LIBRARY/resource.properties b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/resources/CLASSLOADER-TEST-LIBRARY/resource.properties
new file mode 100644
index 0000000000000..1f8d78c809f1d
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/resources/CLASSLOADER-TEST-LIBRARY/resource.properties
@@ -0,0 +1,16 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.message=This is a resource file from classloader-test-library.
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/resources/MULTIPLE_RESOURCE/common.properties b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/resources/MULTIPLE_RESOURCE/common.properties
new file mode 100644
index 0000000000000..00910d391e730
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/src/main/resources/MULTIPLE_RESOURCE/common.properties
@@ -0,0 +1,16 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+content=from dependency
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/pom.xml b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/pom.xml
new file mode 100644
index 0000000000000..5944b10ece61c
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/pom.xml
@@ -0,0 +1,81 @@
+
+
+
+ 4.0.0
+
+ org.talend.sdk.component.loading-analysis
+ loading-analysis
+ 1.91.0-SNAPSHOT
+
+
+ loading-services-and-resources
+ jar
+ Component Runtime :: Sample Features :: Loading Analysis :: Loading Services and Resources
+
+
+
+ org.talend.sdk.component
+ component-runtime-manager
+ ${project.version}
+ provided
+
+
+ org.talend.sdk.component.loading-analysis
+ loading-services-and-resources-lib
+ ${project.version}
+
+
+ org.talend.sdk.component.loading-analysis
+ service-provider-from-dependency
+ ${project.version}
+
+
+ org.talend.sdk.component.loading-analysis
+ service-provider-from-dynamic-dependency
+ ${project.version}
+ test
+
+
+ org.talend.sdk.component.loading-analysis
+ service-provider-from-external-dependency
+ ${project.version}
+ test
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ loading.services.and.resources
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Config.java b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Config.java
new file mode 100644
index 0000000000000..893e4da4fe251
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Config.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withspi.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.ui.layout.AutoLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+
+import lombok.Data;
+
+/**
+ * For this sample, the same configuration is used for all connectors input/processor/output.
+ */
+@Data
+@AutoLayout
+public class Config implements Serializable {
+
+ @Option
+ @Documentation("The dataset configuration.")
+ private Dataset dse = new Dataset();
+
+ @Option
+ @Documentation("Unused option to force dependency inclusion.")
+ private String unusedOption;
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Dataset.java b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Dataset.java
new file mode 100644
index 0000000000000..43282beb84a0f
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Dataset.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withspi.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.type.DataSet;
+import org.talend.sdk.component.api.configuration.ui.layout.AutoLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+
+import lombok.Data;
+
+@Data
+@DataSet("dyndepsdse")
+@AutoLayout
+public class Dataset implements Serializable {
+
+ @Option
+ @Documentation("A datastore.")
+ private Datastore dso = new Datastore();
+
+ @Option
+ @Documentation("Unused option to force dependency inclusion.")
+ private String unusedOption;
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Datastore.java b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Datastore.java
new file mode 100644
index 0000000000000..45d1b7b8d1dbe
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Datastore.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withspi.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.type.DataStore;
+import org.talend.sdk.component.api.configuration.ui.layout.AutoLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+
+import lombok.Data;
+
+@Data
+@DataStore("dyndepsdso")
+@AutoLayout
+public class Datastore implements Serializable {
+
+ @Option
+ @Documentation("Unused option to force dependency inclusion.")
+ private String unusedOption;
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/input/DynamicDependenciesWithSPIInput.java b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/input/DynamicDependenciesWithSPIInput.java
new file mode 100644
index 0000000000000..d53e1160737c8
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/input/DynamicDependenciesWithSPIInput.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withspi.input;
+
+import java.io.Serializable;
+import java.util.Iterator;
+
+import javax.annotation.PostConstruct;
+
+import org.talend.sdk.component.api.component.Icon;
+import org.talend.sdk.component.api.component.Version;
+import org.talend.sdk.component.api.input.Emitter;
+import org.talend.sdk.component.api.input.Producer;
+import org.talend.sdk.component.api.meta.Documentation;
+import org.talend.sdk.component.api.record.Record;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withspi.config.Config;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withspi.service.DynamicDependenciesWithSPIService;
+
+@Version
+@Icon(value = Icon.IconType.CUSTOM, custom = "icon")
+@Emitter(name = "Input")
+@Documentation("Loading SPIs and resources.")
+public class DynamicDependenciesWithSPIInput implements Serializable {
+
+ private final Config config;
+
+ private final DynamicDependenciesWithSPIService service;
+
+ private Iterator recordIterator;
+
+ public DynamicDependenciesWithSPIInput(final Config config,
+ final DynamicDependenciesWithSPIService service) {
+ this.config = config;
+ this.service = service;
+ }
+
+ @PostConstruct
+ public void init() {
+ this.recordIterator = this.service.getRecordIterator();
+ }
+
+ @Producer
+ public Record next() {
+ if (recordIterator == null || !recordIterator.hasNext()) {
+ return null;
+ }
+
+ return recordIterator.next();
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/package-info.java b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/package-info.java
new file mode 100644
index 0000000000000..299d6369ad9cc
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.
+ */
+@Components(
+ family = "LoadingSPIsAndResources",
+ categories = "sample")
+@Icon(value = Icon.IconType.CUSTOM, custom = "icon")
+package org.talend.sdk.component.sample.feature.loadinganalysis.withspi;
+
+import org.talend.sdk.component.api.component.Components;
+import org.talend.sdk.component.api.component.Icon;
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/service/CustomizeClassLoader.java b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/service/CustomizeClassLoader.java
new file mode 100644
index 0000000000000..7bf31d629ac80
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/service/CustomizeClassLoader.java
@@ -0,0 +1,107 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withspi.service;
+
+import java.util.stream.Stream;
+
+import org.talend.sdk.component.runtime.manager.ComponentManager;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Custom class loader customizer for component runtime.
+ *
+ * This customizer allows specific classes and resources to be loaded from the parent classloader
+ * instead of the component's isolated classloader.
+ *
+ */
+@Slf4j
+public class CustomizeClassLoader implements ComponentManager.Customizer {
+
+ private static final String DISABLE_CUSTOMIZE_PROPERTY =
+ "org.talend.sdk.component.sample.feature.loadinganalysis.withspi.service.CustomizeClassLoader.disabled";
+
+ private static final boolean DISABLE_CUSTOMIZE =
+ Boolean.parseBoolean(System.getProperty(DISABLE_CUSTOMIZE_PROPERTY, "false"));
+
+ private static final String EXTERNAL_SPI_CLASS =
+ "org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderFromExternalSPI";
+
+ private static final String MULTIPLE_RESOURCE_PATH = "MULTIPLE_RESOURCE/content.txt";
+
+ private static final String SPI_SERVICE_PATH =
+ "META-INF/services/org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderFromExternalSPI";
+
+ private static final String RESOURCE_LOADED_FROM_EXTERNAL_DEPENDENCY =
+ "FROM_EXTERNAL_DEPENDENCY/resource.properties";
+
+ /**
+ * Specifies which classes and packages should be loaded from the container classloader.
+ *
+ * When disabled (default), returns an empty stream.
+ * When enabled, returns the list of classes that should be shared across components.
+ *
+ *
+ * @return A stream of class/package names to be loaded from the parent classloader
+ */
+ @Override
+ public Stream containerClassesAndPackages() {
+ if (DISABLE_CUSTOMIZE) {
+ logDisabledState();
+ return Stream.empty();
+ }
+
+ logEnabledState();
+ return Stream.of(EXTERNAL_SPI_CLASS);
+ }
+
+ /**
+ * Specifies which resources should be loaded from the parent classloader.
+ *
+ * This includes resource files and service provider configuration files.
+ *
+ *
+ * @return A stream of resource paths to be loaded from the parent classloader
+ */
+ @Override
+ public Stream parentResources() {
+ if (DISABLE_CUSTOMIZE) {
+ logDisabledState();
+ return Stream.empty();
+ }
+
+ logEnabledState();
+ return Stream.of(MULTIPLE_RESOURCE_PATH, SPI_SERVICE_PATH, RESOURCE_LOADED_FROM_EXTERNAL_DEPENDENCY);
+ }
+
+ /**
+ * Logs a message indicating that the customizer is disabled.
+ */
+ private void logDisabledState() {
+ log.info("{} is disabled.\nUse \"{}=false\" property to enable it.",
+ CustomizeClassLoader.class.getName(),
+ DISABLE_CUSTOMIZE_PROPERTY);
+ }
+
+ /**
+ * Logs a message indicating that the customizer is enabled.
+ */
+ private void logEnabledState() {
+ log.info("{} is enabled.\nUse \"{}=true\" property to disable it.",
+ CustomizeClassLoader.class.getName(),
+ DISABLE_CUSTOMIZE_PROPERTY);
+ }
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/service/DynamicDependenciesWithSPIService.java b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/service/DynamicDependenciesWithSPIService.java
new file mode 100644
index 0000000000000..52c8895e9164a
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/service/DynamicDependenciesWithSPIService.java
@@ -0,0 +1,279 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withspi.service;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Serializable;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.stream.Collectors;
+
+import javax.json.JsonBuilderFactory;
+import javax.json.JsonObject;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.exception.ComponentException;
+import org.talend.sdk.component.api.record.Record;
+import org.talend.sdk.component.api.record.Schema;
+import org.talend.sdk.component.api.record.Schema.Type;
+import org.talend.sdk.component.api.service.Service;
+import org.talend.sdk.component.api.service.dependency.DynamicDependencies;
+import org.talend.sdk.component.api.service.record.RecordBuilderFactory;
+import org.talend.sdk.component.api.service.schema.DiscoverSchema;
+import org.talend.sdk.component.runtime.manager.ComponentManager;
+import org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderFromExternalSPI;
+import org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDependency;
+import org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDynamicDependency;
+import org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.spiConsumers.DependencySPIConsumer;
+import org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.spiConsumers.DynamicDependencySPIConsumer;
+import org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.spiConsumers.ExternalDependencySPIConsumer;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withspi.config.Dataset;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Service
+public class DynamicDependenciesWithSPIService implements Serializable {
+
+ private static String version;
+
+ @Service
+ private RecordBuilderFactory recordBuilderFactory;
+
+ @Service
+ private JsonBuilderFactory jsonBuilderFactory;
+
+ @DynamicDependencies
+ public List getDynamicDependencies(@Option("theDataset") final Dataset dataset) {
+ String dep = "org.talend.sdk.component.loading-analysis:service-provider-from-dynamic-dependency:"
+ + loadVersion();
+ List strings = Collections.singletonList(dep);
+ log.info("Dynamic dependencies for SPI: {}", String.join(";", strings));
+ return strings;
+ }
+
+ @DiscoverSchema("dyndepsdse")
+ public Schema guessSchema4Input(final @Option("configuration") Dataset dse) {
+ return recordBuilderFactory.newSchemaBuilder(Type.RECORD)
+ .withEntry(recordBuilderFactory.newEntryBuilder().withType(Type.STRING).withName("value").build())
+ .withEntry(
+ recordBuilderFactory.newEntryBuilder().withType(Type.STRING).withName("SPI_Interface").build())
+ .withEntry(recordBuilderFactory.newEntryBuilder()
+ .withType(Type.STRING)
+ .withName("SPI_Interface_classloader")
+ .build())
+ .withEntry(recordBuilderFactory.newEntryBuilder().withType(Type.STRING).withName("SPI_Impl").build())
+ .withEntry(recordBuilderFactory.newEntryBuilder()
+ .withType(Type.STRING)
+ .withName("SPI_Impl_classloader")
+ .build())
+ .withEntry(recordBuilderFactory.newEntryBuilder().withType(Type.STRING).withName("comment").build())
+ .withEntry(
+ recordBuilderFactory.newEntryBuilder().withType(Type.STRING).withName("rootRepository").build())
+ .withEntry(recordBuilderFactory.newEntryBuilder().withType(Type.STRING).withName("classpath").build())
+ .withEntry(recordBuilderFactory.newEntryBuilder()
+ .withType(Type.STRING)
+ .withName("workingDirectory")
+ .build())
+ .build();
+ }
+
+ public Iterator getRecordIterator() {
+ String rootRepository =
+ String.valueOf(ComponentManager.instance().getContainer().getRootRepositoryLocationPath());
+ String runtimeClasspath = System.getProperty("java.class.path");
+ String workDirectory = System.getProperty("user.dir");
+
+ String contentFromResourceDependency = loadAPropertyFromResource("FROM_DEPENDENCY/resource.properties",
+ "ServiceProviderFromDependency.message");
+
+ String contentFromResourceDynamicDependency = loadAPropertyFromResource(
+ "FROM_DYNAMIC_DEPENDENCY/resource.properties",
+ "ServiceProviderFromDynamicDependency.message");
+
+ String contentFromResourceExternalDependency = loadAPropertyFromResource(
+ "FROM_EXTERNAL_DEPENDENCY/resource.properties",
+ "ServiceProviderFromExternalDependency.message");
+
+ String contentFromMultipleResources;
+ try {
+ Enumeration resources = DynamicDependenciesWithSPIService.class.getClassLoader()
+ .getResources("MULTIPLE_RESOURCE/content.txt");
+
+ StringBuilder stringBuilder = new StringBuilder("There should be 3 different values:");
+ while (resources.hasMoreElements()) {
+ URL url = resources.nextElement();
+
+ try (InputStream is = url.openStream()) {
+ String content = filterComments(is);
+ stringBuilder.append("\n");
+ stringBuilder.append(content);
+ }
+ }
+ contentFromMultipleResources = stringBuilder.toString();
+ } catch (IOException e) {
+ throw new ComponentException("Can't retrieve multiple resources at once.", e);
+ }
+
+ DependencySPIConsumer dependencySPIConsumer = new DependencySPIConsumer<>();
+ Record recordsFromDependencySPI = dependencySPIConsumer
+ .transform(s -> recordBuilderFactory.newRecordBuilder()
+ .withString("value", s)
+ .withString("SPI_Interface", String.valueOf(StringProviderSPIAsDependency.class))
+ .withString("SPI_Impl",
+ dependencySPIConsumer.getSPIImpl().isPresent()
+ ? String.valueOf(dependencySPIConsumer.getSPIImpl().get().getClass())
+ : "Not found")
+ .withString("SPI_Interface_classloader",
+ String.valueOf(StringProviderSPIAsDependency.class.getClassLoader()))
+ .withString("SPI_Impl_classloader",
+ dependencySPIConsumer.getSPIImpl().isPresent()
+ ? String.valueOf(
+ dependencySPIConsumer.getSPIImpl().get().getClass().getClassLoader())
+ : "Not found")
+ .withString("comment", "SPI implementation loaded from a dependency.")
+ .withString("rootRepository", rootRepository)
+ .withString("classpath", runtimeClasspath)
+ .withString("workingDirectory", workDirectory)
+ .build());
+
+ DynamicDependencySPIConsumer dynamicDependencySPIConsumer = new DynamicDependencySPIConsumer<>();
+ Record recordsFromDynamicDependencySPI = dynamicDependencySPIConsumer
+ .transform(s -> recordBuilderFactory.newRecordBuilder()
+ .withString("value", s)
+ .withString("SPI_Interface", String.valueOf(StringProviderSPIAsDynamicDependency.class))
+ .withString("SPI_Impl",
+ dynamicDependencySPIConsumer.getSPIImpl().isPresent()
+ ? String.valueOf(dynamicDependencySPIConsumer.getSPIImpl().get().getClass())
+ : "Not found")
+ .withString("SPI_Interface_classloader",
+ String.valueOf(StringProviderSPIAsDynamicDependency.class.getClassLoader()))
+ .withString("SPI_Impl_classloader",
+ dynamicDependencySPIConsumer.getSPIImpl().isPresent() ? String.valueOf(
+ dynamicDependencySPIConsumer.getSPIImpl().get().getClass().getClassLoader())
+ : "Not found")
+ .withString("comment", "SPI implementation loaded from a dynamic dependency.")
+ .withString("rootRepository", rootRepository)
+ .withString("classpath", runtimeClasspath)
+ .withString("workingDirectory", workDirectory)
+ .build());
+
+ ExternalDependencySPIConsumer externalDependencySPI = new ExternalDependencySPIConsumer<>();
+ Record recordsFromExternalSPI = externalDependencySPI
+ .transform(s -> recordBuilderFactory.newRecordBuilder()
+ .withString("value", s)
+ .withString("SPI_Interface", String.valueOf(StringProviderFromExternalSPI.class))
+ .withString("SPI_Impl",
+ externalDependencySPI.getSPIImpl().isPresent()
+ ? String.valueOf(externalDependencySPI.getSPIImpl().get().getClass())
+ : "Not found")
+ .withString("SPI_Interface_classloader",
+ String.valueOf(StringProviderFromExternalSPI.class.getClassLoader()))
+ .withString("SPI_Impl_classloader",
+ externalDependencySPI.getSPIImpl().isPresent()
+ ? String.valueOf(
+ externalDependencySPI.getSPIImpl().get().getClass().getClassLoader())
+ : "Not found")
+ .withString("comment", "SPI implementation loaded from a runtime/provided dependency.")
+ .withString("rootRepository", rootRepository)
+ .withString("classpath", runtimeClasspath)
+ .withString("workingDirectory", workDirectory)
+ .build());
+
+ JsonObject contentFromResources = jsonBuilderFactory.createObjectBuilder()
+ .add("contentFromResourceDependency", contentFromResourceDependency)
+ .add("contentFromResourceDynamicDependency", contentFromResourceDynamicDependency)
+ .add("contentFromResourceExternalDependency", contentFromResourceExternalDependency)
+ .add("contentFromMultipleResources", contentFromMultipleResources)
+ .build();
+ Record recordWithContentFromResources = recordBuilderFactory.newRecordBuilder()
+ .withString("value", contentFromResources.toString())
+ .withString("SPI_Interface", "N/A")
+ .withString("SPI_Impl", "N/A")
+ .withString("SPI_Interface_classloader", "N/A")
+ .withString("SPI_Impl_classloader", "N/A")
+ .withString("comment", "Resources loading.")
+ .withString("rootRepository", rootRepository)
+ .withString("classpath", runtimeClasspath)
+ .withString("workingDirectory", workDirectory)
+ .build();
+
+ List values = new ArrayList<>();
+ values.add(recordsFromDependencySPI);
+ values.add(recordsFromDynamicDependencySPI);
+ values.add(recordsFromExternalSPI);
+ values.add(recordWithContentFromResources);
+
+ return values.iterator();
+ }
+
+ private static String loadVersion() {
+ if (version == null) {
+ try (InputStream is = DynamicDependenciesWithSPIService.class.getClassLoader()
+ .getResourceAsStream("version.properties")) {
+ if (is == null) {
+ throw new ComponentException("Can't retrieve version.properties resource.");
+ }
+ Properties props = new Properties();
+ props.load(is);
+ version = props.getProperty("version");
+ } catch (IOException e) {
+ throw new ComponentException("Unable to load project version", e);
+ }
+ }
+ return version;
+ }
+
+ private String filterComments(final InputStream stream) {
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
+ return reader.lines()
+ .map(String::trim)
+ .filter(line -> !line.trim().startsWith("#"))
+ .filter(line -> !line.trim().isEmpty())
+ .collect(Collectors.joining("\n"));
+ } catch (IOException e) {
+ throw new ComponentException("Can't close a resource reader.", e);
+ }
+
+ }
+
+ private String loadAPropertyFromResource(final String resource, final String property) {
+ try (InputStream resourceStreamFromDependency = DynamicDependenciesWithSPIService.class.getClassLoader()
+ .getResourceAsStream(resource)) {
+
+ if (resourceStreamFromDependency == null) {
+ return "The resource '%s' has not been found, it can't retrieve the '%s' property value."
+ .formatted(resource, property);
+ }
+
+ Properties prop = new Properties();
+ prop.load(resourceStreamFromDependency);
+ return prop.getProperty(property);
+ } catch (IOException e) {
+ throw new ComponentException("Can't retrieve resource from a dependency.", e);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/META-INF/services/org.talend.sdk.component.runtime.manager.ComponentManager$Customizer b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/META-INF/services/org.talend.sdk.component.runtime.manager.ComponentManager$Customizer
new file mode 100644
index 0000000000000..1bbc17b34e21f
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/META-INF/services/org.talend.sdk.component.runtime.manager.ComponentManager$Customizer
@@ -0,0 +1 @@
+org.talend.sdk.component.sample.feature.loadinganalysis.withspi.service.CustomizeClassLoader
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/icons/dark/icon.svg b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/icons/dark/icon.svg
new file mode 100644
index 0000000000000..09ae5f65a3b5e
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/icons/dark/icon.svg
@@ -0,0 +1,65 @@
+
+
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/icons/light/icon.svg b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/icons/light/icon.svg
new file mode 100644
index 0000000000000..09ae5f65a3b5e
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/icons/light/icon.svg
@@ -0,0 +1,65 @@
+
+
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/Messages.properties
new file mode 100644
index 0000000000000..e6e61860f5e63
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/Messages.properties
@@ -0,0 +1,19 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+LoadingSPIsAndResources.datastore.dyndepsdso._displayName = Datastore
+LoadingSPIsAndResources.dataset.dyndepsdse._displayName = Dataset
+LoadingSPIsAndResources.actions.schema.dyndepsdse._displayName = Discover schema
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Messages.properties
new file mode 100644
index 0000000000000..52be7aba4aa43
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/config/Messages.properties
@@ -0,0 +1,25 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+Dataset.dso._displayName =
+Config.dse._displayName =
+
+Config.unusedOption._displayName = Unused in config
+Dataset.unusedOption._displayName = Unused in dataset
+Datastore.unusedOption._displayName = Unused in datastore
+
+Config.unusedOption._placeholder =
+Dataset.unusedOption._placeholder =
+Datastore.unusedOption._placeholder =
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/input/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/input/Messages.properties
new file mode 100644
index 0000000000000..ed2e60dc0fc13
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/input/Messages.properties
@@ -0,0 +1,17 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+LoadingSPIsAndResources.Input._displayName = Loading SPIs and Resources
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/version.properties b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/version.properties
new file mode 100644
index 0000000000000..bbe2f4191301e
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/main/resources/version.properties
@@ -0,0 +1,17 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+version=${project.version}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/input/DynamicDependenciesWithSPIInputTest.java b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/input/DynamicDependenciesWithSPIInputTest.java
new file mode 100644
index 0000000000000..2fcd4cc9da3fd
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withspi/input/DynamicDependenciesWithSPIInputTest.java
@@ -0,0 +1,110 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.withspi.input;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.talend.sdk.component.api.record.Record;
+import org.talend.sdk.component.junit.BaseComponentsHandler;
+import org.talend.sdk.component.junit.SimpleFactory;
+import org.talend.sdk.component.junit5.Injected;
+import org.talend.sdk.component.junit5.WithComponents;
+import org.talend.sdk.component.runtime.manager.chain.Job;
+import org.talend.sdk.component.sample.feature.loadinganalysis.withspi.config.Config;
+
+@WithComponents("org.talend.sdk.component.sample.feature.loadinganalysis.withspi")
+class DynamicDependenciesWithSPIInputTest {
+
+ @Injected
+ protected BaseComponentsHandler handler;
+
+ @Test
+ public void testGeneratedRecord() {
+ Config config = new Config();
+ String queryString = SimpleFactory.configurationByExample().forInstance(config).configured().toQueryString();
+
+ Job.components()
+ .component("input", "LoadingSPIsAndResources://Input?" + queryString)
+ .component("collector", "test://collector")
+ .connections()
+ .from("input")
+ .to("collector")
+ .build()
+ .run();
+
+ List records = handler.getCollectedData(Record.class);
+ Assertions.assertEquals(4, records.size());
+
+ Result expected0 = new Result(
+ "interface org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDependency",
+ "class org.talend.sdk.component.sample.feature.loadinganalysis.serviceproviderfromdependency.ServiceProviderFromDependency",
+ "jdk.internal.loader.ClassLoaders$AppClassLoader",
+ "jdk.internal.loader.ClassLoaders$AppClassLoader",
+ "SPI implementation loaded from a dependency.",
+ "ServiceProviderFromDependency value");
+ validate(expected0, records.get(0));
+
+ Result expected1 = new Result(
+ "interface org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDynamicDependency",
+ "class org.talend.sdk.component.sample.feature.loadinganalysis.serviceproviderfromdynamicdependency.ServiceProviderFromDynamicDependency",
+ "jdk.internal.loader.ClassLoaders$AppClassLoader",
+ "jdk.internal.loader.ClassLoaders$AppClassLoader",
+ "SPI implementation loaded from a dynamic dependency.",
+ "ServiceProviderFromDynamicDependency value");
+ validate(expected1, records.get(1));
+
+ Result expected2 = new Result(
+ "interface org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderFromExternalSPI",
+ "class org.talend.sdk.component.sample.feature.loadinganalysis.serviceproviderfromexternaldependency.ServiceProviderFromExternalDependency",
+ "jdk.internal.loader.ClassLoaders$AppClassLoader",
+ "jdk.internal.loader.ClassLoaders$AppClassLoader",
+ "SPI implementation loaded from a runtime/provided dependency.",
+ "ServiceProviderFromExternalDependency value");
+ validate(expected2, records.get(2));
+
+ Result expected3 = new Result(
+ "N/A",
+ "N/A",
+ "N/A",
+ "N/A",
+ "Resources loading.",
+ "{\"contentFromResourceDependency\":\"Message from a dependency resource.\",\"contentFromResourceDynamicDependency\":\"Message from a dynamic dependency resource.\",\"contentFromResourceExternalDependency\":\"Message from an external dependency resource.\",\"contentFromMultipleResources\":\"There should be 3 different values:\\nContent from static dependency\\nContent from dynamic dependency\\nContent from external dependency\"}");
+ validate(expected3, records.get(3));
+ }
+
+ private void validate(Result expected, Record record) {
+ Assertions.assertEquals(expected.spiInterface(), record.getString("SPI_Interface"));
+ Assertions.assertEquals(expected.spiImpl(), record.getString("SPI_Impl"));
+ Assertions.assertTrue(
+ record.getString("SPI_Interface_classloader").startsWith(expected.spiInterfaceClassloader()));
+ Assertions.assertTrue(record.getString("SPI_Impl_classloader").startsWith(expected.spiImplClassloader()));
+ Assertions.assertEquals(expected.comment(), record.getString("comment"));
+ Assertions.assertEquals(expected.value(), record.getString("value"));
+ }
+
+ private record Result(
+ String spiInterface,
+ String spiImpl,
+ String spiInterfaceClassloader,
+ String spiImplClassloader,
+ String comment,
+ String value
+ ) {
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/pom.xml b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/pom.xml
new file mode 100644
index 0000000000000..a6b50baf94a5a
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/pom.xml
@@ -0,0 +1,53 @@
+
+
+
+ 4.0.0
+
+ org.talend.sdk.component.loading-analysis
+ loading-analysis
+ 1.91.0-SNAPSHOT
+
+
+ loading-with-specific-isolation
+ jar
+ Component Runtime :: Sample Features :: Loading Analysis :: Loading with Specific Isolation
+
+
+
+ org.talend.sdk.component
+ component-runtime-manager
+ ${project.version}
+ provided
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ loading.with.specific.isolation
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Config.java b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Config.java
new file mode 100644
index 0000000000000..cedc133585a0e
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Config.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.ui.layout.AutoLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+
+import lombok.Data;
+
+/**
+ * For this sample, the same configuration is used for all connectors input/processor/output.
+ */
+@Data
+@AutoLayout
+public class Config implements Serializable {
+
+ @Option
+ @Documentation("The dataset configuration.")
+ private Dataset dse = new Dataset();
+
+ @Option
+ @Documentation("Unused option.")
+ private String unusedOption;
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Dataset.java b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Dataset.java
new file mode 100644
index 0000000000000..17cb29db62453
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Dataset.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.type.DataSet;
+import org.talend.sdk.component.api.configuration.ui.layout.AutoLayout;
+import org.talend.sdk.component.api.meta.Documentation;
+
+import lombok.Data;
+
+@Data
+@DataSet("specificisolationdse")
+@AutoLayout
+public class Dataset implements Serializable {
+
+ @Option
+ @Documentation("A datastore.")
+ private Datastore dso = new Datastore();
+
+ @Option
+ @Documentation("Unused option.")
+ private String unusedOption;
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Datastore.java b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Datastore.java
new file mode 100644
index 0000000000000..806d5b1afc8bb
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Datastore.java
@@ -0,0 +1,111 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.config;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.configuration.condition.ActiveIf;
+import org.talend.sdk.component.api.configuration.type.DataStore;
+import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
+import org.talend.sdk.component.api.configuration.ui.widget.TextArea;
+import org.talend.sdk.component.api.meta.Documentation;
+
+import lombok.Data;
+
+@Data
+@DataStore("specificisolationdso")
+@GridLayout({
+ @GridLayout.Row("noDynamicDependency"),
+ @GridLayout.Row("group"),
+ @GridLayout.Row("artifact"),
+ @GridLayout.Row("version"),
+ @GridLayout.Row("clazz"),
+ @GridLayout.Row("resource")
+})
+@GridLayout(names = GridLayout.FormType.ADVANCED, value = {
+ @GridLayout.Row("classesFilterAcceptAll"),
+ @GridLayout.Row("classesFilterOption"),
+ @GridLayout.Row("parentClassesFilterAcceptAll"),
+ @GridLayout.Row("parentClassesFilterOption"),
+ @GridLayout.Row("jarAsResource"),
+ @GridLayout.Row("parentResourcesFilterAcceptAll"),
+ @GridLayout.Row("parentResourcesFilterOption")
+})
+public class Datastore implements Serializable {
+
+ @Option
+ @Documentation("Don't add dynamic dependency.")
+ private boolean noDynamicDependency;
+
+ @Option
+ @Documentation("The dependency group.")
+ @ActiveIf(target = "noDynamicDependency", value = "false")
+ private String group;
+
+ @Option
+ @Documentation("The dependency artifact.")
+ @ActiveIf(target = "noDynamicDependency", value = "false")
+ private String artifact;
+
+ @Option
+ @Documentation("The dependency version.")
+ @ActiveIf(target = "noDynamicDependency", value = "false")
+ private String version;
+
+ @Option
+ @Documentation("A class to load.")
+ private String clazz;
+
+ @Option
+ @Documentation("A resource to load.")
+ private String resource;
+
+ @Option
+ @Documentation("Child classloader classfilter predicate always true.")
+ private boolean classesFilterAcceptAll;
+
+ @Option
+ @Documentation("Child classloader class filter. One filter by line. Can be empty.")
+ @TextArea
+ @ActiveIf(target = "classesFilterAcceptAll", value = "false")
+ private String classesFilterOption;
+
+ @Option
+ @Documentation("Child classloader parentClassesFilter predicate always true.")
+ private boolean parentClassesFilterAcceptAll;
+
+ @Option
+ @Documentation("Child classloader parent class filter. One filter by line. Can be empty.")
+ @TextArea
+ @ActiveIf(target = "parentClassesFilterAcceptAll", value = "false")
+ private String parentClassesFilterOption;
+
+ @Option
+ @Documentation("Jar in jar compliant.")
+ private boolean jarAsResource;
+
+ @Option
+ @Documentation("Child classloader parent resource filter predicate always true.")
+ private boolean parentResourcesFilterAcceptAll;
+
+ @Option
+ @Documentation("Child classloader parent resource filter. One filter by line. Can be empty.")
+ @TextArea
+ @ActiveIf(target = "parentResourcesFilterAcceptAll", value = "false")
+ private String parentResourcesFilterOption;
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/SpecificIsolationInput.java b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/SpecificIsolationInput.java
new file mode 100644
index 0000000000000..667179e81086c
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/SpecificIsolationInput.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.input;
+
+import java.io.Serializable;
+
+import org.talend.sdk.component.api.component.Icon;
+import org.talend.sdk.component.api.component.Version;
+import org.talend.sdk.component.api.input.Emitter;
+import org.talend.sdk.component.api.input.Producer;
+import org.talend.sdk.component.api.meta.Documentation;
+import org.talend.sdk.component.api.record.Record;
+import org.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.config.Config;
+import org.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.service.SpecificIsolationService;
+
+@Version
+@Icon(value = Icon.IconType.CUSTOM, custom = "icon")
+@Emitter(name = "Input")
+@Documentation("Loading dependencies with specific isolation.")
+public class SpecificIsolationInput implements Serializable {
+
+ private final Config config;
+
+ private final SpecificIsolationService service;
+
+ private boolean done;
+
+ public SpecificIsolationInput(final Config config,
+ final SpecificIsolationService service) {
+ this.config = config;
+ this.service = service;
+ }
+
+ @Producer
+ public Record next() {
+ if (done) {
+ return null;
+ }
+
+ return service.buildRecord(config);
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/package-info.java b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/package-info.java
new file mode 100644
index 0000000000000..51947c5629a2f
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.
+ */
+@Components(
+ family = "DependenciesWithSpecificIsolation",
+ categories = "sample")
+@Icon(value = Icon.IconType.CUSTOM, custom = "icon")
+package org.talend.sdk.component.sample.feature.loadinganalysis.specificisolation;
+
+import org.talend.sdk.component.api.component.Components;
+import org.talend.sdk.component.api.component.Icon;
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationService.java b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationService.java
new file mode 100644
index 0000000000000..234dbe2ea9165
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationService.java
@@ -0,0 +1,119 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.service;
+
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Predicate;
+
+import org.talend.sdk.component.api.configuration.Option;
+import org.talend.sdk.component.api.exception.ComponentException;
+import org.talend.sdk.component.api.record.Record;
+import org.talend.sdk.component.api.service.Service;
+import org.talend.sdk.component.api.service.dependency.DynamicDependencies;
+import org.talend.sdk.component.api.service.dependency.Resolver;
+import org.talend.sdk.component.api.service.dependency.Resolver.ClassLoaderDescriptor;
+import org.talend.sdk.component.api.service.record.RecordBuilderFactory;
+import org.talend.sdk.component.container.ContainerManager.ClassLoaderConfiguration;
+import org.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.config.Config;
+import org.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.config.Datastore;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Service
+public class SpecificIsolationService {
+
+ @Service
+ private RecordBuilderFactory recordBuilderFactory;
+
+ @Service
+ private Resolver resolver;
+
+ @DynamicDependencies
+ public List getDynamicDependencies(final @Option("configuration") Datastore datastore) {
+ if (datastore.isNoDynamicDependency()) {
+ log.info("No dynamic dependency");
+ return Collections.emptyList();
+ }
+
+ String dependency = getDependency(datastore);
+ log.info("Dynamic dependency: " + dependency);
+ return Collections.singletonList(dependency);
+ }
+
+ private static String getDependency(final Datastore datastore) {
+ return datastore.getGroup() + ":" + datastore.getArtifact() + ":" + datastore.getVersion();
+ }
+
+ public Record buildRecord(final Config config) {
+
+ final Predicate classfilterPredicate = config.getDse().getDso().isClassesFilterAcceptAll() ? s -> true
+ : predicateFromString(config.getDse().getDso().getClassesFilterOption());
+
+ final Predicate parentClassfilterPredicate =
+ config.getDse().getDso().isParentClassesFilterAcceptAll() ? s -> true
+ : predicateFromString(config.getDse().getDso().getParentClassesFilterOption());
+
+ final Predicate parentResourcesfilterPredicate =
+ config.getDse().getDso().isParentResourcesFilterAcceptAll() ? s -> true
+ : predicateFromString(config.getDse().getDso().getParentResourcesFilterOption());
+
+ final ClassLoader loader = getClass().getClassLoader();
+ final ClassLoaderConfiguration clConfiguration = ClassLoaderConfiguration
+ .builder()
+ .parent(loader)
+ .classesFilter(classfilterPredicate)
+ .parentClassesFilter(parentClassfilterPredicate)
+ .supportsResourceDependencies(config.getDse().getDso().isJarAsResource())
+ .parentResourcesFilter(parentResourcesfilterPredicate)
+ .create();
+
+ String dependency = getDependency(config.getDse().getDso());
+ List deps = Collections.singletonList(dependency);
+ try (ClassLoaderDescriptor classLoaderDescriptor = resolver.mapDescriptorToClassLoader(deps, clConfiguration)) {
+ ClassLoader specificClassLoader = classLoaderDescriptor.asClassLoader();
+
+ Class> aClass = specificClassLoader.loadClass(config.getDse().getDso().getClazz());
+
+ String content = "Can't read resource " + config.getDse().getDso().getResource();
+ try (InputStream resourceAsStream =
+ specificClassLoader.getResourceAsStream(config.getDse().getDso().getResource())) {
+ if (resourceAsStream != null) {
+ content = new String(resourceAsStream.readAllBytes());
+ } else {
+ log.warn("Resource not found: " + config.getDse().getDso().getResource());
+ }
+ }
+
+ return recordBuilderFactory.newRecordBuilder()
+ .withString("connector_classloader", this.getClass().getClassLoader().toString())
+ .withString("loaded_class_classloader", aClass.getClassLoader().toString())
+ .withString("loaded_resource_content", content)
+ .build();
+
+ } catch (Exception e) {
+ throw new ComponentException("Failed to load class or resource with specific isolation", e);
+ }
+ }
+
+ private Predicate predicateFromString(final String filterAsString) {
+ final List filters = List.of(filterAsString.split("\\n"));
+ return s -> filters.stream().anyMatch(s::startsWith);
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/dark/icon.svg b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/dark/icon.svg
new file mode 100644
index 0000000000000..09ae5f65a3b5e
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/dark/icon.svg
@@ -0,0 +1,65 @@
+
+
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/light/icon.svg b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/light/icon.svg
new file mode 100644
index 0000000000000..09ae5f65a3b5e
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/light/icon.svg
@@ -0,0 +1,65 @@
+
+
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/Messages.properties
new file mode 100644
index 0000000000000..149e722e1ae15
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/Messages.properties
@@ -0,0 +1,18 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+DependenciesWithSpecificIsolation.datastore.specificisolationdso._displayName = Datastore for loading with specific isolation
+DependenciesWithSpecificIsolation.dataset.specificisolationdse._displayName = Dataset for loading with specific isolation
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Messages.properties
new file mode 100644
index 0000000000000..a9ba6ec247072
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Messages.properties
@@ -0,0 +1,43 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+Datastore.noDynamicDependency._displayName = No dynamic dependency
+Datastore.group._displayName = Maven group
+Datastore.artifact._displayName = Maven artifact
+Datastore.version._displayName = Version
+Datastore.clazz._displayName = Class to load
+Datastore.resource._displayName = Resource to load
+Datastore.classesFilterAcceptAll._displayName = Specific classloader accept all classes
+Datastore.classesFilterOption._displayName = Specific classloader class filter
+Datastore.parentClassesFilterAcceptAll._displayName = Parent classloader accept all classes
+Datastore.parentClassesFilterOption._displayName = Parent classloader class filter
+Datastore.jarAsResource._displayName = Jar as resource compliance
+Datastore.parentResourcesFilterAcceptAll._displayName = Parent classloader accept all resources
+Datastore.parentResourcesFilterOption._displayName = Parent classloader resource filter
+Dataset.dso._displayName =
+Dataset.unusedOption._displayName = Unused option...
+Config.dse._displayName =
+Config.unusedOption._displayName = Unused option...
+Datastore.group._placeholder =
+Datastore.artifact._placeholder =
+Datastore.version._placeholder =
+Datastore.clazz._placeholder =
+Datastore.resource._placeholder =
+Datastore.classesFilterOption._placeholder =
+Datastore.parentClassesFilterOption._placeholder =
+Datastore.parentResourcesFilterOption._placeholder =
+Dataset.unusedOption._placeholder =
+Config.unusedOption._placeholder =
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/Messages.properties
new file mode 100644
index 0000000000000..3f26bb364cf17
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/Messages.properties
@@ -0,0 +1,17 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+
+DependenciesWithSpecificIsolation.Input._displayName = Loading With Specific Isolation Input
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationServiceTest.java b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationServiceTest.java
new file mode 100644
index 0000000000000..8895d528ea8de
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationServiceTest.java
@@ -0,0 +1,22 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.service;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class SpecificIsolationServiceTest {
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/pom.xml b/sample-parent/sample-features/loading-analysis/pom.xml
new file mode 100644
index 0000000000000..0ac8c40dcbe64
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/pom.xml
@@ -0,0 +1,57 @@
+
+
+
+ 4.0.0
+
+ org.talend.sdk.component
+ sample-features
+ 1.91.0-SNAPSHOT
+
+
+ org.talend.sdk.component.loading-analysis
+ loading-analysis
+ pom
+
+ Component Runtime :: Sample Features :: Loading Analysis
+
+ loading-dependencies-common
+ loading-dependencies-with-dataset
+ loading-dependencies-with-datastore
+ loading-dependencies-with-dynamicDependenciesConfiguration
+ loading-dependencies-with-dataprepRunAnnotation
+ loading-services-and-resources
+ loading-services-and-resources-lib
+ service-provider-from-dependency
+ service-provider-from-dynamic-dependency
+ service-provider-from-external-dependency
+ loading-with-specific-isolation
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+
+ suppressions.xml
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/pom.xml b/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/pom.xml
new file mode 100644
index 0000000000000..807ce7757d8f5
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/pom.xml
@@ -0,0 +1,95 @@
+
+
+
+ 4.0.0
+
+ org.talend.sdk.component.loading-analysis
+ loading-analysis
+ 1.91.0-SNAPSHOT
+
+
+ service-provider-from-dependency
+
+ jar
+ Component Runtime :: Sample Features :: Loading Analysis :: Service Provider from Dependency
+
+
+ true
+
+
+
+
+ org.talend.sdk.component.loading-analysis
+ loading-services-and-resources-lib
+ ${project.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ service.provider.from.dependency
+
+
+
+
+
+ org.talend.sdk.component
+ talend-component-maven-plugin
+ ${project.version}
+
+
+ talend-component-validate
+
+ false
+ false
+ false
+
+
+
+ talend-dependencies
+
+ dependencies
+
+ none
+
+
+ talend-component-bundle
+
+ car
+
+ none
+
+
+ talend-scan-descriptor
+
+ scan-descriptor
+
+ none
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdependency/ServiceProviderFromDependency.java b/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdependency/ServiceProviderFromDependency.java
new file mode 100644
index 0000000000000..40e013a02a509
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdependency/ServiceProviderFromDependency.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.serviceproviderfromdependency;
+
+import org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDependency;
+
+public class ServiceProviderFromDependency implements StringProviderSPIAsDependency {
+
+ @Override
+ public String getValueFromDependency() {
+ return "ServiceProviderFromDependency value";
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/resources/FROM_DEPENDENCY/resource.properties b/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/resources/FROM_DEPENDENCY/resource.properties
new file mode 100644
index 0000000000000..ba6218230f4b1
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/resources/FROM_DEPENDENCY/resource.properties
@@ -0,0 +1,16 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+ServiceProviderFromDependency.message=Message from a dependency resource.
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/resources/META-INF/services/org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDependency b/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/resources/META-INF/services/org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDependency
new file mode 100644
index 0000000000000..2f9456a42e33b
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/resources/META-INF/services/org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDependency
@@ -0,0 +1,16 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+org.talend.sdk.component.sample.feature.loadinganalysis.serviceproviderfromdependency.ServiceProviderFromDependency
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/resources/MULTIPLE_RESOURCE/content.txt b/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/resources/MULTIPLE_RESOURCE/content.txt
new file mode 100644
index 0000000000000..0019899e6606f
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/main/resources/MULTIPLE_RESOURCE/content.txt
@@ -0,0 +1,16 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+Content from static dependency
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdependency/ServiceProviderFromDependencyTest.java b/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdependency/ServiceProviderFromDependencyTest.java
new file mode 100644
index 0000000000000..d0aef2d49a4da
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdependency/ServiceProviderFromDependencyTest.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.serviceproviderfromdependency;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.spiConsumers.DependencySPIConsumer;
+
+class ServiceProviderFromDependencyTest {
+
+ @Test
+ void testSPI() {
+ DependencySPIConsumer dependencySPIConsumer = new DependencySPIConsumer<>();
+ String transform = dependencySPIConsumer.transform(String::valueOf);
+
+ Assertions.assertTrue(transform.startsWith("ServiceProviderFromDependency value"));
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/pom.xml b/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/pom.xml
new file mode 100644
index 0000000000000..a5126ad45a8d3
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/pom.xml
@@ -0,0 +1,95 @@
+
+
+
+ 4.0.0
+
+ org.talend.sdk.component.loading-analysis
+ loading-analysis
+ 1.91.0-SNAPSHOT
+
+
+ service-provider-from-dynamic-dependency
+
+ jar
+ Component Runtime :: Sample Features :: Loading Analysis :: Service Provider from Dynamic Dependency
+
+
+ true
+
+
+
+
+ org.talend.sdk.component.loading-analysis
+ loading-services-and-resources-lib
+ ${project.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ service.provider.from.dynamic.dependency
+
+
+
+
+
+ org.talend.sdk.component
+ talend-component-maven-plugin
+ ${project.version}
+
+
+ talend-component-validate
+
+ false
+ false
+ false
+
+
+
+ talend-dependencies
+
+ dependencies
+
+ none
+
+
+ talend-component-bundle
+
+ car
+
+ none
+
+
+ talend-scan-descriptor
+
+ scan-descriptor
+
+ none
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdynamicdependency/ServiceProviderFromDynamicDependency.java b/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdynamicdependency/ServiceProviderFromDynamicDependency.java
new file mode 100644
index 0000000000000..20065ec025541
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdynamicdependency/ServiceProviderFromDynamicDependency.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.serviceproviderfromdynamicdependency;
+
+import org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDynamicDependency;
+
+public class ServiceProviderFromDynamicDependency implements StringProviderSPIAsDynamicDependency {
+
+ @Override
+ public String getValueFromASPIAsDynamicDependency() {
+ return "ServiceProviderFromDynamicDependency value";
+ }
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/resources/FROM_DYNAMIC_DEPENDENCY/resource.properties b/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/resources/FROM_DYNAMIC_DEPENDENCY/resource.properties
new file mode 100644
index 0000000000000..5114014c6e8cc
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/resources/FROM_DYNAMIC_DEPENDENCY/resource.properties
@@ -0,0 +1,16 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+ServiceProviderFromDynamicDependency.message=Message from a dynamic dependency resource.
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/resources/META-INF/services/org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDynamicDependency b/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/resources/META-INF/services/org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDynamicDependency
new file mode 100644
index 0000000000000..bd7f67fa1851a
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/resources/META-INF/services/org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderSPIAsDynamicDependency
@@ -0,0 +1,16 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+org.talend.sdk.component.sample.feature.loadinganalysis.serviceproviderfromdynamicdependency.ServiceProviderFromDynamicDependency
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/resources/MULTIPLE_RESOURCE/content.txt b/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/resources/MULTIPLE_RESOURCE/content.txt
new file mode 100644
index 0000000000000..f05e70a21279c
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/main/resources/MULTIPLE_RESOURCE/content.txt
@@ -0,0 +1,16 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+Content from dynamic dependency
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdynamicdependency/ServiceProviderFromDependencyTest.java b/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdynamicdependency/ServiceProviderFromDependencyTest.java
new file mode 100644
index 0000000000000..03948ea515962
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromdynamicdependency/ServiceProviderFromDependencyTest.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.serviceproviderfromdynamicdependency;
+
+import java.util.function.Function;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.spiConsumers.DynamicDependencySPIConsumer;
+
+class ServiceProviderFromDependencyTest {
+
+ @Test
+ void testSPI() {
+ DynamicDependencySPIConsumer useADynamicDependencySPI = new DynamicDependencySPIConsumer<>();
+ String transform = useADynamicDependencySPI.transform(Function.identity());
+ Assertions.assertTrue(transform.startsWith("ServiceProviderFromDynamicDependency value"));
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/pom.xml b/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/pom.xml
new file mode 100644
index 0000000000000..d797a278dda94
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/pom.xml
@@ -0,0 +1,95 @@
+
+
+
+ 4.0.0
+
+ org.talend.sdk.component.loading-analysis
+ loading-analysis
+ 1.91.0-SNAPSHOT
+
+
+ service-provider-from-external-dependency
+
+ jar
+ Component Runtime :: Sample Features :: Loading Analysis :: Service Provider from External Dependency
+
+
+ true
+
+
+
+
+ org.talend.sdk.component.loading-analysis
+ loading-services-and-resources-lib
+ ${project.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+
+ service.provider.from.external.dependency
+
+
+
+
+
+ org.talend.sdk.component
+ talend-component-maven-plugin
+ ${project.version}
+
+
+ talend-component-validate
+
+ false
+ false
+ false
+
+
+
+ talend-dependencies
+
+ dependencies
+
+ none
+
+
+ talend-component-bundle
+
+ car
+
+ none
+
+
+ talend-scan-descriptor
+
+ scan-descriptor
+
+ none
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromexternaldependency/ServiceProviderFromExternalDependency.java b/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromexternaldependency/ServiceProviderFromExternalDependency.java
new file mode 100644
index 0000000000000..7bb7486cdba09
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromexternaldependency/ServiceProviderFromExternalDependency.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.serviceproviderfromexternaldependency;
+
+import org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderFromExternalSPI;
+
+public class ServiceProviderFromExternalDependency implements StringProviderFromExternalSPI {
+
+ @Override
+ public String getValueFromExternalSPI() {
+ return "ServiceProviderFromExternalDependency value";
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/resources/FROM_EXTERNAL_DEPENDENCY/resource.properties b/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/resources/FROM_EXTERNAL_DEPENDENCY/resource.properties
new file mode 100644
index 0000000000000..6d29057d6285b
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/resources/FROM_EXTERNAL_DEPENDENCY/resource.properties
@@ -0,0 +1,16 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+ServiceProviderFromExternalDependency.message=Message from an external dependency resource.
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/resources/META-INF/services/org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderFromExternalSPI b/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/resources/META-INF/services/org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderFromExternalSPI
new file mode 100644
index 0000000000000..1fa9119d3e6df
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/resources/META-INF/services/org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.serviceInterfaces.StringProviderFromExternalSPI
@@ -0,0 +1,16 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+org.talend.sdk.component.sample.feature.loadinganalysis.serviceproviderfromexternaldependency.ServiceProviderFromExternalDependency
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/resources/MULTIPLE_RESOURCE/content.txt b/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/resources/MULTIPLE_RESOURCE/content.txt
new file mode 100644
index 0000000000000..4f25e41044df4
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/main/resources/MULTIPLE_RESOURCE/content.txt
@@ -0,0 +1,16 @@
+# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+#
+# Licensed 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.
+# Here you can change all your configuration display names to use more explicit labels
+# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
+Content from external dependency
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromexternaldependency/ServiceProviderFromExternalDependencyTest.java b/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromexternaldependency/ServiceProviderFromExternalDependencyTest.java
new file mode 100644
index 0000000000000..d72d444e28c24
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/serviceproviderfromexternaldependency/ServiceProviderFromExternalDependencyTest.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
+ *
+ * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.serviceproviderfromexternaldependency;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.talend.sdk.component.sample.feature.loadinganalysis.classloadertestlibrary.spiConsumers.ExternalDependencySPIConsumer;
+
+class ServiceProviderFromExternalDependencyTest {
+
+ @Test
+ void testSPI() {
+ ExternalDependencySPIConsumer values = new ExternalDependencySPIConsumer<>();
+ String transform = values.transform(String::valueOf);
+ Assertions.assertTrue(transform.startsWith("ServiceProviderFromExternalDependency value"));
+ }
+
+}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/suppressions.xml b/sample-parent/sample-features/loading-analysis/suppressions.xml
new file mode 100644
index 0000000000000..f34aa9beccbec
--- /dev/null
+++ b/sample-parent/sample-features/loading-analysis/suppressions.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample-parent/sample-features/pom.xml b/sample-parent/sample-features/pom.xml
index 44bd97946317e..098fc462a80b8 100644
--- a/sample-parent/sample-features/pom.xml
+++ b/sample-parent/sample-features/pom.xml
@@ -13,7 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
+4.0.0
@@ -36,6 +37,7 @@
configuration-formentry-with-erroractions-in-forms
+ loading-analysis
@@ -55,6 +57,14 @@
+
+ maven-surefire-plugin
+
+
+ ${settings.localRepository}
+
+
+ org.talend.sdk.componenttalend-component-maven-plugin
From c9c8cdf652f17d998d19362074c9e52758b0af29 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Wed, 13 May 2026 11:46:08 +0200
Subject: [PATCH 39/41] feat(QTDI-2134): bump
sample-features/loading-dependencies to 1.92.0-snapshot
---
.../loading-analysis/loading-dependencies-common/pom.xml | 2 +-
.../loading-dependencies-with-dataprepRunAnnotation/pom.xml | 2 +-
.../loading-analysis/loading-dependencies-with-dataset/pom.xml | 2 +-
.../loading-dependencies-with-datastore/pom.xml | 2 +-
.../pom.xml | 2 +-
.../loading-analysis/loading-services-and-resources-lib/pom.xml | 2 +-
.../loading-analysis/loading-services-and-resources/pom.xml | 2 +-
.../loading-analysis/loading-with-specific-isolation/pom.xml | 2 +-
sample-parent/sample-features/loading-analysis/pom.xml | 2 +-
.../loading-analysis/service-provider-from-dependency/pom.xml | 2 +-
.../service-provider-from-dynamic-dependency/pom.xml | 2 +-
.../service-provider-from-external-dependency/pom.xml | 2 +-
12 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-common/pom.xml b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/pom.xml
index a3d37787e4ecd..7cc163c1c93ef 100644
--- a/sample-parent/sample-features/loading-analysis/loading-dependencies-common/pom.xml
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-common/pom.xml
@@ -19,7 +19,7 @@
org.talend.sdk.component.loading-analysisloading-analysis
- 1.91.0-SNAPSHOT
+ 1.92.0-SNAPSHOT
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/pom.xml b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/pom.xml
index 8c7a20e2b8268..182dc83617720 100644
--- a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/pom.xml
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/pom.xml
@@ -19,7 +19,7 @@
org.talend.sdk.component.loading-analysisloading-analysis
- 1.91.0-SNAPSHOT
+ 1.92.0-SNAPSHOTloading-dependencies-with-dataprepRunAnnotation
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/pom.xml b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/pom.xml
index d814ac0db2e99..dc01ef3de636b 100644
--- a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/pom.xml
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataset/pom.xml
@@ -18,7 +18,7 @@
org.talend.sdk.component.loading-analysisloading-analysis
- 1.91.0-SNAPSHOT
+ 1.92.0-SNAPSHOTloading-dependencies-with-dataset
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/pom.xml b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/pom.xml
index 885c45b726ed5..3d56e63dae92f 100644
--- a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/pom.xml
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-datastore/pom.xml
@@ -19,7 +19,7 @@
org.talend.sdk.component.loading-analysisloading-analysis
- 1.91.0-SNAPSHOT
+ 1.92.0-SNAPSHOTloading-dependencies-with-datastore
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/pom.xml b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/pom.xml
index c47b9fd46c69e..745e54b810247 100644
--- a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/pom.xml
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dynamicDependenciesConfiguration/pom.xml
@@ -18,7 +18,7 @@
org.talend.sdk.component.loading-analysisloading-analysis
- 1.91.0-SNAPSHOT
+ 1.92.0-SNAPSHOTloading-dependencies-with-dynamicDependenciesConfiguration
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/pom.xml b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/pom.xml
index ad9c66d3022eb..05e8847534e41 100644
--- a/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/pom.xml
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources-lib/pom.xml
@@ -20,7 +20,7 @@
org.talend.sdk.component.loading-analysisloading-analysis
- 1.91.0-SNAPSHOT
+ 1.92.0-SNAPSHOTloading-services-and-resources-lib
diff --git a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/pom.xml b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/pom.xml
index 5944b10ece61c..fddd9e9d2f662 100644
--- a/sample-parent/sample-features/loading-analysis/loading-services-and-resources/pom.xml
+++ b/sample-parent/sample-features/loading-analysis/loading-services-and-resources/pom.xml
@@ -19,7 +19,7 @@
org.talend.sdk.component.loading-analysisloading-analysis
- 1.91.0-SNAPSHOT
+ 1.92.0-SNAPSHOTloading-services-and-resources
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/pom.xml b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/pom.xml
index a6b50baf94a5a..76c69a5a80a8b 100644
--- a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/pom.xml
+++ b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/pom.xml
@@ -19,7 +19,7 @@
org.talend.sdk.component.loading-analysisloading-analysis
- 1.91.0-SNAPSHOT
+ 1.92.0-SNAPSHOTloading-with-specific-isolation
diff --git a/sample-parent/sample-features/loading-analysis/pom.xml b/sample-parent/sample-features/loading-analysis/pom.xml
index 0ac8c40dcbe64..3df1e13d02a1d 100644
--- a/sample-parent/sample-features/loading-analysis/pom.xml
+++ b/sample-parent/sample-features/loading-analysis/pom.xml
@@ -20,7 +20,7 @@
org.talend.sdk.componentsample-features
- 1.91.0-SNAPSHOT
+ 1.92.0-SNAPSHOTorg.talend.sdk.component.loading-analysis
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/pom.xml b/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/pom.xml
index 807ce7757d8f5..7e237993c2bed 100644
--- a/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/pom.xml
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-dependency/pom.xml
@@ -20,7 +20,7 @@
org.talend.sdk.component.loading-analysisloading-analysis
- 1.91.0-SNAPSHOT
+ 1.92.0-SNAPSHOTservice-provider-from-dependency
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/pom.xml b/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/pom.xml
index a5126ad45a8d3..9ac4b481348d2 100644
--- a/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/pom.xml
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-dynamic-dependency/pom.xml
@@ -20,7 +20,7 @@
org.talend.sdk.component.loading-analysisloading-analysis
- 1.91.0-SNAPSHOT
+ 1.92.0-SNAPSHOTservice-provider-from-dynamic-dependency
diff --git a/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/pom.xml b/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/pom.xml
index d797a278dda94..ea258d19fb539 100644
--- a/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/pom.xml
+++ b/sample-parent/sample-features/loading-analysis/service-provider-from-external-dependency/pom.xml
@@ -20,7 +20,7 @@
org.talend.sdk.component.loading-analysisloading-analysis
- 1.91.0-SNAPSHOT
+ 1.92.0-SNAPSHOTservice-provider-from-external-dependency
From cb806e3e76b857fdeb2e8b3c922786c198d6d6a8 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Fri, 15 May 2026 10:40:34 +0200
Subject: [PATCH 40/41] feat(QTDI-2134): remove unused module in
sample-features/loading-dependencies
---
.../loading-with-specific-isolation/pom.xml | 53 --------
.../specificisolation/config/Config.java | 41 ------
.../specificisolation/config/Dataset.java | 40 ------
.../specificisolation/config/Datastore.java | 111 ----------------
.../input/SpecificIsolationInput.java | 56 ---------
.../specificisolation/package-info.java | 23 ----
.../service/SpecificIsolationService.java | 119 ------------------
.../src/main/resources/icons/dark/icon.svg | 65 ----------
.../src/main/resources/icons/light/icon.svg | 65 ----------
.../specificisolation/Messages.properties | 18 ---
.../config/Messages.properties | 43 -------
.../input/Messages.properties | 17 ---
.../service/SpecificIsolationServiceTest.java | 22 ----
.../sample-features/loading-analysis/pom.xml | 1 -
14 files changed, 674 deletions(-)
delete mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/pom.xml
delete mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Config.java
delete mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Dataset.java
delete mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Datastore.java
delete mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/SpecificIsolationInput.java
delete mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/package-info.java
delete mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationService.java
delete mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/dark/icon.svg
delete mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/light/icon.svg
delete mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/Messages.properties
delete mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Messages.properties
delete mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/Messages.properties
delete mode 100644 sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationServiceTest.java
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/pom.xml b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/pom.xml
deleted file mode 100644
index 76c69a5a80a8b..0000000000000
--- a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/pom.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
- 4.0.0
-
- org.talend.sdk.component.loading-analysis
- loading-analysis
- 1.92.0-SNAPSHOT
-
-
- loading-with-specific-isolation
- jar
- Component Runtime :: Sample Features :: Loading Analysis :: Loading with Specific Isolation
-
-
-
- org.talend.sdk.component
- component-runtime-manager
- ${project.version}
- provided
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-jar-plugin
-
-
-
- loading.with.specific.isolation
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Config.java b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Config.java
deleted file mode 100644
index cedc133585a0e..0000000000000
--- a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Config.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
- *
- * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.config;
-
-import java.io.Serializable;
-
-import org.talend.sdk.component.api.configuration.Option;
-import org.talend.sdk.component.api.configuration.ui.layout.AutoLayout;
-import org.talend.sdk.component.api.meta.Documentation;
-
-import lombok.Data;
-
-/**
- * For this sample, the same configuration is used for all connectors input/processor/output.
- */
-@Data
-@AutoLayout
-public class Config implements Serializable {
-
- @Option
- @Documentation("The dataset configuration.")
- private Dataset dse = new Dataset();
-
- @Option
- @Documentation("Unused option.")
- private String unusedOption;
-
-}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Dataset.java b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Dataset.java
deleted file mode 100644
index 17cb29db62453..0000000000000
--- a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Dataset.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
- *
- * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.config;
-
-import java.io.Serializable;
-
-import org.talend.sdk.component.api.configuration.Option;
-import org.talend.sdk.component.api.configuration.type.DataSet;
-import org.talend.sdk.component.api.configuration.ui.layout.AutoLayout;
-import org.talend.sdk.component.api.meta.Documentation;
-
-import lombok.Data;
-
-@Data
-@DataSet("specificisolationdse")
-@AutoLayout
-public class Dataset implements Serializable {
-
- @Option
- @Documentation("A datastore.")
- private Datastore dso = new Datastore();
-
- @Option
- @Documentation("Unused option.")
- private String unusedOption;
-
-}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Datastore.java b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Datastore.java
deleted file mode 100644
index 806d5b1afc8bb..0000000000000
--- a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Datastore.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
- *
- * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.config;
-
-import java.io.Serializable;
-
-import org.talend.sdk.component.api.configuration.Option;
-import org.talend.sdk.component.api.configuration.condition.ActiveIf;
-import org.talend.sdk.component.api.configuration.type.DataStore;
-import org.talend.sdk.component.api.configuration.ui.layout.GridLayout;
-import org.talend.sdk.component.api.configuration.ui.widget.TextArea;
-import org.talend.sdk.component.api.meta.Documentation;
-
-import lombok.Data;
-
-@Data
-@DataStore("specificisolationdso")
-@GridLayout({
- @GridLayout.Row("noDynamicDependency"),
- @GridLayout.Row("group"),
- @GridLayout.Row("artifact"),
- @GridLayout.Row("version"),
- @GridLayout.Row("clazz"),
- @GridLayout.Row("resource")
-})
-@GridLayout(names = GridLayout.FormType.ADVANCED, value = {
- @GridLayout.Row("classesFilterAcceptAll"),
- @GridLayout.Row("classesFilterOption"),
- @GridLayout.Row("parentClassesFilterAcceptAll"),
- @GridLayout.Row("parentClassesFilterOption"),
- @GridLayout.Row("jarAsResource"),
- @GridLayout.Row("parentResourcesFilterAcceptAll"),
- @GridLayout.Row("parentResourcesFilterOption")
-})
-public class Datastore implements Serializable {
-
- @Option
- @Documentation("Don't add dynamic dependency.")
- private boolean noDynamicDependency;
-
- @Option
- @Documentation("The dependency group.")
- @ActiveIf(target = "noDynamicDependency", value = "false")
- private String group;
-
- @Option
- @Documentation("The dependency artifact.")
- @ActiveIf(target = "noDynamicDependency", value = "false")
- private String artifact;
-
- @Option
- @Documentation("The dependency version.")
- @ActiveIf(target = "noDynamicDependency", value = "false")
- private String version;
-
- @Option
- @Documentation("A class to load.")
- private String clazz;
-
- @Option
- @Documentation("A resource to load.")
- private String resource;
-
- @Option
- @Documentation("Child classloader classfilter predicate always true.")
- private boolean classesFilterAcceptAll;
-
- @Option
- @Documentation("Child classloader class filter. One filter by line. Can be empty.")
- @TextArea
- @ActiveIf(target = "classesFilterAcceptAll", value = "false")
- private String classesFilterOption;
-
- @Option
- @Documentation("Child classloader parentClassesFilter predicate always true.")
- private boolean parentClassesFilterAcceptAll;
-
- @Option
- @Documentation("Child classloader parent class filter. One filter by line. Can be empty.")
- @TextArea
- @ActiveIf(target = "parentClassesFilterAcceptAll", value = "false")
- private String parentClassesFilterOption;
-
- @Option
- @Documentation("Jar in jar compliant.")
- private boolean jarAsResource;
-
- @Option
- @Documentation("Child classloader parent resource filter predicate always true.")
- private boolean parentResourcesFilterAcceptAll;
-
- @Option
- @Documentation("Child classloader parent resource filter. One filter by line. Can be empty.")
- @TextArea
- @ActiveIf(target = "parentResourcesFilterAcceptAll", value = "false")
- private String parentResourcesFilterOption;
-
-}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/SpecificIsolationInput.java b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/SpecificIsolationInput.java
deleted file mode 100644
index 667179e81086c..0000000000000
--- a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/SpecificIsolationInput.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
- *
- * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.input;
-
-import java.io.Serializable;
-
-import org.talend.sdk.component.api.component.Icon;
-import org.talend.sdk.component.api.component.Version;
-import org.talend.sdk.component.api.input.Emitter;
-import org.talend.sdk.component.api.input.Producer;
-import org.talend.sdk.component.api.meta.Documentation;
-import org.talend.sdk.component.api.record.Record;
-import org.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.config.Config;
-import org.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.service.SpecificIsolationService;
-
-@Version
-@Icon(value = Icon.IconType.CUSTOM, custom = "icon")
-@Emitter(name = "Input")
-@Documentation("Loading dependencies with specific isolation.")
-public class SpecificIsolationInput implements Serializable {
-
- private final Config config;
-
- private final SpecificIsolationService service;
-
- private boolean done;
-
- public SpecificIsolationInput(final Config config,
- final SpecificIsolationService service) {
- this.config = config;
- this.service = service;
- }
-
- @Producer
- public Record next() {
- if (done) {
- return null;
- }
-
- return service.buildRecord(config);
- }
-
-}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/package-info.java b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/package-info.java
deleted file mode 100644
index 51947c5629a2f..0000000000000
--- a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
- *
- * Licensed 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.
- */
-@Components(
- family = "DependenciesWithSpecificIsolation",
- categories = "sample")
-@Icon(value = Icon.IconType.CUSTOM, custom = "icon")
-package org.talend.sdk.component.sample.feature.loadinganalysis.specificisolation;
-
-import org.talend.sdk.component.api.component.Components;
-import org.talend.sdk.component.api.component.Icon;
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationService.java b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationService.java
deleted file mode 100644
index 234dbe2ea9165..0000000000000
--- a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationService.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
- *
- * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.service;
-
-import java.io.InputStream;
-import java.util.Collections;
-import java.util.List;
-import java.util.function.Predicate;
-
-import org.talend.sdk.component.api.configuration.Option;
-import org.talend.sdk.component.api.exception.ComponentException;
-import org.talend.sdk.component.api.record.Record;
-import org.talend.sdk.component.api.service.Service;
-import org.talend.sdk.component.api.service.dependency.DynamicDependencies;
-import org.talend.sdk.component.api.service.dependency.Resolver;
-import org.talend.sdk.component.api.service.dependency.Resolver.ClassLoaderDescriptor;
-import org.talend.sdk.component.api.service.record.RecordBuilderFactory;
-import org.talend.sdk.component.container.ContainerManager.ClassLoaderConfiguration;
-import org.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.config.Config;
-import org.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.config.Datastore;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@Service
-public class SpecificIsolationService {
-
- @Service
- private RecordBuilderFactory recordBuilderFactory;
-
- @Service
- private Resolver resolver;
-
- @DynamicDependencies
- public List getDynamicDependencies(final @Option("configuration") Datastore datastore) {
- if (datastore.isNoDynamicDependency()) {
- log.info("No dynamic dependency");
- return Collections.emptyList();
- }
-
- String dependency = getDependency(datastore);
- log.info("Dynamic dependency: " + dependency);
- return Collections.singletonList(dependency);
- }
-
- private static String getDependency(final Datastore datastore) {
- return datastore.getGroup() + ":" + datastore.getArtifact() + ":" + datastore.getVersion();
- }
-
- public Record buildRecord(final Config config) {
-
- final Predicate classfilterPredicate = config.getDse().getDso().isClassesFilterAcceptAll() ? s -> true
- : predicateFromString(config.getDse().getDso().getClassesFilterOption());
-
- final Predicate parentClassfilterPredicate =
- config.getDse().getDso().isParentClassesFilterAcceptAll() ? s -> true
- : predicateFromString(config.getDse().getDso().getParentClassesFilterOption());
-
- final Predicate parentResourcesfilterPredicate =
- config.getDse().getDso().isParentResourcesFilterAcceptAll() ? s -> true
- : predicateFromString(config.getDse().getDso().getParentResourcesFilterOption());
-
- final ClassLoader loader = getClass().getClassLoader();
- final ClassLoaderConfiguration clConfiguration = ClassLoaderConfiguration
- .builder()
- .parent(loader)
- .classesFilter(classfilterPredicate)
- .parentClassesFilter(parentClassfilterPredicate)
- .supportsResourceDependencies(config.getDse().getDso().isJarAsResource())
- .parentResourcesFilter(parentResourcesfilterPredicate)
- .create();
-
- String dependency = getDependency(config.getDse().getDso());
- List deps = Collections.singletonList(dependency);
- try (ClassLoaderDescriptor classLoaderDescriptor = resolver.mapDescriptorToClassLoader(deps, clConfiguration)) {
- ClassLoader specificClassLoader = classLoaderDescriptor.asClassLoader();
-
- Class> aClass = specificClassLoader.loadClass(config.getDse().getDso().getClazz());
-
- String content = "Can't read resource " + config.getDse().getDso().getResource();
- try (InputStream resourceAsStream =
- specificClassLoader.getResourceAsStream(config.getDse().getDso().getResource())) {
- if (resourceAsStream != null) {
- content = new String(resourceAsStream.readAllBytes());
- } else {
- log.warn("Resource not found: " + config.getDse().getDso().getResource());
- }
- }
-
- return recordBuilderFactory.newRecordBuilder()
- .withString("connector_classloader", this.getClass().getClassLoader().toString())
- .withString("loaded_class_classloader", aClass.getClassLoader().toString())
- .withString("loaded_resource_content", content)
- .build();
-
- } catch (Exception e) {
- throw new ComponentException("Failed to load class or resource with specific isolation", e);
- }
- }
-
- private Predicate predicateFromString(final String filterAsString) {
- final List filters = List.of(filterAsString.split("\\n"));
- return s -> filters.stream().anyMatch(s::startsWith);
- }
-
-}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/dark/icon.svg b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/dark/icon.svg
deleted file mode 100644
index 09ae5f65a3b5e..0000000000000
--- a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/dark/icon.svg
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/light/icon.svg b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/light/icon.svg
deleted file mode 100644
index 09ae5f65a3b5e..0000000000000
--- a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/icons/light/icon.svg
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/Messages.properties
deleted file mode 100644
index 149e722e1ae15..0000000000000
--- a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/Messages.properties
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
-#
-# Licensed 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.
-# Here you can change all your configuration display names to use more explicit labels
-# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
-
-DependenciesWithSpecificIsolation.datastore.specificisolationdso._displayName = Datastore for loading with specific isolation
-DependenciesWithSpecificIsolation.dataset.specificisolationdse._displayName = Dataset for loading with specific isolation
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Messages.properties
deleted file mode 100644
index a9ba6ec247072..0000000000000
--- a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/config/Messages.properties
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
-#
-# Licensed 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.
-# Here you can change all your configuration display names to use more explicit labels
-# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
-
-Datastore.noDynamicDependency._displayName = No dynamic dependency
-Datastore.group._displayName = Maven group
-Datastore.artifact._displayName = Maven artifact
-Datastore.version._displayName = Version
-Datastore.clazz._displayName = Class to load
-Datastore.resource._displayName = Resource to load
-Datastore.classesFilterAcceptAll._displayName = Specific classloader accept all classes
-Datastore.classesFilterOption._displayName = Specific classloader class filter
-Datastore.parentClassesFilterAcceptAll._displayName = Parent classloader accept all classes
-Datastore.parentClassesFilterOption._displayName = Parent classloader class filter
-Datastore.jarAsResource._displayName = Jar as resource compliance
-Datastore.parentResourcesFilterAcceptAll._displayName = Parent classloader accept all resources
-Datastore.parentResourcesFilterOption._displayName = Parent classloader resource filter
-Dataset.dso._displayName =
-Dataset.unusedOption._displayName = Unused option...
-Config.dse._displayName =
-Config.unusedOption._displayName = Unused option...
-Datastore.group._placeholder =
-Datastore.artifact._placeholder =
-Datastore.version._placeholder =
-Datastore.clazz._placeholder =
-Datastore.resource._placeholder =
-Datastore.classesFilterOption._placeholder =
-Datastore.parentClassesFilterOption._placeholder =
-Datastore.parentResourcesFilterOption._placeholder =
-Dataset.unusedOption._placeholder =
-Config.unusedOption._placeholder =
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/Messages.properties b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/Messages.properties
deleted file mode 100644
index 3f26bb364cf17..0000000000000
--- a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/main/resources/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/input/Messages.properties
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2006-2026 Talend Inc. - www.talend.com
-#
-# Licensed 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.
-# Here you can change all your configuration display names to use more explicit labels
-# You can also translate your configuration by adding one file by local Messages_fr.properties for french for example
-
-DependenciesWithSpecificIsolation.Input._displayName = Loading With Specific Isolation Input
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationServiceTest.java b/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationServiceTest.java
deleted file mode 100644
index 8895d528ea8de..0000000000000
--- a/sample-parent/sample-features/loading-analysis/loading-with-specific-isolation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/specificisolation/service/SpecificIsolationServiceTest.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * Copyright (C) 2006-2026 Talend Inc. - www.talend.com
- *
- * Licensed 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.talend.sdk.component.sample.feature.loadinganalysis.specificisolation.service;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-class SpecificIsolationServiceTest {
-
-}
\ No newline at end of file
diff --git a/sample-parent/sample-features/loading-analysis/pom.xml b/sample-parent/sample-features/loading-analysis/pom.xml
index 3df1e13d02a1d..1722f26594e53 100644
--- a/sample-parent/sample-features/loading-analysis/pom.xml
+++ b/sample-parent/sample-features/loading-analysis/pom.xml
@@ -39,7 +39,6 @@
service-provider-from-dependencyservice-provider-from-dynamic-dependencyservice-provider-from-external-dependency
- loading-with-specific-isolation
From 32d0fd0860f5ec93f68eb8f9abe41240dd2d67c3 Mon Sep 17 00:00:00 2001
From: Emmanuel GALLOIS
Date: Fri, 15 May 2026 10:46:23 +0200
Subject: [PATCH 41/41] feat(QTDI-2134): fix pr comments
---
.../form/internal/validation/JavascriptRegex.java | 2 +-
.../sdk/component/runtime/manager/ComponentManager.java | 6 ++++--
.../runtime/manager/reflect/ReflectionService.java | 2 +-
.../talend/sdk/component/container/ContainerManager.java | 3 ++-
...namicDependenciesDataprepRunAnnotationServiceTest.java | 8 ++++++--
5 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/component-form/component-form-core/src/main/java/org/talend/sdk/component/form/internal/validation/JavascriptRegex.java b/component-form/component-form-core/src/main/java/org/talend/sdk/component/form/internal/validation/JavascriptRegex.java
index 66839b8b4750a..88bed07972620 100644
--- a/component-form/component-form-core/src/main/java/org/talend/sdk/component/form/internal/validation/JavascriptRegex.java
+++ b/component-form/component-form-core/src/main/java/org/talend/sdk/component/form/internal/validation/JavascriptRegex.java
@@ -50,7 +50,7 @@ public boolean test(final CharSequence text) {
final String script = "new RegExp(regex, indicators).test(text)";
final Context context = Context.enter();
try {
- // Rhino 1.9.0+: RegExp is registered via ServiceLoader.
+ // Rhino 1.9.0+ (QTDI-2292): RegExp is registered via ServiceLoader.
// The ServiceLoader uses Thread.currentThread().getContextClassLoader() by default,
// which may not find the service in an isolated classloader context.
// Explicitly register RegExpProxy using Rhino's own classloader as fallback.
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
index d2f80c4f1c8e7..356175e80a65a 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/ComponentManager.java
@@ -927,8 +927,10 @@ private void autoDiscoverPlugins0(final boolean callers, final boolean classpath
final URL marker = componentMarkers.nextElement();
File file = Files.toFile(marker);
if (file != null) {
- if (file.getName().equals("dependencies.txt") && file.getParentFile() != null
- && file.getParentFile().getName().equals("TALEND-INF")) {
+ if (file.getName().equals("dependencies.txt")
+ && file.getParentFile() != null
+ && file.getParentFile().getName().equals("TALEND-INF")
+ && file.getParentFile().getParentFile() != null) {
file = file.getParentFile().getParentFile();
}
if (!hasPlugin(ContainerManager.buildAutoIdFromName(file.getName()))) {
diff --git a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/reflect/ReflectionService.java b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/reflect/ReflectionService.java
index cbc46f55ad124..881d96a1c27c1 100644
--- a/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/reflect/ReflectionService.java
+++ b/component-runtime-manager/src/main/java/org/talend/sdk/component/runtime/manager/reflect/ReflectionService.java
@@ -858,7 +858,7 @@ public boolean test(final CharSequence text) {
final String script = "new RegExp(regex, indicators).test(text)";
final Context context = Context.enter();
try {
- // Rhino 1.9.0+: RegExp is registered via ServiceLoader.
+ // Rhino 1.9.0+ (QTDI-2292): RegExp is registered via ServiceLoader.
// The ServiceLoader uses Thread.currentThread().getContextClassLoader() by default,
// which may not find the service in an isolated classloader context.
// Explicitly register RegExpProxy using Rhino's own classloader as fallback.
diff --git a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
index d137831baaef8..28cfa33b87ef0 100644
--- a/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
+++ b/container/container-core/src/main/java/org/talend/sdk/component/container/ContainerManager.java
@@ -54,6 +54,7 @@
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.function.Predicate;
+import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -487,7 +488,7 @@ private void readRuntimeClasspath() {
* read or doesn't contain a Class-Path entry
*/
public List getClasspathFromJar(final Path jar) {
- try (final java.util.jar.JarFile jarFile = new java.util.jar.JarFile(jar.toFile())) {
+ try (final JarFile jarFile = new JarFile(jar.toFile())) {
final java.util.jar.Manifest manifest = jarFile.getManifest();
if (manifest != null) {
final String cp = manifest.getMainAttributes().getValue("Class-Path");
diff --git a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/service/DynamicDependenciesDataprepRunAnnotationServiceTest.java b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/service/DynamicDependenciesDataprepRunAnnotationServiceTest.java
index 710bfb9b58441..3967b19d39d11 100644
--- a/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/service/DynamicDependenciesDataprepRunAnnotationServiceTest.java
+++ b/sample-parent/sample-features/loading-analysis/loading-dependencies-with-dataprepRunAnnotation/src/test/java/org/talend/sdk/component/sample/feature/loadinganalysis/withDataprepRunAnnotation/service/DynamicDependenciesDataprepRunAnnotationServiceTest.java
@@ -15,7 +15,9 @@
*/
package org.talend.sdk.component.sample.feature.loadinganalysis.withDataprepRunAnnotation.service;
-import java.util.ArrayList;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;
@@ -57,6 +59,8 @@ protected DynamicDependenciesDataprepRunAnnotationService getService() {
@Test
void getDynamicDependenciesTest() {
List dynamicDependencies = this.dynamicDependenciesServiceService.getDynamicDependencies(buildConfig());
- List expectedDynamicDependencies = new ArrayList<>();
+ List expectedDynamicDependencies = Arrays.asList("org.apache.commons:commons-numbers-primes:1.2",
+ "org.apache.maven.resolver:maven-resolver-api:2.0.14");
+ assertEquals(expectedDynamicDependencies, dynamicDependencies);
}
}
\ No newline at end of file