CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springdoc--springdoc-openapi

Java library that automates OpenAPI 3 documentation generation for Spring Boot applications with seamless Swagger UI integration

Pending
Overview
Eval results
Files

resource-processing.mddocs/

Resource Processing

Resource transformation and resolution for Swagger UI assets, including dynamic configuration injection and web jar handling. This system ensures that Swagger UI resources are properly located, resolved, and configured at runtime.

Capabilities

SwaggerIndexPageTransformer

Resource transformer that dynamically injects configuration into Swagger UI initializer JavaScript.

/**
 * Resource transformer for Swagger UI index page and initializer JavaScript
 * Dynamically injects runtime configuration into Swagger UI assets
 */
public class SwaggerIndexPageTransformer extends AbstractSwaggerIndexTransformer 
    implements SwaggerIndexTransformer {
    
    /**
     * Constructor for index page transformer
     * @param swaggerUiConfig Swagger UI configuration properties
     * @param swaggerUiOAuthProperties OAuth configuration properties
     * @param swaggerWelcomeCommon Common welcome functionality for URL building
     * @param objectMapperProvider JSON object mapper for configuration serialization
     */
    public SwaggerIndexPageTransformer(SwaggerUiConfigProperties swaggerUiConfig, 
        SwaggerUiOAuthProperties swaggerUiOAuthProperties, SwaggerWelcomeCommon swaggerWelcomeCommon, 
        ObjectMapperProvider objectMapperProvider);

    /**
     * Transforms resources to inject dynamic configuration
     * Identifies Swagger UI initializer JavaScript and injects runtime configuration
     * @param request HTTP request for context-specific configuration
     * @param resource Original resource to transform
     * @param transformerChain Resource transformer chain for further processing
     * @return Transformed resource with injected configuration or original resource
     * @throws IOException if resource transformation fails
     */
    @Override
    public Resource transform(HttpServletRequest request, Resource resource, 
        ResourceTransformerChain transformerChain) throws IOException;
}

SwaggerIndexTransformer

Interface marker for Swagger UI resource transformation.

/**
 * Interface for Swagger UI resource transformation
 * Extends Spring's ResourceTransformer for integration with resource handling
 */
public interface SwaggerIndexTransformer extends ResourceTransformer {
    // Marker interface - inherits all methods from ResourceTransformer
}

SwaggerResourceResolver

Resource resolver that handles Swagger UI web jar asset resolution with version management.

/**
 * Resource resolver for Swagger UI web jar assets
 * Extends Spring's LiteWebJarsResourceResolver with Swagger-specific functionality
 */
public class SwaggerResourceResolver extends LiteWebJarsResourceResolver {
    
    /**
     * Constructor for Swagger resource resolver
     * @param swaggerUiConfigProperties Configuration properties containing version information
     */
    public SwaggerResourceResolver(SwaggerUiConfigProperties swaggerUiConfigProperties);

    /**
     * Finds web jar resource paths for Swagger UI assets
     * First attempts standard web jar resolution, then falls back to Swagger-specific resolution
     * @param pathStr Resource path to resolve
     * @return Resolved resource path or null if not found
     */
    @Nullable
    @Override
    protected String findWebJarResourcePath(String pathStr);
}

Resource Transformation Process

Transformation Detection

The transformer identifies Swagger UI initializer JavaScript using pattern matching:

/**
 * Resource pattern matching for transformation
 */
interface TransformationDetection {
    /**
     * Pattern used to identify Swagger UI initializer JavaScript
     */
    String SWAGGER_INITIALIZER_PATTERN = "**/swagger-ui/**/swagger-initializer.js";
    
    /**
     * AntPathMatcher used for pattern matching against resource URLs
     */
    AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher();
    
    /**
     * Checks if resource matches transformation pattern
     * @param resourceUrl URL of the resource to check
     * @return true if resource should be transformed
     */
    boolean shouldTransform(String resourceUrl);
}

Configuration Injection Process

When a matching resource is found, the transformer:

  1. Builds Configuration: Creates SwaggerUiConfigParameters from request context
  2. Updates URLs: Calls SwaggerWelcomeCommon.buildFromCurrentContextPath()
  3. Applies Transformations: Injects configuration into JavaScript content
  4. Returns Resource: Wraps transformed content in TransformedResource
/**
 * Configuration injection steps
 */
interface ConfigurationInjection {
    /**
     * Create configuration parameters from current request
     */
    SwaggerUiConfigParameters createConfigParameters(HttpServletRequest request);
    
    /**
     * Build context-specific URLs and paths
     */
    void buildContextPaths(SwaggerUiConfigParameters parameters, HttpServletRequest request);
    
    /**
     * Apply default transformations to resource content
     */
    String applyTransformations(SwaggerUiConfigParameters parameters, InputStream resourceStream);
    
    /**
     * Wrap transformed content in Spring Resource
     */
    TransformedResource wrapTransformedContent(Resource originalResource, byte[] transformedContent);
}

Resource Resolution Process

Web Jar Resolution

The resolver follows a two-tier resolution strategy:

/**
 * Web jar resolution strategy
 */
interface WebJarResolution {
    /**
     * Primary resolution using Spring's LiteWebJarsResourceResolver
     * Handles standard web jar path resolution and version matching
     */
    String primaryResolution(String pathStr);
    
    /**
     * Fallback resolution using Swagger-specific utilities
     * Uses SwaggerResourceResolverUtils.findSwaggerResourcePath()
     */
    String fallbackResolution(String pathStr, String swaggerUiVersion);
    
    /**
     * Combined resolution logic
     */
    @Nullable
    default String resolveResourcePath(String pathStr, String version) {
        String primaryResult = primaryResolution(pathStr);
        return primaryResult != null ? primaryResult : fallbackResolution(pathStr, version);
    }
}

Version Management

Resource resolution uses version information from configuration:

/**  
 * Version-aware resource resolution
 */
interface VersionManagement {
    /**
     * Gets Swagger UI version from configuration properties
     */
    String getSwaggerUiVersion(SwaggerUiConfigProperties properties);
    
    /**
     * Resolves versioned web jar paths
     */
    String resolveVersionedPath(String basePath, String version);
    
    /**
     * Handles version conflicts and fallbacks
     */
    String handleVersionConflict(String requestedVersion, String availableVersion);
}

Usage Examples

Basic Resource Processing

Resource processing happens automatically during resource serving:

// When browser requests: /swagger-ui/swagger-initializer.js
// 1. SwaggerResourceResolver locates the web jar asset
// 2. SwaggerIndexPageTransformer injects runtime configuration
// 3. Transformed resource served to browser with current API URLs

Custom Transformation

Extend transformation for custom requirements:

@Component
public class CustomSwaggerTransformer implements SwaggerIndexTransformer {
    
    @Override
    public Resource transform(HttpServletRequest request, Resource resource, 
        ResourceTransformerChain transformerChain) throws IOException {
        
        if (isCustomResource(resource)) {
            String customContent = addCustomConfiguration(resource);
            return new TransformedResource(resource, customContent.getBytes(StandardCharsets.UTF_8));
        }
        
        return resource;
    }
    
    private boolean isCustomResource(Resource resource) {
        try {
            return resource.getURL().toString().contains("custom-swagger");
        } catch (IOException e) {
            return false;
        }
    }
    
    private String addCustomConfiguration(Resource resource) throws IOException {
        String originalContent = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
        return originalContent.replace("// CUSTOM_CONFIG_PLACEHOLDER", 
            "window.customSwaggerConfig = { theme: 'dark', layout: 'sidebar' };");
    }
}

Custom Resource Resolution

Override resource resolution for specific requirements:

@Component
@Primary
public class CustomSwaggerResourceResolver extends SwaggerResourceResolver {
    
    public CustomSwaggerResourceResolver(SwaggerUiConfigProperties properties) {
        super(properties);
    }
    
    @Override
    protected String findWebJarResourcePath(String pathStr) {
        // Try custom resolution first
        String customPath = findCustomSwaggerResource(pathStr);
        if (customPath != null) {
            return customPath;
        }
        
        // Fall back to standard resolution
        return super.findWebJarResourcePath(pathStr);
    }
    
    private String findCustomSwaggerResource(String pathStr) {
        if (pathStr.contains("swagger-ui-custom")) {
            return "META-INF/resources/custom-swagger/" + pathStr;
        }
        return null;
    }
}

Configuration-Specific Transformations

Apply different transformations based on configuration:

@Configuration
public class ConditionalTransformationConfig {
    
    @Bean
    @ConditionalOnProperty("app.swagger.custom-branding")
    public SwaggerIndexTransformer brandedTransformer() {
        return new BrandedSwaggerTransformer();
    }
    
    @Bean
    @ConditionalOnProperty("app.swagger.development-mode")
    public SwaggerIndexTransformer developmentTransformer() {
        return new DevelopmentSwaggerTransformer();
    }
}

class BrandedSwaggerTransformer implements SwaggerIndexTransformer {
    @Override
    public Resource transform(HttpServletRequest request, Resource resource, 
        ResourceTransformerChain transformerChain) throws IOException {
        
        if (isSwaggerInitializer(resource)) {
            String content = injectBrandingConfiguration(resource);
            return new TransformedResource(resource, content.getBytes(StandardCharsets.UTF_8));
        }
        
        return resource;
    }
    
    private String injectBrandingConfiguration(Resource resource) throws IOException {
        String content = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
        return content.replace(
            "// Configuration placeholder",
            "window.ui = SwaggerUIBundle({ " +
            "customCss: '.swagger-ui .topbar { background-color: #1976d2; }', " +
            "customSiteTitle: 'Custom API Documentation' })"
        );
    }
}

Performance Optimization

Caching Strategy

Resource processing can be optimized through strategic caching:

/**
 * Caching considerations for resource processing
 */
interface CachingStrategy {
    /**
     * Static assets (CSS, images) can be cached longer
     */
    void cacheStaticAssets(int cacheSeconds);
    
    /**
     * Dynamic content (initializer JS) should not be cached
     */
    void disableCacheForDynamicContent();
    
    /**
     * Version-based cache invalidation
     */
    void versionBasedCacheInvalidation(String version);
    
    /**
     * Production vs development caching strategies
     */
    void environmentSpecificCaching(String environment);
}

Resource Processing Pipeline

// Optimized processing pipeline:
// 1. Quick pattern check (avoid expensive operations for non-matching resources)
// 2. Lazy configuration building (only when transformation needed)
// 3. Efficient string replacement (avoid full parsing when possible)
// 4. Resource wrapping optimization (minimal object creation)

Memory Management

/**
 * Memory optimization for resource processing
 */
interface MemoryOptimization {
    /**
     * Stream-based processing to avoid loading large resources into memory
     */
    void streamBasedProcessing();
    
    /**
     * Resource pooling for frequently accessed assets
     */
    void resourcePooling();
    
    /**
     * Lazy initialization of expensive components
     */
    void lazyInitialization();
    
    /**
     * Proper resource cleanup after transformation
     */
    void resourceCleanup();
}

Error Handling

Resource processing includes robust error handling:

/**
 * Error handling strategies for resource processing
 */
interface ErrorHandling {
    /**
     * Handle missing web jar resources
     */
    void handleMissingResource(String resourcePath);
    
    /**
     * Handle transformation failures
     */
    void handleTransformationError(Exception error, Resource resource);
    
    /**
     * Handle version conflicts
     */
    void handleVersionConflict(String requestedVersion, String availableVersion);
    
    /**
     * Graceful degradation for configuration errors
     */
    void gracefulDegradation(ConfigurationException error);
}

Common error scenarios and handling:

// 1. Missing Swagger UI web jar → Fall back to CDN or show error page
// 2. Transformation failure → Serve original resource without configuration
// 3. Configuration building error → Use default configuration
// 4. Resource access error → Return 404 with helpful error message

Install with Tessl CLI

npx tessl i tessl/maven-org-springdoc--springdoc-openapi

docs

auto-configuration.md

controllers.md

core-api-generation.md

index.md

resource-processing.md

web-configuration.md

tile.json