Class ChildFirstURLClassLoader

All Implemented Interfaces:
Closeable, AutoCloseable

public class ChildFirstURLClassLoader extends URLClassLoader
A URLClassLoader that resolves Spring Boot's own bootstrap classes (org.springframework.boot.loader.*: Launcher, JarLauncher, Archive, LaunchedClassLoader, the "nested:"/"jar:" URL protocol handlers, etc.) from its own URLs before delegating to its parent. Every other class name uses standard parent-first delegation. Used to bootstrap in-process Spring Boot fat-jar services (RESTV3, MCP): the JVM's system classpath also carries spring-boot-loader.jar (required for the JDK to resolve Spring Boot's "nested:" URL protocol), so with plain parent-first delegation, Spring Boot's own Launcher/JarLauncher/Archive classes get defined by the system classloader instead of by this loader - orphaning any extra jars (e.g. lib/optional/security) added only to this loader's own URLs, since Launcher.createClassLoader() parents its internal app classloader on "this.getClass().getClassLoader()", i.e. whichever loader actually defined the Launcher class.

The child-first override is deliberately scoped to just that one package: this loader's own URLs also carry jars (e.g. lib/optional/security's spring-security-*) that RESTV3's fat jar bundles its own copies of internally. Applying child-first broadly would let this loader's copy of those classes win over the fat jar's, and since the two copies aren't necessarily the same build, a class defined by this loader can fail to link against a supertype that only exists in the fat jar's own nested dependencies (observed as NoClassDefFoundError for org.springframework.beans.factory.xml.NamespaceHandler when spring-security-config was resolved from lib/optional/security instead of the fat jar's bundled spring-beans). Standard parent-first delegation is what actually resolves lib/optional/security-only classes (e.g. a customer's own LDAP UserDetailsContextMapper) correctly: they simply aren't present on the parent chain above this loader, so delegation falls through to this loader's own URLs regardless.