Compare commits

..
Author SHA1 Message Date
robin.bygrave 72ce587629 Add dbName() to MetaQueryPlan - easier to support multi-db query plan capture handling 2026-08-14 18:03:02 +12:00
robin.bygrave 77e98a3f54 Metrics - support both CUMULATIVE and DELTA metrics collection concurrently
ebean insight [and StatsD] work off DELTA metrics, where as OTEL
and Prometheus want CUMULATIVE. With this change we can have a metrics
collection for ebean insight using DELTA mode and have a second collection
use CUMULATIVE for reporting to OTEL - for the case of fan-out metrics
going to 2 places.

This isn't strictly needed when only one collection mode is used.
2026-08-14 16:31:28 +12:00
robin.bygrave 3c4e87f3f7 Docs: Update docs on OneToOne mapping with mappedBy 2026-08-06 21:53:14 +12:00
Rob Bygrave f5eee70ec4 Bump test modules to 18.4.0 2026-07-28 22:35:46 +12:00
Rob Bygrave 46a73f6250 Version 18.4.0 2026-07-28 22:29:48 +12:00
Rob Bygrave 4a46cc0706 Tests: use redis 8.6.2 explicitly in tests 2026-07-28 22:26:49 +12:00
Rob Bygrave 94630b7e1e Tests: Rename ebean-reddison test entities 2026-07-28 21:42:48 +12:00
robin.bygrave aac85eec89 Tests: Move redisson tests to use database 1 / isolate from ebean-redis tests 2026-07-28 21:23:41 +12:00
robin.bygrave a8ec4ee437 Tests: Improve flakey test TestHistoryOneToOne 2026-07-28 21:18:56 +12:00
Rob Bygrave 12b9d0eaae Bump ebean-migration to 14.4.0 - adds rebaseMigrationHistory feature (#3873) 2026-07-28 21:09:27 +12:00
Rob Bygraveandrobin.bygrave eeb32514be DB2 exists - use existsWithCaseWhen true, similar to #3849 (#3872)
* DB2 exists - use existsWithCaseWhen true, similar to #3849

Fixes exists() query regression with DB2 by using the platform flag existsWithCaseWhen = true;

* DB2 using existsFromClause = " from sysibm.sysdummy1";

---------

Co-authored-by: robin.bygrave <robin.bygrave@eroad.com>
2026-07-28 20:18:34 +12:00
robin.bygrave 02936735c1 Tests: Disable query plan capture tests for DB2 2026-07-28 19:40:14 +12:00
dependabot[bot] 57713a9686 Build(deps): Bump org.postgresql:postgresql in /ebean-core-type (#3870)
Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.7.11 to 42.7.12.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.7.11...REL42.7.12)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-version: 42.7.12
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-24 10:01:59 +12:00
dependabot[bot] 4076b0fcbd Build(deps): Bump org.postgresql:postgresql in /ebean-postgis-types (#3869)
Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.7.11 to 42.7.12.
- [Release notes](https://github.com/pgjdbc/pgjdbc/releases)
- [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.7.11...REL42.7.12)

---
updated-dependencies:
- dependency-name: org.postgresql:postgresql
  dependency-version: 42.7.12
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-24 10:01:34 +12:00
Rob Bygraveandrobin.bygrave 49f6bef2fb Add ebean-avajejsonb-mapper module - Mapping DbJson content using avaje jsonb library (no reflection, graalvm support) (#3871)
* Add ebean-avajejsonb-mapper module - Mapping DbJson content using avaje jsonb library (no reflection, graalvm support)

* Fix flakey test TestInheritance

---------

Co-authored-by: robin.bygrave <robin.bygrave@eroad.com>
2026-07-24 10:01:03 +12:00
Rob Bygraveandrobin.bygrave d6ba4967b6 ORM Update - add usingTransaction() to support using explicit transaction (#3868)
Co-authored-by: robin.bygrave <robin.bygrave@eroad.com>
2026-07-22 09:45:54 +12:00
104 changed files with 1301 additions and 426 deletions
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -17,13 +17,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -42,13 +42,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId> <artifactId>ebean-platform-clickhouse</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -17,13 +17,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -42,13 +42,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId> <artifactId>ebean-platform-postgres</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -17,13 +17,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -42,13 +42,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId> <artifactId>ebean-platform-db2</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -17,13 +17,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -42,13 +42,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId> <artifactId>ebean-platform-h2</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -17,13 +17,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -42,13 +42,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId> <artifactId>ebean-platform-hana</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -17,13 +17,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -42,13 +42,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId> <artifactId>ebean-platform-mariadb</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -17,13 +17,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -42,13 +42,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId> <artifactId>ebean-platform-mysql</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -22,13 +22,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -47,19 +47,19 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId> <artifactId>ebean-platform-postgres</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-net-postgis-types</artifactId> <artifactId>ebean-net-postgis-types</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -17,13 +17,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -42,13 +42,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId> <artifactId>ebean-platform-nuodb</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -17,13 +17,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -42,13 +42,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId> <artifactId>ebean-platform-oracle</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -22,13 +22,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -47,19 +47,19 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId> <artifactId>ebean-platform-postgres</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-pgvector-types</artifactId> <artifactId>ebean-pgvector-types</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -22,13 +22,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -47,19 +47,19 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId> <artifactId>ebean-platform-postgres</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId> <artifactId>ebean-postgis-types</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -17,13 +17,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -42,13 +42,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId> <artifactId>ebean-platform-postgres</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -17,13 +17,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -42,13 +42,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId> <artifactId>ebean-platform-sqlite</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -17,13 +17,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -42,13 +42,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId> <artifactId>ebean-platform-sqlserver</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -17,13 +17,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -42,13 +42,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId> <artifactId>ebean-platform-postgres</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -17,13 +17,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -41,7 +41,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId> <artifactId>ebean-jackson-mapper</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -60,13 +60,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId> <artifactId>ebean-platform-all</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<artifactId>composites</artifactId> <artifactId>composites</artifactId>
+96 -26
View File
@@ -1,40 +1,39 @@
# Guide: `@DbJson` / `@DbJsonB` mapping support — built-in vs Jackson ObjectMapper # Guide: `@DbJson` / `@DbJsonB` mapping support
## Purpose ## Purpose
Ebean can map `@DbJson` and `@DbJsonB` properties in two ways: Ebean can map `@DbJson` and `@DbJsonB` properties in three ways:
- **Built-in** JSON support, backed by **avaje-json-core** — no extra dependency. - **Built-in** JSON support, backed by **avaje-json-core** — no extra dependency.
- **Jackson `ObjectMapper`**, provided by the **`ebean-jackson-mapper`** module — used - **Jackson `ObjectMapper`**, provided by **`ebean-jackson-mapper`**.
for everything the built-in support does not handle. - **Avaje Jsonb**, provided by **`ebean-avajejsonb-mapper`** and its generated adapters.
This guide lists exactly which property types are handled built-in and which require The built-in mapper handles the common natural JSON types. Add one mapper module for
`ebean-jackson-mapper`. typed collections, POJOs, records, and other custom types.
> If a property type is **not** handled built-in and `ebean-jackson-mapper` is not on the > If a property type is **not** handled built-in and no mapper module is on the classpath,
> classpath, Ebean fails fast at startup: > Ebean fails fast at startup:
> >
> ```text > ```text
> Unsupported @DbJson mapping - Missing dependency ebean-jackson-mapper? > Unsupported @DbJson mapping - missing JSON mapper dependency for <property>
> Jackson ObjectMapper not present for <property>
> ``` > ```
--- ---
## Quick reference ## Quick reference
| Property type | Built-in (avaje-json-core) | Needs `ebean-jackson-mapper` | | Property type | Built-in (avaje-json-core) | Mapper module |
|---|:---:|:---:| |---|:---:|---|
| `String` | ✅ | | | `String` | ✅ | |
| `List<String>`, `List<Long>` | ✅ | | | `List<String>`, `List<Long>` | ✅ | |
| `Set<String>`, `Set<Long>` | ✅ | | | `Set<String>`, `Set<Long>` | ✅ | |
| `Map<String, Object>`, `Map<String, ?>` | ✅ | | | `Map<String, Object>`, `Map<String, ?>` | ✅ | |
| `Map<String, String>` | ✅ | | | `Map<String, String>` | ✅ | |
| `Map<Enum, Object>`, `Map<Enum, String>` | ✅ | | | `Map<Enum, Object>`, `Map<Enum, String>` | ✅ | |
| `List`/`Set` of any other element type (`Integer`, `Double`, `UUID`, `LocalDate`, an enum, a POJO, …) | | ✅ | | `List`/`Set` of any other element type (`Integer`, `Double`, `UUID`, `LocalDate`, an enum, a POJO, …) | | Jackson or Avaje Jsonb |
| `Map` with a typed value other than `String`/`Object` (`Map<String,Integer>`, `Map<String,UUID>`, …) | | ✅ | | `Map` with a typed value other than `String`/`Object` (`Map<String,Integer>`, `Map<String,UUID>`, …) | | Jackson or Avaje Jsonb |
| `Map` with a key other than `String` or an enum (`Map<Integer, …>`, `Map<UUID, …>`) | | ✅ | | `Map` with a key other than `String` or an enum (`Map<Integer, …>`, `Map<UUID, …>`) | | Jackson or Avaje Jsonb |
| POJOs, records, or any other type | | ✅ | | POJOs, records, or any other type | | Jackson or Avaje Jsonb |
--- ---
@@ -59,10 +58,10 @@ Postgres `json` / `jsonb` — without `ebean-jackson-mapper`.
--- ---
## Everything else → Jackson `ObjectMapper` ## Jackson `ObjectMapper`
Any other `@DbJson` / `@DbJsonB` property routes to the Jackson `ObjectMapper` path, which `ebean-jackson-mapper` uses a Jackson `ObjectMapper` for the property types not handled
requires `ebean-jackson-mapper`: built-in:
- **Typed collections** — `List`/`Set` whose element type is not `String` or `Long` - **Typed collections** — `List`/`Set` whose element type is not `String` or `Long`
(for example `List<Integer>`, `List<UUID>`, `List<LocalDate>`, `List<MyEnum>`, `List<MyPojo>`). (for example `List<Integer>`, `List<UUID>`, `List<LocalDate>`, `List<MyEnum>`, `List<MyPojo>`).
@@ -77,7 +76,7 @@ requires `ebean-jackson-mapper`:
--- ---
## Adding `ebean-jackson-mapper` ### Adding `ebean-jackson-mapper`
```xml ```xml
<dependency> <dependency>
@@ -92,6 +91,79 @@ registers the mapper-based JSON support automatically.
--- ---
## Avaje Jsonb
`ebean-avajejsonb-mapper` uses Avaje Jsonb adapters. Annotate each JSON payload type with
`@Json`, or use `@Json.Import`, and configure `avaje-jsonb-generator` as an annotation
processor.
```xml
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-avajejsonb-mapper</artifactId>
<version>${ebean.version}</version>
</dependency>
```
```xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.avaje</groupId>
<artifactId>avaje-jsonb-generator</artifactId>
<version>${avaje-jsonb.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
```
For example:
```java
import io.avaje.jsonb.Json;
@Json
public class Address {
public String line1;
public String city;
}
```
Avaje Jsonb preserves a property's declared generic type, so `List<Address>` and other
parameterised JSON values use the generated `Address` adapter.
### Avaje JsonNode
`@DbJson` and `@DbJsonB` properties declared as `io.avaje.json.node.JsonNode` are supported
when the application includes `avaje-json-node`. Its Jsonb component supplies the JSON tree
adapters; no application-generated adapter is needed for the node hierarchy.
```xml
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-json-node</artifactId>
<version>${avaje-jsonb.version}</version>
</dependency>
```
## Mapper module selection
Use exactly one mapper module in an application: `ebean-jackson-mapper` or
`ebean-avajejsonb-mapper`. Ebean selects a single `ScalarJsonMapper` service provider, so
having both modules on the runtime classpath is not supported.
The `ebean` composite dependency includes `ebean-jackson-mapper`. Applications using Avaje
Jsonb should depend on the individual Ebean modules they need instead of that composite.
To migrate from Jackson to Avaje Jsonb, remove `ebean-jackson-mapper`, add
`ebean-avajejsonb-mapper`, and generate adapters for each JSON payload type.
---
## Notes ## Notes
- **Enum map keys** are serialised using the enum `name()` (for example `ACTIVE`), not any - **Enum map keys** are serialised using the enum `name()` (for example `ACTIVE`), not any
@@ -102,15 +174,13 @@ registers the mapper-based JSON support automatically.
(with a JSON fallback on platforms without array support) and supports more element types (with a JSON fallback on platforms without array support) and supports more element types
than built-in `@DbJson` collections. than built-in `@DbJson` collections.
- The reason typed value/element collections need a real mapper is that the built-in path - The reason typed value/element collections need a real mapper is that the built-in path
only produces natural JSON types — for example a JSON number always parses to `Long`, so a only produces natural JSON types — for example a JSON number always parses to `Long`.
declared `List<Integer>` or `Map<String,Integer>` could not be populated safely without a
type-aware mapper.
--- ---
## Choosing ## Choosing
- Prefer the **built-in** mappings for the common cases (`String`, string/long lists and sets, - Prefer the **built-in** mappings for the common cases (`String`, string/long lists and sets,
object/string maps) to avoid pulling in Jackson. object/string maps) to avoid an additional mapper module.
- Add **`ebean-jackson-mapper`** when you need rich POJO JSON columns or typed collections / - Add **`ebean-jackson-mapper`** or **`ebean-avajejsonb-mapper`** when you need rich POJO JSON
typed-value maps. columns or typed collections / typed-value maps.
+6 -1
View File
@@ -376,7 +376,12 @@ public class Customer {
**Important:** **Important:**
- Use `List<>` not `Set<>` for collections (Set calls equals/hashCode before beans have IDs) - Use `List<>` not `Set<>` for collections (Set calls equals/hashCode before beans have IDs)
- `mappedBy` means Order.customer is the owner - `mappedBy` means Order.customer is the owner
- Relationships are lazy-loaded by default - Relationships are lazy-loaded by default — **except** `@OneToOne(mappedBy=...)`,
which defaults to `FetchType.EAGER` and adds a `left join` to every default
select of the owning entity. Explicitly set `fetch = FetchType.LAZY` on
`@OneToOne(mappedBy=...)` fields unless the association is needed on
(almost) every load. See "`@OneToOne(mappedBy=...)` is EAGER by default" in
the query-beans guide for details.
--- ---
+42
View File
@@ -431,6 +431,48 @@ List<Customer> customers = new QCustomer()
If the caller needs multiple to-many paths or a paged query, be suspicious of a If the caller needs multiple to-many paths or a paged query, be suspicious of a
plain `fetch(...)` on those paths. `fetchQuery()` is often the safer default. plain `fetch(...)` on those paths. `fetchQuery()` is often the safer default.
### `@OneToOne(mappedBy=...)` is EAGER by default — mark it LAZY
The non-owning side of a `@OneToOne` (the side with `mappedBy`) defaults to
`FetchType.EAGER` per JPA, same as `@ManyToOne`. Unlike a `@ManyToOne`
reference (which is FK-only until `.fetch()`'d), Ebean's default select for an
EAGER `@OneToOne(mappedBy=...)` still adds a `left join` to the target table
on **every** query for the owning entity — even a plain `findById()` — because
there is no local FK column to use as a lazy reference; the only way to know
the associated row exists is to join to it.
If that association is rarely needed (e.g. a rarely-read child/detail table),
this join executes on every load of the parent, including in hot-path list
queries, and can dominate query cost as more such associations accumulate.
**Always set `fetch = FetchType.LAZY` on `@OneToOne(mappedBy=...)`
associations unless the association is genuinely needed on (almost) every
load:**
```java
@OneToOne(mappedBy = "device", fetch = FetchType.LAZY)
private SensorBoard sensorBoard;
```
This correctly excludes the join from Ebean's default select clause (verified
for FK-based, non-shared-primary-key `@OneToOne` relationships — the common
case). Callers that do need the association can still `.fetch("sensorBoard")`
explicitly on the query bean.
**Caveat:** the exclusion is driven by Ebean's default-select-clause
mechanism. It is bypassed if the query has already been switched into an
"all properties" mode by something other than the deploy-time
`FetchType.LAZY`/`EAGER` metadata (for example, an active AutoTune profile
that supplies its own tuned property set). Confirm the join is actually gone
by checking generated SQL (`LoggedSql` in tests, or query logging) after
making this change — don't assume it's excluded from the annotation alone.
### Agent rule
Default new `@OneToOne(mappedBy=...)` fields to `fetch = FetchType.LAZY`
unless there's a clear reason the association is needed on every load. This
is a one-line, low-risk change that avoids an always-on join.
--- ---
## Step 8 - Use DTO projection when the caller does not need entity beans ## Step 8 - Use DTO projection when the caller does not need entity beans
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<name>ebean api</name> <name>ebean api</name>
@@ -9,6 +9,11 @@ import java.time.Instant;
*/ */
public interface MetaQueryPlan { public interface MetaQueryPlan {
/**
* Return the name of the database for the query.
*/
String dbName();
/** /**
* Return the bean type for the query. * Return the bean type for the query.
*/ */
+113
View File
@@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>18.4.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ebean-avajejsonb-mapper</artifactId>
<name>ebean-avajejsonb-mapper</name>
<dependencies>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>18.4.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-json-core</artifactId>
<version>${avaje-json-core.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-jsonb</artifactId>
<version>${avaje-jsonb.version}</version>
</dependency>
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-json-node</artifactId>
<version>${avaje-jsonb.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>18.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>18.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-datasource</artifactId>
<version>${ebean-datasource.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2database.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>18.4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.avaje</groupId>
<artifactId>avaje-jsonb-generator</artifactId>
<version>${avaje-jsonb.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>${ebean-maven-plugin.version}</version>
<executions>
<execution>
<id>test</id>
<phase>process-test-classes</phase>
<configuration>
<packages>org/example/avajejsonb/**</packages>
<transformArgs>debug=0</transformArgs>
</configuration>
<goals>
<goal>testEnhance</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,223 @@
package io.ebean.avajejsonb.mapper;
import io.avaje.json.JsonReader;
import io.avaje.json.JsonWriter;
import io.avaje.jsonb.JsonType;
import io.avaje.jsonb.Jsonb;
import io.ebean.annotation.MutationDetection;
import io.ebean.core.type.DataBinder;
import io.ebean.core.type.DataReader;
import io.ebean.core.type.DocPropertyType;
import io.ebean.core.type.JsonTrim;
import io.ebean.core.type.PostgresHelper;
import io.ebean.core.type.ScalarJsonManager;
import io.ebean.core.type.ScalarJsonMapper;
import io.ebean.core.type.ScalarJsonRequest;
import io.ebean.core.type.ScalarType;
import io.ebean.core.type.ScalarTypeBase;
import io.ebean.text.TextException;
import jakarta.persistence.PersistenceException;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.sql.Types;
import java.util.concurrent.ConcurrentHashMap;
/**
* Supports {@code @DbJson} properties using Avaje Jsonb.
*/
public final class ScalarJsonAvajeJsonbMapper implements ScalarJsonMapper {
private final ConcurrentHashMap<Type, JsonType<Object>> jsonTypes = new ConcurrentHashMap<>();
@Override
public <A extends Annotation> Class<A> markerAnnotation() {
return null;
}
@Override
public ScalarType<?> createType(ScalarJsonRequest request) {
Type genericType = genericType(request);
JsonType<Object> jsonType = jsonTypes.computeIfAbsent(genericType, type -> jsonb(request.manager()).type(type));
if (request.mode() == MutationDetection.NONE) {
return new NoMutationDetection(request.manager(), jsonType, request.dbType(), request.docType());
}
return new GenericObject(request.manager(), jsonType, request.dbType(), request.docType());
}
private Jsonb jsonb(ScalarJsonManager manager) {
Object mapper = manager.mapper();
return mapper instanceof Jsonb ? (Jsonb) mapper : Jsonb.instance();
}
private Type genericType(ScalarJsonRequest request) {
Class<?> type = request.beanType();
while (type != null) {
try {
Field field = type.getDeclaredField(request.name());
return field.getGenericType();
} catch (NoSuchFieldException e) {
type = type.getSuperclass();
}
}
throw new IllegalStateException("Field not found to match " + request.name());
}
private static final class NoMutationDetection extends Base<Object> {
NoMutationDetection(ScalarJsonManager jsonManager, JsonType<Object> jsonType, int dbType, DocPropertyType docType) {
super(Object.class, jsonManager, jsonType, dbType, docType);
}
}
private static final class GenericObject extends Base<Object> {
private final boolean jsonb;
GenericObject(ScalarJsonManager jsonManager, JsonType<Object> jsonType, int dbType, DocPropertyType docType) {
super(Object.class, jsonManager, jsonType, dbType, docType);
this.jsonb = "jsonb".equals(pgType);
}
@Override
public boolean mutable() {
return true;
}
@Override
public boolean jsonMapper() {
return true;
}
@Override
public Object read(DataReader reader) throws SQLException {
String json = reader.getString();
if (jsonb) {
json = JsonTrim.trim(json);
}
reader.pushJson(json);
return parseJson(json);
}
@Override
public void bind(DataBinder binder, Object value) throws SQLException {
String rawJson = binder.popJson();
if (rawJson == null && value != null) {
rawJson = formatValue(value);
}
bindJson(binder, value, rawJson);
}
}
private static abstract class Base<T> extends ScalarTypeBase<T> {
private final JsonType<T> jsonType;
protected final String pgType;
private final DocPropertyType docType;
Base(Class<T> cls, ScalarJsonManager jsonManager, JsonType<T> jsonType, int dbType, DocPropertyType docType) {
super(cls, false, dbType);
this.jsonType = jsonType;
this.pgType = jsonManager.postgresType(dbType);
this.docType = docType;
}
@Override
public T read(DataReader reader) throws SQLException {
return parseJson(reader.getString());
}
@Override
public void bind(DataBinder binder, T value) throws SQLException {
bindJson(binder, value, value == null ? null : formatValue(value));
}
final T parseJson(String json) {
if (json == null || json.isEmpty()) {
return null;
}
try {
return jsonType.fromJson(json);
} catch (RuntimeException e) {
throw new TextException("Failed to parse JSON [{}] as " + jsonType, json, e);
}
}
final void bindJson(DataBinder binder, Object value, String rawJson) throws SQLException {
if (pgType != null) {
binder.setObject(PostgresHelper.asObject(pgType, rawJson));
} else if (value == null) {
binder.setNull(Types.VARCHAR);
} else {
binder.setString(rawJson);
}
}
@Override
public final Object toJdbcType(Object value) {
return value;
}
@Override
@SuppressWarnings("unchecked")
public final T toBeanType(Object value) {
return (T) value;
}
@Override
public final String formatValue(T value) {
try {
return jsonType.toJson(value);
} catch (RuntimeException e) {
throw new PersistenceException("Unable to create JSON", e);
}
}
@Override
public final T parse(String value) {
return parseJson(value);
}
@Override
public final DocPropertyType docType() {
return docType;
}
@Override
public final T jsonRead(JsonReader parser) {
if (parser.isNullValue()) {
return null;
}
return parseJson(parser.readRaw());
}
@Override
public final void jsonWrite(JsonWriter writer, T value) throws IOException {
if (value == null) {
writer.nullValue();
} else {
writer.rawValue(formatValue(value));
}
}
@Override
public final T readData(DataInput dataInput) throws IOException {
return dataInput.readBoolean() ? parse(dataInput.readUTF()) : null;
}
@Override
public final void writeData(DataOutput dataOutput, T value) throws IOException {
if (value == null) {
dataOutput.writeBoolean(false);
} else {
dataOutput.writeBoolean(true);
dataOutput.writeUTF(format(value));
}
}
}
}
@@ -0,0 +1,9 @@
import io.ebean.avajejsonb.mapper.ScalarJsonAvajeJsonbMapper;
module io.ebean.avajejsonb.mapper {
requires io.avaje.jsonb;
requires io.ebean.core.type;
provides io.ebean.core.type.ScalarJsonMapper with ScalarJsonAvajeJsonbMapper;
}
@@ -0,0 +1 @@
io.ebean.avajejsonb.mapper.ScalarJsonAvajeJsonbMapper
@@ -0,0 +1,56 @@
package io.ebean.avajejsonb.mapper;
import io.avaje.json.node.JsonNode;
import io.avaje.json.node.JsonObject;
import io.ebean.Database;
import io.ebean.DatabaseBuilder;
import org.example.avajejsonb.JsonbEntity;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Properties;
import static org.assertj.core.api.Assertions.assertThat;
class JsonbDatabaseTest {
@Test
void dbJson_roundTripsJsonbPayloadsAndJsonNode() {
Database database = buildDatabase();
try {
JsonbEntity entity = new JsonbEntity();
entity.setPayload(new JsonbPayload("main", 1));
entity.setPayloads(List.of(new JsonbPayload("first", 2), new JsonbPayload("second", 3)));
entity.setNode(JsonObject.create().add("name", "node").add("count", 4));
database.save(entity);
JsonbEntity found = database.find(JsonbEntity.class, entity.getId());
assertThat(found.getPayload()).isEqualTo(new JsonbPayload("main", 1));
assertThat(found.getPayloads()).containsExactly(new JsonbPayload("first", 2), new JsonbPayload("second", 3));
JsonNode node = found.getNode();
assertThat(node.extract("name")).isEqualTo("node");
assertThat(node.extract("count", 0)).isEqualTo(4);
} finally {
database.shutdown();
}
}
private static Database buildDatabase() {
DatabaseBuilder config = Database.builder();
config.setName("avajeJsonbMapper");
config.setDefaultServer(false);
config.setDdlGenerate(true);
config.setDdlRun(true);
config.setDdlExtra(false);
Properties properties = new Properties();
properties.setProperty("datasource.avajeJsonbMapper.username", "sa");
properties.setProperty("datasource.avajeJsonbMapper.password", "");
properties.setProperty("datasource.avajeJsonbMapper.databaseUrl", "jdbc:h2:mem:avajeJsonbMapper");
properties.setProperty("datasource.avajeJsonbMapper.databaseDriver", "org.h2.Driver");
config.loadFromProperties(properties);
config.addClass(JsonbEntity.class);
return config.build();
}
}
@@ -0,0 +1,37 @@
package io.ebean.avajejsonb.mapper;
import io.avaje.jsonb.Json;
import java.util.Objects;
@Json
public class JsonbPayload {
public String name;
public int count;
public JsonbPayload() {
}
JsonbPayload(String name, int count) {
this.name = name;
this.count = count;
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!(object instanceof JsonbPayload)) {
return false;
}
JsonbPayload other = (JsonbPayload) object;
return count == other.count && Objects.equals(name, other.name);
}
@Override
public int hashCode() {
return Objects.hash(name, count);
}
}
@@ -0,0 +1,130 @@
package io.ebean.avajejsonb.mapper;
import io.avaje.json.node.JsonNode;
import io.avaje.json.node.JsonObject;
import io.avaje.jsonb.Json;
import io.ebean.annotation.MutationDetection;
import io.ebean.core.type.DocPropertyType;
import io.ebean.core.type.ScalarJsonManager;
import io.ebean.core.type.ScalarJsonRequest;
import io.ebean.core.type.ScalarType;
import org.junit.jupiter.api.Test;
import java.sql.Types;
import java.util.List;
import java.util.Objects;
import static org.assertj.core.api.Assertions.assertThat;
class ScalarJsonAvajeJsonbMapperTest {
private static final ScalarJsonManager JSON_MANAGER = new ScalarJsonManager() {
@Override
public MutationDetection mutationDetection() {
return MutationDetection.HASH;
}
@Override
public Object mapper() {
return null;
}
@Override
public String postgresType(int dbType) {
return null;
}
};
private final ScalarJsonAvajeJsonbMapper mapper = new ScalarJsonAvajeJsonbMapper();
@Test
void pojo_roundTripsThroughGeneratedJsonbAdapter() {
ScalarType<Object> scalarType = scalarType("document", MutationDetection.HASH);
Payload payload = new Payload("hello", 42);
String json = scalarType.formatValue(payload);
assertThat(json).isEqualTo("{\"name\":\"hello\",\"count\":42}");
assertThat(scalarType.parse(json)).isEqualTo(payload);
assertThat(scalarType.mutable()).isTrue();
assertThat(scalarType.jsonMapper()).isTrue();
}
@Test
void genericList_roundTripsUsingPropertyGenericType() {
ScalarType<Object> scalarType = scalarType("payloads", MutationDetection.HASH);
List<Payload> payloads = List.of(new Payload("one", 1), new Payload("two", 2));
String json = scalarType.formatValue(payloads);
assertThat(json).isEqualTo("[{\"name\":\"one\",\"count\":1},{\"name\":\"two\",\"count\":2}]");
assertThat(scalarType.parse(json)).isEqualTo(payloads);
}
@Test
void jsonNode_roundTripsThroughAvajeJsonNodeComponent() {
ScalarType<Object> scalarType = scalarType("node", MutationDetection.HASH);
JsonNode node = JsonObject.create().add("name", "node").add("count", 3);
String json = scalarType.formatValue(node);
assertThat(json).isEqualTo("{\"name\":\"node\",\"count\":3}");
JsonNode parsed = (JsonNode) scalarType.parse(json);
assertThat(parsed.extract("name")).isEqualTo("node");
assertThat(parsed.extract("count", 0)).isEqualTo(3);
}
@Test
void mutationDetectionNone_isNotMutable() {
ScalarType<Object> scalarType = scalarType("document", MutationDetection.NONE);
assertThat(scalarType.mutable()).isFalse();
assertThat(scalarType.jsonMapper()).isFalse();
}
@SuppressWarnings("unchecked")
private ScalarType<Object> scalarType(String property, MutationDetection mutationDetection) {
var request = new ScalarJsonRequest(JSON_MANAGER, Types.VARCHAR, DocPropertyType.OBJECT, Entity.class, mutationDetection, property);
return (ScalarType<Object>) mapper.createType(request);
}
private static final class Entity {
Payload document;
List<Payload> payloads;
JsonNode node;
}
@Json
static class Payload {
public String name;
public int count;
Payload() {
}
Payload(String name, int count) {
this.name = name;
this.count = count;
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!(object instanceof Payload)) {
return false;
}
Payload other = (Payload) object;
return count == other.count && Objects.equals(name, other.name);
}
@Override
public int hashCode() {
return Objects.hash(name, count);
}
}
}
@@ -0,0 +1,54 @@
package org.example.avajejsonb;
import io.avaje.json.node.JsonNode;
import io.ebean.avajejsonb.mapper.JsonbPayload;
import io.ebean.annotation.DbJson;
import io.ebean.annotation.DbJsonB;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import java.util.List;
@Entity
public class JsonbEntity {
@Id
long id;
@DbJson
JsonbPayload payload;
@DbJson
List<JsonbPayload> payloads;
@DbJsonB
JsonNode node;
public long getId() {
return id;
}
public JsonbPayload getPayload() {
return payload;
}
public void setPayload(JsonbPayload payload) {
this.payload = payload;
}
public List<JsonbPayload> getPayloads() {
return payloads;
}
public void setPayloads(List<JsonbPayload> payloads) {
this.payloads = payloads;
}
public JsonNode getNode() {
return node;
}
public void setNode(JsonNode node) {
this.node = node;
}
}
@@ -0,0 +1 @@
entity-packages: org.example.avajejsonb
+1 -1
View File
@@ -6,7 +6,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<artifactId>ebean-bench</artifactId> <artifactId>ebean-bench</artifactId>
+34 -28
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<name>ebean bom</name> <name>ebean bom</name>
@@ -89,25 +89,25 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean</artifactId> <artifactId>ebean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId> <artifactId>ebean-core-type</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -125,13 +125,19 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId> <artifactId>ebean-jackson-mapper</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-avajejsonb-mapper</artifactId>
<version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId> <artifactId>ebean-ddl-generator</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -155,37 +161,37 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId> <artifactId>querybean-generator</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId> <artifactId>kotlin-querybean-generator</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId> <artifactId>ebean-test</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId> <artifactId>ebean-redis</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-spring-txn</artifactId> <artifactId>ebean-spring-txn</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<!-- platforms --> <!-- platforms -->
@@ -193,91 +199,91 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-clickhouse</artifactId> <artifactId>ebean-clickhouse</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-db2</artifactId> <artifactId>ebean-db2</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-h2</artifactId> <artifactId>ebean-h2</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-hana</artifactId> <artifactId>ebean-hana</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-mariadb</artifactId> <artifactId>ebean-mariadb</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-mysql</artifactId> <artifactId>ebean-mysql</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-nuodb</artifactId> <artifactId>ebean-nuodb</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-oracle</artifactId> <artifactId>ebean-oracle</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-postgres</artifactId> <artifactId>ebean-postgres</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId> <artifactId>ebean-postgis</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-postgis-types</artifactId> <artifactId>ebean-postgis-types</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-pgvector</artifactId> <artifactId>ebean-pgvector</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-pgvector-types</artifactId> <artifactId>ebean-pgvector-types</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-sqlite</artifactId> <artifactId>ebean-sqlite</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-sqlserver</artifactId> <artifactId>ebean-sqlserver</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+2 -2
View File
@@ -3,7 +3,7 @@
<parent> <parent>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<artifactId>ebean-core-json</artifactId> <artifactId>ebean-core-json</artifactId>
<name>ebean-core-json</name> <name>ebean-core-json</name>
@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<artifactId>ebean-core-type</artifactId> <artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -29,7 +29,7 @@
<dependency> <dependency>
<groupId>org.postgresql</groupId> <groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId> <artifactId>postgresql</artifactId>
<version>42.7.11</version> <version>42.7.12</version>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
@@ -1,14 +1,19 @@
package io.ebean.jackson.mapper; package io.ebean.core.type;
/** /**
* Helper that removes whitespace from JSON. Used to normalise Postgres JSONB content. * Helper that removes whitespace from JSON content.
* <p>
* Used to normalise PostgreSQL JSONB content before it is retained for mutation detection.
*/ */
final class JsonTrim { public final class JsonTrim {
private JsonTrim() {
}
/** /**
* Return JSON with whitespace trimmed. * Return JSON with whitespace trimmed.
*/ */
static String trim(String json) { public static String trim(String json) {
if (json == null) { if (json == null) {
return null; return null;
} }
@@ -18,7 +23,7 @@ final class JsonTrim {
boolean quoted = false; boolean quoted = false;
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
char c = json.charAt(i); char c = json.charAt(i);
if (c == '\"') { if (c == '"') {
if (!escaped) { if (!escaped) {
quoted = !quoted; quoted = !quoted;
} else { } else {
+7 -7
View File
@@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
@@ -22,13 +22,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core-json</artifactId> <artifactId>ebean-core-json</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -52,7 +52,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId> <artifactId>ebean-core-type</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -157,21 +157,21 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId> <artifactId>ebean-platform-h2</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId> <artifactId>ebean-platform-postgres</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId> <artifactId>ebean-platform-sqlserver</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -80,6 +80,10 @@ public final class DtoMappingRequest {
return name; return name;
} }
public String dbName() {
return server.name();
}
public String hash() { public String hash() {
return hash; return hash;
} }
@@ -15,6 +15,7 @@ abstract class DtoQueryPlanBase implements DtoQueryPlan, SpiQueryPlan {
private final QueryPlanMetric planMetric; private final QueryPlanMetric planMetric;
private final TimedMetric metric; private final TimedMetric metric;
private final Class<?> beanType; private final Class<?> beanType;
private final String dbName;
private final String name; private final String name;
private final String hash; private final String hash;
private final String sql; private final String sql;
@@ -26,6 +27,7 @@ abstract class DtoQueryPlanBase implements DtoQueryPlan, SpiQueryPlan {
this.planMetric = request.createMetric(); this.planMetric = request.createMetric();
this.metric = planMetric.metric(); this.metric = planMetric.metric();
this.beanType = request.type(); this.beanType = request.type();
this.dbName = request.dbName();
this.name = request.name(); this.name = request.name();
this.hash = request.hash(); this.hash = request.hash();
this.sql = request.sql(); this.sql = request.sql();
@@ -91,6 +93,6 @@ abstract class DtoQueryPlanBase implements DtoQueryPlan, SpiQueryPlan {
@Override @Override
public SpiDbQueryPlan createMeta(String bind, String planString) { public SpiDbQueryPlan createMeta(String bind, String planString) {
return new DQueryPlanOutput(beanType, name, hash, sql, profileLocation, bind, planString); return new DQueryPlanOutput(beanType, dbName, name, hash, sql, profileLocation, bind, planString);
} }
} }
@@ -4,15 +4,13 @@ import io.ebean.meta.MetricVisitor;
import io.ebean.metric.CountMetric; import io.ebean.metric.CountMetric;
import io.ebean.metric.CountMetricStats; import io.ebean.metric.CountMetricStats;
import java.util.concurrent.atomic.LongAdder;
/** /**
* Used to collect counter metrics. * Used to collect counter metrics.
*/ */
final class DCountMetric implements CountMetric { final class DCountMetric implements CountMetric {
private final String name; private final String name;
private final LongAdder count = new LongAdder(); private final ValueAdder count = new ValueAdder();
private String reportName; private String reportName;
DCountMetric(String name) { DCountMetric(String name) {
@@ -29,12 +27,12 @@ final class DCountMetric implements CountMetric {
@Override @Override
public void increment() { public void increment() {
count.increment(); count.add(1);
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
return count.sum() == 0; return count.currentValue() == 0;
} }
@Override @Override
@@ -44,12 +42,12 @@ final class DCountMetric implements CountMetric {
@Override @Override
public long get(boolean reset) { public long get(boolean reset) {
return reset ? count.sumThenReset() : count.sum(); return count.get(reset);
} }
@Override @Override
public void visit(MetricVisitor visitor) { public void visit(MetricVisitor visitor) {
long val = visitor.reset() ? count.sumThenReset() : count.sum(); long val = count.get(visitor.reset());
if (val > 0) { if (val > 0) {
final String name = reportName != null ? reportName : reportName(visitor); final String name = reportName != null ? reportName : reportName(visitor);
visitor.visitCount(new DCountMetricStats(name, val)); visitor.visitCount(new DCountMetricStats(name, val));
@@ -4,7 +4,6 @@ import io.ebean.meta.MetricVisitor;
import io.ebean.metric.TimedMetric; import io.ebean.metric.TimedMetric;
import java.util.concurrent.atomic.LongAccumulator; import java.util.concurrent.atomic.LongAccumulator;
import java.util.concurrent.atomic.LongAdder;
/** /**
* Used to collect timed execution statistics. * Used to collect timed execution statistics.
@@ -15,8 +14,8 @@ import java.util.concurrent.atomic.LongAdder;
final class DTimedMetric implements TimedMetric { final class DTimedMetric implements TimedMetric {
private final String name; private final String name;
private final LongAdder count = new LongAdder(); private final ValueAdder count = new ValueAdder();
private final LongAdder total = new LongAdder(); private final ValueAdder total = new ValueAdder();
private final LongAccumulator max = new LongAccumulator(Math::max, 0); private final LongAccumulator max = new LongAccumulator(Math::max, 0);
private boolean collected; private boolean collected;
private String reportName; private String reportName;
@@ -43,14 +42,14 @@ final class DTimedMetric implements TimedMetric {
@Override @Override
public void add(long value) { public void add(long value) {
count.increment(); count.add(1);
total.add(value); total.add(value);
max.accumulate(value); max.accumulate(value);
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
return count.sum() == 0; return count.currentValue() == 0;
} }
@Override @Override
@@ -62,16 +61,17 @@ final class DTimedMetric implements TimedMetric {
@Override @Override
public void visit(MetricVisitor visitor) { public void visit(MetricVisitor visitor) {
final long countSum = visitor.reset() ? count.sumThenReset() : count.sum(); final boolean reset = visitor.reset();
final long countSum = count.get(reset);
if (countSum > 0) { if (countSum > 0) {
final String name = reportName != null ? reportName : reportName(visitor); final String name = reportName != null ? reportName : reportName(visitor);
visitor.visitTimed(stats(visitor.reset(), name, countSum)); visitor.visitTimed(stats(reset, name, countSum));
} }
} }
@Override @Override
public DTimeMetricStats collect(boolean reset) { public DTimeMetricStats collect(boolean reset) {
final long countSum = reset ? count.sumThenReset() : count.sum(); final long countSum = count.get(reset);
if (countSum == 0) { if (countSum == 0) {
return null; return null;
} else { } else {
@@ -84,7 +84,7 @@ final class DTimedMetric implements TimedMetric {
*/ */
private DTimeMetricStats stats(boolean reset, String name, long countSum) { private DTimeMetricStats stats(boolean reset, String name, long countSum) {
try { try {
final long totalSum = reset ? total.sumThenReset() : total.sum(); final long totalSum = total.get(reset);
return new DTimeMetricStats(name, collected, countSum, totalSum, max.getThenReset()); return new DTimeMetricStats(name, collected, countSum, totalSum, max.getThenReset());
} finally { } finally {
collected = true; collected = true;
@@ -0,0 +1,36 @@
package io.ebeaninternal.server.profile;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
/**
* Accumulates a value while supporting cumulative and reset-based delta reads.
*/
final class ValueAdder {
private final LongAdder value = new LongAdder();
private final AtomicLong previousValue = new AtomicLong();
void add(long amount) {
value.add(amount);
}
long get(boolean reset) {
long currentValue = value.sum();
if (!reset) {
return currentValue;
}
long previous = previousValue.getAndSet(currentValue);
return currentValue >= previous ? currentValue - previous : currentValue;
}
void reset() {
value.reset();
previousValue.set(0);
}
long currentValue() {
return value.sum();
}
}
@@ -274,7 +274,7 @@ public class CQueryPlan implements SpiQueryPlan {
@Override @Override
public final DQueryPlanOutput createMeta(String bind, String planString) { public final DQueryPlanOutput createMeta(String bind, String planString) {
return new DQueryPlanOutput(beanType(), name, hash, sql, profileLocation, bind, planString); return new DQueryPlanOutput(beanType(), server.name(), name, hash, sql, profileLocation, bind, planString);
} }
public DataReader createDataReader(boolean unmodifiable, ResultSet rset) { public DataReader createDataReader(boolean unmodifiable, ResultSet rset) {
@@ -12,6 +12,7 @@ import java.time.Instant;
public final class DQueryPlanOutput implements MetaQueryPlan, SpiDbQueryPlan { public final class DQueryPlanOutput implements MetaQueryPlan, SpiDbQueryPlan {
private final Class<?> beanType; private final Class<?> beanType;
private final String dbName;
private final String label; private final String label;
private final ProfileLocation profileLocation; private final ProfileLocation profileLocation;
@@ -25,8 +26,9 @@ public final class DQueryPlanOutput implements MetaQueryPlan, SpiDbQueryPlan {
private Instant whenCaptured; private Instant whenCaptured;
private Object tenantId; private Object tenantId;
public DQueryPlanOutput(Class<?> beanType, String label, String hash, String sql, ProfileLocation profileLocation, String bind, String plan) { public DQueryPlanOutput(Class<?> beanType, String dbName, String label, String hash, String sql, ProfileLocation profileLocation, String bind, String plan) {
this.beanType = beanType; this.beanType = beanType;
this.dbName = dbName;
this.label = label; this.label = label;
this.hash = hash; this.hash = hash;
this.sql = sql; this.sql = sql;
@@ -35,6 +37,11 @@ public final class DQueryPlanOutput implements MetaQueryPlan, SpiDbQueryPlan {
this.plan = plan; this.plan = plan;
} }
@Override
public String dbName() {
return dbName;
}
@Override @Override
public String hash() { public String hash() {
return hash; return hash;
@@ -21,11 +21,13 @@ public final class SqlQueryPlan implements SpiQueryPlan {
private final String name; private final String name;
private final String hash; private final String hash;
private final String sql; private final String sql;
private final String dbName;
private final SpiQueryBindCapture bindCapture; private final SpiQueryBindCapture bindCapture;
SqlQueryPlan(SpiEbeanServer server, String name, String sql) { SqlQueryPlan(SpiEbeanServer server, String name, String sql) {
this.name = name; this.name = name;
this.sql = sql; this.sql = sql;
this.dbName = server.name();
this.hash = Md5.hash(sql, name); this.hash = Md5.hash(sql, name);
this.bindCapture = server.createQueryBindCapture(this); this.bindCapture = server.createQueryBindCapture(this);
} }
@@ -77,6 +79,6 @@ public final class SqlQueryPlan implements SpiQueryPlan {
@Override @Override
public SpiDbQueryPlan createMeta(String bind, String planString) { public SpiDbQueryPlan createMeta(String bind, String planString) {
return new DQueryPlanOutput(null, name, hash, sql, null, bind, planString); return new DQueryPlanOutput(null, dbName, name, hash, sql, null, bind, planString);
} }
} }
@@ -88,8 +88,8 @@ public final class DefaultTypeManager implements TypeManager {
this.databasePlatform = config.getDatabasePlatform(); this.databasePlatform = config.getDatabasePlatform();
this.postgres = isPostgresCompatible(config.getDatabasePlatform()); this.postgres = isPostgresCompatible(config.getDatabasePlatform());
this.objectMapperPresent = config.getClassLoadConfig().isJacksonObjectMapperPresent(); this.objectMapperPresent = config.getClassLoadConfig().isJacksonObjectMapperPresent();
this.objectMapper = (objectMapperPresent) ? initObjectMapper(config) : null; this.objectMapper = (objectMapperPresent) ? initObjectMapper(config) : config.getObjectMapper();
this.jsonManager = (objectMapperPresent) ? new TypeJsonManager(postgres, objectMapper, config.getJsonMutationDetection()) : null; this.jsonManager = new TypeJsonManager(postgres, objectMapper, config.getJsonMutationDetection());
this.extraTypeFactory = new DefaultTypeFactory(config); this.extraTypeFactory = new DefaultTypeFactory(config);
this.arrayTypeListFactory = arrayTypeListFactory(config.getDatabasePlatform()); this.arrayTypeListFactory = arrayTypeListFactory(config.getDatabasePlatform());
this.arrayTypeSetFactory = arrayTypeSetFactory(config.getDatabasePlatform()); this.arrayTypeSetFactory = arrayTypeSetFactory(config.getDatabasePlatform());
@@ -413,7 +413,7 @@ public final class DefaultTypeManager implements TypeManager {
private ScalarType<?> createJsonObjectMapperType(DeployProperty prop, int dbType, DocPropertyType docType) { private ScalarType<?> createJsonObjectMapperType(DeployProperty prop, int dbType, DocPropertyType docType) {
if (jsonMapper == null) { if (jsonMapper == null) {
throw new IllegalArgumentException("Unsupported @DbJson mapping - Missing dependency ebean-jackson-mapper? Jackson ObjectMapper not present for " + prop); throw new IllegalArgumentException("Unsupported @DbJson mapping - missing JSON mapper dependency for " + prop);
} }
if (MutationDetection.DEFAULT == prop.mutationDetection()) { if (MutationDetection.DEFAULT == prop.mutationDetection()) {
prop.setMutationDetection(jsonManager.mutationDetection()); prop.setMutationDetection(jsonManager.mutationDetection());
@@ -40,4 +40,19 @@ class DCountMetricTest {
assertThat(result2.get(0).count()).isEqualTo(12); assertThat(result2.get(0).count()).isEqualTo(12);
} }
} }
@Test
void cumulativeAndDeltaAreIndependent() {
DCountMetric counter = new DCountMetric("org.hello");
counter.add(7);
assertThat(counter.get(false)).isEqualTo(7);
assertThat(counter.get(false)).isEqualTo(7);
assertThat(counter.get(true)).isEqualTo(7);
counter.add(5);
assertThat(counter.get(false)).isEqualTo(12);
assertThat(counter.get(true)).isEqualTo(5);
assertThat(counter.get(true)).isEqualTo(0);
}
} }
@@ -116,4 +116,25 @@ public class DTimedMetricTest {
assertThat(stats.total()).isEqualTo(1470); assertThat(stats.total()).isEqualTo(1470);
assertThat(stats.max()).isEqualTo(160); assertThat(stats.max()).isEqualTo(160);
} }
@Test
void cumulativeAndDeltaAreIndependent() {
DTimedMetric metric = new DTimedMetric("org.timed");
metric.add(560);
metric.add(500);
DTimeMetricStats cumulative = metric.collect(false);
assertThat(cumulative.count()).isEqualTo(2);
assertThat(cumulative.total()).isEqualTo(1060);
metric.add(160);
DTimeMetricStats delta = metric.collect(true);
assertThat(delta.count()).isEqualTo(3);
assertThat(delta.total()).isEqualTo(1220);
cumulative = metric.collect(false);
assertThat(cumulative.count()).isEqualTo(3);
assertThat(cumulative.total()).isEqualTo(1220);
}
} }
+4 -4
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<name>ebean ddl generation</name> <name>ebean ddl generation</name>
@@ -28,14 +28,14 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId> <artifactId>ebean-core-type</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -65,7 +65,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId> <artifactId>ebean-platform-all</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
+2 -2
View File
@@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -15,7 +15,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId> <artifactId>ebean-core-type</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -1,6 +1,6 @@
package io.ebean.jackson.mapper; package io.ebean.jackson.mapper;
import io.ebean.core.type.JsonTrim;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
+4 -4
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<name>ebean net postgis types</name> <name>ebean net postgis types</name>
@@ -19,14 +19,14 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId> <artifactId>ebean-platform-postgres</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<!-- provided scope --> <!-- provided scope -->
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -54,7 +54,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId> <artifactId>ebean-test</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<artifactId>ebean-opentelemetry</artifactId> <artifactId>ebean-opentelemetry</artifactId>
@@ -28,7 +28,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -71,21 +71,21 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId> <artifactId>ebean-test</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId> <artifactId>querybean-generator</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
+4 -4
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<name>ebean pgvector types</name> <name>ebean pgvector types</name>
@@ -19,14 +19,14 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId> <artifactId>ebean-platform-postgres</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<!-- provided scope --> <!-- provided scope -->
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -54,7 +54,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId> <artifactId>ebean-test</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<name>ebean postgis types</name> <name>ebean postgis types</name>
@@ -19,14 +19,14 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId> <artifactId>ebean-platform-postgres</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<!-- provided scope --> <!-- provided scope -->
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -47,7 +47,7 @@
<dependency> <dependency>
<groupId>org.postgresql</groupId> <groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId> <artifactId>postgresql</artifactId>
<version>42.7.11</version> <version>42.7.12</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -62,7 +62,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId> <artifactId>ebean-test</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<name>ebean querybean</name> <name>ebean querybean</name>
@@ -17,7 +17,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -59,14 +59,14 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId> <artifactId>ebean-ddl-generator</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId> <artifactId>ebean-test</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -80,7 +80,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId> <artifactId>querybean-generator</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<artifactId>ebean-redis</artifactId> <artifactId>ebean-redis</artifactId>
@@ -29,35 +29,35 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId> <artifactId>ebean-test</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId> <artifactId>querybean-generator</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -3,7 +3,7 @@ ebean:
dumpMetricsOptions: sql,hash,loc dumpMetricsOptions: sql,hash,loc
test: test:
registerTestTenantProvider: false registerTestTenantProvider: false
redis: latest redis: 8.6.2
# shutdown: stop # stop | remove # shutdown: stop # stop | remove
platform: h2 # h2, postgres, mysql, oracle, sqlserver, sqlite platform: h2 # h2, postgres, mysql, oracle, sqlserver, sqlite
ddlMode: dropCreate # none | dropCreate | create | migration | createOnly | migrationDropCreate ddlMode: dropCreate # none | dropCreate | create | migration | createOnly | migrationDropCreate
+6 -6
View File
@@ -6,7 +6,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<artifactId>ebean-redisson</artifactId> <artifactId>ebean-redisson</artifactId>
@@ -29,35 +29,35 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId> <artifactId>ebean-test</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId> <artifactId>querybean-generator</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -10,13 +10,13 @@ import jakarta.persistence.Entity;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Cache(naturalKey = {"one", "two"}) @Cache(naturalKey = {"one", "two"})
@Entity @Entity
public class OtherOne extends EBase { public class FOtherOne extends EBase {
private final String one; private final String one;
private final String two; private final String two;
private String notes; private String notes;
public OtherOne(String one, String two, String notes) { public FOtherOne(String one, String two, String notes) {
this.one = one; this.one = one;
this.two = two; this.two = two;
this.notes = notes; this.notes = notes;
@@ -11,7 +11,7 @@ import java.time.LocalDate;
@Cache(enableQueryCache = true, nearCache = true, naturalKey = "name") @Cache(enableQueryCache = true, nearCache = true, naturalKey = "name")
@CacheBeanTuning(maxSecsToLive = 1) @CacheBeanTuning(maxSecsToLive = 1)
@Entity @Entity
public class Person extends EBase { public class FPerson extends EBase {
public enum Status { public enum Status {
NEW, NEW,
@@ -33,7 +33,7 @@ public class Person extends EBase {
*/ */
String key; String key;
public Person(String name) { public FPerson(String name) {
this.name = name; this.name = name;
this.status = Status.NEW; this.status = Status.NEW;
} }
@@ -7,12 +7,12 @@ import jakarta.persistence.Entity;
@Cache(naturalKey = "name") @Cache(naturalKey = "name")
@Entity @Entity
public class RCust extends EBase { public class FRCust extends EBase {
@Index(unique = true) @Index(unique = true)
String name; String name;
public RCust(String name) { public FRCust(String name) {
this.name = name; this.name = name;
} }
@@ -8,7 +8,7 @@ import jakarta.persistence.ManyToOne;
@Cache @Cache
@Entity @Entity
public class UChild extends Model { public class FUChild extends Model {
@Id @Id
long id; long id;
@@ -16,9 +16,9 @@ public class UChild extends Model {
String name; String name;
@ManyToOne @ManyToOne
final UParent parent; final FUParent parent;
public UChild(UParent parent, String name) { public FUChild(FUParent parent, String name) {
this.parent = parent; this.parent = parent;
this.name = name; this.name = name;
} }
@@ -15,7 +15,7 @@ import java.util.UUID;
@Cache(enableQueryCache = true) @Cache(enableQueryCache = true)
@CacheBeanTuning(maxSecsToLive = 1) @CacheBeanTuning(maxSecsToLive = 1)
@Entity @Entity
public class UParent extends Model { public class FUParent extends Model {
@Id @Id
private UUID id; private UUID id;
@@ -23,9 +23,9 @@ public class UParent extends Model {
private String name; private String name;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL) @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private final List<UChild> children = new ArrayList<>(); private final List<FUChild> children = new ArrayList<>();
public UParent(String name) { public FUParent(String name) {
this.name = name; this.name = name;
} }
@@ -45,7 +45,7 @@ public class UParent extends Model {
this.name = name; this.name = name;
} }
public List<UChild> children() { public List<FUChild> children() {
return children; return children;
} }
} }
@@ -9,7 +9,7 @@ import java.util.List;
@Cache @Cache
@Entity @Entity
public class TestOne extends Model { public class RTestOne extends Model {
@Id @Id
private String id; private String id;
@@ -18,9 +18,9 @@ public class TestOne extends Model {
private String otherUnique; private String otherUnique;
@OneToMany(mappedBy = "testOne", cascade = CascadeType.ALL, orphanRemoval = true) @OneToMany(mappedBy = "testOne", cascade = CascadeType.ALL, orphanRemoval = true)
private List<TestTwo> testTwos = new ArrayList<>(); private List<RTestTwo> testTwos = new ArrayList<>();
public TestOne(String id, String otherUnique) { public RTestOne(String id, String otherUnique) {
this.id = id; this.id = id;
this.otherUnique = otherUnique; this.otherUnique = otherUnique;
} }
@@ -37,11 +37,11 @@ public class TestOne extends Model {
this.otherUnique = otherUnique; this.otherUnique = otherUnique;
} }
public List<TestTwo> getTestTwos() { public List<RTestTwo> getTestTwos() {
return testTwos; return testTwos;
} }
public void setTestTwos(List<TestTwo> testTwos) { public void setTestTwos(List<RTestTwo> testTwos) {
this.testTwos = testTwos; this.testTwos = testTwos;
} }
} }
@@ -7,16 +7,16 @@ import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
@Entity @Entity
public class TestTwo extends Model { public class RTestTwo extends Model {
@Id @Id
private String id; private String id;
@ManyToOne @ManyToOne
@JoinColumn @JoinColumn
private TestOne testOne; private RTestOne testOne;
public TestTwo(String id) { public RTestTwo(String id) {
this.id = id; this.id = id;
} }
@@ -24,11 +24,11 @@ public class TestTwo extends Model {
return id; return id;
} }
public TestOne getTestOne() { public RTestOne getTestOne() {
return testOne; return testOne;
} }
public void setTestOne(TestOne testOne) { public void setTestOne(RTestOne testOne) {
this.testOne = testOne; this.testOne = testOne;
} }
} }
@@ -3,8 +3,8 @@ package org.integration;
import io.ebean.DB; import io.ebean.DB;
import io.ebean.Database; import io.ebean.Database;
import io.ebean.redisson.DuelCache; import io.ebean.redisson.DuelCache;
import org.domain.Person; import org.domain.FPerson;
import org.domain.query.QPerson; import org.domain.query.QFPerson;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -37,65 +37,65 @@ class ClusterTest {
@Test @Test
void testBothNear() throws InterruptedException { void testBothNear() throws InterruptedException {
new QPerson() new QFPerson()
.name.eq("Someone") .name.eq("Someone")
.delete(); .delete();
Person foo = new Person("Someone"); FPerson foo = new FPerson("Someone");
foo.save(); foo.save();
DB.cacheManager().clearAll(); DB.cacheManager().clearAll();
db.metaInfo().resetAllMetrics(); db.metaInfo().resetAllMetrics();
other.metaInfo().resetAllMetrics(); other.metaInfo().resetAllMetrics();
Person fooA = DB.find(Person.class, foo.getId()); FPerson fooA = DB.find(FPerson.class, foo.getId());
allowAsyncMessaging(); // allow time for background cache load allowAsyncMessaging(); // allow time for background cache load
Person fooB = other.find(Person.class, foo.getId()); FPerson fooB = other.find(FPerson.class, foo.getId());
DuelCache dualCacheA = db.cacheManager().beanCache(Person.class).unwrap(DuelCache.class); DuelCache dualCacheA = db.cacheManager().beanCache(FPerson.class).unwrap(DuelCache.class);
assertCounts(dualCacheA, 0, 1, 0, 1); assertCounts(dualCacheA, 0, 1, 0, 1);
fooA = DB.find(Person.class, foo.getId()); fooA = DB.find(FPerson.class, foo.getId());
assertCounts(dualCacheA, 1, 1, 0, 1); assertCounts(dualCacheA, 1, 1, 0, 1);
fooB = other.find(Person.class, foo.getId()); fooB = other.find(FPerson.class, foo.getId());
fooA = DB.find(Person.class, foo.getId()); fooA = DB.find(FPerson.class, foo.getId());
assertCounts(dualCacheA, 2, 1, 0, 1); assertCounts(dualCacheA, 2, 1, 0, 1);
fooB = other.find(Person.class, foo.getId()); fooB = other.find(FPerson.class, foo.getId());
DuelCache dualCacheB = other.cacheManager().beanCache(Person.class).unwrap(DuelCache.class); DuelCache dualCacheB = other.cacheManager().beanCache(FPerson.class).unwrap(DuelCache.class);
assertCounts(dualCacheB, 2, 1, 1, 0); assertCounts(dualCacheB, 2, 1, 1, 0);
} }
@Test @Test
void test() throws InterruptedException { void test() throws InterruptedException {
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
Person foo = new Person("name " + i); FPerson foo = new FPerson("name " + i);
foo.save(); foo.save();
} }
other.cacheManager().clearAll(); other.cacheManager().clearAll();
other.metaInfo().resetAllMetrics(); other.metaInfo().resetAllMetrics();
DuelCache dualCache = other.cacheManager().beanCache(Person.class).unwrap(DuelCache.class); DuelCache dualCache = other.cacheManager().beanCache(FPerson.class).unwrap(DuelCache.class);
Person foo0 = other.find(Person.class, 1); FPerson foo0 = other.find(FPerson.class, 1);
assertCounts(dualCache, 0, 1, 0, 1); assertCounts(dualCache, 0, 1, 0, 1);
other.find(Person.class, 1); other.find(FPerson.class, 1);
assertCounts(dualCache, 1, 1, 0, 1); assertCounts(dualCache, 1, 1, 0, 1);
other.find(Person.class, 1); other.find(FPerson.class, 1);
assertCounts(dualCache, 2, 1, 0, 1); assertCounts(dualCache, 2, 1, 0, 1);
other.find(Person.class, 1); other.find(FPerson.class, 1);
assertCounts(dualCache, 3, 1, 0, 1); assertCounts(dualCache, 3, 1, 0, 1);
other.find(Person.class, 2); other.find(FPerson.class, 2);
assertCounts(dualCache, 3, 2, 0, 2); assertCounts(dualCache, 3, 2, 0, 2);
foo0.setName("name2"); foo0.setName("name2");
foo0.save(); foo0.save();
allowAsyncMessaging(); allowAsyncMessaging();
Person foo3 = other.find(Person.class, 1); FPerson foo3 = other.find(FPerson.class, 1);
assertThat(foo3.getName()).isEqualTo("name2"); assertThat(foo3.getName()).isEqualTo("name2");
assertCounts(dualCache, 3, 3, 1, 2); assertCounts(dualCache, 3, 3, 1, 2);
@@ -103,7 +103,7 @@ class ClusterTest {
foo0.save(); foo0.save();
allowAsyncMessaging(); allowAsyncMessaging();
foo3 = other.find(Person.class, 1); foo3 = other.find(FPerson.class, 1);
assertThat(foo3.getName()).isEqualTo("name3"); assertThat(foo3.getName()).isEqualTo("name3");
assertCounts(dualCache, 3, 4, 2, 2); assertCounts(dualCache, 3, 4, 2, 2);
} }
@@ -5,10 +5,10 @@ import io.ebean.cache.ServerCache;
import io.ebean.cache.ServerCacheStatistics; import io.ebean.cache.ServerCacheStatistics;
import io.ebeaninternal.server.cache.CachedBeanData; import io.ebeaninternal.server.cache.CachedBeanData;
import org.domain.*; import org.domain.*;
import org.domain.query.QOtherOne; import org.domain.query.QFOtherOne;
import org.domain.query.QPerson; import org.domain.query.QFPerson;
import org.domain.query.QRCust; import org.domain.query.QFRCust;
import org.domain.test.TestOne; import org.domain.test.RTestOne;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.time.LocalDate; import java.time.LocalDate;
@@ -21,8 +21,8 @@ import static org.assertj.core.api.Assertions.assertThat;
class IntegrationTest { class IntegrationTest {
private static OtherOne findOther(String a, String b) { private static FOtherOne findOther(String a, String b) {
return new QOtherOne() return new QFOtherOne()
.one.eq(a) .one.eq(a)
.two.eq(b) .two.eq(b)
.findOne(); .findOne();
@@ -30,22 +30,22 @@ class IntegrationTest {
@Test @Test
void uuid_getPut() { void uuid_getPut() {
UParent b0 = new UParent("b0"); FUParent b0 = new FUParent("b0");
b0.children().add(new UChild(b0, "b0c0")); b0.children().add(new FUChild(b0, "b0c0"));
b0.children().add(new UChild(b0, "b0c1")); b0.children().add(new FUChild(b0, "b0c1"));
b0.save(); b0.save();
ServerCache beanCache = DB.cacheManager().beanCache(UParent.class); ServerCache beanCache = DB.cacheManager().beanCache(FUParent.class);
beanCache.clear(); beanCache.clear();
beanCache.statistics(true); beanCache.statistics(true);
UParent found0 = DB.find(UParent.class, b0.id()); FUParent found0 = DB.find(FUParent.class, b0.id());
assertThat(found0.name()).isEqualTo("b0"); assertThat(found0.name()).isEqualTo("b0");
List<UChild> children = found0.children(); List<FUChild> children = found0.children();
assertThat(children).hasSize(2); assertThat(children).hasSize(2);
UParent found1 = DB.find(UParent.class, b0.id()); FUParent found1 = DB.find(FUParent.class, b0.id());
assertThat(found1.name()).isEqualTo("b0"); assertThat(found1.name()).isEqualTo("b0");
DB.delete(found1); DB.delete(found1);
@@ -57,13 +57,13 @@ class IntegrationTest {
@Test @Test
void mget_when_emptyCollectionOfIds() { void mget_when_emptyCollectionOfIds() {
List<RCust> f0 = new QRCust() List<FRCust> f0 = new QFRCust()
.setIdIn(Collections.emptyList()) .setIdIn(Collections.emptyList())
.findList(); .findList();
assertThat(f0).isEmpty(); assertThat(f0).isEmpty();
List<RCust> f1 = new QRCust() List<FRCust> f1 = new QFRCust()
.id.in(Collections.emptyList()) .id.in(Collections.emptyList())
.findList(); .findList();
@@ -73,18 +73,18 @@ class IntegrationTest {
@Test @Test
void mput_via_setIdIn() throws InterruptedException { void mput_via_setIdIn() throws InterruptedException {
ServerCache beanCache = DB.cacheManager().beanCache(RCust.class); ServerCache beanCache = DB.cacheManager().beanCache(FRCust.class);
beanCache.clear(); beanCache.clear();
beanCache.statistics(true); beanCache.statistics(true);
List<RCust> people = new ArrayList<>(); List<FRCust> people = new ArrayList<>();
for (String name : new String[]{"mp0", "mp1", "mp2"}) { for (String name : new String[]{"mp0", "mp1", "mp2"}) {
people.add(new RCust(name)); people.add(new FRCust(name));
} }
DB.saveAll(people); DB.saveAll(people);
List<Long> ids = people.stream().map(RCust::getId).collect(Collectors.toList()); List<Long> ids = people.stream().map(FRCust::getId).collect(Collectors.toList());
List<RCust> f0 = new QRCust() List<FRCust> f0 = new QFRCust()
.setIdIn(ids) // using collection argument .setIdIn(ids) // using collection argument
.findList(); .findList();
@@ -95,7 +95,7 @@ class IntegrationTest {
Thread.sleep(5); Thread.sleep(5);
// we will hit the cache this time // we will hit the cache this time
List<RCust> f1 = new QRCust() List<FRCust> f1 = new QFRCust()
.setIdIn(ids.toArray()) // using varargs argument .setIdIn(ids.toArray()) // using varargs argument
.findList(); .findList();
@@ -104,7 +104,7 @@ class IntegrationTest {
assertThat(stats1.getHitCount()).isEqualTo(3); assertThat(stats1.getHitCount()).isEqualTo(3);
// we will hit the cache again // we will hit the cache again
List<RCust> f2 = new QRCust() List<FRCust> f2 = new QFRCust()
.setIdIn(ids) // using collection argument .setIdIn(ids) // using collection argument
.findList(); .findList();
assertThat(f2).hasSize(3); assertThat(f2).hasSize(3);
@@ -115,18 +115,18 @@ class IntegrationTest {
@Test @Test
void mput_via_propertyInExpression() throws InterruptedException { void mput_via_propertyInExpression() throws InterruptedException {
ServerCache beanCache = DB.cacheManager().beanCache(RCust.class); ServerCache beanCache = DB.cacheManager().beanCache(FRCust.class);
beanCache.clear(); beanCache.clear();
beanCache.statistics(true); beanCache.statistics(true);
List<RCust> people = new ArrayList<>(); List<FRCust> people = new ArrayList<>();
for (String name : new String[]{"mpx0", "mpx1", "mpx2"}) { for (String name : new String[]{"mpx0", "mpx1", "mpx2"}) {
people.add(new RCust(name)); people.add(new FRCust(name));
} }
DB.saveAll(people); DB.saveAll(people);
List<Long> ids = people.stream().map(RCust::getId).collect(Collectors.toList()); List<Long> ids = people.stream().map(FRCust::getId).collect(Collectors.toList());
List<RCust> f0 = new QRCust() List<FRCust> f0 = new QFRCust()
.id.in(ids) .id.in(ids)
.findList(); .findList();
@@ -137,7 +137,7 @@ class IntegrationTest {
Thread.sleep(5); Thread.sleep(5);
// we will hit the cache this time // we will hit the cache this time
List<RCust> f1 = new QRCust() List<FRCust> f1 = new QFRCust()
.id.in(ids) .id.in(ids)
.findList(); .findList();
@@ -146,7 +146,7 @@ class IntegrationTest {
assertThat(stats1.getHitCount()).isEqualTo(3); assertThat(stats1.getHitCount()).isEqualTo(3);
// we will hit the cache again // we will hit the cache again
List<RCust> f2 = new QRCust() List<FRCust> f2 = new QFRCust()
.id.isIn(ids) .id.isIn(ids)
.findList(); .findList();
assertThat(f2).hasSize(3); assertThat(f2).hasSize(3);
@@ -156,18 +156,18 @@ class IntegrationTest {
@Test @Test
void testOtherOne() { void testOtherOne() {
DB.save(new OtherOne("A", "B", "ab")); DB.save(new FOtherOne("A", "B", "ab"));
DB.save(new OtherOne("A", "C", "ac")); DB.save(new FOtherOne("A", "C", "ac"));
DB.save(new OtherOne("B", "B", "bb")); DB.save(new FOtherOne("B", "B", "bb"));
ServerCache nkeyCache = DB.cacheManager().naturalKeyCache(OtherOne.class); ServerCache nkeyCache = DB.cacheManager().naturalKeyCache(FOtherOne.class);
nkeyCache.clear(); nkeyCache.clear();
nkeyCache.statistics(true); nkeyCache.statistics(true);
OtherOne ab0 = findOther("A", "B"); FOtherOne ab0 = findOther("A", "B");
OtherOne ab1 = findOther("A", "B"); FOtherOne ab1 = findOther("A", "B");
OtherOne ab2 = findOther("A", "B"); FOtherOne ab2 = findOther("A", "B");
OtherOne bb = findOther("B", "B"); FOtherOne bb = findOther("B", "B");
assertThat(ab0).isNotNull(); assertThat(ab0).isNotNull();
assertThat(ab1).isNotNull(); assertThat(ab1).isNotNull();
@@ -183,21 +183,21 @@ class IntegrationTest {
insertSomePeople(); insertSomePeople();
Person fiona = findByName("Fiona"); FPerson fiona = findByName("Fiona");
fiona.setName("Fortuna"); fiona.setName("Fortuna");
fiona.setLocalDate(LocalDate.now()); fiona.setLocalDate(LocalDate.now());
fiona.update(); fiona.update();
Thread.sleep(100); Thread.sleep(100);
Person one = findById(1); FPerson one = findById(1);
assertThat(one).isNotNull(); assertThat(one).isNotNull();
for (int i = 1; i < 4; i++) { for (int i = 1; i < 4; i++) {
System.out.println("hit " + findById(i)); System.out.println("hit " + findById(i));
} }
List<Person> one2 = nameStartsWith("fo"); List<FPerson> one2 = nameStartsWith("fo");
assertThat(one2).hasSize(1); assertThat(one2).hasSize(1);
one2 = nameStartsWith("j"); one2 = nameStartsWith("j");
@@ -207,7 +207,7 @@ class IntegrationTest {
assertThat(one2).hasSize(2); assertThat(one2).hasSize(2);
List<Person> byNames = findByNames("Jack", "Rob"); List<FPerson> byNames = findByNames("Jack", "Rob");
assertThat(byNames).hasSize(2); assertThat(byNames).hasSize(2);
byNames = findByNames("Jack", "Rob", "Moby"); byNames = findByNames("Jack", "Rob", "Moby");
@@ -228,40 +228,40 @@ class IntegrationTest {
System.out.println("one2 " + one2); System.out.println("one2 " + one2);
DB.cacheManager().clear(Person.class); DB.cacheManager().clear(FPerson.class);
System.out.println("done"); System.out.println("done");
} }
private void insertSomePeople() { private void insertSomePeople() {
List<Person> people = new ArrayList<>(); List<FPerson> people = new ArrayList<>();
for (String name : new String[]{"Jack", "John", "Rob", "Moby", "Fiona"}) { for (String name : new String[]{"Jack", "John", "Rob", "Moby", "Fiona"}) {
people.add(new Person(name)); people.add(new FPerson(name));
} }
DB.saveAll(people); DB.saveAll(people);
} }
private Person findByName(String name) { private FPerson findByName(String name) {
return new QPerson() return new QFPerson()
.name.eq(name) .name.eq(name)
.findOne(); .findOne();
} }
private List<Person> findByNames(String... names) { private List<FPerson> findByNames(String... names) {
return new QPerson() return new QFPerson()
.name.in(names) .name.in(names)
.setUseCache(true) .setUseCache(true)
.findList(); .findList();
} }
private Person findById(int id) { private FPerson findById(int id) {
return new QPerson() return new QFPerson()
.id.eq(id) .id.eq(id)
.findOne(); .findOne();
} }
private List<Person> nameStartsWith(String pattern) { private List<FPerson> nameStartsWith(String pattern) {
return new QPerson() return new QFPerson()
.name.istartsWith(pattern) .name.istartsWith(pattern)
.setUseQueryCache(true) .setUseQueryCache(true)
.findList(); .findList();
@@ -273,15 +273,15 @@ class IntegrationTest {
*/ */
@Test @Test
void versionGated_newerCached_staleWriteIsIgnored() throws InterruptedException { void versionGated_newerCached_staleWriteIsIgnored() throws InterruptedException {
ServerCache beanCache = DB.cacheManager().beanCache(RCust.class); ServerCache beanCache = DB.cacheManager().beanCache(FRCust.class);
beanCache.clear(); beanCache.clear();
RCust cust = new RCust("stale-test-orig"); FRCust cust = new FRCust("stale-test-orig");
DB.save(cust); DB.save(cust);
long id = cust.getId(); long id = cust.getId();
// prime cache at version 1 // prime cache at version 1
DB.find(RCust.class, id); DB.find(FRCust.class, id);
Thread.sleep(150); Thread.sleep(150);
Object staleV1 = beanCache.get(id); Object staleV1 = beanCache.get(id);
assertThat(staleV1).isNotNull(); assertThat(staleV1).isNotNull();
@@ -289,7 +289,7 @@ class IntegrationTest {
// update to version 2; ensure v2 is in cache // update to version 2; ensure v2 is in cache
cust.setName("stale-test-updated"); cust.setName("stale-test-updated");
DB.save(cust); DB.save(cust);
DB.find(RCust.class, id); DB.find(FRCust.class, id);
Thread.sleep(150); Thread.sleep(150);
// stale write attempt: v2 is cached, v1 should be rejected // stale write attempt: v2 is cached, v1 should be rejected
@@ -302,7 +302,7 @@ class IntegrationTest {
assertThat(((CachedBeanData) staleV2).getVersion()).isEqualTo(2L); assertThat(((CachedBeanData) staleV2).getVersion()).isEqualTo(2L);
beanCache.statistics(true); beanCache.statistics(true);
RCust found = DB.find(RCust.class, id); FRCust found = DB.find(FRCust.class, id);
ServerCacheStatistics stats = beanCache.statistics(true); ServerCacheStatistics stats = beanCache.statistics(true);
assertThat(stats.getHitCount()).isEqualTo(1); assertThat(stats.getHitCount()).isEqualTo(1);
assertThat(found.getVersion()).isEqualTo(2L); assertThat(found.getVersion()).isEqualTo(2L);
@@ -316,14 +316,14 @@ class IntegrationTest {
*/ */
@Test @Test
void zeroVersion_equalVersion_staleWriteIsNotBlocked() throws InterruptedException { void zeroVersion_equalVersion_staleWriteIsNotBlocked() throws InterruptedException {
ServerCache beanCache = DB.cacheManager().beanCache(TestOne.class); ServerCache beanCache = DB.cacheManager().beanCache(RTestOne.class);
beanCache.clear(); beanCache.clear();
TestOne t1 = new TestOne("zvw-test", "unique-a"); RTestOne t1 = new RTestOne("zvw-test", "unique-a");
DB.save(t1); DB.save(t1);
// prime cache at version 0 (no @Version field) // prime cache at version 0 (no @Version field)
DB.find(TestOne.class, "zvw-test"); DB.find(RTestOne.class, "zvw-test");
Thread.sleep(150); Thread.sleep(150);
Object staleV0 = beanCache.get("zvw-test"); Object staleV0 = beanCache.get("zvw-test");
assertThat(staleV0).isNotNull(); assertThat(staleV0).isNotNull();
@@ -331,7 +331,7 @@ class IntegrationTest {
// update; ensure new v0 is in cache // update; ensure new v0 is in cache
t1.setOtherUnique("unique-b"); t1.setOtherUnique("unique-b");
DB.save(t1); DB.save(t1);
DB.find(TestOne.class, "zvw-test"); DB.find(RTestOne.class, "zvw-test");
Thread.sleep(150); Thread.sleep(150);
// stale write: v0 in cache, incoming v0 — must NOT be blocked (0 > 0 is false) // stale write: v0 in cache, incoming v0 — must NOT be blocked (0 > 0 is false)
@@ -339,7 +339,7 @@ class IntegrationTest {
// stale data should now be in cache (unlike the versioned case above) // stale data should now be in cache (unlike the versioned case above)
beanCache.statistics(true); beanCache.statistics(true);
TestOne found = DB.find(TestOne.class, "zvw-test"); RTestOne found = DB.find(RTestOne.class, "zvw-test");
ServerCacheStatistics stats = beanCache.statistics(true); ServerCacheStatistics stats = beanCache.statistics(true);
assertThat(stats.getHitCount()).isEqualTo(1); assertThat(stats.getHitCount()).isEqualTo(1);
assertThat(found.getOtherUnique()).isEqualTo("unique-a"); assertThat(found.getOtherUnique()).isEqualTo("unique-a");
@@ -4,8 +4,7 @@ import io.ebean.DB;
import io.ebean.Database; import io.ebean.Database;
import io.ebean.cache.ServerCache; import io.ebean.cache.ServerCache;
import io.ebean.cache.ServerCacheStatistics; import io.ebean.cache.ServerCacheStatistics;
import org.domain.RCust; import org.domain.FRCust;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.ArrayList; import java.util.ArrayList;
@@ -36,27 +35,27 @@ class RedissonTenantAwareCacheTest {
void singleBean_tenantA_hits_tenantB_misses() { void singleBean_tenantA_hits_tenantB_misses() {
Database db = buildTenantDb(); Database db = buildTenantDb();
try { try {
RCust cust = new RCust("t-single-iso"); FRCust cust = new FRCust("t-single-iso");
DB.save(cust); DB.save(cust);
long id = cust.getId(); long id = cust.getId();
ServerCache beanCache = db.cacheManager().beanCache(RCust.class); ServerCache beanCache = db.cacheManager().beanCache(FRCust.class);
beanCache.clear(); beanCache.clear();
// Tenant A: first load – goes to DB // Tenant A: first load – goes to DB
TENANT.set("tenantA"); TENANT.set("tenantA");
beanCache.statistics(true); // reset counters beanCache.statistics(true); // reset counters
assertThat(db.find(RCust.class, id)).isNotNull(); assertThat(db.find(FRCust.class, id)).isNotNull();
assertThat(Objects.requireNonNull(beanCache.statistics(true)).getMissCount()).isEqualTo(1); assertThat(Objects.requireNonNull(beanCache.statistics(true)).getMissCount()).isEqualTo(1);
// Tenant A: second load – must hit cache // Tenant A: second load – must hit cache
assertThat(db.find(RCust.class, id)).isNotNull(); assertThat(db.find(FRCust.class, id)).isNotNull();
assertThat(Objects.requireNonNull(beanCache.statistics(true)).getHitCount()).isEqualTo(1); assertThat(Objects.requireNonNull(beanCache.statistics(true)).getHitCount()).isEqualTo(1);
// Tenant B: same ID, different tenant key – must miss // Tenant B: same ID, different tenant key – must miss
TENANT.set("tenantB"); TENANT.set("tenantB");
beanCache.statistics(true); // reset counters beanCache.statistics(true); // reset counters
assertThat(db.find(RCust.class, id)).isNotNull(); assertThat(db.find(FRCust.class, id)).isNotNull();
ServerCacheStatistics statsB = beanCache.statistics(true); ServerCacheStatistics statsB = beanCache.statistics(true);
assertNotNull(statsB); assertNotNull(statsB);
assertThat(statsB.getHitCount()).isEqualTo(0); assertThat(statsB.getHitCount()).isEqualTo(0);
@@ -72,26 +71,26 @@ class RedissonTenantAwareCacheTest {
void getAll_tenantA_hits_tenantB_misses() throws InterruptedException { void getAll_tenantA_hits_tenantB_misses() throws InterruptedException {
Database db = buildTenantDb(); Database db = buildTenantDb();
try { try {
List<RCust> custs = new ArrayList<>(); List<FRCust> custs = new ArrayList<>();
for (String n : new String[]{"tga0", "tga1", "tga2"}) { for (String n : new String[]{"tga0", "tga1", "tga2"}) {
custs.add(new RCust(n)); custs.add(new FRCust(n));
} }
DB.saveAll(custs); DB.saveAll(custs);
List<Long> ids = custs.stream().map(RCust::getId).collect(Collectors.toList()); List<Long> ids = custs.stream().map(FRCust::getId).collect(Collectors.toList());
ServerCache beanCache = db.cacheManager().beanCache(RCust.class); ServerCache beanCache = db.cacheManager().beanCache(FRCust.class);
beanCache.clear(); beanCache.clear();
// Tenant A: first batch load – DB misses, cache populated // Tenant A: first batch load – DB misses, cache populated
TENANT.set("tenantA"); TENANT.set("tenantA");
List<RCust> listA0 = db.find(RCust.class).where().idIn(ids).setUseCache(true).findList(); List<FRCust> listA0 = db.find(FRCust.class).where().idIn(ids).setUseCache(true).findList();
assertThat(listA0).hasSize(3); assertThat(listA0).hasSize(3);
Thread.sleep(10); Thread.sleep(10);
// Tenant A: second batch load – all 3 must be cache hits // Tenant A: second batch load – all 3 must be cache hits
beanCache.statistics(true); // reset beanCache.statistics(true); // reset
List<RCust> listA1 = db.find(RCust.class).where().idIn(ids).setUseCache(true).findList(); List<FRCust> listA1 = db.find(FRCust.class).where().idIn(ids).setUseCache(true).findList();
assertThat(listA1).hasSize(3); assertThat(listA1).hasSize(3);
ServerCacheStatistics statsA = beanCache.statistics(true); ServerCacheStatistics statsA = beanCache.statistics(true);
assertNotNull(statsA); assertNotNull(statsA);
@@ -101,7 +100,7 @@ class RedissonTenantAwareCacheTest {
// Tenant B: same IDs, different tenant – all 3 must miss // Tenant B: same IDs, different tenant – all 3 must miss
TENANT.set("tenantB"); TENANT.set("tenantB");
beanCache.statistics(true); // reset beanCache.statistics(true); // reset
List<RCust> listB = db.find(RCust.class).where().idIn(ids).setUseCache(true).findList(); List<FRCust> listB = db.find(FRCust.class).where().idIn(ids).setUseCache(true).findList();
assertThat(listB).hasSize(3); assertThat(listB).hasSize(3);
ServerCacheStatistics statsB = beanCache.statistics(true); ServerCacheStatistics statsB = beanCache.statistics(true);
assertNotNull(statsB); assertNotNull(statsB);
@@ -3,7 +3,7 @@ ebean:
dumpMetricsOptions: sql,hash,loc dumpMetricsOptions: sql,hash,loc
test: test:
registerTestTenantProvider: false registerTestTenantProvider: false
redis: latest redis: 8.6.2
# shutdown: stop # stop | remove # shutdown: stop # stop | remove
platform: h2 # h2, postgres, mysql, oracle, sqlserver, sqlite platform: h2 # h2, postgres, mysql, oracle, sqlserver, sqlite
ddlMode: dropCreate # none | dropCreate | create | migration | createOnly | migrationDropCreate ddlMode: dropCreate # none | dropCreate | create | migration | createOnly | migrationDropCreate
@@ -1,7 +1,8 @@
singleServerConfig: singleServerConfig:
address: "redis://127.0.0.1:6379" address: "redis://127.0.0.1:6379"
password: null password: null
database: 0 # ebean-redis test clients use database 0 in the shared Redis container.
database: 1
connectionMinimumIdleSize: 2 connectionMinimumIdleSize: 2
connectionPoolSize: 10 connectionPoolSize: 10
idleConnectionTimeout: 3000 idleConnectionTimeout: 3000
+3 -3
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<artifactId>ebean-spring-txn</artifactId> <artifactId>ebean-spring-txn</artifactId>
@@ -28,7 +28,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -77,7 +77,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId> <artifactId>ebean-test</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
+6 -6
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<name>ebean test</name> <name>ebean test</name>
@@ -33,20 +33,20 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId> <artifactId>ebean-platform-h2</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId> <artifactId>ebean-ddl-generator</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -149,14 +149,14 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId> <artifactId>ebean-jackson-mapper</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId> <artifactId>ebean-platform-all</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -2,10 +2,12 @@ package io.ebean.xtest.base;
import io.ebean.DB; import io.ebean.DB;
import io.ebean.ProfileLocation; import io.ebean.ProfileLocation;
import io.ebean.annotation.Platform;
import io.ebean.meta.MetaQueryPlan; import io.ebean.meta.MetaQueryPlan;
import io.ebean.meta.QueryPlanInit; import io.ebean.meta.QueryPlanInit;
import io.ebean.meta.QueryPlanRequest; import io.ebean.meta.QueryPlanRequest;
import io.ebean.xtest.BaseTestCase; import io.ebean.xtest.BaseTestCase;
import io.ebean.xtest.IgnorePlatform;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.tests.model.basic.Customer; import org.tests.model.basic.Customer;
import org.tests.model.basic.ResetBasicData; import org.tests.model.basic.ResetBasicData;
@@ -80,6 +82,7 @@ class DtoQueryPlanCaptureTest extends BaseTestCase {
} }
@Test @Test
@IgnorePlatform(Platform.DB2)
void nativeDtoQuery_capturesQueryPlan() { void nativeDtoQuery_capturesQueryPlan() {
ResetBasicData.reset(); ResetBasicData.reset();
@@ -122,11 +125,13 @@ class DtoQueryPlanCaptureTest extends BaseTestCase {
.orElse(null); .orElse(null);
assertThat(dtoPlan).as("captured a native DTO query plan").isNotNull(); assertThat(dtoPlan).as("captured a native DTO query plan").isNotNull();
assertThat(dtoPlan.dbName()).isEqualTo(DB.getDefault().name());
assertThat(dtoPlan.sql()).contains("from o_customer where id > ?"); assertThat(dtoPlan.sql()).contains("from o_customer where id > ?");
assertThat(dtoPlan.plan()).isNotEmpty(); assertThat(dtoPlan.plan()).isNotEmpty();
} }
@Test @Test
@IgnorePlatform(Platform.DB2)
void nativeDtoQuery_withProfileLocation_capturesQueryPlan() { void nativeDtoQuery_withProfileLocation_capturesQueryPlan() {
ResetBasicData.reset(); ResetBasicData.reset();
@@ -2,10 +2,12 @@ package io.ebean.xtest.base;
import io.ebean.DB; import io.ebean.DB;
import io.ebean.SqlRow; import io.ebean.SqlRow;
import io.ebean.annotation.Platform;
import io.ebean.meta.MetaQueryPlan; import io.ebean.meta.MetaQueryPlan;
import io.ebean.meta.QueryPlanInit; import io.ebean.meta.QueryPlanInit;
import io.ebean.meta.QueryPlanRequest; import io.ebean.meta.QueryPlanRequest;
import io.ebean.xtest.BaseTestCase; import io.ebean.xtest.BaseTestCase;
import io.ebean.xtest.IgnorePlatform;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.tests.model.basic.ResetBasicData; import org.tests.model.basic.ResetBasicData;
@@ -34,6 +36,7 @@ class SqlQueryPlanCaptureTest extends BaseTestCase {
} }
@Test @Test
@IgnorePlatform(Platform.DB2)
void sqlQuery_capturesQueryPlan() { void sqlQuery_capturesQueryPlan() {
ResetBasicData.reset(); ResetBasicData.reset();
@@ -68,6 +71,7 @@ class SqlQueryPlanCaptureTest extends BaseTestCase {
.orElse(null); .orElse(null);
assertThat(sqlPlan).as("captured a SqlQuery query plan").isNotNull(); assertThat(sqlPlan).as("captured a SqlQuery query plan").isNotNull();
assertThat(sqlPlan.dbName()).isEqualTo(DB.getDefault().name());
assertThat(sqlPlan.sql()).contains("from o_customer where id > ?"); assertThat(sqlPlan.sql()).contains("from o_customer where id > ?");
assertThat(sqlPlan.plan()).isNotEmpty(); assertThat(sqlPlan.plan()).isNotEmpty();
} }
@@ -103,6 +103,7 @@ public class TestInheritance extends BaseTestCase {
server().save(grandparent1); server().save(grandparent1);
var parent1Id = parent1.getIdentifier();
testMyDynamicFormulaWithIncludes(); testMyDynamicFormulaWithIncludes();
testMyDynamicFormulaWithIncludesAndFetchJoin(); testMyDynamicFormulaWithIncludesAndFetchJoin();
@@ -111,7 +112,7 @@ public class TestInheritance extends BaseTestCase {
//grandparent1 = server().find(GrandParentPerson.class).setId(grandparent1.getIdentifier()).where() //grandparent1 = server().find(GrandParentPerson.class).setId(grandparent1.getIdentifier()).where()
// .in("effectiveBean.id",2,null) // geht nicht! // .in("effectiveBean.id",2,null) // geht nicht!
// .findOne(); // .findOne();
parent1 = server().find(ParentPerson.class).setId(1).fetch("someBean").findOne(); parent1 = server().find(ParentPerson.class).setId(parent1Id).fetch("someBean").findOne();
assertEquals("A Bean", parent1.getSomeBean().getName()); assertEquals("A Bean", parent1.getSomeBean().getName());
grandparent1 = server().find(GrandParentPerson.class) grandparent1 = server().find(GrandParentPerson.class)
.fetch("children", "*") // FIXME If I do not fetch childrenBean, I will get an exception .fetch("children", "*") // FIXME If I do not fetch childrenBean, I will get an exception
@@ -37,11 +37,12 @@ class TestHistoryOneToOne extends BaseTestCase {
@IgnorePlatform({Platform.ORACLE, Platform.COCKROACH}) @IgnorePlatform({Platform.ORACLE, Platform.COCKROACH})
@Test @Test
void testVersionsWithHistoryOverHistoryless() { void testVersionsWithHistoryOverHistoryless() throws InterruptedException {
HistorylessOneToOne historylessOneToOne = new HistorylessOneToOne("less"); HistorylessOneToOne historylessOneToOne = new HistorylessOneToOne("less");
historylessOneToOne.setHistoryOneToOne(new HistoryOneToOne("one")); historylessOneToOne.setHistoryOneToOne(new HistoryOneToOne("one"));
historylessOneToOne.setHistoryManyToOne(new HistoryManyToOne("many")); historylessOneToOne.setHistoryManyToOne(new HistoryManyToOne("many"));
DB.save(historylessOneToOne); DB.save(historylessOneToOne);
Thread.sleep(DB_CLOCK_DELTA);
LoggedSql.start(); LoggedSql.start();
int count = DB.find(HistoryOneToOne.class) int count = DB.find(HistoryOneToOne.class)
@@ -191,6 +191,7 @@ public class TestCustomerFinder extends BaseTestCase {
request.maxTimeMillis(10_000); request.maxTimeMillis(10_000);
List<MetaQueryPlan> plans0 = server().metaInfo().queryPlanCollectNow(request); List<MetaQueryPlan> plans0 = server().metaInfo().queryPlanCollectNow(request);
assertThat(plans0).isNotEmpty(); assertThat(plans0).isNotEmpty();
assertThat(plans0).extracting(MetaQueryPlan::dbName).containsOnly(server().name());
for (MetaQueryPlan plan : plans0) { for (MetaQueryPlan plan : plans0) {
logger.info("queryPlan label:{}, queryTimeMicros:{} captureMicros:{} whenCaptured:{} captureCount:{} loc:{} sql:{} bind:{} plan:{}", logger.info("queryPlan label:{}, queryTimeMicros:{} captureMicros:{} whenCaptured:{} captureCount:{} loc:{} sql:{} bind:{} plan:{}",
+2 -2
View File
@@ -15,8 +15,8 @@ mvn -T 4 clean package
mvn -T 4 deploy -pl '!composites,!platforms' -Pcentral -DskipTests mvn -T 4 deploy -pl '!composites,!platforms' -Pcentral -DskipTests
## git commit, git tag, git push --tags ## git commit, git tag, git push --tags
git commit -am 'Version 18.3.0' git commit -am 'Version 18.4.0'
git tag 18.3.0 git tag 18.4.0
git push --tags git push --tags
### convert to javax ### convert to javax
+5 -5
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<name>kotlin querybean generator</name> <name>kotlin querybean generator</name>
@@ -21,7 +21,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -35,7 +35,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -56,14 +56,14 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId> <artifactId>ebean-platform-h2</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId> <artifactId>ebean-ddl-generator</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
+14 -14
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -16,67 +16,67 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId> <artifactId>ebean-platform-h2</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId> <artifactId>ebean-platform-clickhouse</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId> <artifactId>ebean-platform-db2</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId> <artifactId>ebean-platform-hana</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-hsqldb</artifactId> <artifactId>ebean-platform-hsqldb</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId> <artifactId>ebean-platform-mysql</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId> <artifactId>ebean-platform-mariadb</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId> <artifactId>ebean-platform-nuodb</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId> <artifactId>ebean-platform-oracle</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId> <artifactId>ebean-platform-postgres</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlanywhere</artifactId> <artifactId>ebean-platform-sqlanywhere</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId> <artifactId>ebean-platform-sqlite</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId> <artifactId>ebean-platform-sqlserver</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -19,6 +19,8 @@ public abstract class BaseDB2Platform extends DatabasePlatform {
this.supportsNativeJavaTime = false; this.supportsNativeJavaTime = false;
this.truncateTable = "truncate table %s reuse storage ignore delete triggers immediate"; this.truncateTable = "truncate table %s reuse storage ignore delete triggers immediate";
this.likeClauseRaw = "like ?"; this.likeClauseRaw = "like ?";
this.existsWithCaseWhen = true;
this.existsFromClause = " from sysibm.sysdummy1";
this.sqlLimiter = new AnsiSqlRowsLimiter(); this.sqlLimiter = new AnsiSqlRowsLimiter();
this.dbIdentity.setSupportsGetGeneratedKeys(true); this.dbIdentity.setSupportsGetGeneratedKeys(true);
@@ -0,0 +1,17 @@
package io.ebean.platform.db2;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
class DB2PlatformTest {
@Test
void existsWithCaseWhen_trueForDB2() {
DB2LuwPlatform platform = new DB2LuwPlatform();
assertTrue(platform.existsWithCaseWhen());
assertEquals(" from sysibm.sysdummy1", platform.existsFromClause());
}
}
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<!-- Provided scope so that the H2HistoryTrigger can live in Ebean core <!-- Provided scope so that the H2HistoryTrigger can live in Ebean core
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId> <artifactId>ebean-platform-h2</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+3 -3
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -16,13 +16,13 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId> <artifactId>ebean-platform-mysql</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<artifactId>platforms</artifactId> <artifactId>platforms</artifactId>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
<dependency> <dependency>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
<relativePath>../..</relativePath> <relativePath>../..</relativePath>
</parent> </parent>
@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
+6 -4
View File
@@ -9,7 +9,7 @@
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>ebean parent</name> <name>ebean parent</name>
@@ -41,6 +41,7 @@
<properties> <properties>
<jackson.version>2.22.0</jackson.version> <jackson.version>2.22.0</jackson.version>
<avaje-json-core.version>3.14</avaje-json-core.version> <avaje-json-core.version>3.14</avaje-json-core.version>
<avaje-jsonb.version>3.14</avaje-jsonb.version>
<h2database.version>2.2.220</h2database.version> <h2database.version>2.2.220</h2database.version>
<ebean-persistence-api.version>3.2</ebean-persistence-api.version> <ebean-persistence-api.version>3.2</ebean-persistence-api.version>
<ebean-types.version>3.0</ebean-types.version> <ebean-types.version>3.0</ebean-types.version>
@@ -48,11 +49,11 @@
<ebean-annotation.version>8.11</ebean-annotation.version> <ebean-annotation.version>8.11</ebean-annotation.version>
<ebean-ddl-runner.version>2.3</ebean-ddl-runner.version> <ebean-ddl-runner.version>2.3</ebean-ddl-runner.version>
<ebean-migration-auto.version>1.2</ebean-migration-auto.version> <ebean-migration-auto.version>1.2</ebean-migration-auto.version>
<ebean-migration.version>14.3.0</ebean-migration.version> <ebean-migration.version>14.4.0</ebean-migration.version>
<ebean-test-containers.version>8.2</ebean-test-containers.version> <ebean-test-containers.version>8.2</ebean-test-containers.version>
<ebean-datasource.version>10.10</ebean-datasource.version> <ebean-datasource.version>10.10</ebean-datasource.version>
<ebean-agent.version>18.3.0</ebean-agent.version> <ebean-agent.version>18.4.0</ebean-agent.version>
<ebean-maven-plugin.version>18.3.0</ebean-maven-plugin.version> <ebean-maven-plugin.version>18.4.0</ebean-maven-plugin.version>
<surefire.useModulePath>false</surefire.useModulePath> <surefire.useModulePath>false</surefire.useModulePath>
</properties> </properties>
@@ -98,6 +99,7 @@
<module>platforms</module> <module>platforms</module>
<module>composites</module> <module>composites</module>
<module>ebean-jackson-mapper</module> <module>ebean-jackson-mapper</module>
<module>ebean-avajejsonb-mapper</module>
<module>ebean-spring-txn</module> <module>ebean-spring-txn</module>
<module>ebean-opentelemetry</module> <module>ebean-opentelemetry</module>
<module>ebean-core-json</module> <module>ebean-core-json</module>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>18.3.0</version> <version>18.4.0</version>
</parent> </parent>
<name>querybean generator</name> <name>querybean generator</name>
@@ -45,7 +45,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>18.3.0</version> <version>18.4.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>

Some files were not shown because too many files have changed in this diff Show More