|
| 1 | +# Changelog |
| 2 | + |
| 3 | +All notable changes to JEHibernate are documented here. The format is based on |
| 4 | +[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to |
| 5 | +[Semantic Versioning](https://semver.org/spec/v2.0.0.html). |
| 6 | + |
| 7 | +## [4.0.0] — 2026-06-02 |
| 8 | + |
| 9 | +Major release. The library is now a **multi-module build** and the connection-pool and |
| 10 | +schema-management defaults changed. See the migration notes below. |
| 11 | + |
| 12 | +### Added |
| 13 | + |
| 14 | +- **Multi-module build** (ADR-0001): `jehibernate-core` (mandatory), `jehibernate-spring-boot`, |
| 15 | + `jehibernate-plugin`, `jehibernate-testing`. Gradle version catalog at |
| 16 | + `gradle/libs.versions.toml`. Shared build config in the root `subprojects {}` block. |
| 17 | +- **HikariCP connection pool** as the default (TODO-1, ADR-0003): |
| 18 | + - `PoolConfig` record with `maximumPoolSize`, `minimumIdle`, `idleTimeout`, `connectionTimeout`, |
| 19 | + `maxLifetime`, `leakDetectionThreshold`, `validationTimeout` (+ sensible defaults). |
| 20 | + - `ConfigurationBuilder.pool(PoolConfig)` and `ConfigurationBuilder.dataSource(DataSource)` for |
| 21 | + reusing an external (e.g. Spring) `DataSource`. |
| 22 | + - `JEHibernate.getPoolHealth()` → `PoolHealth(active, idle, total, threadsAwaiting, available)`. |
| 23 | + - `JEHibernate.getDataSource()`. |
| 24 | + - Pool properties readable from `hibernate.properties` via `jehibernate.pool.*`. |
| 25 | + - Deterministic pool shutdown in `JEHibernate.close()` (only when JEHibernate owns the pool). |
| 26 | +- **Schema migration** (TODO-2, ADR-0002): |
| 27 | + - Flyway by default (`V001__init.sql` under `classpath:db/migration`); Liquibase opt-in. |
| 28 | + - `MigrationConfig`, `MigrationTool`, `MigrationRunner`, `MigrationSupport`, |
| 29 | + `FlywayMigrationRunner`, `LiquibaseMigrationRunner`. |
| 30 | + - `ConfigurationBuilder.migration(MigrationConfig)`; properties `jehibernate.migration.{enabled, |
| 31 | + tool,location}`. |
| 32 | + - Migrations run before `SessionFactory.build()`. Absent tool → silent no-op. |
| 33 | +- **Lazy-loading / EntityGraph helpers** (TODO-3): |
| 34 | + - `AbstractCrudRepository.findByIdWithGraph(id, paths...)`, `findAllWithGraph(paths...)`, |
| 35 | + `findByIdWithNamedGraph(id, name)` — fetch named associations in a single query (no N+1), |
| 36 | + applied as a JPA `loadgraph` hint. Dot-separated paths supported for nested graphs. |
| 37 | + - `docs/lazy-loading-guide.md` with a when-to-use decision table (scoping vs read-only vs |
| 38 | + EntityGraph vs OSIV). OSIV is documented as a copy-ready last-resort pattern, deliberately |
| 39 | + not shipped as a bean. |
| 40 | +- **Multi-tenancy** (TODO-5, ADR-0004), off by default: |
| 41 | + - `MultiTenancyStrategy` (NONE/DATABASE/SCHEMA/DISCRIMINATOR), `MultiTenancyConfig`, |
| 42 | + `ConfigurationBuilder.multiTenancy(...)`. |
| 43 | + - `TenantContext` (thread-local, nesting `AutoCloseable` scope), `TenantResolver` SPI, |
| 44 | + `TenantContextResolver` (Hibernate `CurrentTenantIdentifierResolver` adapter with strict |
| 45 | + leak-guard that throws when no tenant is bound). |
| 46 | + - `SchemaMultiTenantConnectionProvider` (one shared pool, per-tenant `setSchema`, reset on |
| 47 | + release), `DatabaseMultiTenantConnectionProvider` (tenant → DataSource). |
| 48 | + - `docs/multi-tenancy-guide.md`. |
| 49 | + - Note: TODO-4 (Envers audit) is skipped, so the planned `tenant_id` column on the audit |
| 50 | + revision entity is deferred with it. |
| 51 | +- Integration tests: `PoolIntegrationTest` (50 parallel queries, health, defaults), |
| 52 | + `MigrationIntegrationTest` (apply-on-empty, no-op-on-restart, disabled, Liquibase config), |
| 53 | + `EntityGraphIntegrationTest` (single-query collection fetch verified via Hibernate Statistics), |
| 54 | + `DiscriminatorMultiTenancyTest` (tenant isolation, leak-guard throws, thread switch, shared pool), |
| 55 | + `MultiTenantConnectionProviderTest` (SCHEMA/DATABASE provider unit coverage). |
| 56 | +- **Testing module** `jehibernate-testing` (TODO-6): |
| 57 | + - `@JEHibernateTest` + `JEHibernateExtension` (JUnit 5): boots JEHibernate against H2 or a |
| 58 | + Testcontainers container (PostgreSQL/MySQL/MariaDB/MSSQL), injects `JEHibernate`/ |
| 59 | + `EntityManagerFactory` as test parameters, resets the DB after each test. |
| 60 | + - `TestDatabase`, `DatabaseReset` (NONE/TRUNCATE_ALL/DROP_CREATE/ROLLBACK_TX, FK-aware via |
| 61 | + Hibernate `SchemaManager`), `Fixtures` + `Fixtures.Builder` fixture pattern. |
| 62 | + - Container-backed tests skip (not fail) when Docker is unavailable. |
| 63 | + - `docs/testing-guide.md`. The Spring `@JEHibernateRepositoryTest` slice is deferred until the |
| 64 | + Spring Boot auto-configuration exists. |
| 65 | +- **Plugin-bias decoupling** (TODO-7): |
| 66 | + - `PropertyLoader.fromClasspath(String)` and `fromFile(Path)` named entry points in core. |
| 67 | + - `PluginPropertyLoader.fromPluginDataFolder(...)` in `jehibernate-plugin` (the File/data-folder |
| 68 | + convenience now lives in the plugin module). |
| 69 | + - `slf4j-api` is now an `implementation` dependency of core (bundled transitively) so |
| 70 | + standalone/Spring consumers get the logging facade without manual setup. |
| 71 | + - `examples/spring-boot-demo/` (bootstrap < 50 lines) and `examples/spigot-plugin-demo/` |
| 72 | + (unchanged plugin API) added; `jehibernate-plugin` targets Java 21 (Paper runtime). |
| 73 | +- Integration/extension tests: `H2JEHibernateExtensionTest` (boot + reset between tests); |
| 74 | + a shared `AbstractCrudAcrossDatabasesIT` CRUD+query scenario run per database via |
| 75 | + `H2CrudIT` (always runs) and `PostgresCrudIT`/`MySqlCrudIT`/`MariaDbCrudIT` |
| 76 | + (Testcontainers, skipped without Docker). |
| 77 | +- ADRs under `docs/adr/`. |
| 78 | + |
| 79 | +### Changed |
| 80 | + |
| 81 | +- **BREAKING — published coordinate:** `de.jexcellence.hibernate:JEHibernate` → |
| 82 | + `de.jexcellence.hibernate:jehibernate-core`. |
| 83 | +- **BREAKING — `ddl-auto` default:** `update` → `validate`. Migrations now own the schema. Callers |
| 84 | + relying on the implicit `update` default must set `ddlAuto("update")` explicitly, provide |
| 85 | + migrations, or set `jehibernate.migration.enabled=false`. |
| 86 | +- **BREAKING — connection pool:** `connectionPool(min, max)` now configures HikariCP via |
| 87 | + `PoolConfig` instead of writing `hibernate.agroal.*`. Method signature unchanged. Agroal |
| 88 | + `compileOnly` dependencies removed. |
| 89 | +- `BukkitPluginExample` and other samples moved to `jehibernate-plugin/examples/`. |
| 90 | + |
| 91 | +### Fixed |
| 92 | + |
| 93 | +- `EntityScanner` / `RepositoryScanner` now also enumerate the package via the classloader in |
| 94 | + addition to JEHibernate's code-source URL, so entities/repositories located in a different |
| 95 | + output root than the JEHibernate jar (e.g. test sources, non-shaded consumers) are discovered. |
| 96 | + Previously scanning only the code-source URL returned zero results in those layouts. |
| 97 | +- `Specifications.equal(...)` reference in `IntegrationTest` updated to the renamed `equalTo(...)` |
| 98 | + (the suite no longer compiled after the 3.x rename). |
| 99 | + |
| 100 | +### Migration from 3.x |
| 101 | + |
| 102 | +```kotlin |
| 103 | +// before |
| 104 | +implementation("de.jexcellence.hibernate:JEHibernate:3.0.4") |
| 105 | +// after |
| 106 | +implementation("de.jexcellence.hibernate:jehibernate-core:4.0.0") |
| 107 | +implementation("org.flywaydb:flyway-core:11.1.1") // optional: enables migrations |
| 108 | +``` |
| 109 | + |
| 110 | +If you relied on Hibernate auto-DDL, keep the old behaviour explicitly: |
| 111 | + |
| 112 | +```java |
| 113 | +.configuration(c -> c.database(...).url(...).ddlAuto("update")) |
| 114 | +``` |
0 commit comments