CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-testcontainers--jdbc

Testcontainers JDBC driver that provides lightweight, throwaway database instances for testing

Overview
Eval results
Files

container-providers.mddocs/

Container Providers

The JdbcDatabaseContainerProvider system uses the Service Provider Interface (SPI) pattern to create database-specific container implementations based on JDBC URL database types.

Capabilities

Provider Base Class

Abstract base class for database container providers that integrate with the JDBC driver's discovery mechanism.

/**
 * Base class for classes that can provide a JDBC container
 * Discovered via ServiceLoader mechanism
 */
public abstract class JdbcDatabaseContainerProvider {
}

Database Type Support

Method to determine if a provider can handle a specific database type.

/**
 * Test if the specified database type is supported by this provider
 * Should match the base image name from JDBC URL
 * @param databaseType database type extracted from JDBC URL (e.g., "mysql", "postgresql")
 * @return true if provider can handle this database type, false otherwise
 */
public abstract boolean supports(String databaseType);

Usage Example:

public class MySQLContainerProvider extends JdbcDatabaseContainerProvider {
    @Override
    public boolean supports(String databaseType) {
        return "mysql".equals(databaseType);
    }
}

Container Instance Creation

Methods for creating container instances with different configurations.

/**
 * Create new container instance with default tag
 * Subclasses should override to provide stable default instead of "latest"
 * @return new JdbcDatabaseContainer instance
 */
public JdbcDatabaseContainer newInstance();

/**
 * Create new container instance with specified image tag
 * @param tag Docker image tag to use
 * @return new JdbcDatabaseContainer instance
 */
public abstract JdbcDatabaseContainer newInstance(String tag);

/**
 * Create new container instance using ConnectionUrl information
 * Automatically extracts image tag and reusability settings from URL
 * @param url parsed ConnectionUrl with configuration
 * @return configured JdbcDatabaseContainer instance
 */
public JdbcDatabaseContainer newInstance(ConnectionUrl url);

Implementation Example:

public class PostgreSQLContainerProvider extends JdbcDatabaseContainerProvider {
    @Override
    public boolean supports(String databaseType) {
        return "postgresql".equals(databaseType);
    }
    
    @Override
    public JdbcDatabaseContainer newInstance() {
        return newInstance("13"); // Use stable default instead of "latest"
    }
    
    @Override
    public JdbcDatabaseContainer newInstance(String tag) {
        return new PostgreSQLContainer<>("postgres:" + tag);
    }
}

Helper Method for URL-based Creation

Protected helper method for creating instances from connection URLs with standard parameter mapping.

/**
 * Helper method to create container instance from ConnectionUrl
 * Handles common parameter extraction and container configuration
 * @param connectionUrl parsed connection URL
 * @param userParamName query parameter name for username (e.g., "user")
 * @param pwdParamName query parameter name for password (e.g., "password")
 * @return configured JdbcDatabaseContainer instance
 * @throws NullPointerException if connectionUrl is null
 */
protected JdbcDatabaseContainer newInstanceFromConnectionUrl(
    ConnectionUrl connectionUrl,
    String userParamName,
    String pwdParamName
);

Usage in Provider Implementation:

public class MySQLContainerProvider extends JdbcDatabaseContainerProvider {
    @Override
    public JdbcDatabaseContainer newInstance(ConnectionUrl connectionUrl) {
        // Use helper method with MySQL-specific parameter names
        return newInstanceFromConnectionUrl(connectionUrl, "user", "password");
    }
}

Service Provider Interface (SPI) Integration

ServiceLoader Discovery

The JDBC driver discovers providers using Java's ServiceLoader mechanism:

  1. Provider implementations must extend JdbcDatabaseContainerProvider
  2. Provider classes must be listed in META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider
  3. At runtime, ServiceLoader loads all available providers
  4. Driver queries each provider with supports() method to find matches

Provider Registration

To register a custom provider, create a file in your JAR:

File: src/main/resources/META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider

Content:

com.example.CustomDatabaseContainerProvider
com.example.AnotherDatabaseContainerProvider

Custom Provider Implementation

Example of a complete custom provider:

package com.example;

import org.testcontainers.containers.JdbcDatabaseContainer;
import org.testcontainers.containers.JdbcDatabaseContainerProvider;
import org.testcontainers.jdbc.ConnectionUrl;

public class CustomDatabaseContainerProvider extends JdbcDatabaseContainerProvider {
    
    @Override
    public boolean supports(String databaseType) {
        return "customdb".equals(databaseType);
    }
    
    @Override
    public JdbcDatabaseContainer newInstance() {
        return newInstance("1.0"); // Stable default version
    }
    
    @Override
    public JdbcDatabaseContainer newInstance(String tag) {
        return new CustomDatabaseContainer("customdb:" + tag);
    }
    
    @Override
    public JdbcDatabaseContainer newInstance(ConnectionUrl url) {
        final JdbcDatabaseContainer container;
        
        if (url.getImageTag().isPresent()) {
            container = newInstance(url.getImageTag().get());
        } else {
            container = newInstance();
        }
        
        // Configure reusability from URL
        container.withReuse(url.isReusable());
        
        // Extract database name, username, password from URL parameters  
        String dbName = url.getDatabaseName().orElse("defaultdb");
        String user = url.getQueryParameters().getOrDefault("user", "test");
        String password = url.getQueryParameters().getOrDefault("password", "test");
        
        return container
            .withDatabaseName(dbName)
            .withUsername(user)
            .withPassword(password);
    }
}

Built-in Providers

Testcontainers includes providers for common databases:

MySQL Provider

  • Database Type: mysql
  • Default Image: mysql:8.0
  • Parameters: user, password

PostgreSQL Provider

  • Database Type: postgresql
  • Default Image: postgres:13
  • Parameters: user, password

Oracle Provider

  • Database Type: oracle
  • Special URL Format: Supports Oracle thin client URL format
  • Parameters: user, password

SQL Server Provider

  • Database Type: sqlserver
  • Default Image: mcr.microsoft.com/mssql/server
  • Parameters: user, password

Provider Selection Process

When the JDBC driver encounters a jdbc:tc: URL:

  1. URL Parsing: Extract database type from URL (e.g., mysql from jdbc:tc:mysql:8.0://...)
  2. Provider Discovery: Use ServiceLoader to find all available providers
  3. Provider Matching: Call supports(databaseType) on each provider until match found
  4. Container Creation: Use matching provider to create container instance
  5. Configuration: Apply URL parameters and container-specific settings
  6. Error Handling: If no provider supports the database type, throw UnsupportedOperationException

Provider Best Practices

Stable Default Versions

Always override newInstance() to provide a stable default version instead of "latest":

@Override
public JdbcDatabaseContainer newInstance() {
    // Good: stable version
    return newInstance("13.7");
    
    // Avoid: unpredictable "latest" 
    // return newInstance("latest");
}

Parameter Handling

Use the helper method newInstanceFromConnectionUrl() for consistent parameter extraction:

@Override  
public JdbcDatabaseContainer newInstance(ConnectionUrl url) {
    return newInstanceFromConnectionUrl(url, "user", "password");
}

Image Tag Validation

Validate image tags when possible to prevent runtime errors:

@Override
public JdbcDatabaseContainer newInstance(String tag) {
    if (tag == null || tag.trim().isEmpty()) {
        throw new IllegalArgumentException("Image tag cannot be null or empty");
    }
    return new MySQLContainer<>("mysql:" + tag);
}

Resource Management

Ensure containers are properly configured for resource cleanup:

@Override
public JdbcDatabaseContainer newInstance(String tag) {
    return new MySQLContainer<>("mysql:" + tag)
        .withReuse(false)  // Explicit cleanup unless URL specifies reuse
        .withStartupTimeout(Duration.ofMinutes(2));
}

Install with Tessl CLI

npx tessl i tessl/maven-org-testcontainers--jdbc

docs

container-providers.md

database-containers.md

index.md

jdbc-driver.md

url-configuration.md

tile.json