Class StaticAssetDetector

java.lang.Object
com.kingsrook.qqq.middleware.javalin.routeproviders.StaticAssetDetector

public class StaticAssetDetector extends Object
Utility class for detecting whether a request path represents a static asset versus a client-side SPA route. PROBLEM: When serving SPAs with deep linking support, we need to distinguish between: - 404s for missing static assets (should stay 404) - 404s for SPA client-side routes (should serve index.html) SOLUTION: Use heuristics based on file extensions and common path patterns to make an educated guess about whether a path is likely a static asset. LIMITATIONS invalid input: '&' CAVEATS: This class uses heuristics and cannot be 100% accurate because: 1. False Positives: SPA routes that look like assets (e.g., /learn/javascript.js) will be incorrectly identified as assets and return 404 instead of serving the SPA's index.html 2. False Negatives: Assets without standard extensions (e.g., /assets/logo) may be incorrectly identified as routes and serve index.html instead of 404 3. Framework-Specific: Some frameworks use non-standard asset paths that may not be recognized (e.g., Vite's /@vite/client) 4. Maintenance: New file formats and web standards require periodic updates CUSTOMIZATION: For cases where the default heuristics don't work, you can: - Add custom extensions: detector.withCustomExtensions(".myext") - Add custom path patterns: detector.withCustomPathPatterns("/my-assets/") - Provide custom logic: detector.withCustomDetector(path -> ...) METRICS: Tracks detection statistics via incrementCounter() for monitoring and debugging. Override incrementCounter() to integrate with your metrics system. THREAD SAFETY: This class is thread-safe for read operations after configuration. Configuration methods should only be called during initialization.
Since:
0.31.0
  • Constructor Details

    • StaticAssetDetector

      public StaticAssetDetector()
      Constructor - creates detector with default configuration
  • Method Details

    • isStaticAsset

      public boolean isStaticAsset(String path)
      Detect if a request path represents a static asset. Uses the following logic in order: 1. Custom detectors (if any configured) 2. File extension matching (e.g., .js, .css, .png) 3. Path pattern matching (e.g., /assets/, /static/)
      Parameters:
      path - The request path to check (e.g., "/admin/assets/main.js")
      Returns:
      true if the path appears to be a static asset, false otherwise
    • incrementCounter

      protected void incrementCounter(String counterName)
      Increment a counter for metrics tracking. Override this method to integrate with your metrics system (e.g., Prometheus, Micrometer, custom metrics). Default implementation does nothing.
      Parameters:
      counterName - Name of the counter to increment Values: "custom_detector", "extension_match", "path_pattern_match", "not_asset"
    • withCustomExtensions

      public StaticAssetDetector withCustomExtensions(String... customExtensions)
      Fluent setter: Add custom file extensions to detect as static assets
      Parameters:
      customExtensions - Extensions to add (e.g., ".myext", ".custom")
      Returns:
      this for method chaining
    • withCustomPathPatterns

      public StaticAssetDetector withCustomPathPatterns(String... patterns)
      Fluent setter: Add custom path patterns to detect as static assets
      Parameters:
      patterns - Path patterns to add (e.g., "/my-assets/", "/resources/")
      Returns:
      this for method chaining
    • withCustomDetector

      public StaticAssetDetector withCustomDetector(Predicate<String> detector)
      Fluent setter: Add custom detection logic Custom detectors are evaluated FIRST, before extension and path matching. If any custom detector returns true, the path is considered a static asset.
      Parameters:
      detector - Predicate that returns true if path is a static asset
      Returns:
      this for method chaining
    • withName

      public StaticAssetDetector withName(String name)
      Fluent setter: Set a name for this detector (used in logging)
      Parameters:
      name - Name for this detector instance
      Returns:
      this for method chaining
    • getExtensions

      public Set<String> getExtensions()
      Get the set of file extensions this detector recognizes
      Returns:
      Unmodifiable set of extensions (includes defaults + custom)
    • getPathPatterns

      public List<String> getPathPatterns()
      Get the list of path patterns this detector recognizes
      Returns:
      Unmodifiable list of patterns (includes defaults + custom)