or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

container-providers.mddatabase-containers.mdindex.mdjdbc-driver.mdurl-configuration.md

container-providers.mddocs/

0

# Container Providers

1

2

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

3

4

## Capabilities

5

6

### Provider Base Class

7

8

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

9

10

```java { .api }

11

/**

12

* Base class for classes that can provide a JDBC container

13

* Discovered via ServiceLoader mechanism

14

*/

15

public abstract class JdbcDatabaseContainerProvider {

16

}

17

```

18

19

### Database Type Support

20

21

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

22

23

```java { .api }

24

/**

25

* Test if the specified database type is supported by this provider

26

* Should match the base image name from JDBC URL

27

* @param databaseType database type extracted from JDBC URL (e.g., "mysql", "postgresql")

28

* @return true if provider can handle this database type, false otherwise

29

*/

30

public abstract boolean supports(String databaseType);

31

```

32

33

**Usage Example:**

34

```java

35

public class MySQLContainerProvider extends JdbcDatabaseContainerProvider {

36

@Override

37

public boolean supports(String databaseType) {

38

return "mysql".equals(databaseType);

39

}

40

}

41

```

42

43

### Container Instance Creation

44

45

Methods for creating container instances with different configurations.

46

47

```java { .api }

48

/**

49

* Create new container instance with default tag

50

* Subclasses should override to provide stable default instead of "latest"

51

* @return new JdbcDatabaseContainer instance

52

*/

53

public JdbcDatabaseContainer newInstance();

54

55

/**

56

* Create new container instance with specified image tag

57

* @param tag Docker image tag to use

58

* @return new JdbcDatabaseContainer instance

59

*/

60

public abstract JdbcDatabaseContainer newInstance(String tag);

61

62

/**

63

* Create new container instance using ConnectionUrl information

64

* Automatically extracts image tag and reusability settings from URL

65

* @param url parsed ConnectionUrl with configuration

66

* @return configured JdbcDatabaseContainer instance

67

*/

68

public JdbcDatabaseContainer newInstance(ConnectionUrl url);

69

```

70

71

**Implementation Example:**

72

```java

73

public class PostgreSQLContainerProvider extends JdbcDatabaseContainerProvider {

74

@Override

75

public boolean supports(String databaseType) {

76

return "postgresql".equals(databaseType);

77

}

78

79

@Override

80

public JdbcDatabaseContainer newInstance() {

81

return newInstance("13"); // Use stable default instead of "latest"

82

}

83

84

@Override

85

public JdbcDatabaseContainer newInstance(String tag) {

86

return new PostgreSQLContainer<>("postgres:" + tag);

87

}

88

}

89

```

90

91

### Helper Method for URL-based Creation

92

93

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

94

95

```java { .api }

96

/**

97

* Helper method to create container instance from ConnectionUrl

98

* Handles common parameter extraction and container configuration

99

* @param connectionUrl parsed connection URL

100

* @param userParamName query parameter name for username (e.g., "user")

101

* @param pwdParamName query parameter name for password (e.g., "password")

102

* @return configured JdbcDatabaseContainer instance

103

* @throws NullPointerException if connectionUrl is null

104

*/

105

protected JdbcDatabaseContainer newInstanceFromConnectionUrl(

106

ConnectionUrl connectionUrl,

107

String userParamName,

108

String pwdParamName

109

);

110

```

111

112

**Usage in Provider Implementation:**

113

```java

114

public class MySQLContainerProvider extends JdbcDatabaseContainerProvider {

115

@Override

116

public JdbcDatabaseContainer newInstance(ConnectionUrl connectionUrl) {

117

// Use helper method with MySQL-specific parameter names

118

return newInstanceFromConnectionUrl(connectionUrl, "user", "password");

119

}

120

}

121

```

122

123

## Service Provider Interface (SPI) Integration

124

125

### ServiceLoader Discovery

126

127

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

128

129

1. Provider implementations must extend `JdbcDatabaseContainerProvider`

130

2. Provider classes must be listed in `META-INF/services/org.testcontainers.containers.JdbcDatabaseContainerProvider`

131

3. At runtime, ServiceLoader loads all available providers

132

4. Driver queries each provider with `supports()` method to find matches

133

134

### Provider Registration

135

136

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

137

138

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

139

140

**Content**:

141

```

142

com.example.CustomDatabaseContainerProvider

143

com.example.AnotherDatabaseContainerProvider

144

```

145

146

### Custom Provider Implementation

147

148

Example of a complete custom provider:

149

150

```java

151

package com.example;

152

153

import org.testcontainers.containers.JdbcDatabaseContainer;

154

import org.testcontainers.containers.JdbcDatabaseContainerProvider;

155

import org.testcontainers.jdbc.ConnectionUrl;

156

157

public class CustomDatabaseContainerProvider extends JdbcDatabaseContainerProvider {

158

159

@Override

160

public boolean supports(String databaseType) {

161

return "customdb".equals(databaseType);

162

}

163

164

@Override

165

public JdbcDatabaseContainer newInstance() {

166

return newInstance("1.0"); // Stable default version

167

}

168

169

@Override

170

public JdbcDatabaseContainer newInstance(String tag) {

171

return new CustomDatabaseContainer("customdb:" + tag);

172

}

173

174

@Override

175

public JdbcDatabaseContainer newInstance(ConnectionUrl url) {

176

final JdbcDatabaseContainer container;

177

178

if (url.getImageTag().isPresent()) {

179

container = newInstance(url.getImageTag().get());

180

} else {

181

container = newInstance();

182

}

183

184

// Configure reusability from URL

185

container.withReuse(url.isReusable());

186

187

// Extract database name, username, password from URL parameters

188

String dbName = url.getDatabaseName().orElse("defaultdb");

189

String user = url.getQueryParameters().getOrDefault("user", "test");

190

String password = url.getQueryParameters().getOrDefault("password", "test");

191

192

return container

193

.withDatabaseName(dbName)

194

.withUsername(user)

195

.withPassword(password);

196

}

197

}

198

```

199

200

## Built-in Providers

201

202

Testcontainers includes providers for common databases:

203

204

### MySQL Provider

205

- **Database Type**: `mysql`

206

- **Default Image**: `mysql:8.0`

207

- **Parameters**: `user`, `password`

208

209

### PostgreSQL Provider

210

- **Database Type**: `postgresql`

211

- **Default Image**: `postgres:13`

212

- **Parameters**: `user`, `password`

213

214

### Oracle Provider

215

- **Database Type**: `oracle`

216

- **Special URL Format**: Supports Oracle thin client URL format

217

- **Parameters**: `user`, `password`

218

219

### SQL Server Provider

220

- **Database Type**: `sqlserver`

221

- **Default Image**: `mcr.microsoft.com/mssql/server`

222

- **Parameters**: `user`, `password`

223

224

## Provider Selection Process

225

226

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

227

228

1. **URL Parsing**: Extract database type from URL (e.g., `mysql` from `jdbc:tc:mysql:8.0://...`)

229

2. **Provider Discovery**: Use ServiceLoader to find all available providers

230

3. **Provider Matching**: Call `supports(databaseType)` on each provider until match found

231

4. **Container Creation**: Use matching provider to create container instance

232

5. **Configuration**: Apply URL parameters and container-specific settings

233

6. **Error Handling**: If no provider supports the database type, throw `UnsupportedOperationException`

234

235

## Provider Best Practices

236

237

### Stable Default Versions

238

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

239

240

```java

241

@Override

242

public JdbcDatabaseContainer newInstance() {

243

// Good: stable version

244

return newInstance("13.7");

245

246

// Avoid: unpredictable "latest"

247

// return newInstance("latest");

248

}

249

```

250

251

### Parameter Handling

252

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

253

254

```java

255

@Override

256

public JdbcDatabaseContainer newInstance(ConnectionUrl url) {

257

return newInstanceFromConnectionUrl(url, "user", "password");

258

}

259

```

260

261

### Image Tag Validation

262

Validate image tags when possible to prevent runtime errors:

263

264

```java

265

@Override

266

public JdbcDatabaseContainer newInstance(String tag) {

267

if (tag == null || tag.trim().isEmpty()) {

268

throw new IllegalArgumentException("Image tag cannot be null or empty");

269

}

270

return new MySQLContainer<>("mysql:" + tag);

271

}

272

```

273

274

### Resource Management

275

Ensure containers are properly configured for resource cleanup:

276

277

```java

278

@Override

279

public JdbcDatabaseContainer newInstance(String tag) {

280

return new MySQLContainer<>("mysql:" + tag)

281

.withReuse(false) // Explicit cleanup unless URL specifies reuse

282

.withStartupTimeout(Duration.ofMinutes(2));

283

}

284

```