CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-dropwizard--dropwizard-util

Dropwizard utility classes for data sizes, durations, enums, generics, resources, exceptions, JAR locations, and direct execution services.

Pending
Overview
Eval results
Files

resource-exception.mddocs/

Resource and Exception Utilities

Utilities for resource loading with context class loader fallback and exception chain analysis tools.

Resources Class

The Resources utility class provides helper methods to work with resources using appropriate class loaders.

Resource Loading

public static URL getResource(String resourceName);

Returns a URL pointing to the specified resource using intelligent class loader selection.

Parameters:

  • resourceName - The name of the resource to locate

Returns: The URL of the resource

Throws:

  • IllegalArgumentException - If the resource is not found

Class Loader Selection:

  1. Context Class Loader: Uses Thread.currentThread().getContextClassLoader() when available
  2. Fallback: Uses Resources.class.getClassLoader() if context class loader is null

This approach works correctly in various environments including app servers where different threads may have different class loaders.

Usage Examples

Basic Resource Loading

import io.dropwizard.util.Resources;
import java.net.URL;
import java.io.InputStream;

// Load a resource from the classpath
URL configUrl = Resources.getResource("config/application.yml");
URL templateUrl = Resources.getResource("templates/email-template.html");
URL imageUrl = Resources.getResource("static/images/logo.png");

// Convert to InputStream for reading
try (InputStream configStream = configUrl.openStream()) {
    // Read configuration file
    byte[] configBytes = configStream.readAllBytes();
    String configContent = new String(configBytes);
}

Configuration File Loading

public class ConfigurationLoader {
    public Properties loadProperties(String resourceName) {
        try {
            URL resourceUrl = Resources.getResource(resourceName);
            Properties props = new Properties();
            try (InputStream input = resourceUrl.openStream()) {
                props.load(input);
            }
            return props;
        } catch (IllegalArgumentException e) {
            throw new RuntimeException("Configuration file not found: " + resourceName, e);
        } catch (IOException e) {
            throw new RuntimeException("Failed to load configuration: " + resourceName, e);
        }
    }
}

// Usage
ConfigurationLoader loader = new ConfigurationLoader();
Properties appProps = loader.loadProperties("application.properties");
Properties dbProps = loader.loadProperties("database.properties");

Template and Asset Loading

public class TemplateService {
    public String loadTemplate(String templateName) {
        try {
            URL templateUrl = Resources.getResource("templates/" + templateName);
            try (InputStream input = templateUrl.openStream()) {
                return new String(input.readAllBytes(), StandardCharsets.UTF_8);
            }
        } catch (IllegalArgumentException e) {
            throw new RuntimeException("Template not found: " + templateName, e);
        } catch (IOException e) {
            throw new RuntimeException("Failed to read template: " + templateName, e);
        }
    }
}

// Usage
TemplateService templateService = new TemplateService();
String emailTemplate = templateService.loadTemplate("email-notification.html");
String reportTemplate = templateService.loadTemplate("monthly-report.html");

Web Application Context

// In servlet or web application contexts where context class loader
// is set appropriately for resource discovery
public class WebResourceLoader {
    public byte[] loadWebAsset(String assetPath) {
        try {
            // Resources.getResource will use the context class loader
            // which is typically set correctly in web applications
            URL assetUrl = Resources.getResource("static/" + assetPath);
            try (InputStream input = assetUrl.openStream()) {
                return input.readAllBytes();
            }
        } catch (IllegalArgumentException e) {
            throw new RuntimeException("Web asset not found: " + assetPath, e);
        } catch (IOException e) {
            throw new RuntimeException("Failed to load web asset: " + assetPath, e);
        }
    }
}

Throwables Class

The Throwables utility class provides helper methods to work with exception objects and exception chains.

Exception Chain Search

public static Optional<Throwable> findThrowableInChain(
    Predicate<Throwable> condition, 
    Throwable t
);

Search an exception chain for an exception matching a given condition.

Parameters:

  • condition - The condition predicate to match against each exception in the chain
  • t - The head of the exception chain (can be null)

Returns: An Optional containing the first matching exception in the chain, or empty if no match found

Search Behavior:

  • Starts from the head exception and traverses the chain using getCause()
  • Prevents infinite loops by tracking visited exceptions
  • Returns the first exception that matches the condition
  • Returns empty Optional if no match is found or if the input throwable is null

Usage Examples

Find Specific Exception Types

import io.dropwizard.util.Throwables;
import java.util.Optional;

// Example exception chain
Exception rootCause = new SQLException("Connection failed");
Exception cause = new RuntimeException("Database error", rootCause);
Exception topLevel = new ServiceException("Service unavailable", cause);

// Find SQLException in the chain
Optional<Throwable> sqlEx = Throwables.findThrowableInChain(
    ex -> ex instanceof SQLException,
    topLevel
);

if (sqlEx.isPresent()) {
    SQLException sql = (SQLException) sqlEx.get();
    System.out.println("Found SQL error: " + sql.getMessage());
}

// Find by exception message
Optional<Throwable> connectionError = Throwables.findThrowableInChain(
    ex -> ex.getMessage() != null && ex.getMessage().contains("Connection"),
    topLevel
);

Database Exception Analysis

public class DatabaseService {
    public void handleDatabaseOperation() {
        try {
            performDatabaseOperation();
        } catch (Exception e) {
            analyzeDatabaseException(e);
            throw e;
        }
    }
    
    private void analyzeDatabaseException(Exception e) {
        // Look for specific database errors
        Optional<Throwable> sqlEx = Throwables.findThrowableInChain(
            ex -> ex instanceof SQLException,
            e
        );
        
        if (sqlEx.isPresent()) {
            SQLException sql = (SQLException) sqlEx.get();
            logDatabaseError(sql.getErrorCode(), sql.getSQLState(), sql.getMessage());
        }
        
        // Look for connection-related errors
        Optional<Throwable> connectionEx = Throwables.findThrowableInChain(
            ex -> ex.getMessage() != null && 
                  (ex.getMessage().contains("connection") || 
                   ex.getMessage().contains("Connection")),
            e
        );
        
        if (connectionEx.isPresent()) {
            alertConnectionIssue(connectionEx.get().getMessage());
        }
    }
}

Retry Logic Based on Exception Analysis

public class RetryableService {
    public void performWithRetry() {
        int maxRetries = 3;
        int attempt = 0;
        
        while (attempt < maxRetries) {
            try {
                performOperation();
                return; // Success
            } catch (Exception e) {
                if (shouldRetry(e)) {
                    attempt++;
                    if (attempt >= maxRetries) {
                        throw new RuntimeException("Max retries exceeded", e);
                    }
                    try {
                        Thread.sleep(1000 * attempt); // Exponential backoff
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        throw new RuntimeException("Interrupted during retry", ie);
                    }
                } else {
                    throw e; // Don't retry
                }
            }
        }
    }
    
    private boolean shouldRetry(Exception e) {
        // Retry on temporary network issues
        Optional<Throwable> networkError = Throwables.findThrowableInChain(
            ex -> ex instanceof SocketTimeoutException || 
                  ex instanceof ConnectException ||
                  (ex.getMessage() != null && ex.getMessage().contains("timeout")),
            e
        );
        
        if (networkError.isPresent()) {
            return true;
        }
        
        // Don't retry on authentication/authorization issues
        Optional<Throwable> authError = Throwables.findThrowableInChain(
            ex -> ex instanceof SecurityException ||
                  (ex.getMessage() != null && 
                   (ex.getMessage().contains("authentication") ||
                    ex.getMessage().contains("authorization"))),
            e
        );
        
        return authError.isEmpty(); // Retry only if no auth error found
    }
}

Exception Logging and Monitoring

public class ExceptionAnalyzer {
    private static final Logger logger = LoggerFactory.getLogger(ExceptionAnalyzer.class);
    
    public void analyzeAndLog(Exception e, String operation) {
        // Log the top-level exception
        logger.error("Operation failed: {}", operation, e);
        
        // Find and log specific error types with additional context
        findAndLogSpecificErrors(e);
        
        // Extract metrics for monitoring
        extractMetricsFromException(e, operation);
    }
    
    private void findAndLogSpecificErrors(Exception e) {
        // Look for timeout issues
        Optional<Throwable> timeout = Throwables.findThrowableInChain(
            ex -> ex instanceof TimeoutException ||
                  (ex.getMessage() != null && ex.getMessage().contains("timeout")),
            e
        );
        timeout.ifPresent(ex -> logger.warn("Timeout detected: {}", ex.getMessage()));
        
        // Look for resource issues
        Optional<Throwable> resource = Throwables.findThrowableInChain(
            ex -> ex instanceof OutOfMemoryError ||
                  ex instanceof IOException,
            e
        );
        resource.ifPresent(ex -> logger.error("Resource issue: {}", ex.getMessage()));
        
        // Look for configuration issues
        Optional<Throwable> config = Throwables.findThrowableInChain(
            ex -> ex instanceof IllegalArgumentException ||
                  ex instanceof IllegalStateException,
            e
        );
        config.ifPresent(ex -> logger.warn("Configuration issue: {}", ex.getMessage()));
    }
    
    private void extractMetricsFromException(Exception e, String operation) {
        // Count different types of errors for monitoring dashboards
        Throwables.findThrowableInChain(ex -> ex instanceof SQLException, e)
            .ifPresent(ex -> incrementMetric("database.errors", operation));
            
        Throwables.findThrowableInChain(ex -> ex instanceof SocketTimeoutException, e)
            .ifPresent(ex -> incrementMetric("network.timeouts", operation));
            
        Throwables.findThrowableInChain(ex -> ex instanceof SecurityException, e)
            .ifPresent(ex -> incrementMetric("security.errors", operation));
    }
}

Error Handling

Resources Error Handling

try {
    URL resource = Resources.getResource("missing-file.txt");
} catch (IllegalArgumentException e) {
    // Resource not found
    logger.warn("Resource not found: {}", e.getMessage());
    // Provide fallback or default behavior
}

Throwables Error Handling

// findThrowableInChain handles null input gracefully
Exception nullException = null;
Optional<Throwable> result = Throwables.findThrowableInChain(
    ex -> ex instanceof IOException,
    nullException
);
// result will be Optional.empty(), no exception thrown

// Handles circular reference detection automatically
Exception circular1 = new RuntimeException("Error 1");
Exception circular2 = new RuntimeException("Error 2", circular1);
// Don't do this in real code, but if it happens, the method handles it
// circular1.initCause(circular2); // Would create circular reference

Optional<Throwable> result2 = Throwables.findThrowableInChain(
    ex -> ex.getMessage().contains("Error"),
    circular1
);
// Method prevents infinite loops by tracking visited exceptions

Integration Patterns

Configuration Loading with Fallbacks

public class ConfigurationManager {
    public Properties loadConfiguration(String primaryResource, String fallbackResource) {
        Properties props = new Properties();
        
        // Try primary resource first
        try {
            URL primaryUrl = Resources.getResource(primaryResource);
            try (InputStream input = primaryUrl.openStream()) {
                props.load(input);
                return props;
            }
        } catch (IllegalArgumentException e) {
            logger.info("Primary config not found: {}, trying fallback", primaryResource);
        } catch (IOException e) {
            logger.warn("Failed to load primary config: {}", primaryResource, e);
        }
        
        // Fallback to secondary resource
        try {
            URL fallbackUrl = Resources.getResource(fallbackResource);
            try (InputStream input = fallbackUrl.openStream()) {
                props.load(input);
                return props;
            }
        } catch (Exception e) {
            throw new RuntimeException("Cannot load configuration from either primary or fallback resource", e);
        }
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-io-dropwizard--dropwizard-util

docs

data-size.md

duration.md

enum-generics.md

index.md

jar-executor.md

resource-exception.md

tile.json