Jakarta Annotations defines a collection of annotations representing common semantic concepts that enable a declarative style of programming that applies across a variety of Java technologies.
—
Jakarta SQL Annotations provide declarative database DataSource configuration and JNDI registration. These annotations enable database setup without external configuration files, allowing developers to define DataSource properties directly in code.
Annotations for defining and configuring database connections with JNDI registration.
Defines a container DataSource to be registered with JNDI. Configures all DataSource properties including connection details, pool settings, and transaction behavior.
Important: DataSource properties should not be specified more than once. If the URL contains properties that are also specified using annotation elements, the precedence order is undefined and implementation-specific. If properties are specified in both the properties array and as annotation elements, the annotation element value takes precedence.
/**
* Defines a container DataSource for JNDI registration.
* Configures database connection and pooling properties.
*/
@Target(TYPE)
@Retention(RUNTIME)
@Repeatable(DataSourceDefinitions.class)
public @interface DataSourceDefinition {
/**
* JNDI name by which the data source will be registered (required).
*/
String name();
/**
* DataSource implementation class name (required).
* Must implement DataSource, XADataSource, or ConnectionPoolDataSource.
*/
String className();
/**
* Description of the data source.
*/
String description() default "";
/**
* JDBC URL for the database connection.
*/
String url() default "";
/**
* User name for database authentication.
*/
String user() default "";
/**
* Password for database authentication.
*/
String password() default "";
/**
* Database name on the server.
*/
String databaseName() default "";
/**
* Port number where database server is listening.
*/
int portNumber() default -1;
/**
* Database server name.
*/
String serverName() default "localhost";
/**
* Transaction isolation level.
* Values from Connection interface: TRANSACTION_READ_UNCOMMITTED,
* TRANSACTION_READ_COMMITTED, TRANSACTION_REPEATABLE_READ, TRANSACTION_SERIALIZABLE.
*/
int isolationLevel() default -1;
/**
* Whether connections participate in transactions.
*/
boolean transactional() default true;
/**
* Initial number of connections in the pool.
*/
int initialPoolSize() default -1;
/**
* Maximum number of concurrent connections in the pool.
*/
int maxPoolSize() default -1;
/**
* Minimum number of connections in the pool.
*/
int minPoolSize() default -1;
/**
* Maximum time (seconds) unused connection remains in pool.
*/
int maxIdleTime() default -1;
/**
* Total number of statements the connection pool should keep open.
*/
int maxStatements() default -1;
/**
* Vendor-specific properties in "propertyName=propertyValue" format.
*/
String[] properties() default {};
/**
* Maximum time (seconds) to wait while connecting to database.
*/
int loginTimeout() default 0;
}Usage Examples:
import jakarta.annotation.sql.DataSourceDefinition;
import java.sql.Connection;
// Basic MySQL DataSource
@DataSourceDefinition(
name = "java:global/MyAppDataSource",
className = "com.mysql.cj.jdbc.MysqlDataSource",
url = "jdbc:mysql://localhost:3306/myapp",
user = "appuser",
password = "secret123"
)
public class DatabaseConfig {
}
// Advanced PostgreSQL configuration with connection pooling
@DataSourceDefinition(
name = "java:app/PostgresDS",
className = "org.postgresql.ds.PGPoolingDataSource",
serverName = "db.example.com",
portNumber = 5432,
databaseName = "production",
user = "produser",
password = "prodpass",
description = "Production PostgreSQL database",
isolationLevel = Connection.TRANSACTION_READ_COMMITTED,
transactional = true,
initialPoolSize = 5,
maxPoolSize = 20,
minPoolSize = 2,
maxIdleTime = 300,
maxStatements = 100,
loginTimeout = 10,
properties = {
"ssl=true",
"sslmode=require",
"prepareThreshold=3"
}
)
public class ProductionDatabaseConfig {
}
// H2 in-memory database for testing
@DataSourceDefinition(
name = "java:comp/env/TestDB",
className = "org.h2.jdbcx.JdbcDataSource",
url = "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1",
user = "sa",
password = "",
description = "In-memory H2 database for testing"
)
public class TestConfiguration {
}
// Oracle with XA support
@DataSourceDefinition(
name = "java:global/OracleXADS",
className = "oracle.jdbc.xa.client.OracleXADataSource",
url = "jdbc:oracle:thin:@oracle.example.com:1521:ORCL",
user = "appuser",
password = "oraclepass",
transactional = true,
isolationLevel = Connection.TRANSACTION_SERIALIZABLE,
properties = {
"oracle.jdbc.implicitStatementCacheSize=20",
"oracle.jdbc.fanEnabled=false"
}
)
public class OracleConfig {
}Container annotation for multiple @DataSourceDefinition declarations. Allows defining multiple DataSources on a single class.
/**
* Container for multiple @DataSourceDefinition annotations.
* Allows multiple DataSource definitions on a single class.
*/
@Target(TYPE)
@Retention(RUNTIME)
public @interface DataSourceDefinitions {
/**
* Array of DataSourceDefinition annotations.
*/
DataSourceDefinition[] value();
}Usage Examples:
import jakarta.annotation.sql.DataSourceDefinitions;
import jakarta.annotation.sql.DataSourceDefinition;
// Multiple DataSources for microservice architecture
@DataSourceDefinitions({
@DataSourceDefinition(
name = "java:global/UserDB",
className = "com.mysql.cj.jdbc.MysqlDataSource",
url = "jdbc:mysql://userdb:3306/users",
user = "userservice",
password = "userpass",
description = "User management database"
),
@DataSourceDefinition(
name = "java:global/OrderDB",
className = "org.postgresql.ds.PGSimpleDataSource",
url = "jdbc:postgresql://orderdb:5432/orders",
user = "orderservice",
password = "orderpass",
description = "Order processing database"
),
@DataSourceDefinition(
name = "java:global/InventoryDB",
className = "com.mysql.cj.jdbc.MysqlDataSource",
url = "jdbc:mysql://inventorydb:3306/inventory",
user = "inventoryservice",
password = "invpass",
description = "Inventory tracking database"
)
})
public class MultiDatabaseApplication {
}
// Read/Write split configuration
@DataSourceDefinitions({
@DataSourceDefinition(
name = "java:comp/env/ReadOnlyDB",
className = "com.mysql.cj.jdbc.MysqlDataSource",
url = "jdbc:mysql://slave.db.example.com:3306/myapp",
user = "readonly",
password = "readpass",
description = "Read-only slave database",
maxPoolSize = 10,
properties = {"readOnly=true"}
),
@DataSourceDefinition(
name = "java:comp/env/ReadWriteDB",
className = "com.mysql.cj.jdbc.MysqlDataSource",
url = "jdbc:mysql://master.db.example.com:3306/myapp",
user = "readwrite",
password = "writepass",
description = "Read-write master database",
maxPoolSize = 5,
transactional = true
)
})
public class ReadWriteSplitConfig {
}
// Development vs Production configurations
@DataSourceDefinitions({
@DataSourceDefinition(
name = "java:global/DevDB",
className = "org.h2.jdbcx.JdbcDataSource",
url = "jdbc:h2:~/devdb",
user = "dev",
password = "dev",
description = "Development H2 database"
),
@DataSourceDefinition(
name = "java:global/ProdDB",
className = "org.postgresql.ds.PGPoolingDataSource",
serverName = "prod.db.company.com",
portNumber = 5432,
databaseName = "production",
user = "produser",
password = "prodpass",
description = "Production PostgreSQL database",
initialPoolSize = 10,
maxPoolSize = 50,
minPoolSize = 5
)
})
public class EnvironmentDatabaseConfig {
}import jakarta.annotation.Resource;
import jakarta.annotation.sql.DataSourceDefinition;
import javax.sql.DataSource;
@DataSourceDefinition(
name = "java:app/MyDS",
className = "com.mysql.cj.jdbc.MysqlDataSource",
url = "jdbc:mysql://localhost:3306/mydb",
user = "user",
password = "pass"
)
public class DatabaseService {
// Injecting the defined DataSource
@Resource(lookup = "java:app/MyDS")
private DataSource dataSource;
public List<User> getUsers() {
try (Connection conn = dataSource.getConnection();
PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users")) {
ResultSet rs = stmt.executeQuery();
List<User> users = new ArrayList<>();
while (rs.next()) {
users.add(mapToUser(rs));
}
return users;
} catch (SQLException e) {
throw new RuntimeException("Database error", e);
}
}
}// High-performance production setup
@DataSourceDefinition(
name = "java:global/HighPerformanceDB",
className = "com.zaxxer.hikari.HikariDataSource",
url = "jdbc:postgresql://db.example.com:5432/app",
user = "appuser",
password = "apppass",
initialPoolSize = 10, // Start with 10 connections
maxPoolSize = 50, // Max 50 concurrent connections
minPoolSize = 5, // Keep minimum 5 connections
maxIdleTime = 600, // 10 minutes idle timeout
maxStatements = 250, // Statement cache size
loginTimeout = 5, // 5 second connection timeout
properties = {
"maximumPoolSize=50",
"minimumIdle=5",
"connectionTimeout=5000",
"idleTimeout=600000",
"maxLifetime=1800000", // 30 minutes max connection lifetime
"leakDetectionThreshold=60000" // 1 minute leak detection
}
)
public class HighPerformanceConfig {
}@DataSourceDefinitions({
@DataSourceDefinition(
name = "java:global/TenantA_DB",
className = "com.mysql.cj.jdbc.MysqlDataSource",
url = "jdbc:mysql://tenant-a.db.example.com:3306/tenant_a",
user = "tenant_a_user",
password = "tenant_a_pass",
description = "Tenant A dedicated database"
),
@DataSourceDefinition(
name = "java:global/TenantB_DB",
className = "com.mysql.cj.jdbc.MysqlDataSource",
url = "jdbc:mysql://tenant-b.db.example.com:3306/tenant_b",
user = "tenant_b_user",
password = "tenant_b_pass",
description = "Tenant B dedicated database"
),
@DataSourceDefinition(
name = "java:global/SharedDB",
className = "com.mysql.cj.jdbc.MysqlDataSource",
url = "jdbc:mysql://shared.db.example.com:3306/shared",
user = "shared_user",
password = "shared_pass",
description = "Shared tenant database"
)
})
public class MultiTenantConfiguration {
}Install with Tessl CLI
npx tessl i tessl/maven-jakarta-annotation--jakarta-annotation-api