@@ -223,10 +223,69 @@ private String extractBase64FromJson(String json) throws IOException {
223223 return json .substring (start , end );
224224 }
225225
226+ /**
227+ * Creates a new Builder for constructing RestApiClassSource instances.
228+ *
229+ * @return A new Builder with default configuration
230+ */
226231 public static Builder builder () {
227232 return new Builder ();
228233 }
229234
235+ /**
236+ * Builder for constructing RestApiClassSource instances with fluent API.
237+ *
238+ * <p>Configures a custom REST API for class loading with flexible URL templates,
239+ * headers, query parameters, authentication, and response formats.</p>
240+ *
241+ * <p><b>Basic Example (Binary Response):</b></p>
242+ * <pre>{@code
243+ * RestApiClassSource source = RestApiClassSource.builder()
244+ * .baseUrl("https://classes.example.com/api/v1")
245+ * .classPathTemplate("classes/{fullclass}")
246+ * .auth(AuthConfig.bearer("token123"))
247+ * .build();
248+ * }</pre>
249+ *
250+ * <p><b>Advanced Example (JSON Response with Base64):</b></p>
251+ * <pre>{@code
252+ * RestApiClassSource source = RestApiClassSource.builder()
253+ * .baseUrl("https://api.example.com")
254+ * .classPathTemplate("classes/{package}/{class}")
255+ * .addHeader("X-API-Version", "2.0")
256+ * .addQueryParam("env", "production")
257+ * .auth(AuthConfig.apiKey("X-API-Key", "secret123"))
258+ * .responseFormat(ResponseFormat.BASE64_JSON_FIELD)
259+ * .connectTimeout(15000)
260+ * .readTimeout(60000)
261+ * .enableCanLoadCheck(true) // Enable HEAD requests
262+ * .build();
263+ * }</pre>
264+ *
265+ * <p><b>URL Template Variables:</b></p>
266+ * <ul>
267+ * <li>{@code {package}} - Package path (e.g., "com/example")</li>
268+ * <li>{@code {class}} - Simple class name (e.g., "MyClass")</li>
269+ * <li>{@code {fullclass}} - Full class path (e.g., "com/example/MyClass")</li>
270+ * </ul>
271+ *
272+ * <p><b>Response Formats:</b></p>
273+ * <ul>
274+ * <li><b>BINARY</b> - Raw class bytes in response body (default)</li>
275+ * <li><b>BASE64_JSON_FIELD</b> - JSON with base64-encoded class in "data" or "content" field</li>
276+ * <li><b>DIRECT</b> - Same as BINARY</li>
277+ * </ul>
278+ *
279+ * <p><b>Defaults:</b></p>
280+ * <ul>
281+ * <li>classPathTemplate: "{package}/{class}.class"</li>
282+ * <li>responseFormat: BINARY</li>
283+ * <li>connectTimeout: 10000ms (10 seconds)</li>
284+ * <li>readTimeout: 30000ms (30 seconds)</li>
285+ * <li>enableCanLoadCheck: false (skip HEAD requests for performance)</li>
286+ * <li>auth: none</li>
287+ * </ul>
288+ */
230289 public static class Builder {
231290 private String baseUrl ;
232291 private String classPathTemplate ;
@@ -238,40 +297,138 @@ public static class Builder {
238297 private int readTimeout = DEFAULT_READ_TIMEOUT ;
239298 private boolean enableCanLoadCheck = false ; // Default: skip expensive checks
240299
300+ /**
301+ * Sets the base URL of the REST API.
302+ *
303+ * <p>This is prepended to the classPathTemplate.</p>
304+ *
305+ * <p>Examples:</p>
306+ * <ul>
307+ * <li>"https://classes.example.com/api/v1"</li>
308+ * <li>"http://localhost:8080/classes"</li>
309+ * <li>"https://cdn.example.com"</li>
310+ * </ul>
311+ *
312+ * @param baseUrl Base URL (automatically adds trailing slash if missing)
313+ * @return this builder
314+ * @throws NullPointerException if baseUrl is null
315+ */
241316 public Builder baseUrl (String baseUrl ) {
242317 this .baseUrl = Objects .requireNonNull (baseUrl , "baseUrl cannot be null" );
243318 return this ;
244319 }
245320
321+ /**
322+ * Sets the URL template for class paths.
323+ *
324+ * <p>Uses placeholders: {package}, {class}, {fullclass}</p>
325+ *
326+ * <p>Examples:</p>
327+ * <ul>
328+ * <li>"{package}/{class}.class" (default)</li>
329+ * <li>"classes/{fullclass}" → "classes/com/example/MyClass"</li>
330+ * <li>"v2/{package}/{class}.bin"</li>
331+ * </ul>
332+ *
333+ * @param template URL template (null to use default)
334+ * @return this builder
335+ */
246336 public Builder classPathTemplate (String template ) {
247337 this .classPathTemplate = template ;
248338 return this ;
249339 }
250340
341+ /**
342+ * Adds a custom HTTP header to all requests.
343+ *
344+ * <p>Useful for API versioning, custom authentication, or metadata.</p>
345+ *
346+ * <p>Example:</p>
347+ * <pre>{@code
348+ * builder.addHeader("X-API-Version", "2.0")
349+ * .addHeader("Accept", "application/octet-stream")
350+ * }</pre>
351+ *
352+ * @param name Header name
353+ * @param value Header value
354+ * @return this builder
355+ * @throws NullPointerException if name or value is null
356+ */
251357 public Builder addHeader (String name , String value ) {
252358 Objects .requireNonNull (name , "header name cannot be null" );
253359 Objects .requireNonNull (value , "header value cannot be null" );
254360 this .headers .put (name , value );
255361 return this ;
256362 }
257363
364+ /**
365+ * Adds a query parameter to all requests.
366+ *
367+ * <p>Example:</p>
368+ * <pre>{@code
369+ * builder.addQueryParam("env", "production")
370+ * .addQueryParam("version", "1.0")
371+ * // URLs become: baseUrl/path?env=production&version=1.0
372+ * }</pre>
373+ *
374+ * @param name Parameter name
375+ * @param value Parameter value
376+ * @return this builder
377+ * @throws NullPointerException if name or value is null
378+ */
258379 public Builder addQueryParam (String name , String value ) {
259380 Objects .requireNonNull (name , "query param name cannot be null" );
260381 Objects .requireNonNull (value , "query param value cannot be null" );
261382 this .queryParams .put (name , value );
262383 return this ;
263384 }
264385
386+ /**
387+ * Sets authentication configuration.
388+ *
389+ * <p>Supported types:</p>
390+ * <ul>
391+ * <li>AuthConfig.none() - No authentication (default)</li>
392+ * <li>AuthConfig.basic(username, password) - HTTP Basic</li>
393+ * <li>AuthConfig.bearer(token) - Bearer token</li>
394+ * <li>AuthConfig.apiKey(headerName, key) - API key header</li>
395+ * </ul>
396+ *
397+ * @param authConfig Authentication configuration (null = no auth)
398+ * @return this builder
399+ */
265400 public Builder auth (AuthConfig authConfig ) {
266401 this .authConfig = authConfig ;
267402 return this ;
268403 }
269404
405+ /**
406+ * Sets the response format.
407+ *
408+ * <p>Determines how to parse the API response:</p>
409+ * <ul>
410+ * <li><b>BINARY</b> - Raw bytes (default, most efficient)</li>
411+ * <li><b>BASE64_JSON_FIELD</b> - JSON with base64 in "data" or "content" field</li>
412+ * <li><b>DIRECT</b> - Same as BINARY</li>
413+ * </ul>
414+ *
415+ * @param format Response format (null = BINARY)
416+ * @return this builder
417+ */
270418 public Builder responseFormat (ResponseFormat format ) {
271419 this .responseFormat = format ;
272420 return this ;
273421 }
274422
423+ /**
424+ * Sets the connection timeout.
425+ *
426+ * <p>Prevents hanging indefinitely when connecting to the API.</p>
427+ *
428+ * @param timeoutMs Timeout in milliseconds (default: 10000ms = 10 seconds, 0 = infinite)
429+ * @return this builder
430+ * @throws IllegalArgumentException if timeoutMs < 0
431+ */
275432 public Builder connectTimeout (int timeoutMs ) {
276433 if (timeoutMs < 0 ) {
277434 throw new IllegalArgumentException ("connectTimeout must be >= 0" );
@@ -280,6 +437,15 @@ public Builder connectTimeout(int timeoutMs) {
280437 return this ;
281438 }
282439
440+ /**
441+ * Sets the read timeout.
442+ *
443+ * <p>Prevents hanging indefinitely when reading response data.</p>
444+ *
445+ * @param timeoutMs Timeout in milliseconds (default: 30000ms = 30 seconds, 0 = infinite)
446+ * @return this builder
447+ * @throws IllegalArgumentException if timeoutMs < 0
448+ */
283449 public Builder readTimeout (int timeoutMs ) {
284450 if (timeoutMs < 0 ) {
285451 throw new IllegalArgumentException ("readTimeout must be >= 0" );
@@ -288,11 +454,30 @@ public Builder readTimeout(int timeoutMs) {
288454 return this ;
289455 }
290456
457+ /**
458+ * Enables or disables canLoad() HEAD requests.
459+ *
460+ * <p><b>Performance Impact:</b> When enabled, canLoad() makes a HEAD request
461+ * to check if a class exists, which <b>doubles network traffic</b>. When disabled
462+ * (default), canLoad() always returns true and loadClassData() fails if the
463+ * class doesn't exist.</p>
464+ *
465+ * <p><b>Recommendation:</b> Leave disabled (false) unless your application
466+ * specifically needs to check class existence before loading.</p>
467+ *
468+ * @param enable true to enable HEAD requests, false to skip (default: false)
469+ * @return this builder
470+ */
291471 public Builder enableCanLoadCheck (boolean enable ) {
292472 this .enableCanLoadCheck = enable ;
293473 return this ;
294474 }
295475
476+ /**
477+ * Builds the RestApiClassSource with configured settings.
478+ *
479+ * @return A new RestApiClassSource instance
480+ */
296481 public RestApiClassSource build () {
297482 return new RestApiClassSource (baseUrl , classPathTemplate , headers ,
298483 queryParams , authConfig , responseFormat ,
0 commit comments