Skip to content

Commit d8fa060

Browse files
Flossyclaude
andcommitted
docs: add comprehensive Javadoc to ApplicationClassLoader.Builder API
Enhanced ApplicationClassLoader.Builder with detailed documentation: Class-level: - Complete feature overview (sources, caching, delegation, listeners, verification) - Basic and advanced usage examples with real code - Default configuration values documented Method-level added Javadoc for: - parent() - Parent ClassLoader configuration - addClassSource() - Custom source addition with limits - addLocalSource() - Filesystem class loading - addRemoteSource() - HTTP/HTTPS class loading (with/without auth) - addRemoteJar() - Remote JAR file loading - addMavenCentral() - Maven Central artifact loading with examples - delegationStrategy() - Custom delegation - parentFirst() - Standard Java delegation - parentLast() - Class override capability with default prefixes - bytecodeVerifier() - Security validation with example - build() - Final construction All methods now have: - Clear descriptions - @param, @return, @throws tags - Usage examples where helpful - Behavior details and defaults Relates to #71 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent bb816ab commit d8fa060

1 file changed

Lines changed: 171 additions & 0 deletions

File tree

src/main/java/org/flossware/classloader/ApplicationClassLoader.java

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,10 +426,56 @@ public BytecodeVerifier getBytecodeVerifier() {
426426
return bytecodeVerifier;
427427
}
428428

429+
/**
430+
* Creates a new Builder for constructing ApplicationClassLoader instances.
431+
*
432+
* @return A new Builder with default configuration
433+
*/
429434
public static Builder builder() {
430435
return new Builder();
431436
}
432437

438+
/**
439+
* Builder for constructing ApplicationClassLoader instances with fluent API.
440+
*
441+
* <p>Supports configuration of:</p>
442+
* <ul>
443+
* <li>Multiple class sources (local, HTTP, cloud storage, databases, Maven, etc.)</li>
444+
* <li>Class caching (in-memory or filesystem-based)</li>
445+
* <li>Delegation strategy (parent-first, parent-last, custom)</li>
446+
* <li>Lifecycle listeners (logging, resource tracking, metrics)</li>
447+
* <li>Bytecode verification (checksum validation)</li>
448+
* </ul>
449+
*
450+
* <p><b>Basic Example:</b></p>
451+
* <pre>{@code
452+
* ApplicationClassLoader loader = ApplicationClassLoader.builder()
453+
* .addLocalSource("/path/to/classes")
454+
* .addRemoteSource("https://example.com/classes")
455+
* .addMavenCentral("com.example:my-lib:1.0")
456+
* .parentLast() // Load from sources before parent
457+
* .build();
458+
* }</pre>
459+
*
460+
* <p><b>Advanced Example with Caching and Listeners:</b></p>
461+
* <pre>{@code
462+
* ApplicationClassLoader loader = ApplicationClassLoader.builder()
463+
* .addRemoteJar("https://cdn.example.com/lib.jar")
464+
* .cache(new FileSystemCache(Paths.get("/tmp/class-cache")))
465+
* .addLoggingListener(true) // Verbose logging
466+
* .trackResources() // Track loaded resources
467+
* .bytecodeVerifier(new ChecksumValidator(checksumMap))
468+
* .build();
469+
* }</pre>
470+
*
471+
* <p><b>Defaults:</b></p>
472+
* <ul>
473+
* <li>parent: Thread.currentThread().getContextClassLoader()</li>
474+
* <li>delegation: ParentFirstDelegation (standard Java behavior)</li>
475+
* <li>cache: In-memory cache (if useCache=true)</li>
476+
* <li>bytecodeVerifier: null (no verification)</li>
477+
* </ul>
478+
*/
433479
public static class Builder {
434480
private static final int MAX_CLASS_SOURCES = 100;
435481

@@ -441,11 +487,29 @@ public static class Builder {
441487
private final List<ClassLoaderLifecycleListener> listeners = new ArrayList<>();
442488
private BytecodeVerifier bytecodeVerifier;
443489

490+
/**
491+
* Sets the parent ClassLoader for delegation.
492+
*
493+
* <p>If not set, defaults to {@code Thread.currentThread().getContextClassLoader()}.</p>
494+
*
495+
* @param parent The parent ClassLoader (null to use bootstrap classloader as parent)
496+
* @return this builder
497+
*/
444498
public Builder parent(ClassLoader parent) {
445499
this.parent = parent;
446500
return this;
447501
}
448502

503+
/**
504+
* Adds a custom ClassSource to the loading chain.
505+
*
506+
* <p>Sources are tried in the order they're added. Maximum 100 sources.</p>
507+
*
508+
* @param source The ClassSource to add
509+
* @return this builder
510+
* @throws NullPointerException if source is null
511+
* @throws IllegalStateException if MAX_CLASS_SOURCES (100) is exceeded
512+
*/
449513
public Builder addClassSource(ClassSource source) {
450514
Objects.requireNonNull(source, "source cannot be null");
451515
if (classSources.size() >= MAX_CLASS_SOURCES) {
@@ -456,18 +520,49 @@ public Builder addClassSource(ClassSource source) {
456520
return this;
457521
}
458522

523+
/**
524+
* Adds a local filesystem directory as a class source.
525+
*
526+
* <p>Classes are loaded from {@code path + "/" + className.replace('.', '/') + ".class"}</p>
527+
*
528+
* @param path Base directory path (e.g., "/opt/app/classes" or "target/classes")
529+
* @return this builder
530+
*/
459531
public Builder addLocalSource(String path) {
460532
return addClassSource(new LocalClassSource(path));
461533
}
462534

535+
/**
536+
* Adds an HTTP/HTTPS URL as a class source (no authentication).
537+
*
538+
* <p>Classes are loaded from {@code baseUrl + "/" + className.replace('.', '/') + ".class"}</p>
539+
*
540+
* @param baseUrl Base URL (e.g., "https://cdn.example.com/classes")
541+
* @return this builder
542+
*/
463543
public Builder addRemoteSource(String baseUrl) {
464544
return addClassSource(new RemoteClassSource(baseUrl));
465545
}
466546

547+
/**
548+
* Adds an HTTP/HTTPS URL as a class source with authentication.
549+
*
550+
* @param baseUrl Base URL
551+
* @param authConfig Authentication configuration (basic auth, bearer token, API key, etc.)
552+
* @return this builder
553+
*/
467554
public Builder addRemoteSource(String baseUrl, AuthConfig authConfig) {
468555
return addClassSource(new RemoteClassSource(baseUrl, authConfig));
469556
}
470557

558+
/**
559+
* Adds a remote JAR file as a class source (no authentication).
560+
*
561+
* <p>Downloads and caches the entire JAR, then loads classes from it.</p>
562+
*
563+
* @param jarUrl URL to JAR file (e.g., "https://cdn.example.com/lib-1.0.jar")
564+
* @return this builder
565+
*/
471566
public Builder addRemoteJar(String jarUrl) {
472567
return addClassSource(new JarRemoteClassSource(jarUrl));
473568
}
@@ -488,6 +583,22 @@ public Builder addNexusMavenSource(MavenNexusClassSource source) {
488583
return addClassSource(source);
489584
}
490585

586+
/**
587+
* Adds Maven Central as a class source for specified artifacts.
588+
*
589+
* <p>Coordinates format: {@code "groupId:artifactId:version"}</p>
590+
*
591+
* <p>Example:</p>
592+
* <pre>{@code
593+
* builder.addMavenCentral(
594+
* "com.google.guava:guava:32.1.0-jre",
595+
* "org.apache.commons:commons-lang3:3.12.0"
596+
* )
597+
* }</pre>
598+
*
599+
* @param artifactCoordinates Maven coordinates (groupId:artifactId:version)
600+
* @return this builder
601+
*/
491602
public Builder addMavenCentral(String... artifactCoordinates) {
492603
MavenRepositoryClassSource.Builder builder = MavenRepositoryClassSource.builder()
493604
.mavenCentral();
@@ -530,15 +641,53 @@ public Builder useCache(boolean useCache) {
530641
return this;
531642
}
532643

644+
/**
645+
* Sets a custom delegation strategy.
646+
*
647+
* <p>Determines whether to check parent ClassLoader before or after custom sources.</p>
648+
*
649+
* @param strategy The delegation strategy
650+
* @return this builder
651+
* @throws NullPointerException if strategy is null
652+
*/
533653
public Builder delegationStrategy(DelegationStrategy strategy) {
534654
this.delegationStrategy = Objects.requireNonNull(strategy, "delegationStrategy cannot be null");
535655
return this;
536656
}
537657

658+
/**
659+
* Uses parent-first delegation (standard Java ClassLoader behavior).
660+
*
661+
* <p>Checks parent ClassLoader first, then custom sources. This is the default.</p>
662+
*
663+
* @return this builder
664+
*/
538665
public Builder parentFirst() {
539666
return delegationStrategy(new ParentFirstDelegation());
540667
}
541668

669+
/**
670+
* Uses parent-last delegation (checks custom sources before parent).
671+
*
672+
* <p>Allows overriding classes from parent ClassLoader, except for specified prefixes
673+
* which are always loaded from parent (e.g., JDK classes).</p>
674+
*
675+
* <p>Default always-parent prefixes include:</p>
676+
* <ul>
677+
* <li>java. (Java platform classes)</li>
678+
* <li>javax. (Java extensions)</li>
679+
* <li>sun. (Sun/Oracle internal classes)</li>
680+
* <li>jdk. (JDK internal classes)</li>
681+
* </ul>
682+
*
683+
* <p>Example:</p>
684+
* <pre>{@code
685+
* builder.parentLast("com.example.core.") // Always load com.example.core.* from parent
686+
* }</pre>
687+
*
688+
* @param alwaysParentPrefixes Additional prefixes to always load from parent
689+
* @return this builder
690+
*/
542691
public Builder parentLast(String... alwaysParentPrefixes) {
543692
return delegationStrategy(new org.flossware.classloader.delegation.ParentLastDelegation(alwaysParentPrefixes));
544693
}
@@ -564,11 +713,33 @@ public Builder trackResources() {
564713
return addListener(new org.flossware.classloader.lifecycle.ResourceTrackingListener());
565714
}
566715

716+
/**
717+
* Sets a bytecode verifier for security validation.
718+
*
719+
* <p>Verifies loaded bytecode before defining classes (e.g., checksum validation).</p>
720+
*
721+
* <p>Example:</p>
722+
* <pre>{@code
723+
* Map<String, String> checksums = new HashMap<>();
724+
* checksums.put("com.example.MyClass", "sha256:abc123...");
725+
*
726+
* builder.bytecodeVerifier(new ChecksumValidator(checksums));
727+
* }</pre>
728+
*
729+
* @param verifier The bytecode verifier (null to disable verification)
730+
* @return this builder
731+
*/
567732
public Builder bytecodeVerifier(BytecodeVerifier verifier) {
568733
this.bytecodeVerifier = verifier;
569734
return this;
570735
}
571736

737+
/**
738+
* Builds the ApplicationClassLoader with configured settings.
739+
*
740+
* @return A new ApplicationClassLoader instance
741+
* @throws IllegalStateException if no class sources are configured
742+
*/
572743
public ApplicationClassLoader build() {
573744
if (classSources.isEmpty()) {
574745
throw new IllegalStateException("At least one class source must be configured");

0 commit comments

Comments
 (0)