diff --git a/README.md b/README.md index 1456ff8ff0..9c01d7567e 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,9 @@ or [github discussions](https://github.com/ebean-orm/ebean/discussions) ## Documentation Goto [https://ebean.io/docs/](https://ebean.io/docs/) +## Guides +Step-by-step guides for common tasks: [docs/guides/](docs/guides/README.md) + ## Maven central [Maven central - g:io.ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.ebean%22%20) diff --git a/docs/guides/README.md b/docs/guides/README.md new file mode 100644 index 0000000000..4b03e77180 --- /dev/null +++ b/docs/guides/README.md @@ -0,0 +1,13 @@ +# Guides + +Step-by-step guides written as instructions for AI agents and developers. + +## Adding Ebean ORM with PostgreSQL to an existing Maven project + +A two-part guide covering everything needed to wire Ebean + PostgreSQL into an +existing Maven project. Complete the steps in order. + +| Step | Guide | Description | +|------|-------|-------------| +| 1 | [Maven POM setup](add-ebean-postgres-maven-pom.md) | Add Ebean dependencies, the enhancement plugin, and the querybean-generator annotation processor to `pom.xml` | +| 2 | [Database configuration](add-ebean-postgres-database-config.md) | Configure the Ebean `Database` bean using `DataSourceBuilder` and `DatabaseConfig` with Avaje Inject | diff --git a/docs/guides/add-ebean-postgres-database-config.md b/docs/guides/add-ebean-postgres-database-config.md new file mode 100644 index 0000000000..50eac3fe85 --- /dev/null +++ b/docs/guides/add-ebean-postgres-database-config.md @@ -0,0 +1,211 @@ +# Guide: Add Ebean ORM (PostgreSQL) to an Existing Maven Project — Step 2: Database Configuration + +## Purpose + +This guide provides step-by-step instructions for configuring an Ebean `Database` bean +using **Avaje Inject** (`@Factory` / `@Bean`), backed by a PostgreSQL datasource built +with Ebean's `DataSourceBuilder`. Follow every step in order. This is Step 2 of 2. + +--- + +## Prerequisites + +- **Step 1 complete**: `pom.xml` already includes `ebean-postgres`, `ebean-maven-plugin`, + and `querybean-generator` (see `add-ebean-postgres-maven-pom.md`) +- **Avaje Inject** is on the classpath (e.g. `io.avaje:avaje-inject`) +- A configuration source is available at runtime (e.g. `avaje-config` reading + `application.yml` or environment variables) +- The following configuration keys are resolvable at runtime (adapt names to your project): + | Key | Description | + |-----|-------------| + | `db_url` | JDBC URL for the master/write connection | + | `db_user` | Database username | + | `db_pass` | Database password | + | `db_master_min_connections` | Minimum pool size (default: 1) | + | `db_master_max_connections` | Maximum pool size (default: 200) | + +--- + +## Step 1 — Locate or create the `@Factory` class + +Look for an existing Avaje Inject `@Factory`-annotated class in the project +(often named `AppConfig`, `DatabaseConfig`, or similar). If one exists, add the new +`@Bean` method to it. If none exists, create one: + +```java +package com.example.configuration; + +import io.avaje.inject.Bean; +import io.avaje.inject.Factory; + +@Factory +class DatabaseConfig { + // beans will be added in the steps below +} +``` + +--- + +## Step 2 — Add the `Database` bean method (minimal — master datasource only) + +Add the following `@Bean` method to the `@Factory` class. This creates an Ebean +`Database` backed by a single master (read-write) PostgreSQL datasource. + +```java +import io.ebean.Database; +import io.ebean.config.DatabaseConfig; +import io.ebean.datasource.DataSourceBuilder; + +@Bean +Database database() { + var dataSource = DataSourceBuilder.create() + .url(/* resolve from config, e.g.: */ Config.get("db_url")) + .username(Config.get("db_user")) + .password(Config.get("db_pass")) + .driver("org.postgresql.Driver") + .schema("myschema") // set to your target schema + .applicationName("my-app") // visible in pg_stat_activity + .minConnections(Config.getInt("db_master_min_connections", 1)) + .maxConnections(Config.getInt("db_master_max_connections", 200)); + + return new DatabaseConfig() + .name("db") // logical name for this Database instance + .dataSourceBuilder(dataSource) + .build(); +} +``` + +### Field guidance + +| Field | Notes | +|-------|-------| +| `url` | Full JDBC URL, e.g. `jdbc:postgresql://host:5432/dbname` | +| `schema` | The Postgres schema Ebean should use (omit if using `public`) | +| `applicationName` | Shown in `pg_stat_activity.application_name`; helps with DB-side diagnostics | +| `name("db")` | Logical Ebean database name; relevant if multiple Database instances exist | + +--- + +## Step 3 — Inject configuration via a constructor or config helper (recommended) + +Rather than calling `Config.get(...)` inline, inject a typed config helper or the +Avaje `Configuration` bean if one is available. This makes the factory testable and +keeps the wiring explicit. For example: + +```java +@Bean +Database database(Configuration config) { + String url = config.get("db_url"); + String user = config.get("db_user"); + String pass = config.get("db_pass"); + int min = config.getInt("db_master_min_connections", 1); + int max = config.getInt("db_master_max_connections", 200); + + var dataSource = DataSourceBuilder.create() + .url(url) + .username(user) + .password(pass) + .driver("org.postgresql.Driver") + .schema("myschema") + .applicationName("my-app") + .minConnections(min) + .maxConnections(max); + + return new DatabaseConfig() + .name("db") + .dataSourceBuilder(dataSource) + .skipDataSourceCheck(true) + .build(); +} +``` + +If the project has a dedicated config-wrapper class (a `@Component` that reads config +keys), accept it as a parameter instead of `Configuration`. + +--- + +## Step 4 (Optional) — Add a read-only datasource + +For production services that have a separate read-replica, add a second +`DataSourceBuilder` for read-only queries and wire it via +`readOnlyDataSourceBuilder(...)`. The read-only datasource: + +- Uses `readOnly(true)` and `autoCommit(true)` (Ebean routes read queries there automatically) +- Typically has a higher max connection count than the master +- Benefits from a prepared-statement cache (`pstmtCacheSize`) + +```java +@Bean +Database database(Configuration config) { + String masterUrl = config.get("db_url"); + String readOnlyUrl = config.get("db_url_readonly"); + String user = config.get("db_user"); + String pass = config.get("db_pass"); + + var masterDataSource = buildDataSource(user, pass) + .url(masterUrl) + .minConnections(config.getInt("db_master_min_connections", 1)) + .maxConnections(config.getInt("db_master_max_connections", 50)); + + var readOnlyDataSource = buildDataSource(user, pass) + .url(readOnlyUrl) + .readOnly(true) + .autoCommit(true) + .pstmtCacheSize(250) // cache up to 250 prepared statements per connection + .maxInactiveTimeSecs(600) // close idle connections after 10 minutes + .minConnections(config.getInt("db_readonly_min_connections", 2)) + .initialConnections(config.getInt("db_readonly_initial_connections", 10)) + .maxConnections(config.getInt("db_readonly_max_connections", 200)); + + return new DatabaseConfig() + .name("db") + .dataSourceBuilder(masterDataSource) + .readOnlyDataSourceBuilder(readOnlyDataSource) + .build(); +} + +private static DataSourceBuilder buildDataSource(String user, String pass) { + return DataSourceBuilder.create() + .username(user) + .password(pass) + .driver("org.postgresql.Driver") + .schema("myschema") + .applicationName("my-app") + .addProperty("prepareThreshold", "2"); // PostgreSQL: server-side prepared statements +} +``` + +### Additional configuration keys for the read-only datasource + +| Key | Description | Default | +|-----|-------------|---------| +| `db_url_readonly` | JDBC URL for the read replica | — | +| `db_readonly_min_connections` | Minimum pool size | 2 | +| `db_readonly_initial_connections` | Initial pool size at startup | same as min | +| `db_readonly_max_connections` | Maximum pool size | 20 | + +--- + +## Verification + +1. Start the application (or run `mvn test -pl `). +2. Look for log output similar to: + + ``` + INFO o.a.datasource.pool.ConnectionPool - DataSourcePool [db] autoCommit[false] min[1] max[5] + INFO io.ebean.internal.DefaultContainer - DatabasePlatform name:db platform:postgres + ``` + +3. If you see `DataSourcePool` and `DatabasePlatform` log lines, Ebean is connected and + the database bean is wired correctly. + +--- + +## Troubleshooting + +| Symptom | Likely cause | Fix | +|---------|-------------|-----| +| `ClassNotFoundException: org.postgresql.Driver` | PostgreSQL JDBC driver missing | Add `org.postgresql:postgresql` dependency (see Step 1 guide) | +| `Cannot connect to database` at startup | DB unreachable but `skipDataSourceCheck` is `false` | Set `.skipDataSourceCheck(true)` | +| Ebean enhancement warnings in logs | `ebean-maven-plugin` not configured | Complete Step 1 guide | +| `NullPointerException` reading config key | Config key not defined | Add the key to `application.yml` or environment | diff --git a/docs/guides/add-ebean-postgres-maven-pom.md b/docs/guides/add-ebean-postgres-maven-pom.md new file mode 100644 index 0000000000..520db55c72 --- /dev/null +++ b/docs/guides/add-ebean-postgres-maven-pom.md @@ -0,0 +1,175 @@ +# Guide: Add Ebean ORM (PostgreSQL) to an Existing Maven Project — Step 1: POM Setup + +## Purpose + +This guide provides step-by-step instructions for modifying an existing Maven `pom.xml` +to add Ebean ORM with PostgreSQL support. Follow every step in order. This is Step 1 of 2. + +--- + +## Prerequisites + +- An existing Maven project (`pom.xml` already exists) +- Java 11 or higher +- The project does **not** yet include any Ebean dependencies + +--- + +## Step 1 — Define the Ebean version property + +Open the module's `pom.xml` (the one that will use Ebean directly, i.e. the module +containing the database configuration and entity classes). + +Inside the `` block, add the `ebean.version` property if it does not +already exist: + +```xml + + + 17.2.0 + +``` + +> If the project has a parent POM that already defines `ebean.version`, skip this step. + +--- + +## Step 2 — Add the PostgreSQL JDBC driver dependency + +Inside the `` block, add the PostgreSQL JDBC driver: + +```xml + + org.postgresql + postgresql + 42.7.8 + +``` + +> Check [Maven Central](https://central.sonatype.com/artifact/org.postgresql/postgresql) +> for the latest version. If the parent POM manages the PostgreSQL version, omit the +> `` tag. + +--- + +## Step 3 — Add the Ebean PostgreSQL platform dependency + +Inside the `` block, add the Ebean Postgres platform dependency: + +```xml + + io.ebean + ebean-postgres + ${ebean.version} + +``` + +This single artifact pulls in the Ebean core, the datasource connection pool +(`ebean-datasource`), and all Postgres-specific support. + +--- + +## Step 4 — Add the ebean-test dependency (test scope) + +`ebean-test` configures Ebean for tests and enables automatic Docker container management +for Postgres test instances: + +```xml + + + io.ebean + ebean-test + ${ebean.version} + test + +``` + +--- + +## Step 5 — Add the ebean-maven-plugin (bytecode enhancement) + +Ebean requires bytecode enhancement to provide dirty-checking and lazy-loading. +The `ebean-maven-plugin` performs this enhancement at build time. + +Inside the `` block, add: + +```xml + + io.ebean + ebean-maven-plugin + ${ebean.version} + true + +``` + +--- + +## Step 6 — Add the querybean-generator annotation processor + +The `querybean-generator` annotation processor generates type-safe query bean classes +at compile time. It must be registered as an `annotationProcessorPath` inside +`maven-compiler-plugin`. + +### Case A — No existing `maven-compiler-plugin` configuration + +Add the full plugin entry to ``: + +```xml + + org.apache.maven.plugins + maven-compiler-plugin + 3.15.0 + + + + io.ebean + querybean-generator + ${ebean.version} + + + + +``` + +### Case B — `maven-compiler-plugin` already exists with `` + +Locate the existing `` block inside the existing +`maven-compiler-plugin` entry and add the new `` inside it. Do **not** add a +second `` block or a second `` block. + +Example — if the existing block already has a path for, say, `avaje-nima-generator`: + +```xml + + + io.avaje + avaje-nima-generator + ${avaje-nima.version} + + + + io.ebean + querybean-generator + ${ebean.version} + + +``` + +--- + +## Verification + +Run the following to confirm the POM is valid and the project compiles: + +```bash +mvn compile -pl +``` + +Expected result: `BUILD SUCCESS` with no errors from Ebean or the annotation processor. + +--- + +## Next Step + +Proceed to **Step 2: Configure the Datasource and Ebean Database bean** +(`add-ebean-postgres-database-config.md`).