Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/guides/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Step-by-step guides for common Ebean tasks (Maven setup, database config, query
Key guides (fetch and follow when performing the relevant task):
- Maven POM setup: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-maven-pom.md
- Database configuration: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-database-config.md
- Migrate to `Database.builder()`: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/migrating-to-database-builder.md
- Write queries with query beans: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/writing-ebean-query-beans.md
- Persisting and transactions: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/persisting-and-transactions-with-ebean.md
- Test container setup: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-test-container.md
Expand Down
8 changes: 8 additions & 0 deletions docs/guides/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ existing Maven project. Complete the steps in order.
| 2 | [Test container setup](add-ebean-postgres-test-container.md) | Start a PostgreSQL (or PostGIS) Docker container for tests using `@TestScope @Factory` with Avaje Inject; verify the test database works with `mvn verify` before adding production configuration |
| 3 | [Database configuration](add-ebean-postgres-database-config.md) | Configure the production Ebean `Database` bean using `DataSourceBuilder` and `DatabaseBuilder` with Avaje Inject |

## Migration & upgrades

| Guide | Description |
|-------|-------------|
| [Migrate to `Database.builder()`](migrating-to-database-builder.md) | Replace legacy `new DatabaseConfig()` and `DatabaseFactory.create(...)` code with `Database.builder()` and `DatabaseBuilder.build()`. Includes common rewrites, fluent builder equivalents, and manual-review cases for semi-automated upgrades |

## Entity beans

| Guide | Description |
Expand Down Expand Up @@ -133,6 +139,7 @@ tasks are at: https://github.com/ebean-orm/ebean/tree/HEAD/docs/guides/
Key guides (fetch and follow these when performing the relevant task):
- Maven POM setup: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-maven-pom.md
- Database configuration: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-database-config.md
- Migrate to `Database.builder()`: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/migrating-to-database-builder.md
- Write queries with query beans: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/writing-ebean-query-beans.md
- Immutable bean cache for read-only references: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/immutable-bean-cache.md
- Persisting and transactions: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/persisting-and-transactions-with-ebean.md
Expand All @@ -158,6 +165,7 @@ tasks are at: https://github.com/ebean-orm/ebean/tree/HEAD/docs/guides/
Key guides (fetch and follow these when performing the relevant task):
- Maven POM setup: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-maven-pom.md
- Database configuration: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-database-config.md
- Migrate to `Database.builder()`: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/migrating-to-database-builder.md
- Write queries with query beans: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/writing-ebean-query-beans.md
- Persisting and transactions: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/persisting-and-transactions-with-ebean.md
- Test container setup: https://raw.githubusercontent.com/ebean-orm/ebean/HEAD/docs/guides/add-ebean-postgres-test-container.md
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/add-ebean-postgres-database-config.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Guide: Add Ebean ORM (PostgreSQL) to an Existing Maven Project — Step 2: Database Configuration
# Guide: Add Ebean ORM (PostgreSQL) to an Existing Maven Project — Step 3: Database Configuration

## Purpose

Expand Down
242 changes: 242 additions & 0 deletions docs/guides/migrating-to-database-builder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
# Guide: Migrate from `DatabaseConfig` / `DatabaseFactory` to `Database.builder()`

## Purpose

This guide shows how to migrate legacy programmatic database creation code from:

- `new DatabaseConfig()`
- `DatabaseFactory.create(...)`
- old `setXxx(...)` builder-style configuration methods

…to the preferred builder-based style using:

- `Database.builder()`
- fluent `DatabaseBuilder` methods such as `name(...)`, `register(...)`, and `defaultDatabase(...)`
- `DatabaseBuilder.build()`

Use this guide when upgrading older Ebean setup code or when building an automated/semi-automated migration.

---

## Preferred pattern

Prefer code shaped like this:

```java
Database database = Database.builder()
.name("db")
.loadFromProperties()
.dataSourceBuilder(dataSource)
.register(true)
.defaultDatabase(true)
.build();
```

The important points are:

1. Start with `Database.builder()`
2. Configure via `DatabaseBuilder`
3. Finish with `.build()`

---

## Step 1 — Replace `new DatabaseConfig()` with `Database.builder()`

### Before

```java
DatabaseConfig config = new DatabaseConfig();
config.setName("db");
config.loadFromProperties();
```

### After

```java
DatabaseBuilder config = Database.builder()
.name("db")
.loadFromProperties();
```

### Notes

- Prefer the `DatabaseBuilder` type for local variables and parameters when possible.
- If existing code only uses standard builder methods, this change is usually mechanical.
- If existing code later reads configuration back, use `config.settings()`.

---

## Step 2 — Replace `DatabaseFactory.create(config)` with `config.build()`

### Before

```java
DatabaseConfig config = new DatabaseConfig();
config.setName("db");
config.loadFromProperties();
Database database = DatabaseFactory.create(config);
```

### After

```java
DatabaseBuilder config = Database.builder()
.name("db")
.loadFromProperties();
Database database = config.build();
```

### Short form

```java
Database database = Database.builder()
.name("db")
.loadFromProperties()
.build();
```

---

## Step 3 — Replace `DatabaseFactory.create("name")`

### Before

```java
Database database = DatabaseFactory.create("other");
```

### After

```java
Database database = Database.builder()
.name("other")
.loadFromProperties()
.build();
```

### Important

For **named databases**, set `.name("...")` before `.loadFromProperties()` so the named configuration is loaded.

---

## Step 4 — Replace legacy `setXxx(...)` methods with fluent builder methods

`DatabaseBuilder` already exposes preferred fluent names for most configuration methods.
Use those names when migrating older setup code.

| Legacy call | Preferred call |
|---|---|
| `setName("db")` | `name("db")` |
| `setRegister(false)` | `register(false)` |
| `setDefaultServer(false)` | `defaultDatabase(false)` |
| `setContainerConfig(cfg)` | `containerConfig(cfg)` |
| `setDbSchema("app")` | `dbSchema("app")` |
| `setDataSourceConfig(ds)` | `dataSourceBuilder(ds)` |
| `setReadOnlyDataSourceConfig(ro)` | `readOnlyDataSourceBuilder(ro)` |
| `setRunMigration(true)` | `runMigration(true)` |
| `setDisableClasspathSearch(true)` | `disableClasspathSearch(true)` |
| `setPersistBatch(batch)` | `persistBatch(batch)` |

### Full example

#### Before

```java
DatabaseConfig config = new DatabaseConfig();
config.setName("db");
config.setRegister(false);
config.setDefaultServer(false);
config.setDataSourceConfig(dataSource);
Database database = DatabaseFactory.create(config);
```

#### After

```java
Database database = Database.builder()
.name("db")
.register(false)
.defaultDatabase(false)
.dataSourceBuilder(dataSource)
.build();
```

---

## Step 5 — Verify semantics after migration

The migration should preserve behavior, but verify these points:

- `register(true)` is still the default
- `defaultDatabase(true)` is still the default
- call `loadFromProperties()` if the old code loaded configuration from properties
- for named databases, set the name before loading properties
- explicit entity registration via `addClass(...)` / `addAll(...)` is unchanged
- custom datasource wiring via `dataSourceBuilder(...)` and `readOnlyDataSourceBuilder(...)` is unchanged

---

## Manual-review cases

These cases are **not** simple search-and-replace migrations and should be reviewed manually:

### `DatabaseFactory.createWithContextClassLoader(...)`

There is no direct builder shorthand for this today. Keep this as-is for now and migrate the surrounding builder configuration first.

### `DatabaseFactory.initialiseContainer(...)`

This is a container lifecycle concern, not a normal database-builder call. Keep it as-is unless you are intentionally moving the `ContainerConfig` onto the first builder via `containerConfig(...)`.

### `DatabaseFactory.shutdown()`

This is also a lifecycle concern rather than normal builder setup. Leave it alone unless you are making a deliberate lifecycle change.

### Variables or method signatures typed as `DatabaseConfig`

If the code only uses standard builder operations, switch the type to `DatabaseBuilder`.
If the code depends on implementation-specific `DatabaseConfig` methods, review it manually.

### Code that needs read access to builder settings

Use:

```java
DatabaseBuilder builder = Database.builder();
DatabaseBuilder.Settings settings = builder.settings();
```

rather than relying on the concrete `DatabaseConfig` type only to read getters.

---

## Automation notes for AI agents and bulk refactors

This migration is a good candidate for semi-automated upgrading.

### Safe mechanical rewrites

These are usually safe to rewrite automatically:

- `new DatabaseConfig()` → `Database.builder()`
- `DatabaseFactory.create(builder)` → `builder.build()`
- `DatabaseFactory.create("name")` → `Database.builder().name("name").loadFromProperties().build()`
- legacy `setXxx(...)` calls → preferred fluent builder methods

### Flag for manual review

Automatically flag, but do not blindly rewrite:

- `DatabaseFactory.createWithContextClassLoader(...)`
- `DatabaseFactory.initialiseContainer(...)`
- `DatabaseFactory.shutdown()`
- parameters, fields, or return types declared as `DatabaseConfig`
- any use that clearly depends on `DatabaseConfig` implementation details rather than `DatabaseBuilder`

---

## Related guides

- [Database configuration](add-ebean-postgres-database-config.md) — preferred modern setup style using `Database.builder()`
- [Guide index](README.md) — full list of Ebean setup and migration guides
24 changes: 14 additions & 10 deletions ebean-api/src/main/java/io/ebean/Database.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,29 @@
/**
* Provides the API for fetching and saving beans to a particular database.
*
* <h5>Constructing a Database</h5>
* <p>
* Databases are typically constructed via {@link #builder()} and {@link DatabaseBuilder#build()}.
* They can also be automatically constructed on demand using configuration information in
* the application.properties file. The underlying implementation is provided by
* {@link DatabaseFactory}.
*
* <h5>Registration with the DB singleton</h5>
* <p>
* When a Database instance is created it can be registered with the DB
* singleton (see {@link DatabaseConfig#setRegister(boolean)}). The DB
* singleton is essentially a map of Database's that have been registered
* When a Database instance is created it can be registered with the {@link DB}
* singleton (see {@link DatabaseBuilder#register(boolean)}). The {@link DB}
* singleton is essentially a map of {@link Database}'s that have been registered
* with it.
* <p>
* The Database can then be retrieved later via {@link DB#byName(String)}.
*
* <h5>The 'default' Database</h5>
* <p>
* One Database can be designated as the 'default' or 'primary' Database
* (see {@link DatabaseConfig#setDefaultServer(boolean)}). Many methods on DB
* (see {@link DatabaseBuilder#defaultDatabase(boolean)}). Many methods on {@link DB}
* such as {@link DB#find(Class)} etc are actually just a convenient way to
* call methods on the 'default/primary' Database.
*
* <h5>Constructing a Database</h5>
* <p>
* Databases are constructed by the DatabaseFactory. They can be created
* programmatically via {@link DatabaseFactory#create(DatabaseBuilder)} or they
* can be automatically constructed on demand using configuration information in
* the application.properties file.
*
* <h5>Example: Get a Database</h5>
* <pre>{@code
Expand Down Expand Up @@ -80,6 +81,7 @@
* method. Example: a single thread requires more than one transaction.
*
* @see DB
* @see DatabaseBuilder
* @see DatabaseFactory
* @see DatabaseConfig
*/
Expand All @@ -94,11 +96,13 @@ public interface Database {
* // from application.properties / application.yaml
*
* Database db = Database.builder()
* .name("db")
* .loadFromProperties()
* .build();
*
* }</pre>
*/
@SuppressWarnings("removal")
static DatabaseBuilder builder() {
return new DatabaseConfig();
}
Expand Down
6 changes: 3 additions & 3 deletions ebean-api/src/main/java/io/ebean/DatabaseBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -982,7 +982,7 @@ default DatabaseBuilder namingConvention(NamingConvention namingConvention) {
* <p>
* Use this to override the default known aggregation functions.
*/
DatabaseConfig aggregateFormulaContext(AggregateFormulaContext aggregateFormulaContext);
DatabaseBuilder aggregateFormulaContext(AggregateFormulaContext aggregateFormulaContext);

/**
* Set to true if all DB column and table names should use quoted identifiers.
Expand Down Expand Up @@ -2221,7 +2221,7 @@ default DatabaseBuilder loadModuleInfo(boolean loadModuleInfo) {
*
* @param includeLabelInSql When true include a SQL inline comment in generated SELECT queries.
*/
DatabaseConfig includeLabelInSql(boolean includeLabelInSql);
DatabaseBuilder includeLabelInSql(boolean includeLabelInSql);

/**
* Set the naming convention to apply to metrics names.
Expand All @@ -2239,7 +2239,7 @@ default DatabaseBuilder metricNaming(Function<String, String> metricNaming) {
/**
* Sets the length check mode.
*/
DatabaseConfig lengthCheck(LengthCheck lengthCheck);
DatabaseBuilder lengthCheck(LengthCheck lengthCheck);

/**
* Provides read access (getters) for the DatabaseBuilder configuration
Expand Down
Loading
Loading