Compare commits

..
1112 changed files with 8851 additions and 17741 deletions
+4 -4
View File
@@ -17,14 +17,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v3
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'zulu'
- name: Maven cache
uses: actions/cache@v3
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
@@ -36,5 +36,5 @@ jobs:
# - name: Maven single test
# run: mvn --batch-mode clean verify -Dtest="io.ebeaninternal.server.core.DefaultServer_getReferenceTest" -DfailIfNoTests=false
- name: Build with Maven
run: mvn -T 8 clean test
run: mvn clean package
+4 -4
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v3
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v3
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
@@ -35,4 +35,4 @@ jobs:
~/.m2
key: build-${{ env.cache-name }}
- name: db2
run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-db2.properties
run: mvn clean test -Dprops.file=testconfig/ebean-db2.properties
+4 -4
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v3
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'zulu'
- name: Maven cache
uses: actions/cache@v3
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
@@ -37,5 +37,5 @@ jobs:
- name: Maven version
run: mvn --version
- name: H2Database
run: mvn -T 8 clean package
run: mvn clean package
+39
View File
@@ -0,0 +1,39 @@
name: JDK 18-ea
on:
workflow_dispatch:
schedule:
- cron: '30 6 * * 1,3,5'
jobs:
build:
runs-on: ${{ matrix.os }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
java_version: [18-ea]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'zulu'
- name: Maven cache
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
path:
~/.m2
key: build-${{ env.cache-name }}
- name: Build with Maven
run: mvn package
+6 -4
View File
@@ -16,18 +16,20 @@ jobs:
strategy:
fail-fast: false
matrix:
java_version: [GA,EA]
## valhalla - failing on javadoc with:
## javadoc: error - The code being documented uses packages in the unnamed module, but the packages defined in https://ebean.io/platforms/ebean-platform-h2/apidocs/ are in named modules.
java_version: [GA,EA,loom,metropolis,panama]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Set up Java
uses: oracle-actions/setup-java@v1
with:
website: jdk.java.net
release: ${{ matrix.java_version }}
- name: Maven cache
uses: actions/cache@v3
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
@@ -37,5 +39,5 @@ jobs:
- name: Maven version
run: mvn --version
- name: Build with Maven
run: mvn -T 8 test
run: mvn package
+4 -4
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v3
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v3
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
@@ -35,4 +35,4 @@ jobs:
~/.m2
key: build-${{ env.cache-name }}
- name: mariadb 10.6
run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-mariadb.properties
run: mvn clean test -Dprops.file=testconfig/ebean-mariadb.properties
+3 -3
View File
@@ -17,14 +17,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v3
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v3
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
+3 -3
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v3
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'zulu'
- name: Maven cache
uses: actions/cache@v3
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
+4 -4
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v3
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v3
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
@@ -35,4 +35,4 @@ jobs:
~/.m2
key: build-${{ env.cache-name }}
- name: mysql
run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-mysql.properties
run: mvn clean test -Dprops.file=testconfig/ebean-mysql.properties
@@ -1,5 +1,5 @@
name: Oracle
name: Oracle18
on:
workflow_dispatch:
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v3
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'zulu'
- name: Maven cache
uses: actions/cache@v3
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
@@ -35,4 +35,4 @@ jobs:
~/.m2
key: build-${{ env.cache-name }}
- name: oracle
run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-oracle.properties
run: mvn clean test -Dprops.file=testconfig/ebean-oracle.properties
+4 -4
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v3
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v3
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
@@ -35,4 +35,4 @@ jobs:
~/.m2
key: build-${{ env.cache-name }}
- name: postgres
run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-postgres.properties
run: mvn clean test -Dprops.file=testconfig/ebean-postgres.properties
+3 -3
View File
@@ -17,14 +17,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v3
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v3
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
+4 -4
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v3
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v3
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
@@ -35,4 +35,4 @@ jobs:
~/.m2
key: build-${{ env.cache-name }}
- name: sqlserver 2017
run: mvn -T 8 clean test -Dprops.file=testconfig/ebean-sqlserver17.properties
run: mvn clean test -Dprops.file=testconfig/ebean-sqlserver17.properties
+3 -3
View File
@@ -20,14 +20,14 @@ jobs:
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v3
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v3
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
+6 -36
View File
@@ -1,55 +1,26 @@
[![Build](https://github.com/ebean-orm/ebean/actions/workflows/build.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/build.yml)
[![Maven Central : ebean](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/ebean-orm/ebean/blob/master/LICENSE)
[![Multi-JDK Build](https://github.com/ebean-orm/ebean/actions/workflows/multi-jdk-build.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/multi-jdk-build.yml)
[![JDK 18-ea](https://github.com/ebean-orm/ebean/actions/workflows/jdk-18-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/jdk-18-ea.yml)
##### Build with database platforms
[![H2Database](https://github.com/ebean-orm/ebean/actions/workflows/h2database.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/h2database.yml)
[![Postgres](https://github.com/ebean-orm/ebean/actions/workflows/postgres.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/postgres.yml)
[![MySql](https://github.com/ebean-orm/ebean/actions/workflows/mysql.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/mysql.yml)
[![MariaDB](https://github.com/ebean-orm/ebean/actions/workflows/mariadb.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/mariadb.yml)
[![Oracle](https://github.com/ebean-orm/ebean/actions/workflows/oracle.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/oracle.yml)
[![SqlServer](https://github.com/ebean-orm/ebean/actions/workflows/sqlserver.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/sqlserver.yml)
[![DB2 LUW](https://github.com/ebean-orm/ebean/actions/workflows/db2luw.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/db2luw.yml)
[![Yugabyte](https://github.com/ebean-orm/ebean/actions/workflows/yugabyte.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/yugabyte.yml)
##### Build with Java Early Access versions
#### Builds against EA (Early Access) versions of Java (19, Loom, panama etc)
[![ebean EA](https://github.com/ebean-orm/ebean/actions/workflows/jdk-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/jdk-ea.yml)
[![datasource EA](https://github.com/ebean-orm/ebean-datasource/actions/workflows/jdk-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean-datasource/actions/workflows/jdk-ea.yml)
[![migration EA](https://github.com/ebean-orm/ebean-migration/actions/workflows/jdk-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean-migration/actions/workflows/jdk-ea.yml)
[![test-docker EA](https://github.com/ebean-orm/ebean-test-docker/actions/workflows/jdk-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean-test-docker/actions/workflows/jdk-ea.yml)
[![ebean-agent EA](https://github.com/ebean-orm/ebean-agent/actions/workflows/jdk-ea.yml/badge.svg)](https://github.com/ebean-orm/ebean-agent/actions/workflows/jdk-ea.yml)
----------------------
# Ebean ORM for Java & Kotlin
**Multiple abstraction levels**: Ebean provides multiple levels of query abstraction [ORM Queries, mixed with SQL](https://ebean.io/docs/intro/queries/orm-query), [DTO Queries](https://ebean.io/docs/intro/queries/dto-query), [SqlQuery and JDBC](https://ebean.io/docs/intro/queries/sql-query).
Work at the highest level of abstraction and drop down levels as needed.
**Database migrations**: Built in [DB migration](https://ebean.io/docs/db-migrations/) generation and running. Support for "rebase" migrations as well as repeatable, init and 'normal' migrations.
**Awesome SQL**: Ebean produces SQL that you would hand craft yourself. Use great SQL, never generate SQL cartesian product, always honor relational limit/offset.
**Automated query tuning**: For ORM queries Ebean can profile the object graph being used and either [automatically tune the query](https://ebean.io/docs/query/background/autotune).
**Docker test containers**: [Docker test containers](https://ebean.io/docs/testing/) for all the supported databases. Get 100% test coverage on all the features of the database we use.
**Type safe queries**: We can build queries using type safe [query beans](https://ebean.io/docs/query/query-beans). IDE auto-complete when writing queries, compile time checking and it's FUN.
**Performance isn't optional**: Optimise queries to only fetch what we need (partial objects). Automatically avoid N+1 via a smart load context.
#### Benefits of ORM
* Automatically avoid N+1
* L2 caching to reduce database load
* Queries mixing database and L2 cache
* Automatically tune ORM queries
* Elasticsearch for search or L3 cache
----------------------
# Sponsors
<table>
<tbody>
@@ -79,14 +50,13 @@ Work at the highest level of abstraction and drop down levels as needed.
</table>
## Need help?
Post questions or issues to the [Ebean google group](https://groups.google.com/forum/#!forum/ebean)
or [github discussions](https://github.com/ebean-orm/ebean/discussions)
Post questions or issues to the Ebean google group - https://groups.google.com/forum/#!forum/ebean
## Documentation
Goto [https://ebean.io/docs/](https://ebean.io/docs/)
## Maven central
[Maven central - g:io.ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.ebean%22%20)
[Maven central - io.ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.ebean%22%20)
## Building Ebean from source
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<name>ebean-clickhouse</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -35,13 +35,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-clickhouse</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<name>ebean-cockroach</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -35,13 +35,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<name>ebean-db2</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -35,13 +35,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-db2</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<name>ebean-h2</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -35,13 +35,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<name>ebean-hana</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -35,13 +35,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-hana</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<name>ebean-mariadb</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -35,13 +35,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mariadb</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<name>ebean-mysql</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -35,13 +35,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-mysql</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<name>ebean-nuodb</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -35,13 +35,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-nuodb</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<name>ebean-oracle</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -35,13 +35,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-oracle</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<name>ebean-postgres</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -35,13 +35,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<name>ebean-sqlite</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -35,13 +35,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlite</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<name>ebean-sqlserver</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -35,13 +35,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-sqlserver</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
</dependencies>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<name>ebean-yugabyte</name>
@@ -16,13 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -35,13 +35,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-postgres</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
</dependencies>
+5 -23
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>composites</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<name>ebean (all platforms)</name>
@@ -16,31 +16,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.15.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-joda-time</artifactId>
<version>13.15.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-jsonnode</artifactId>
<version>13.15.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-jackson-mapper</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -53,13 +35,13 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-all</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</dependency>
</dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<artifactId>composites</artifactId>
+21 -53
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<name>ebean api</name>
@@ -13,23 +13,21 @@
<dependencies>
<!--
Projects are expected to explicit depend on version
of slf4j that they want to use
-->
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-applog</artifactId>
<version>1.0</version>
</dependency>
<!-- exclude avaje-applog-slf4j to direct logging to something else -->
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-applog-slf4j</artifactId>
<version>1.0</version>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-config</artifactId>
<version>2.4</version>
<version>2.0</version>
</dependency>
<!--
@@ -39,25 +37,25 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-lang</artifactId>
<version>1.1</version>
<version>1.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>persistence-api</artifactId>
<version>${ebean-persistence-api.version}</version>
<version>2.2.5</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-annotation</artifactId>
<version>${ebean-annotation.version}</version>
<version>8.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-types</artifactId>
<version>${ebean-types.version}</version>
<version>2.2</version>
</dependency>
<dependency>
@@ -66,14 +64,6 @@
<version>${ebean-datasource.version}</version>
</dependency>
<!-- Support MdcBackgroundExecutorWrapper -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
<optional>true</optional>
</dependency>
<!-- Jackson core used internally by Ebean -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
@@ -90,22 +80,19 @@
<optional>true</optional>
</dependency>
<!-- JAVAX-DEPENDENCY-START -->
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>1.1</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<optional>true</optional>
</dependency>
<!-- JAVAX-DEPENDENCY-END -->
<!-- JAKARTA-DEPENDENCY-START ___
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<optional>true</optional>
</dependency>
____ JAKARTA-DEPENDENCY-END -->
<dependency>
<groupId>io.avaje</groupId>
@@ -116,23 +103,4 @@
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/ebean-maven-version.txt</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<excludes>
<exclude>**/ebean-maven-version.txt</exclude>
</excludes>
</resource>
</resources>
</build>
</project>
@@ -12,7 +12,6 @@ import java.util.Optional;
* </p>
* <pre>{@code
*
* @Component
* public class CustomerFinder extends BeanFinder<Long,Customer> {
*
* @Inject
@@ -27,37 +26,29 @@ import java.util.Optional;
*
* @param <I> The ID type
* @param <T> The Bean type
*
* @see BeanRepository
*/
@NonNullApi
public abstract class BeanFinder<I,T> {
/**
* Migrate to using database rather than server.
*/
@Deprecated
protected final Database server;
protected final Database database;
protected final Class<T> type;
/**
* Create with the given bean type and Database instance.
*
* @param type The bean type
* @param database The Database instance typically created via Spring factory or equivalent.
* @param server The Database instance typically created via Spring factory or equivalent.
*/
protected BeanFinder(Class<T> type, Database database) {
protected BeanFinder(Class<T> type, Database server) {
this.type = type;
this.database = database;
this.server = database;
this.server = server;
}
/**
* Return the Database to use.
*/
public Database db() {
return database;
return server;
}
/**
@@ -79,10 +70,10 @@ public abstract class BeanFinder<I,T> {
* <p>
* This is equivalent to {@link DB#byName(String)}
*
* @param name The name of the Database. If this is null then the default Database is returned.
* @param server The name of the Database. If this is null then the default Database is returned.
*/
public Database db(String name) {
return DB.byName(name);
public Database db(String server) {
return DB.byName(server);
}
/**
@@ -6,15 +6,11 @@ import io.ebean.bean.EntityBean;
import java.util.Collection;
/**
* Provides find and persist functionality for use with "Dependency Injection style" use of Ebean.
* Provides finder functionality for use with "Dependency Injection style" use of Ebean.
* <p>
* Extend the BeanRepository with additional finder and persisting methods as needed by the
* application. The intention is to keep all the related logic together, for example, all the
* persisting and finding logic for Customer would be in CustomerRepository.
*
* <pre>{@code
*
* @Component
* @Repository
* public class CustomerRepository extends BeanRepository<Long,Customer> {
*
* @Inject
@@ -54,10 +50,10 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
* }</pre>
*
* @param type The bean type
* @param database The Database instance typically created via Spring factory or equivalent
* @param server The Database instance typically created via Spring factory or equivalent
*/
protected BeanRepository(Class<T> type, Database database) {
super(type, database);
protected BeanRepository(Class<T> type, Database server) {
super(type, server);
}
/**
@@ -126,8 +122,8 @@ public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
/**
* Save all the beans in the collection.
*/
public int saveAll(Collection<T> beans) {
return db().saveAll(beans);
public int saveAll(Collection<T> bean) {
return db().saveAll(bean);
}
/**
+12 -5
View File
@@ -5,6 +5,7 @@ import io.avaje.lang.Nullable;
import io.ebean.annotation.TxIsolation;
import io.ebean.cache.ServerCacheManager;
import io.ebean.plugin.Property;
import io.ebean.text.csv.CsvReader;
import io.ebean.text.json.JsonContext;
import javax.persistence.OptimisticLockException;
@@ -237,7 +238,7 @@ public final class DB {
}
/**
* The batch will be flushing automatically but, you can use this to explicitly
* The batch will be flushing automatically but you can use this to explicitly
* flush the batch if you like.
* <p>
* Flushing occurs automatically when:
@@ -784,6 +785,12 @@ public final class DB {
return getDefault().createUpdate(beanType, ormUpdate);
}
/**
* Create a CsvReader for a given beanType.
*/
public static <T> CsvReader<T> createCsvReader(Class<T> beanType) {
return getDefault().createCsvReader(beanType);
}
/**
* Create a named query.
@@ -954,7 +961,7 @@ public final class DB {
*
* DB.execute(scope, new TxRunnable() {
* public void run() {
* User u1 = DB.find(User.class, 1);
* User u1 = DB.find(User.class, 1);
* ...
* }
* });
@@ -1003,9 +1010,9 @@ public final class DB {
*
* DB.executeCall(scope, new Callable<String>() {
* public String call() {
* User u1 = DB.find(User.class, 1);
* ...
* return u1.getEmail();
* User u1 = DB.find(User.class, 1);
* ...
* return u1.getEmail();
* }
* });
* }</pre>
+217 -113
View File
@@ -9,6 +9,7 @@ import io.ebean.config.DatabaseConfig;
import io.ebean.meta.MetaInfoManager;
import io.ebean.plugin.Property;
import io.ebean.plugin.SpiServer;
import io.ebean.text.csv.CsvReader;
import io.ebean.text.json.JsonContext;
import javax.persistence.OptimisticLockException;
@@ -29,8 +30,10 @@ import java.util.concurrent.Callable;
* singleton (see {@link DatabaseConfig#setRegister(boolean)}). The DB
* singleton is essentially a map of Database's that have been registered
* with it.
* </p>
* <p>
* The Database can then be retrieved later via {@link DB#byName(String)}.
* </p>
*
* <h5>The 'default' Database</h5>
* <p>
@@ -38,15 +41,18 @@ import java.util.concurrent.Callable;
* (see {@link DatabaseConfig#setDefaultServer(boolean)}. Many methods on DB
* such as {@link DB#find(Class)} etc are actually just a convenient way to
* call methods on the 'default/primary' Database.
* </p>
*
* <h5>Constructing a Database</h5>
* <p>
* Databases are constructed by the DatabaseFactory. They can be created
* Database's are constructed by the DatabaseFactory. They can be created
* programmatically via {@link DatabaseFactory#create(DatabaseConfig)} or they
* can be automatically constructed on demand using configuration information in
* the application.properties file.
* </p>
*
* <h5>Example: Get a Database</h5>
* <p>
* <pre>{@code
*
* // Get access to the Human Resources Database
@@ -65,19 +71,22 @@ import java.util.concurrent.Callable;
*
* <h5>Database vs DB API</h5>
* <p>
* Database provides additional API compared with DB. For example, it
* Database provides additional API compared with DB. For example it
* provides more control over the use of Transactions that is not available in
* the DB API.
* </p>
*
* <p>
* <em>External Transactions:</em> If you wanted to use transactions created
* externally to Ebean then Database provides additional methods where you
* can explicitly pass a transaction (that can be created externally).
* </p>
*
* <p>
* <em>Bypass ThreadLocal Mechanism:</em> If you want to bypass the built-in
* <em>Bypass ThreadLocal Mechanism:</em> If you want to bypass the built in
* ThreadLocal transaction management you can use the createTransaction()
* method. Example: a single thread requires more than one transaction.
* </p>
*
* @see DB
* @see DatabaseFactory
@@ -95,10 +104,12 @@ public interface Database {
* Shutdown the Database instance programmatically.
* <p>
* This method is not normally required. Ebean registers a shutdown hook and shuts down cleanly.
* </p>
* <p>
* If the under underlying DataSource is the Ebean implementation then you
* also have the option of shutting down the DataSource and de-registering the
* also have the option of shutting down the DataSource and deregistering the
* JDBC driver.
* </p>
*
* @param shutdownDataSource if true then shutdown the underlying DataSource if it is the Ebean
* DataSource implementation.
@@ -144,10 +155,10 @@ public interface Database {
* <p>
* Note many platforms have multiple specific platform types so often we want to
* get the base platform via {@link Platform#base()}.
*
* </p>
* <pre>{@code
*
* Platform platform = database.platform().base();
* Platform platform = database.getPlatform().base();
* if (platform == Platform.MYSQL) {
* // do MySql specific function
* }
@@ -167,6 +178,7 @@ public interface Database {
* Return the BeanState for a given entity bean.
* <p>
* This will return null if the bean is not an enhanced entity bean.
* </p>
*/
BeanState beanState(Object bean);
@@ -180,6 +192,7 @@ public interface Database {
* <p>
* For example, if the id value passed in is a String but ought to be a Long or UUID etc
* then it will automatically be converted.
* </p>
*
* @param bean The entity bean to set the id value on.
* @param id The id value to set.
@@ -191,6 +204,7 @@ public interface Database {
* <p>
* When null is passed in for b, then the 'OldValues' of a is used for the
* difference comparison.
* </p>
*/
Map<String, ValuePair> diff(Object newBean, Object oldBean);
@@ -200,9 +214,14 @@ public interface Database {
* Useful if you use BeanPostConstructListeners or &#64;PostConstruct Annotations.
* In this case you should not use "new Bean...()". Making all bean constructors protected
* could be a good idea here.
* </p>
*/
<T> T createEntityBean(Class<T> type);
/**
* Create a CsvReader for a given beanType.
*/
<T> CsvReader<T> createCsvReader(Class<T> beanType);
/**
* Create an Update query to perform a bulk update.
@@ -229,6 +248,7 @@ public interface Database {
* Create a named query.
* <p>
* For RawSql the named query is expected to be in ebean.xml.
* </p>
*
* @param beanType The type of entity bean
* @param namedQuery The name of the query
@@ -284,14 +304,17 @@ public interface Database {
* <p>
* You can use the methods on the Query object to specify fetch paths,
* predicates, order by, limits etc.
* </p>
* <p>
* You then use findList(), findSet(), findMap() and findOne() to execute
* the query and return the collection or bean.
* </p>
* <p>
* Note that a query executed by {@link Query#findList()}
* {@link Query#findSet()} etc will execute against the same Database from
* which is was created.
*
* </p>
* <p>
* <pre>{@code
*
* // Find order 2 specifying explicitly the parts of the object graph to
@@ -321,7 +344,7 @@ public interface Database {
* Create a query using native SQL.
* <p>
* The native SQL can contain named parameters or positioned parameters.
*
* </p>
* <pre>{@code
*
* String sql = "select c.id, c.name from customer c where c.name like ? order by c.name";
@@ -344,10 +367,12 @@ public interface Database {
* <p>
* This will only work when a IdGenerator is on the bean such as for beans
* that use a DB sequence or UUID.
* </p>
* <p>
* For DB's supporting getGeneratedKeys and sequences such as Oracle10 you do
* not need to use this method generally. It is made available for more
* complex cases where it is useful to get an ID prior to some processing.
* </p>
*/
Object nextId(Class<?> beanType);
@@ -356,8 +381,10 @@ public interface Database {
* going back to the database.
* <p>
* This produces and returns a new list with the sort and filters applied.
* </p>
* <p>
* Refer to {@link Filter} for an example of its use.
* </p>
*/
<T> Filter<T> filter(Class<T> beanType);
@@ -374,10 +401,12 @@ public interface Database {
* <p>
* If you leave off any keywords the defaults are ascending order and treating
* nulls as high values.
* </p>
* <p>
* Note that the sorting uses a Comparator and Collections.sort(); and does
* not invoke a DB query.
*
* </p>
* <p>
* <pre>{@code
*
* // find orders and their customers
@@ -402,15 +431,17 @@ public interface Database {
<T> void sort(List<T> list, String sortByClause);
/**
* Create an orm update where you will supply the insert/update or delete
* Create a orm update where you will supply the insert/update or delete
* statement (rather than using a named one that is already defined using the
* &#064;NamedUpdates annotation).
* <p>
* The orm update differs from the sql update in that it you can use the bean
* name and bean property names rather than table and column names.
* </p>
* <p>
* An example:
*
* </p>
* <p>
* <pre>{@code
*
* // The bean name and properties - "topic","postCount" and "id"
@@ -435,6 +466,7 @@ public interface Database {
* <p>
* DTO beans are just normal bean like classes with public constructor(s) and setters.
* They do not need to be registered with DB before use.
* </p>
*
* @param dtoType The type of the DTO bean the rows will be mapped into.
* @param sql The SQL query to execute.
@@ -447,6 +479,7 @@ public interface Database {
* <p>
* DTO beans are just normal bean like classes with public constructor(s) and setters.
* They do not need to be registered with DB before use.
* </p>
*
* @param dtoType The type of the DTO bean the rows will be mapped into.
* @param namedQuery The name of the query
@@ -460,8 +493,10 @@ public interface Database {
*
* <p>
* Refer to {@link DtoQuery} for native sql queries returning DTO beans.
* </p>
* <p>
* Refer to {@link #findNative(Class, String)} for native sql queries returning entity beans.
* </p>
*/
SqlQuery sqlQuery(String sql);
@@ -470,9 +505,11 @@ public interface Database {
* <p>
* Use this to execute a Insert Update or Delete statement. The statement will
* be native to the database and contain database table and column names.
* </p>
*
* <p>
* See {@link SqlUpdate} for example usage.
* </p>
*
* @return The SqlUpdate instance to set parameters and execute
*/
@@ -485,7 +522,7 @@ public interface Database {
/**
* Register a TransactionCallback on the currently active transaction.
* <p>
* <p/>
* If there is no currently active transaction then a PersistenceException is thrown.
*
* @param transactionCallback The transaction callback to be registered with the current transaction.
@@ -499,6 +536,7 @@ public interface Database {
* You will want to do this if you want multiple Transactions in a single
* thread or generally use transactions outside of the TransactionThreadLocal
* management.
* </p>
*/
Transaction createTransaction();
@@ -506,6 +544,7 @@ public interface Database {
* Create a new transaction additionally specifying the isolation level.
* <p>
* Note that this transaction is NOT stored in a thread local.
* </p>
*/
Transaction createTransaction(TxIsolation isolation);
@@ -513,77 +552,86 @@ public interface Database {
* Start a transaction with 'REQUIRED' semantics.
* <p>
* With REQUIRED semantics if an active transaction already exists that transaction will be used.
* </p>
* <p>
* The transaction is stored in a ThreadLocal variable and typically you only
* need to use the returned Transaction <em>IF</em> you wish to do things like
* use batch mode, change the transaction isolation level, use savepoints or
* log comments to the transaction log.
* </p>
* <p>
* Example of using a transaction to span multiple calls to find(), save()
* etc.
* </p>
* <p>
* Example of using a transaction to span multiple calls to find(), save() etc.
*
* <h3>Using try with resources</h3>
* <pre>{@code
*
* // start a transaction (stored in a ThreadLocal)
* try (Transaction txn = database.beginTransaction()) {
* // start a transaction (stored in a ThreadLocal)
*
* Order order = database.find(Order.class, 10);
* ...
* database.save(order);
* try (Transaction txn = database.beginTransaction()) {
*
* txn.commit();
* }
* Order order = database.find(Order.class, 10);
* ...
* database.save(order);
*
* txn.commit();
* }
*
* }</pre>
*
* <p>
* <h3>Using try finally block</h3>
* <pre>{@code
*
* // start a transaction (stored in a ThreadLocal)
* Transaction txn = database.beginTransaction();
* try {
* Order order = database.find(Order.class,10);
* // start a transaction (stored in a ThreadLocal)
* Transaction txn = database.beginTransaction();
* try {
* Order order = database.find(Order.class,10);
*
* database.save(order);
* txn.commit();
* database.save(order);
*
* txn.commit();
*
* } finally {
* txn.end();
* }
*
* } finally {
* txn.end();
* }
* }</pre>
*
* <p>
* <h3>Transaction options</h3>
* <pre>{@code
*
* try (Transaction txn = database.beginTransaction()) {
* try (Transaction txn = database.beginTransaction()) {
*
* // explicitly turn on/off JDBC batch use
* txn.setBatchMode(true);
* txn.setBatchSize(50);
* // explicitly turn on/off JDBC batch use
* txn.setBatchMode(true);
* txn.setBatchSize(50);
*
* // control flushing when mixing save and queries
* txn.setBatchFlushOnQuery(false);
* // control flushing when mixing save and queries
* txn.setBatchFlushOnQuery(false);
*
* // turn off persist cascade if needed
* txn.setPersistCascade(false);
* // turn off persist cascade if needed
* txn.setPersistCascade(false);
*
* // for large batch insert processing when we do not
* // ... need the generatedKeys, don't get them
* txn.setBatchGetGeneratedKeys(false);
* // for large batch insert processing when we do not
* // ... need the generatedKeys, don't get them
* txn.setBatchGetGeneratedKeys(false);
*
* // explicitly flush the JDBC batch buffer
* txn.flush();
* // explicitly flush the JDBC batch buffer
* txn.flush();
*
* ...
* ...
*
* txn.commit();
* }
* txn.commit();
* }
*
* }</pre>
* <p>
* <p>
* If you want to externalise the transaction management then you use
* createTransaction() and pass the transaction around to the various methods on
* Database yourself.
* </p>
*/
Transaction beginTransaction();
@@ -595,9 +643,11 @@ public interface Database {
/**
* Start a transaction typically specifying REQUIRES_NEW or REQUIRED semantics.
* <p>
* <p>
* Note that this provides an try finally alternative to using {@link #executeCall(TxScope, Callable)} or
* {@link #execute(TxScope, Runnable)}.
*
* </p>
* <p>
* <h3>REQUIRES_NEW example:</h3>
* <pre>{@code
* // Start a new transaction. If there is a current transaction
@@ -644,8 +694,10 @@ public interface Database {
* This only is useful when JDBC batch is used. Flush occurs automatically when the
* transaction commits or batch size is reached. This manually flushes the JDBC batch
* buffer.
* </p>
* <p>
* This is the same as <code>currentTransaction().flush()</code>.
* </p>
*/
void flush();
@@ -665,6 +717,7 @@ public interface Database {
* <p>
* Useful to put in a finally block to ensure the transaction is ended, rather
* than a rollbackTransaction() in each catch block.
* </p>
* <p>
* Code example:
* <p>
@@ -691,6 +744,7 @@ public interface Database {
* <p>
* Note that this resets OneToMany and ManyToMany properties so that if they
* are accessed a lazy load will refresh the many property.
* </p>
*/
void refresh(Object bean);
@@ -709,11 +763,12 @@ public interface Database {
* // Fetch order 1
* Order order = database.find(Order.class, 1);
* }</pre>
*
* <p>
* <p>
* If you want more control over the query then you can use createQuery() and
* Query.findOne();
*
* </p>
* <p>
* <pre>{@code
* // ... additionally fetching customer, customer shipping address,
* // order details, and the product associated with each order detail.
@@ -755,9 +810,10 @@ public interface Database {
* <p>
* This will not perform a query against the database unless some property other
* that the id property is accessed.
* </p>
* <p>
* It is most commonly used to set a 'foreign key' on another bean like:
*
* </p>
* <pre>{@code
*
* Product product = database.getReference(Product.class, 1);
@@ -797,10 +853,12 @@ public interface Database {
* <p>
* The extended API has the options for executing queries that take an explicit
* transaction as an argument.
* </p>
* <p>
* Typically, we only need to use the extended API when we do NOT want to use the
* Typically we only need to use the extended API when we do NOT want to use the
* usual ThreadLocal based mechanism to obtain the current transaction but instead
* supply the transaction explicitly.
* </p>
*/
ExtendedServer extended();
@@ -809,27 +867,32 @@ public interface Database {
* <p>
* If there is no current transaction one will be created and committed for
* you automatically.
* </p>
* <p>
* Save can cascade along relationships. For this to happen you need to
* specify a cascade of CascadeType.ALL or CascadeType.PERSIST on the
* OneToMany, OneToOne or ManyToMany annotation.
* </p>
* <p>
* In this example below the details property has a CascadeType.ALL set so
* saving an order will also save all its details.
*
* </p>
* <p>
* <pre>{@code
* public class Order { ...
*
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
* List<OrderDetail> details;
* ...
* List<OrderDetail> details;
* ...
* }
* }</pre>
* <p>
* <p>
* When a save cascades via a OneToMany or ManyToMany Ebean will automatically
* set the 'parent' object to the 'detail' object. In the example below in
* saving the order and cascade saving the order details the 'parent' order
* will be set against each order detail when it is saved.
* </p>
*/
void save(Object bean) throws OptimisticLockException;
@@ -847,13 +910,16 @@ public interface Database {
* Delete the bean.
* <p>
* This will return true if the bean was deleted successfully or JDBC batch is being used.
* </p>
* <p>
* If there is no current transaction one will be created and committed for
* you automatically.
* </p>
* <p>
* If the Bean does not have a version property (or loaded version property) and
* the bean does not exist then this returns false indicating that nothing was
* deleted. Note that, if JDBC batch mode is used then this always returns true.
* </p>
*/
boolean delete(Object bean) throws OptimisticLockException;
@@ -861,10 +927,12 @@ public interface Database {
* Delete the bean with an explicit transaction.
* <p>
* This will return true if the bean was deleted successfully or JDBC batch is being used.
* </p>
* <p>
* If the Bean does not have a version property (or loaded version property) and
* the bean does not exist then this returns false indicating that nothing was
* deleted. However, if JDBC batch mode is used then this always returns true.
* </p>
*/
boolean delete(Object bean, Transaction transaction) throws OptimisticLockException;
@@ -946,13 +1014,16 @@ public interface Database {
* <p>
* If you wish to execute a Sql Select natively then you should use the
* SqlQuery object or DtoQuery.
* </p>
* <p>
* Note that the table modification information is automatically deduced and
* you do not need to call the DB.externalModification() method when you
* use this method.
* </p>
* <p>
* Example:
*
* </p>
* <p>
* <pre>{@code
*
* // example that uses 'named' parameters
@@ -980,6 +1051,7 @@ public interface Database {
* transaction.
* <p>
* This returns the number of rows that where inserted, updated or deleted.
* </p>
*/
int execute(Update<?> update);
@@ -993,7 +1065,8 @@ public interface Database {
* For making calls to stored procedures.
* <p>
* Example:
*
* </p>
* <p>
* <pre>{@code
*
* String sql = "{call sp_order_modify(?,?,?)}";
@@ -1018,19 +1091,23 @@ public interface Database {
* <p>
* If you use database.execute(UpdateSql) then the table modification information
* is automatically deduced and you do not need to call this method yourself.
* </p>
* <p>
* This information is used to invalidate objects out of the cache and
* potentially text indexes. This information is also automatically broadcast
* across the cluster.
* </p>
* <p>
* If there is a transaction then this information is placed into the current
* transactions event information. When the transaction is committed this
* information is registered (with the transaction manager). If this
* transaction is rolled back then none of the transaction event information
* registers including the information you put in via this method.
* </p>
* <p>
* If there is NO current transaction when you call this method then this
* information is registered immediately (with the transaction manager).
* </p>
*
* @param tableName the name of the table that was modified
* @param inserted true if rows where inserted into the table
@@ -1070,6 +1147,7 @@ public interface Database {
* Note: This checks only the root bean!
* <p>
* <pre>{@code
*
* // there is a unique constraint on title
*
* Document doc = new Document();
@@ -1098,7 +1176,7 @@ public interface Database {
* // uniqueProperties > [title]
* // custom msg > property[title] value[One flew over the cuckoo's nest]
*
* }
* }
*
* }</pre>
*
@@ -1122,12 +1200,13 @@ public interface Database {
* dirty so that it is not skipped.
* <p>
* <pre>{@code
* Customer customer = database.find(Customer, id);
*
* // mark the bean as dirty so that a save() or update() will
* // increment the version property
* database.markAsDirty(customer);
* database.save(customer);
* Customer customer = database.find(Customer, id);
*
* // mark the bean as dirty so that a save() or update() will
* // increment the version property
* database.markAsDirty(customer);
* database.save(customer);
*
* }</pre>
*/
@@ -1140,17 +1219,18 @@ public interface Database {
* <b>Stateless updates:</b> Note that the bean does not have to be previously fetched to call
* update().You can create a new instance and set some of its properties programmatically for via
* JSON/XML marshalling etc. This is described as a 'stateless update'.
* </p>
* <p>
* <b>Optimistic Locking: </b> Note that if the version property is not set when update() is
* called then no optimistic locking is performed (internally ConcurrencyMode.NONE is used).
*
* </p>
* <pre>{@code
*
* // A 'stateless update' example
* Customer customer = new Customer();
* customer.setId(7);
* customer.setName("ModifiedNameNoOCC");
* database.update(customer);
* // A 'stateless update' example
* Customer customer = new Customer();
* customer.setId(7);
* customer.setName("ModifiedNameNoOCC");
* database.update(customer);
*
* }</pre>
*/
@@ -1201,6 +1281,7 @@ public interface Database {
* Compared to save() this forces bean to perform an insert rather than trying to decide
* based on the bean state. As such this is useful when you fetch beans from one database
* and want to insert them into another database (and you want to explicitly insert them).
* </p>
*/
void insert(Object bean);
@@ -1233,18 +1314,21 @@ public interface Database {
/**
* Execute a Runnable in a Transaction with an explicit scope.
* <p>
* The scope can control the transaction type, isolation and rollback semantics.
*
* The scope can control the transaction type, isolation and rollback
* semantics.
* </p>
* <p>
* <pre>{@code
* // set specific transactional scope settings
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
*
* database.execute(scope, new Runnable() {
* public void run() {
* User u1 = database.find(User.class, 1);
* ...
* }
* });
* // set specific transactional scope settings
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
*
* database.execute(scope, new Runnable() {
* public void run() {
* User u1 = database.find(User.class, 1);
* ...
* }
* });
*
* }</pre>
*/
@@ -1255,19 +1339,21 @@ public interface Database {
* <p>
* The default scope runs with REQUIRED and by default will rollback on any
* exception (checked or runtime).
*
* </p>
* <p>
* <pre>{@code
* database.execute(() -> {
*
* User u1 = database.find(User.class, 1);
* User u2 = database.find(User.class, 2);
* database.execute(() -> {
*
* u1.setName("u1 mod");
* u2.setName("u2 mod");
* User u1 = database.find(User.class, 1);
* User u2 = database.find(User.class, 2);
*
* u1.save();
* u2.save();
* });
* u1.setName("u1 mod");
* u2.setName("u2 mod");
*
* u1.save();
* u2.save();
* });
*
* }</pre>
*/
@@ -1278,16 +1364,18 @@ public interface Database {
* <p>
* The scope can control the transaction type, isolation and rollback
* semantics.
*
* </p>
* <p>
* <pre>{@code
*
* // set specific transactional scope settings
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
*
* database.executeCall(scope, new Callable<String>() {
* public String call() {
* User u1 = database.find(User.class, 1);
* ...
* return u1.getEmail();
* public String call() {
* User u1 = database.find(User.class, 1);
* ...
* return u1.getEmail();
* }
* });
*
@@ -1300,8 +1388,10 @@ public interface Database {
* <p>
* The default scope runs with REQUIRED and by default will rollback on any
* exception (checked or runtime).
*
* </p>
* <p>
* <pre>{@code
*
* database.executeCall(new Callable<String>() {
* public String call() {
* User u1 = database.find(User.class, 1);
@@ -1316,6 +1406,7 @@ public interface Database {
* return u1.getEmail();
* }
* });
*
* }</pre>
*/
<T> T executeCall(Callable<T> callable);
@@ -1326,7 +1417,8 @@ public interface Database {
ServerCacheManager cacheManager();
/**
* Return the BackgroundExecutor service for asynchronous processing of queries.
* Return the BackgroundExecutor service for asynchronous processing of
* queries.
*/
BackgroundExecutor backgroundExecutor();
@@ -1335,30 +1427,33 @@ public interface Database {
* <p>
* This instance is safe to be used concurrently by multiple threads and this
* method is cheap to call.
*
* </p>
* <p>
* <h3>Simple example:</h3>
* <pre>{@code
* JsonContext json = database.json();
* String jsonOutput = json.toJson(list);
* System.out.println(jsonOutput);
* }</pre>
*
* JsonContext json = database.json();
* String jsonOutput = json.toJson(list);
* System.out.println(jsonOutput);
*
* }</pre>
* <p>
* <h3>Using PathProperties:</h3>
* <pre>{@code
* // specify just the properties we want
* PathProperties paths = PathProperties.parse("name, status, anniversary");
*
* List<Customer> customers =
* database.find(Customer.class)
* // apply those paths to the query (only fetch what we need)
* .apply(paths)
* .where().ilike("name", "rob%")
* .findList();
* // specify just the properties we want
* PathProperties paths = PathProperties.parse("name, status, anniversary");
*
* // ... get the json
* JsonContext jsonContext = database.json();
* String json = jsonContext.toJson(customers, paths);
* List<Customer> customers =
* database.find(Customer.class)
* // apply those paths to the query (only fetch what we need)
* .apply(paths)
* .where().ilike("name", "rob%")
* .findList();
*
* // ... get the json
* JsonContext jsonContext = database.json();
* String json = jsonContext.toJson(customers, paths);
*
* }</pre>
*
@@ -1383,6 +1478,7 @@ public interface Database {
* Publish a single bean given its type and id returning the resulting live bean.
* <p>
* The values are published from the draft to the live bean.
* </p>
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
@@ -1397,6 +1493,7 @@ public interface Database {
* This will use the current transaction or create one if required.
* <p>
* The values are published from the draft to the live bean.
* </p>
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
@@ -1409,6 +1506,7 @@ public interface Database {
* Publish the beans that match the query returning the resulting published beans.
* <p>
* The values are published from the draft beans to the live beans.
* </p>
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to publish
@@ -1421,6 +1519,7 @@ public interface Database {
* This will use the current transaction or create one if required.
* <p>
* The values are published from the draft beans to the live beans.
* </p>
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to publish
@@ -1432,6 +1531,7 @@ public interface Database {
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
* </p>
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
@@ -1446,6 +1546,7 @@ public interface Database {
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
* </p>
*
* @param <T> the type of the entity bean
* @param beanType the type of the entity bean
@@ -1459,6 +1560,7 @@ public interface Database {
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
* </p>
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to restore
@@ -1471,6 +1573,7 @@ public interface Database {
* <p>
* The values from the live beans are set back to the draft bean and the
* <code>@DraftDirty</code> and <code>@DraftReset</code> properties are reset.
* </p>
*
* @param <T> the type of the entity bean
* @param query the query used to select the draft beans to restore
@@ -1482,6 +1585,7 @@ public interface Database {
* <p>
* Validate the query checking the where and orderBy expression paths to confirm if
* they represent valid properties/path for the given bean type.
* </p>
*/
<T> Set<String> validateQuery(Query<T> query);
@@ -1507,6 +1611,6 @@ public interface Database {
/**
* Truncate the base tables for the given bean types.
*/
void truncate(Class<?>... beanTypes);
void truncate(Class<?>... tables);
}
@@ -2,20 +2,20 @@ package io.ebean;
import io.ebean.config.BeanNotEnhancedException;
import io.ebean.datasource.DataSourceConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
import static java.lang.System.Logger.Level.ERROR;
/**
* Holds Database instances.
*/
final class DbContext {
private static final System.Logger log = EbeanVersion.log;
private static final Logger log = LoggerFactory.getLogger("io.ebean");
static {
EbeanVersion.getVersion();
}
@@ -23,9 +23,14 @@ final class DbContext {
private static final DbContext INSTANCE = new DbContext();
private final ConcurrentHashMap<String, Database> concMap = new ConcurrentHashMap<>();
private final HashMap<String, Database> syncMap = new HashMap<>();
private final ReentrantLock lock = new ReentrantLock();
/**
* The 'default' Database.
*/
private Database defaultDatabase;
private DbContext() {
@@ -47,7 +52,7 @@ final class DbContext {
throw new DataSourceConfigurationException(msg, e);
} catch (Throwable e) {
log.log(ERROR, "Error trying to create the default Database", e);
log.error("Error trying to create the default Database", e);
throw new RuntimeException(e);
}
}
@@ -64,9 +69,9 @@ final class DbContext {
*/
Database getDefault() {
if (defaultDatabase == null) {
String msg = "The default Database has not been defined?"
+ " This is normally set via the ebean.datasource.default property."
+ " Otherwise it should be registered programmatically via registerServer()";
String msg = "The default Database has not been defined?";
msg += " This is normally set via the ebean.datasource.default property.";
msg += " Otherwise it should be registered programmatically via registerServer()";
throw new PersistenceException(msg);
}
return defaultDatabase;
@@ -76,9 +76,9 @@ final class DbPrimary {
defaultServerName = System.getProperty("db", defaultServerName);
defaultServerName = System.getProperty("ebean_db", defaultServerName);
if (isEmpty(defaultServerName)) {
defaultServerName = Config.getOptional("datasource.default").orElse(null);
defaultServerName = Config.get("datasource.default", null);
if (isEmpty(defaultServerName)) {
defaultServerName = Config.getOptional("ebean.default.datasource").orElse(null);
defaultServerName = Config.get("ebean.default.datasource", null);
}
}
if (defaultServerName == null) {
@@ -129,11 +129,6 @@ public interface DtoQuery<T> extends CancelableQuery {
*/
DtoQuery<T> setParameter(String name, Object value);
/**
* Bind the named parameter to SQL NULL.
*/
DtoQuery<T> setNullParameter(String name, int jdbcType);
/**
* Bind the named multi-value array parameter which we would use with Postgres ANY.
* <p>
@@ -146,11 +141,6 @@ public interface DtoQuery<T> extends CancelableQuery {
*/
DtoQuery<T> setParameter(int position, Object value);
/**
* Set a positioned parameter to SQL NULL.
*/
DtoQuery<T> setNullParameter(int position, int jdbcType);
/**
* Set the index of the first row of the results to return.
*/
@@ -2,28 +2,6 @@ package io.ebean;
/**
* Thrown when a duplicate is attempted on a unique constraint.
* <p>
* In terms of catching this exception with the view of continuing processing
* using the same transaction look to use {@link Transaction#rollbackAndContinue()}.
*
* <pre>{@code
*
* try (Transaction txn = database.beginTransaction()) {
*
* try {
* ...
* database.save(bean);
* database.flush();
* } catch (DuplicateKeyException e) {
* // carry on processing using the transaction
* txn.rollbackAndContinue();
* ...
* }
*
* txn.commit();
* }
*
* }</pre>
*/
public class DuplicateKeyException extends DataIntegrityException {
private static final long serialVersionUID = -4771932723285724817L;
@@ -1,15 +1,12 @@
package io.ebean;
import io.avaje.applog.AppLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.Properties;
import static java.lang.System.Logger.Level.*;
/**
* Class to determine the ebean version.
*
@@ -17,7 +14,7 @@ import static java.lang.System.Logger.Level.*;
*/
public final class EbeanVersion {
public static final System.Logger log = AppLog.getLogger("io.ebean");
private static final Logger log = LoggerFactory.getLogger("io.ebean");
/**
* Maintain the minimum ebean-agent version manually based on required ebean-agent bug fixes.
@@ -25,7 +22,6 @@ public final class EbeanVersion {
private static final int MIN_AGENT_MAJOR_VERSION = 12;
private static final int MIN_AGENT_MINOR_VERSION = 12;
private static String version = "unknown";
static {
readVersion();
checkAgentVersion();
@@ -33,16 +29,14 @@ public final class EbeanVersion {
private static void readVersion() {
try {
try (InputStream in = ClassLoader.getSystemResourceAsStream("META-INF/ebean-maven-version.txt")) {
try (InputStream in = ClassLoader.getSystemResourceAsStream("META-INF/maven/io.ebean/ebean-api/pom.properties")) {
if (in != null) {
try (LineNumberReader reader = new LineNumberReader(new InputStreamReader(in))) {
version = reader.readLine();
log.log(INFO, "ebean version: {0}", version);
}
version = readVersion(in);
}
}
log.info("ebean version: {}", version);
} catch (IOException e) {
log.log(WARNING, "Could not determine ebean version: {0}", e.getMessage());
log.warn("Could not determine ebean version: {}", e.getMessage());
}
}
@@ -54,13 +48,13 @@ public final class EbeanVersion {
String agentVersion = readVersion(in);
if (agentVersion != null) {
if (checkMinAgentVersion(agentVersion)) {
log.log(ERROR, "Expected minimum ebean-agent version {0}.{1}.0 but we have {2}, please update the ebean-agent", MIN_AGENT_MAJOR_VERSION, MIN_AGENT_MINOR_VERSION, agentVersion);
log.error("Expected minimum ebean-agent version {}.{}.0 but we have {}, please update the ebean-agent", MIN_AGENT_MAJOR_VERSION, MIN_AGENT_MINOR_VERSION, agentVersion);
}
}
}
}
} catch (IOException e) {
log.log(WARNING, "Could not check minimum ebean-agent version {0}.{1}.0 required due to - {2}", MIN_AGENT_MAJOR_VERSION, MIN_AGENT_MINOR_VERSION, e.getMessage());
log.warn("Could not check minimum ebean-agent version {}.{}.0 required due to - {}", MIN_AGENT_MAJOR_VERSION, MIN_AGENT_MINOR_VERSION, e.getMessage());
}
}
@@ -94,7 +88,7 @@ public final class EbeanVersion {
}
/**
* Returns the ebean version (read from META-INF/ebean-maven-version.txt)
* Returns the ebean version (read from /META-INF/maven/io.ebean/ebean/pom.properties)
*/
public static String getVersion() {
return version;
@@ -30,13 +30,6 @@ public final class Expr {
private Expr() {
}
/**
* Return the underlying expression factory.
*/
public static ExpressionFactory factory() {
return DB.expressionFactory();
}
/**
* Equal To - property equal to the given value.
*/
@@ -117,11 +117,6 @@ public interface ExpressionFactory {
*/
Expression arrayIsNotEmpty(String propertyName);
/**
* Equal To the result of a sub-query.
*/
Expression eq(String propertyName, Query<?> subQuery);
/**
* Equal To - property equal to the given value.
*/
@@ -132,11 +127,6 @@ public interface ExpressionFactory {
*/
Expression eqOrNull(String propertyName, Object value);
/**
* Not Equal To the result of a sub-query.
*/
Expression ne(String propertyName, Query<?> subQuery);
/**
* Not Equal To - property not equal to the given value.
*/
@@ -191,23 +181,6 @@ public interface ExpressionFactory {
*/
Expression inRangeWith(String lowProperty, String highProperty, Object value);
/**
* A Property is in Range between 2 properties.
*
* <pre>{@code
*
* .orderDate.inRangeWith(QOrder.Alias.product.startDate, QOrder.Alias.product.endDate)
*
* // which equates to
* product.startDate <= orderDate and (orderDate < product.endDate or product.endDate is null)
*
* }</pre>
*
* <p>
* This is a convenience expression combining a number of simple expressions.
*/
Expression inRangeWithProperties(String propertyName, String lowProperty, String highProperty);
/**
* Between - property between the two given values.
*/
@@ -234,21 +207,11 @@ public interface ExpressionFactory {
*/
Expression geOrNull(String propertyName, Object value);
/**
* Greater Than the result of a sub-query.
*/
Expression gt(String propertyName, Query<?> subQuery);
/**
* Greater Than - property greater than the given value.
*/
Expression gt(String propertyName, Object value);
/**
* Greater Than or Equal to the result of a sub-query.
*/
Expression ge(String propertyName, Query<?> subQuery);
/**
* Greater Than or Equal to - property greater than or equal to the given
* value.
@@ -271,21 +234,11 @@ public interface ExpressionFactory {
*/
Expression leOrNull(String propertyName, Object value);
/**
* Less Than the result of a sub-query.
*/
Expression lt(String propertyName, Query<?> subQuery);
/**
* Less Than - property less than the given value.
*/
Expression lt(String propertyName, Object value);
/**
* Less Than or Equal to the result of a sub-query.
*/
Expression le(String propertyName, Query<?> subQuery);
/**
* Less Than or Equal to - property less than or equal to the given value.
*/
@@ -383,15 +383,6 @@ public interface ExpressionList<T> {
*/
<A> List<A> findSingleAttributeList();
/**
* Executes the query returning a set of values for a single property.
* <p>
* This can be used to cache sets.
*
* @return a HashSet of values for the selegted property
*/
<A> Set<A> findSingleAttributeSet();
/**
* Execute a query returning a single value of a single property/column.
* <pre>{@code
@@ -830,40 +821,16 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> addAll(ExpressionList<T> exprList);
/**
* Equal To the result of a sub-query.
*/
ExpressionList<T> eq(String propertyName, Query<?> subQuery);
/**
* Equal To - property is equal to a given value.
*/
ExpressionList<T> eq(String propertyName, Object value);
/**
* Is EQUAL TO if value is non-null and otherwise no expression is added to the query.
* <p>
* This is the EQUAL TO equivalent to {@link #inOrEmpty(String, Collection)} where the expression/predicate
* is only added when the value is non-null.
* <p>
* This is effectively a helper method that allows a query to be built in fluid style where some predicates are
* effectively optional. We can use <code>eqIfPresent()</code> rather than having a separate if block.
* <p>
* Another option is to instead globally use {@link io.ebean.config.DatabaseConfig#setExpressionEqualsWithNullAsNoop(boolean)}
* but that is not always desirable.
*/
ExpressionList<T> eqIfPresent(String propertyName, @Nullable Object value);
/**
* Equal To or Null - property is equal to a given value or null.
*/
ExpressionList<T> eqOrNull(String propertyName, Object value);
/**
* Not Equal To the result of a sub-query.
*/
ExpressionList<T> ne(String propertyName, Query<?> subQuery);
/**
* Not Equal To - property not equal to the given value.
*/
@@ -900,23 +867,6 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> inRangeWith(String lowProperty, String highProperty, Object value);
/**
* A Property is in Range between 2 properties.
*
* <pre>{@code
*
* .orderDate.inRangeWith(QOrder.Alias.product.startDate, QOrder.Alias.product.endDate)
*
* // which equates to
* product.startDate <= orderDate and (orderDate < product.endDate or product.endDate is null)
*
* }</pre>
*
* <p>
* This is a convenience expression combining a number of simple expressions.
*/
ExpressionList<T> inRangeWithProperties(String propertyName, String lowProperty, String highProperty);
/**
* In Range - {@code property >= value1 and property < value2}.
* <p>
@@ -935,11 +885,6 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> betweenProperties(String lowProperty, String highProperty, Object value);
/**
* Greater Than the result of a sub-query.
*/
ExpressionList<T> gt(String propertyName, Query<?> subQuery);
/**
* Greater Than - property greater than the given value.
*/
@@ -951,17 +896,9 @@ public interface ExpressionList<T> {
ExpressionList<T> gtOrNull(String propertyName, Object value);
/**
* Is GREATER THAN if value is non-null and otherwise no expression is added to the query.
* <p>
* This is effectively a helper method that allows a query to be built in fluid style where some predicates are
* effectively optional. We can use <code>gtIfPresent()</code> rather than having a separate if block.
* Greater Than or Equal to OR Null - ({@code >= or null }).
*/
ExpressionList<T> gtIfPresent(String propertyName, @Nullable Object value);
/**
* Greater Than or Equal to the result of a sub-query.
*/
ExpressionList<T> ge(String propertyName, Query<?> subQuery);
ExpressionList<T> geOrNull(String propertyName, Object value);
/**
* Greater Than or Equal to - property greater than or equal to the given
@@ -969,25 +906,6 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> ge(String propertyName, Object value);
/**
* Greater Than or Equal to OR Null - ({@code >= or null }).
*/
ExpressionList<T> geOrNull(String propertyName, Object value);
/**
* Is GREATER THAN OR EQUAL TO if value is non-null and otherwise no expression is added to the query.
* <p>
* This is effectively a helper method that allows a query to be built in fluid style where some predicates are
* effectively optional. We can use <code>geIfPresent()</code> rather than having a separate if block.
*/
ExpressionList<T> geIfPresent(String propertyName, @Nullable Object value);
/**
* Less Than the result of a sub-query.
*/
ExpressionList<T> lt(String propertyName, Query<?> subQuery);
/**
* Less Than - property less than the given value.
*/
@@ -998,36 +916,15 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> ltOrNull(String propertyName, Object value);
/**
* Is LESS THAN if value is non-null and otherwise no expression is added to the query.
* <p>
* This is effectively a helper method that allows a query to be built in fluid style where some predicates are
* effectively optional. We can use <code>ltIfPresent()</code> rather than having a separate if block.
*/
ExpressionList<T> ltIfPresent(String propertyName, @Nullable Object value);
/**
* Less Than or Equal to the result of a sub-query.
*/
ExpressionList<T> le(String propertyName, Query<?> subQuery);
/**
* Less Than or Equal to - property less than or equal to the given value.
*/
ExpressionList<T> le(String propertyName, Object value);
/**
* Less Than or Equal to OR Null - ({@code <= or null }).
*/
ExpressionList<T> leOrNull(String propertyName, Object value);
/**
* Is LESS THAN OR EQUAL TO if value is non-null and otherwise no expression is added to the query.
* <p>
* This is effectively a helper method that allows a query to be built in fluid style where some predicates are
* effectively optional. We can use <code>leIfPresent()</code> rather than having a separate if block.
* Less Than or Equal to - property less than or equal to the given value.
*/
ExpressionList<T> leIfPresent(String propertyName, @Nullable Object value);
ExpressionList<T> le(String propertyName, Object value);
/**
* Is Null - property is null.
@@ -1763,8 +1660,4 @@ public interface ExpressionList<T> {
*/
ExpressionList<T> endNot();
/**
* Clears the current expression list.
*/
ExpressionList<T> clear();
}
@@ -2,6 +2,7 @@ package io.ebean;
import io.avaje.lang.Nullable;
import javax.persistence.NonUniqueResultException;
import java.time.Clock;
import java.util.List;
import java.util.Map;
@@ -14,182 +15,465 @@ import java.util.stream.Stream;
/**
* The extended API for Database.
* <p>
* Deprecated in favour of using {@link Query#usingTransaction(Transaction)} instead.
* <p>
* This provides the finder methods that take an explicit transaction rather than obtaining
* the transaction from the usual mechanism (which is ThreadLocal based).
* </p>
* <p>
* In general we only want to use this ExtendedServer API when we want to avoid / bypass
* the use of the mechanism to get the current transaction and instead explicitly supply
* the transaction to use.
* </p>
* <p>
* Note that in all cases the transaction supplied can be null and in this case the Database
* will use the normal mechanism to obtain the transaction to use.
* </p>
*/
public interface ExtendedServer {
/**
* Deprecated but no yet determined suitable replacement (to support testing only change of clock).
* <p>
* Return the NOW time from the Clock.
*/
long clockNow();
/**
* Set the Clock to use for <code>@WhenCreated</code> and <code>@WhenModified</code>.
* <p>
* Note that we only expect to change the Clock for testing purposes.
* </p>
*/
@Deprecated
void setClock(Clock clock);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute the query returning true if a row is found.
* <p>
* The query is executed using max rows of 1 and will only select the id property.
* This method is really just a convenient way to optimise a query to perform a
* 'does a row exist in the db' check.
* </p>
*
* <h2>Example:</h2>
* <pre>{@code
*
* boolean userExists = query().where().eq("email", "rob@foo.com").exists();
*
* }</pre>
*
* <h2>Example using a query bean:</h2>
* <pre>{@code
*
* boolean userExists = new QContact().email.equalTo("rob@foo.com").exists();
*
* }</pre>
*
* @return True if the query finds a matching row in the database
*/
@Deprecated
<T> boolean exists(Query<T> ormQuery, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Return the number of 'top level' or 'root' entities this query should return.
*
* @see Query#findCount()
* @see Query#findFutureCount()
*/
@Deprecated
<T> int findCount(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Return the Id values of the query as a List.
*
* @see Query#findIds()
*/
@Deprecated
<A, T> List<A> findIds(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Return a QueryIterator for the query.
* <p>
* Generally using {@link #findEach(Query, Consumer, Transaction)} or
* {@link #findEachWhile(Query, Predicate, Transaction)} is preferred
* to findIterate(). The reason is that those methods automatically take care of
* closing the queryIterator (and the underlying jdbc statement and resultSet).
* <p>
* This is similar to findEach in that not all the result beans need to be held
* in memory at the same time and as such is good for processing large queries.
*
* @see Query#findIterate()
* @see Query#findEach(Consumer)
* @see Query#findEachWhile(Predicate)
*/
@Deprecated
<T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute the query returning the result as a Stream.
* <p>
* Note that this can support very large queries iterating any number of results.
* To do so internally it can use multiple persistence contexts.
* <p>
* Note that the stream needs to be closed so use with try with resources.
* </p>
*/
@Deprecated
<T> Stream<T> findStream(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute the query visiting the each bean one at a time.
* <p>
* Unlike findList() this is suitable for processing a query that will return
* a very large resultSet. The reason is that not all the result beans need to be
* held in memory at the same time and instead processed one at a time.
* </p>
* <p>
* Internally this query using a PersistenceContext scoped to each bean (and the
* beans associated object graph).
* </p>
* <p>
* <pre>{@code
*
* DB.find(Order.class)
* .where().eq("status", Order.Status.NEW)
* .order().asc("id")
* .findEach((Order order) -> {
*
* // do something with the order bean
* System.out.println(" -- processing order ... " + order);
* });
*
* }</pre>
*
* @see Query#findEach(Consumer)
* @see Query#findEachWhile(Predicate)
*/
@Deprecated
<T> void findEach(Query<T> query, Consumer<T> consumer, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute findEach with batch consumer.
*
* @see Query#findEach(int, Consumer)
*/
@Deprecated
<T> void findEach(Query<T> query, int batch, Consumer<List<T>> consumer, Transaction t);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute the query visiting the each bean one at a time.
* <p>
* Compared to findEach() this provides the ability to stop processing the query
* results early by returning false for the Predicate.
* </p>
* <p>
* Unlike findList() this is suitable for processing a query that will return
* a very large resultSet. The reason is that not all the result beans need to be
* held in memory at the same time and instead processed one at a time.
* </p>
* <p>
* Internally this query using a PersistenceContext scoped to each bean (and the
* beans associated object graph).
* </p>
* <p>
* <pre>{@code
*
* DB.find(Order.class)
* .where().eq("status", Order.Status.NEW)
* .order().asc("id")
* .findEachWhile((Order order) -> {
*
* // do something with the order bean
* System.out.println(" -- processing order ... " + order);
*
* boolean carryOnProcessing = ...
* return carryOnProcessing;
* });
*
* }</pre>
*
* @see Query#findEach(Consumer)
* @see Query#findEachWhile(Predicate)
*/
@Deprecated
<T> void findEachWhile(Query<T> query, Predicate<T> consumer, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Return versions of a @History entity bean.
* <p>
* Generally this query is expected to be a find by id or unique predicates query.
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Deprecated
<T> List<Version<T>> findVersions(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute a query returning a list of beans.
* <p>
* Generally you are able to use {@link Query#findList()} rather than
* explicitly calling this method. You could use this method if you wish to
* explicitly control the transaction used for the query.
* </p>
* <p>
* <pre>{@code
*
* List<Customer> customers = DB.find(Customer.class)
* .where().ilike("name", "rob%")
* .findList();
*
* }</pre>
*
* @param <T> the type of entity bean to fetch.
* @param query the query to execute.
* @param transaction the transaction to use (can be null).
* @return the list of fetched beans.
* @see Query#findList()
*/
@Deprecated
<T> List<T> findList(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute find row count query in a background thread.
* <p>
* This returns a Future object which can be used to cancel, check the
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
* @param query the query to execute the row count on
* @param transaction the transaction (can be null).
* @return a Future object for the row count query
* @see Query#findFutureCount()
*/
@Deprecated
<T> FutureRowCount<T> findFutureCount(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute find Id's query in a background thread.
* <p>
* This returns a Future object which can be used to cancel, check the
* execution status (isDone etc) and get the value (with or without a
* timeout).
* </p>
*
* @param query the query to execute the fetch Id's on
* @param transaction the transaction (can be null).
* @return a Future object for the list of Id's
* @see Query#findFutureIds()
*/
@Deprecated
<T> FutureIds<T> findFutureIds(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute find list query in a background thread returning a FutureList object.
* <p>
* This returns a Future object which can be used to cancel, check the
* execution status (isDone etc) and get the value (with or without a timeout).
* <p>
* This query will execute in it's own PersistenceContext and using its own transaction.
* What that means is that it will not share any bean instances with other queries.
*
* @param query the query to execute in the background
* @param transaction the transaction (can be null).
* @return a Future object for the list result of the query
* @see Query#findFutureList()
*/
@Deprecated
<T> FutureList<T> findFutureList(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Return a PagedList for this query using firstRow and maxRows.
* <p>
* The benefit of using this over findList() is that it provides functionality to get the
* total row count etc.
* </p>
* <p>
* If maxRows is not set on the query prior to calling findPagedList() then a
* PersistenceException is thrown.
* </p>
* <p>
* <pre>{@code
*
* PagedList<Order> pagedList = DB.find(Order.class)
* .setFirstRow(50)
* .setMaxRows(20)
* .findPagedList();
*
* // fetch the total row count in the background
* pagedList.loadRowCount();
*
* List<Order> orders = pagedList.getList();
* int totalRowCount = pagedList.getTotalRowCount();
*
* }</pre>
*
* @return The PagedList
* @see Query#findPagedList()
*/
@Deprecated
<T> PagedList<T> findPagedList(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute the query returning a set of entity beans.
* <p>
* Generally you are able to use {@link Query#findSet()} rather than
* explicitly calling this method. You could use this method if you wish to
* explicitly control the transaction used for the query.
* </p>
* <p>
* <pre>{@code
*
* Set<Customer> customers = DB.find(Customer.class)
* .where().ilike("name", "rob%")
* .findSet();
*
* }</pre>
*
* @param <T> the type of entity bean to fetch.
* @param query the query to execute
* @param transaction the transaction to use (can be null).
* @return the set of fetched beans.
* @see Query#findSet()
*/
@Deprecated
<T> Set<T> findSet(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute the query returning the entity beans in a Map.
* <p>
* Generally you are able to use {@link Query#findMap()} rather than
* explicitly calling this method. You could use this method if you wish to
* explicitly control the transaction used for the query.
* </p>
*
* @param <T> the type of entity bean to fetch.
* @param query the query to execute.
* @param transaction the transaction to use (can be null).
* @return the map of fetched beans.
* @see Query#findMap()
*/
@Deprecated
<K, T> Map<K, T> findMap(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute the query returning a list of values for a single property.
* <p>
* <h3>Example 1:</h3>
* <pre>{@code
*
* List<String> names =
* DB.find(Customer.class)
* .select("name")
* .order().asc("name")
* .findSingleAttributeList();
*
* }</pre>
* <h3>Example 2:</h3>
* <pre>{@code
*
* List<String> names =
* DB.find(Customer.class)
* .setDistinct(true)
* .select("name")
* .where().eq("status", Customer.Status.NEW)
* .order().asc("name")
* .setMaxRows(100)
* .findSingleAttributeList();
*
* }</pre>
*
* @return the list of values for the selected property
* @see Query#findSingleAttributeList()
*/
@Deprecated
<A, T> List<A> findSingleAttributeList(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute the query returning at most one entity bean or null (if no matching
* bean is found).
* <p>
* This will throw a NonUniqueResultException if the query finds more than one result.
* </p>
* <p>
* Generally you are able to use {@link Query#findOne()} rather than
* explicitly calling this method. You could use this method if you wish to
* explicitly control the transaction used for the query.
* </p>
*
* @param <T> the type of entity bean to fetch.
* @param query the query to execute.
* @param transaction the transaction to use (can be null).
* @return the list of fetched beans.
* @throws NonUniqueResultException if more than one result was found
* @see Query#findOne()
*/
@Deprecated
<A, T> Set<A> findSingleAttributeSet(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
*/
@Deprecated
@Nullable
<T> T findOne(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Similar to findOne() but returns an Optional (rather than nullable).
*/
@Deprecated
<T> Optional<T> findOneOrEmpty(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute as a delete query deleting the 'root level' beans that match the predicates
* in the query.
* <p>
* Note that if the query includes joins then the generated delete statement may not be
* optimal depending on the database platform.
* </p>
*
* @param query the query used for the delete
* @param transaction the transaction to use (can be null)
* @param <T> the type of entity bean to fetch.
* @return the number of beans/rows that were deleted
*/
@Deprecated
<T> int delete(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute the update query returning the number of rows updated.
* <p>
* The update query must be created using {@link Database#update(Class)}.
* </p>
*
* @param query the update query to execute
* @param transaction the optional transaction to use for the update (can be null)
* @param <T> the type of entity bean
* @return The number of rows updated
*/
@Deprecated
<T> int update(Query<T> query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute the sql query returning a list of MapBean.
* <p>
* Generally you are able to use {@link SqlQuery#findList()} rather than
* explicitly calling this method. You could use this method if you wish to
* explicitly control the transaction used for the query.
* </p>
*
* @param query the query to execute.
* @param transaction the transaction to use (can be null).
* @return the list of fetched MapBean.
* @see SqlQuery#findList()
*/
@Deprecated
List<SqlRow> findList(SqlQuery query, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute the SqlQuery iterating a row at a time.
* <p>
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
* </p>
*/
@Deprecated
void findEach(SqlQuery query, Consumer<SqlRow> consumer, Transaction transaction);
/**
* Deprecated migrate to using {@link Query#usingTransaction(Transaction)}.
* Execute the SqlQuery iterating a row at a time with the ability to stop consuming part way through.
* <p>
* Returning false after processing a row stops the iteration through the query results.
* </p>
* <p>
* This streaming type query is useful for large query execution as only 1 row needs to be held in memory.
* </p>
*/
@Deprecated
void findEachWhile(SqlQuery query, Predicate<SqlRow> consumer, Transaction transaction);
/**
* Deprecated migrate to using {@link SqlQuery#usingTransaction(Transaction)}.
* Execute the sql query returning a single MapBean or null.
* <p>
* This will throw a PersistenceException if the query found more than one
* result.
* </p>
* <p>
* Generally you are able to use {@link SqlQuery#findOne()} rather than
* explicitly calling this method. You could use this method if you wish to
* explicitly control the transaction used for the query.
* </p>
*
* @param query the query to execute.
* @param transaction the transaction to use (can be null).
* @return the fetched MapBean or null if none was found.
* @see SqlQuery#findOne()
*/
@Deprecated
@Nullable
SqlRow findOne(SqlQuery query, Transaction transaction);
@@ -8,9 +8,6 @@ import java.util.List;
* Intended to be used as a base class for 'Finder' implementations that can then
* be injected or used as public static fields on the associated entity bean.
* <p>
* When using dependency injection {@link BeanRepository} and {@link BeanFinder}
* are expected to be used rather than this Finder.
* <p>
* These 'finders' are a place to organise all the finder methods for that bean type
* and specific finder methods are expected to be added (find by unique properties etc).
* </p>
@@ -57,8 +54,6 @@ import java.util.List;
*
* }</pre>
*
* @see BeanRepository
* @see BeanFinder
*/
@NonNullApi
public class Finder<I, T> {
@@ -231,6 +231,18 @@ public class OrderBy<T> implements Serializable {
return this;
}
/**
* Return true if this order by can be used in select clause.
*/
public boolean supportsSelect() {
for (Property property : list) {
if (!property.supportsSelect()) {
return false;
}
}
return true;
}
/**
* A property and its ascending descending order.
*/
@@ -391,6 +403,12 @@ public class OrderBy<T> implements Serializable {
this.ascending = ascending;
}
/**
* Support use in select clause if no collation or nulls ordering.
*/
boolean supportsSelect() {
return nulls == null;
}
}
private void parse(String orderByClause) {
@@ -16,33 +16,16 @@ public interface ProfileLocation {
return XServiceProvider.profileLocationFactory().create();
}
/**
* Create and return a new ProfileLocation with line number.
*/
static ProfileLocation createWithLine() {
return XServiceProvider.profileLocationFactory().createWithLine();
}
/**
* Create and return a new ProfileLocation with a given lineNumber and label.
*/
static ProfileLocation create(String label) {
return XServiceProvider.profileLocationFactory().create(label);
}
/**
* Deprecated in favor of {@link #create(String)}.
*/
@Deprecated
static ProfileLocation create(int lineNumber, String label) {
return create(label);
return XServiceProvider.profileLocationFactory().create(lineNumber, label);
}
/**
* Deprecated for removal - not used.
* Create and return a new ProfileLocation with a given location.
*/
@Deprecated
static ProfileLocation createAt(String location) {
return XServiceProvider.profileLocationFactory().createAt(location);
}
+2 -36
View File
@@ -926,12 +926,7 @@ public interface Query<T> extends CancelableQuery {
<A> List<A> findSingleAttributeList();
/**
* Execute the query returning a hashset of values for a single property.
*/
<A> Set<A> findSingleAttributeSet();
/**
* Execute a query returning a single value or null for a single property/column.
* Execute a query returning a single value of a single property/column.
* <p>
* <pre>{@code
*
@@ -943,7 +938,6 @@ public interface Query<T> extends CancelableQuery {
*
* }</pre>
*/
@Nullable
<A> A findSingleAttribute();
/**
@@ -1580,11 +1574,10 @@ public interface Query<T> extends CancelableQuery {
Query<T> setReadOnly(boolean readOnly);
/**
* Deprecated - migrate to use setBeanCacheMode(CacheMode.PUT) or other CacheMode.
* Will be deprecated - migrate to use setBeanCacheMode(CacheMode.RECACHE).
* <p>
* When set to true all the beans from this query are loaded into the bean cache.
*/
@Deprecated
Query<T> setLoadBeanCache(boolean loadBeanCache);
/**
@@ -1768,31 +1761,4 @@ public interface Query<T> extends CancelableQuery {
*/
Query<T> orderById(boolean orderById);
/**
* Type safe query bean properties and expressions (marker interface).
* <p>
* Implemented by query bean properties and expressions based on those properties.
* <p>
* The base type determines which {@link StdOperators} can be used on the property.
*
* @param <T> The property type.
*/
interface Property<T> {
/**
* Return a property given the expression.
*/
static <T> Property<T> of(String expression) {
return new SimpleProperty<>(expression);
}
/**
* Return the property in string expression form.
* <p>
* This is a path to a database column (like "name" or "billingAddress.city") or a function
* wrapping a path (like <em>lower(name)</em>, <em>concat(name, '-', billingAddress.city)</em>
*/
@Override
String toString();
}
}
@@ -1,15 +0,0 @@
package io.ebean;
final class SimpleProperty<T> implements Query.Property<T> {
private final String expression;
SimpleProperty(String expression) {
this.expression = expression;
}
@Override
public String toString() {
return expression;
}
}
+1 -11
View File
@@ -2,8 +2,8 @@ package io.ebean;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
@@ -40,11 +40,6 @@ import java.util.function.Predicate;
@NonNullApi
public interface SqlQuery extends Serializable, CancelableQuery {
/**
* Execute the query using the given transaction.
*/
SqlQuery usingTransaction(Transaction transaction);
/**
* Execute the query returning a list.
*/
@@ -303,11 +298,6 @@ public interface SqlQuery extends Serializable, CancelableQuery {
*/
interface TypeQuery<T> {
/**
* Execute the query using the given transaction.
*/
TypeQuery<T> usingTransaction(Transaction transaction);
/**
* Return the single value.
*/
@@ -1,332 +0,0 @@
package io.ebean;
import io.ebean.Query.Property;
import java.util.Collection;
/**
* Standard Operators for use with strongly typed query construction.
* <p>
* This is currently deemed to be experimental and subject to change.
*/
@Deprecated(since = "experimental")
public final class StdOperators {
// ---- Functions ---- //
/**
* Sum of the given property.
*/
public static Property<Number> sum(Property<? extends Number> property) {
return Property.of("sum(" + property + ")");
}
/**
* Count of the given property.
*/
public static Property<Number> count(Property<?> property) {
return Property.of("count(" + property + ")");
}
/**
* Average of the given property.
*/
public static <T> Property<T> avg(Property<T> property) {
return Property.of("avg(" + property + ")");
}
/**
* Max of the given property.
*/
public static <T> Property<T> max(Property<T> property) {
return Property.of("max(" + property + ")");
}
/**
* Min of the given property.
*/
public static <T> Property<T> min(Property<T> property) {
return Property.of("min(" + property + ")");
}
/**
* Coalesce of the property and value.
*/
public static <T> Property<T> coalesce(Property<T> property, Object value) {
return Property.of("coalesce(" + property.toString() + "," + sqlValue(value) + ")");
}
/**
* Lower of the given property.
*/
public static Property<String> lower(Property<String> property) {
return Property.of("lower(" + property + ")");
}
/**
* Upper of the given property.
*/
public static Property<String> upper(Property<String> property) {
return Property.of("upper(" + property + ")");
}
/**
* Concat of the given property and values or other properties.
*/
public static Property<String> concat(Property<?> property, Object... values) {
StringBuilder expression = new StringBuilder(50);
expression.append("concat(").append(property.toString());
for (Object value : values) {
expression.append(",").append(sqlConcatString(value));
}
expression.append(")");
return Property.of(expression.toString());
}
private static String sqlConcatString(Object value) {
if (value instanceof Property) {
return value.toString();
} else {
return sqlQuote(value);
}
}
/**
* Allows numbers to be unquoted.
*/
private static String sqlValue(Object value) {
if (value instanceof Property || value instanceof Number) {
return value.toString();
} else {
return sqlQuote(value);
}
}
/**
* SQL quoted escaping single quotes.
*/
private static String sqlQuote(Object value) {
return "'" + String.valueOf(value).replace("'", "''") + "'";
}
// ---- Operators ---- //
/**
* Equal to - for a property and value.
*/
public static <T> Expression eq(Property<T> property, T value) {
return Expr.eq(property.toString(), value);
}
/**
* Equal to - for a property and sub-query.
*/
public static <T> Expression eq(Property<T> property, Query<?> subQuery) {
return Expr.in(property.toString(), subQuery);
}
/**
* Equal to or null - for a property and value.
*/
public static <T> Expression eqOrNull(Property<T> property, T value) {
return Expr.factory().eqOrNull(property.toString(), value);
}
/**
* Not equal to - for a property and value.
*/
public static <T> Expression ne(Property<T> property, T value) {
return Expr.ne(property.toString(), value);
}
/**
* Not equal to - for a property and sub-query.
*/
public static <T> Expression ne(Property<T> property, Query<?> subQuery) {
return Expr.ne(property.toString(), subQuery);
}
/**
* Greater than - for a property and value.
*/
public static <T> Expression gt(Property<T> property, T value) {
return Expr.gt(property.toString(), value);
}
/**
* Greater than - for a property and sub-query.
*/
public static <T> Expression gt(Property<T> property, Query<?> subQuery) {
return Expr.gt(property.toString(), subQuery);
}
/**
* Greater than or null - for a property and value.
*/
public static <T> Expression gtOrNull(Property<T> property, T value) {
return Expr.factory().gtOrNull(property.toString(), value);
}
/**
* Greater than or equal to - for a property and value.
*/
public static <T> Expression ge(Property<T> property, T value) {
return Expr.ge(property.toString(), value);
}
/**
* Greater than or equal to - for a property and sub-query.
*/
public static <T> Expression ge(Property<T> property, Query<?> subQuery) {
return Expr.ge(property.toString(), subQuery);
}
/**
* Greater than or null - for a property and value.
*/
public static <T> Expression geOrNull(Property<T> property, T value) {
return Expr.factory().geOrNull(property.toString(), value);
}
/**
* Less than - for a property and value.
*/
public static <T> Expression lt(Property<T> property, T value) {
return Expr.lt(property.toString(), value);
}
/**
* Less than - for a property and sub-query.
*/
public static <T> Expression lt(Property<T> property, Query<?> subQuery) {
return Expr.lt(property.toString(), subQuery);
}
/**
* Less than or null - for a property and value.
*/
public static <T> Expression ltOrNull(Property<T> property, T value) {
return Expr.factory().ltOrNull(property.toString(), value);
}
/**
* Greater than or equal to - for a property and value.
*/
public static <T> Expression le(Property<T> property, T value) {
return Expr.le(property.toString(), value);
}
/**
* Greater than or equal to - for a property and sub-query.
*/
public static <T> Expression le(Property<T> property, Query<?> subQuery) {
return Expr.le(property.toString(), subQuery);
}
/**
* Greater than or equal to or null - for a property and value.
*/
public static <T> Expression leOrNull(Property<T> property, T value) {
return Expr.factory().leOrNull(property.toString(), value);
}
/**
* In range - for a property and values.
*/
public static <T> Expression inRange(Property<T> property, T lowValue, T highValue) {
return Expr.factory().inRange(property.toString(), lowValue, highValue);
}
/**
* In range - for properties and a value.
*/
public static <T> Expression inRange(Property<T> lowProperty, Property<T> highProperty, T value) {
return Expr.factory().inRangeWith(lowProperty.toString(), highProperty.toString(), value);
}
/**
* In range - for properties.
*/
public static <T> Expression inRange(Property<T> lowProperty, Property<T> property, Property<T> highProperty) {
return Expr.factory().inRangeWithProperties(lowProperty.toString(), property.toString(), highProperty.toString());
}
/**
* In - for a given property and collection of values.
*/
public static <T> Expression in(Property<T> property, Collection<T> value) {
return Expr.in(property.toString(), value);
}
/**
* In - for a given property and sub-query.
*/
public static <T> Expression in(Property<T> property, Query<?> subQuery) {
return Expr.in(property.toString(), subQuery);
}
/**
* In or empty - for a given property and collection of values.
*/
public static <T> Expression inOrEmpty(Property<T> property, Collection<T> value) {
return Expr.inOrEmpty(property.toString(), value);
}
/**
* Not In - for a given property and collection of values.
*/
public static <T> Expression notIn(Property<T> property, Collection<T> value) {
return Expr.factory().notIn(property.toString(), value);
}
/**
* Not In - for a given property and sub-query.
*/
public static <T> Expression notIn(Property<T> property, Query<?> subQuery) {
return Expr.factory().notIn(property.toString(), subQuery);
}
// ---- String operators ---- //
/**
* Like - for a given property and value.
*/
public static Expression like(Property<String> property, String value) {
return Expr.like(property.toString(), value);
}
/**
* Case-insensitive Like - for a given property and value.
*/
public static Expression ilike(Property<String> property, String value) {
return Expr.ilike(property.toString(), value);
}
/**
* Starts with - for a given property and value.
*/
public static Expression startsWith(Property<String> property, String value) {
return Expr.startsWith(property.toString(), value);
}
/**
* Case-insensitive starts with - for a given property and value.
*/
public static Expression istartsWith(Property<String> property, String value) {
return Expr.istartsWith(property.toString(), value);
}
/**
* Contains - for a given property and value.
*/
public static Expression contains(Property<String> property, String value) {
return Expr.contains(property.toString(), value);
}
/**
* Case-insensitive contains - for a given property and value.
*/
public static Expression icontains(Property<String> property, String value) {
return Expr.icontains(property.toString(), value);
}
}
@@ -144,35 +144,6 @@ public interface Transaction extends AutoCloseable {
*/
void rollback(Throwable e) throws PersistenceException;
/**
* Performs a rollback on the underlying JDBC connection with the intention of
* continuing to use this same transaction and performing a commit or rollback
* later to complete the transaction.
* <p>
* Typically used when catching {@link DuplicateKeyException} where we wish to
* rollback work done at that point but carry on processing using the transaction.
*
* <pre>{@code
*
* try (Transaction txn = database.beginTransaction()) {
*
* try {
* ...
* database.save(bean);
* database.flush();
* } catch (DuplicateKeyException e) {
* // carry on processing using the transaction
* txn.rollbackAndContinue();
* ...
* }
*
* txn.commit();
* }
*
* }</pre>
*/
void rollbackAndContinue();
/**
* Set when we want nested transactions to use Savepoint's.
* <p>
@@ -14,7 +14,7 @@ package io.ebean;
*
* int rows = DB.update(Customer.class)
* .set("status", Customer.Status.ACTIVE)
* .set("whenUpdated", Instant.now())
* .set("updtime", new Timestamp(System.currentTimeMillis()))
* .where()
* .gt("id", 1000)
* .update();
@@ -25,20 +25,6 @@ package io.ebean;
* update o_customer set status=?, updtime=? where id > ?
*
* }</pre>
*
* <h4>Example: Using query bean</h4>
* <pre>{@code
*
* var cust = QCustomer.alias();
*
* int rows = new QCustomer()
* .id.gt(1000)
* .asUpdate()
* .set(cust.status, Customer.Status.COMPLETE)
* .set(cust.whenUpdated, Instant.now())
* .update();
*
* }</pre>
* <p>
* Note that if the where() clause contains a join then the SQL update changes to use a
* <code> WHERE ID IN () </code> form.
@@ -54,7 +40,7 @@ package io.ebean;
*
* int rows = DB.update(Customer.class)
* .set("status", Customer.Status.ACTIVE)
* .set("whenUpdated", Instant.now())
* .set("updtime", new Timestamp(System.currentTimeMillis()))
* .where()
* .eq("status", Customer.Status.NEW)
* .eq("billingAddress.country", nz)
@@ -87,7 +73,7 @@ public interface UpdateQuery<T> {
*
* int rows = DB.update(Customer.class)
* .set("status", Customer.Status.ACTIVE)
* .set("whenUpdated", Instant.now())
* .set("updtime", new Timestamp(System.currentTimeMillis()))
* .where()
* .gt("id", 1000)
* .update();
@@ -99,27 +85,6 @@ public interface UpdateQuery<T> {
*/
UpdateQuery<T> set(String property, Object value);
/**
* Set the value of a property.
* <p>
* <pre>{@code
*
* var cust = QCustomer.alias();
*
* int rows = new QCustomer()
* .id.gt(1000)
* .asUpdate()
* .set(cust.status, Customer.Status.COMPLETE)
* .set(cust.whenUpdated, Instant.now())
* .update();
*
* }</pre>
*
* @param property The bean property to be set
* @param value The value to set the property to
*/
<P> UpdateQuery<T> set(Query.Property<P> property, P value);
/**
* Set the property to be null.
* <p>
@@ -137,13 +102,6 @@ public interface UpdateQuery<T> {
*/
UpdateQuery<T> setNull(String property);
/**
* Set the property to be null.
*
* @param property The bean property to be set
*/
UpdateQuery<T> setNull(Query.Property<?> property);
/**
* Set using a property expression that does not need any bind values.
* <p>
@@ -2,7 +2,6 @@ package io.ebean.bean;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import static io.ebean.util.EncodeB64.enc;
@@ -28,26 +27,19 @@ public final class CallStack implements Serializable, CallOrigin {
private final String zeroHash;
private final String pathHash;
private final Object[] callStack;
private final StackTraceElement[] callStack;
private final int hc;
public CallStack(Object[] callStack, int zeroHash, int pathHash) {
public CallStack(StackTraceElement[] callStack, int zeroHash, int pathHash) {
this.callStack = callStack;
this.hc = computeHashCode();
this.zeroHash = enc(zeroHash);
this.pathHash = enc(pathHash);
}
public CallStack(List<StackWalker.StackFrame> frames) {
this.callStack = frames.toArray(new Object[0]);
this.hc = computeHashCode();
this.zeroHash = enc(callStack[0].hashCode());
this.pathHash = enc(hc);
}
private int computeHashCode() {
int hc = 0;
for (Object element : callStack) {
for (StackTraceElement element : callStack) {
hc = 92821 * hc + element.hashCode();
}
return hc;
@@ -6,12 +6,6 @@ import java.io.Serializable;
import java.util.Map;
import java.util.Set;
/**
* This is the object associated to every entity bean using byte code enhancement.
* <p>
* This provides per property state such as loaded state, changed state, original values
* as well as bean level dirty state etc.
*/
public interface EntityBeanIntercept extends Serializable {
/**
@@ -288,14 +282,8 @@ public interface EntityBeanIntercept extends Serializable {
*/
void markPropertyAsChanged(int propertyIndex);
/**
* Set the changed state for the given property.
*/
void setChangedProperty(int propertyIndex);
/**
* Set the changed and loaded state for the given property.
*/
void setChangeLoaded(int propertyIndex);
/**
@@ -303,9 +291,6 @@ public interface EntityBeanIntercept extends Serializable {
*/
void setEmbeddedPropertyDirty(int propertyIndex);
/**
* Set the original value for the property.
*/
void setOriginalValue(int propertyIndex, Object value);
/**
@@ -373,9 +358,6 @@ public interface EntityBeanIntercept extends Serializable {
*/
StringBuilder getLoadedPropertyKey();
/**
* Return the loaded state for all the properties.
*/
boolean[] getLoaded();
/**
@@ -403,9 +385,6 @@ public interface EntityBeanIntercept extends Serializable {
*/
void initialisedMany(int propertyIndex);
/**
* Invoke the PreGetterCallback if it has been set due to getter for the given property.
*/
void preGetterCallback(int propertyIndex);
/**
@@ -423,14 +402,8 @@ public interface EntityBeanIntercept extends Serializable {
*/
void preSetterMany(boolean interceptField, int propertyIndex, Object oldValue, Object newValue);
/**
* Set the property changed state, bean dirtyState and property original value.
*/
void setChangedPropertyValue(int propertyIndex, boolean setDirtyState, Object origValue);
/**
* Set the dirty state on the bean.
*/
void setDirtyStatus();
/**
@@ -509,9 +482,6 @@ public interface EntityBeanIntercept extends Serializable {
*/
void setDeletedFromCollection(boolean deletedFromCollection);
/**
* Return true if the bean was orphan deleted from a collection.
*/
boolean isOrphanDelete();
/**
@@ -524,10 +494,7 @@ public interface EntityBeanIntercept extends Serializable {
*/
Map<String, Exception> getLoadErrors();
/**
* Return true if the property has its changed state set.
*/
boolean isChangedProp(int propertyIndex);
boolean isChangedProp(int i);
/**
* Return the MutableValueInfo for the given property or null.
@@ -6,20 +6,10 @@ import java.util.Collections;
import java.util.Map;
import java.util.Set;
/**
* EntityBeanIntercept optimised for read only use.
* <p>
* For the read only use this intercept doesn't need to hold any state that is normally
* required for updates such as per property changed, loaded, dirty state, original values
* bean state etc.
*/
public class InterceptReadOnly implements EntityBeanIntercept {
private final EntityBean owner;
/**
* Create with a given entity.
*/
public InterceptReadOnly(Object ownerBean) {
this.owner = (EntityBean) ownerBean;
}
@@ -21,6 +21,7 @@ import java.util.concurrent.locks.ReentrantLock;
* <p>
* This provides the mechanisms to support deferred fetching of reference beans
* and oldValues generation for concurrency checking.
* </p>
*/
public final class InterceptReadWrite implements EntityBeanIntercept {
@@ -31,17 +32,24 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
private static final int STATE_LOADED = 2;
/**
* Used when a bean is partially loaded.
* Used when a bean is partially filled.
*/
private static final byte FLAG_LOADED_PROP = 1;
private static final byte FLAG_CHANGED_PROP = 2;
private static final byte FLAG_CHANGEDLOADED_PROP = 3;
/**
* Flags indicating if a property is a dirty embedded bean. Used to distinguish between an
* embedded bean being completely overwritten vs one with embedded properties that are dirty.
* Flags indicating if a property is a dirty embedded bean. Used to distinguish
* between an embedded bean being completely overwritten and one of its
* embedded properties being made dirty.
*/
private static final byte FLAG_EMBEDDED_DIRTY = 4;
/**
* Flags indicating if a property is a dirty embedded bean. Used to distinguish
* between an embedded bean being completely overwritten and one of its
* embedded properties being made dirty.
*/
private static final byte FLAG_ORIG_VALUE_SET = 8;
/**
* Flags indicating if the mutable hash is set.
*/
@@ -70,9 +78,10 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
private boolean readOnly;
private boolean dirty;
/**
* Flag set to disable lazy loading.
* Flag set to disable lazy loading - typically for SQL "report" type entity beans.
*/
private boolean disableLazyLoad;
/**
* Flag set when lazy loading failed due to the underlying bean being deleted in the DB.
*/
@@ -98,7 +107,7 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
private MutableValueNext[] mutableNext;
/**
* Create with a given entity.
* Create a intercept with a given entity.
*/
public InterceptReadWrite(Object ownerBean) {
this.owner = (EntityBean) ownerBean;
@@ -690,7 +699,7 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
if (beanLoader == null) {
final Database database = DB.byName(ebeanServerName);
if (database == null) {
throw new PersistenceException(ebeanServerName == null ? "No registered default server" : "Database [" + ebeanServerName + "] is not registered");
throw new PersistenceException("Database [" + ebeanServerName + "] was not found?");
}
// For stand alone reference bean or after deserialisation lazy load
// using the ebeanServer. Synchronise only on the bean.
@@ -725,7 +734,7 @@ public final class InterceptReadWrite implements EntityBeanIntercept {
loader.loadBean(this);
if (lazyLoadFailure) {
// failed when lazy loading this bean
throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted. BeanLoader: " + beanLoader);
throw new EntityNotFoundException("Lazy loading failed on type:" + owner.getClass().getName() + " id:" + ownerId + " - Bean has been deleted.");
}
// bean should be loaded and intercepting now. setLoaded() has
// been called by the lazy loading mechanism
@@ -6,6 +6,7 @@ import java.util.Set;
* Notification event that dependent tables have been modified.
* <p>
* This is sent to other interested servers (in the cluster).
* </p>
*/
public class ServerCacheNotification {
@@ -6,6 +6,7 @@ import io.ebean.config.DatabaseConfig;
* Plugin that provides a ServerCacheNotify implementation.
* <p>
* Is supplied this will be used to send the ServerCacheNotification event to other cluster members.
* </p>
*/
public interface ServerCacheNotifyPlugin {
@@ -29,11 +29,6 @@ public class ServerCacheStatistics {
protected long evictCount;
protected long gcCount;
protected long idleCount;
protected long ttlCount;
protected long lruCount;
@Override
public String toString() {
//noinspection StringBufferReplaceableByString
@@ -48,10 +43,6 @@ public class ServerCacheStatistics {
sb.append(" remove:").append(removeCount);
sb.append(" clear:").append(clearCount);
sb.append(" evict:").append(evictCount);
sb.append(" gc:").append(gcCount);
sb.append(" idle:").append(idleCount);
sb.append(" ttl:").append(ttlCount);
sb.append(" lru:").append(lruCount);
return sb.toString();
}
@@ -200,37 +191,4 @@ public class ServerCacheStatistics {
return evictCount;
}
/**
* Set the count of entries removed by the garbage collection.
*/
public void setGcCount(long gcCount) {
this.gcCount = gcCount;
}
/**
* Return the count of entries removed by the garbage collection.
*/
public long getGcCount() {
return gcCount;
}
public void setIdleCount(long idleCount) {
this.idleCount = idleCount;
}
public long getIdleCount() {
return idleCount;
}
public void setTtlCount(long ttlCount) {
this.ttlCount = ttlCount;
}
public long getTtlCount() {
return ttlCount;
}
public void setLruCount(long lruCount) {
this.lruCount = lruCount;
}
}
@@ -17,28 +17,39 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
private static final long serialVersionUID = 3365725236140187588L;
protected final ReentrantLock lock = new ReentrantLock();
protected boolean readOnly;
protected boolean disableLazyLoad;
/**
* The Database this is associated with. (used for lazy fetch).
*/
protected transient BeanCollectionLoader loader;
protected transient ExpressionList<?> filterMany;
/**
* Flag set when registered with the batch loading context.
*/
protected boolean registeredWithLoadContext;
protected String ebeanServerName;
/**
* The owning bean (used for lazy fetch).
*/
protected EntityBean ownerBean;
/**
* The name of this property in the owning bean (used for lazy fetch).
*/
protected String propertyName;
protected ModifyHolder<E> modifyHolder;
protected ModifyListenMode modifyListenMode;
protected boolean modifyListening;
/**
@@ -115,7 +126,8 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
void checkReadOnly() {
if (readOnly) {
throw new IllegalStateException("This collection is in ReadOnly mode");
String msg = "This collection is in ReadOnly mode";
throw new IllegalStateException(msg);
}
}
@@ -11,7 +11,7 @@ import java.util.List;
import java.util.ListIterator;
/**
* List capable of lazy loading and modification awareness.
* List capable of lazy loading.
*/
public final class BeanList<E> extends AbstractBeanCollection<E> implements List<E>, BeanCollectionAdd {
@@ -150,6 +150,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
* Set the actual underlying list.
* <p>
* This is primarily for the deferred fetching function.
* </p>
*/
@SuppressWarnings("unchecked")
public void setActualList(List<?> list) {
@@ -205,11 +206,12 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
* Specifically obj does not need to be a BeanList but any list. This does not
* use the FindMany, fetchedMaxRows or finishedFetch properties in the equals
* test.
* </p>
*/
@Override
public boolean equals(Object other) {
public boolean equals(Object obj) {
init();
return list.equals(other);
return list.equals(obj);
}
@Override
@@ -242,40 +244,40 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
}
@Override
public boolean add(E bean) {
public boolean add(E o) {
checkReadOnly();
init();
if (modifyListening) {
if (list.add(bean)) {
modifyAddition(bean);
if (list.add(o)) {
modifyAddition(o);
return true;
} else {
return false;
}
}
return list.add(bean);
return list.add(o);
}
@Override
public boolean addAll(Collection<? extends E> beans) {
public boolean addAll(Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyListening) {
// all elements in c are added (no contains checking)
getModifyHolder().modifyAdditionAll(beans);
getModifyHolder().modifyAdditionAll(c);
}
return list.addAll(beans);
return list.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends E> beans) {
public boolean addAll(int index, Collection<? extends E> c) {
checkReadOnly();
init();
if (modifyListening) {
// all elements in c are added (no contains checking)
getModifyHolder().modifyAdditionAll(beans);
getModifyHolder().modifyAdditionAll(c);
}
return list.addAll(index, beans);
return list.addAll(index, c);
}
@Override
@@ -285,23 +287,23 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
// and fetch just the Id's
initClear();
if (modifyListening) {
for (E element : list) {
getModifyHolder().modifyRemoval(element);
for (E aList : list) {
getModifyHolder().modifyRemoval(aList);
}
}
list.clear();
}
@Override
public boolean contains(Object bean) {
public boolean contains(Object o) {
init();
return list.contains(bean);
return list.contains(o);
}
@Override
public boolean containsAll(Collection<?> beans) {
public boolean containsAll(Collection<?> c) {
init();
return list.containsAll(beans);
return list.containsAll(c);
}
@Override
@@ -311,9 +313,9 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
}
@Override
public int indexOf(Object bean) {
public int indexOf(Object o) {
init();
return list.indexOf(bean);
return list.indexOf(o);
}
@Override
@@ -325,29 +327,31 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
@Override
public Iterator<E> iterator() {
init();
if (readOnly) {
if (isReadOnly()) {
return new ReadOnlyListIterator<>(list.listIterator());
}
if (modifyListening) {
return new ModifyIterator<>(this, list.iterator());
Iterator<E> it = list.iterator();
return new ModifyIterator<>(this, it);
}
return list.iterator();
}
@Override
public int lastIndexOf(Object bean) {
public int lastIndexOf(Object o) {
init();
return list.lastIndexOf(bean);
return list.lastIndexOf(o);
}
@Override
public ListIterator<E> listIterator() {
init();
if (readOnly) {
if (isReadOnly()) {
return new ReadOnlyListIterator<>(list.listIterator());
}
if (modifyListening) {
return new ModifyListIterator<>(this, list.listIterator());
ListIterator<E> it = list.listIterator();
return new ModifyListIterator<>(this, it);
}
return list.listIterator();
}
@@ -355,11 +359,12 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
@Override
public ListIterator<E> listIterator(int index) {
init();
if (readOnly) {
if (isReadOnly()) {
return new ReadOnlyListIterator<>(list.listIterator(index));
}
if (modifyListening) {
return new ModifyListIterator<>(this, list.listIterator(index));
ListIterator<E> it = list.listIterator(index);
return new ModifyListIterator<>(this, it);
}
return list.listIterator(index);
}
@@ -384,17 +389,17 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
}
@Override
public boolean remove(Object bean) {
public boolean remove(Object o) {
checkReadOnly();
init();
if (modifyListening) {
boolean isRemove = list.remove(bean);
boolean isRemove = list.remove(o);
if (isRemove) {
modifyRemoval(bean);
modifyRemoval(o);
}
return isRemove;
}
return list.remove(bean);
return list.remove(o);
}
@Override
@@ -458,7 +463,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
@Override
public List<E> subList(int fromIndex, int toIndex) {
init();
if (readOnly) {
if (isReadOnly()) {
return Collections.unmodifiableList(list.subList(fromIndex, toIndex));
}
if (modifyListening) {
@@ -474,13 +479,13 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
}
@Override
public <T> T[] toArray(T[] array) {
public <T> T[] toArray(T[] a) {
init();
//noinspection SuspiciousToArrayCall
return list.toArray(array);
return list.toArray(a);
}
private static final class ReadOnlyListIterator<E> implements ListIterator<E>, Serializable {
private static class ReadOnlyListIterator<E> implements ListIterator<E>, Serializable {
private static final long serialVersionUID = 3097271091406323699L;
@@ -12,7 +12,7 @@ import java.util.Map;
import java.util.Set;
/**
* Map capable of lazy loading and modification aware.
* Map capable of lazy loading.
*/
public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Map<K, E> {
@@ -247,7 +247,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
@Override
public Set<Entry<K, E>> entrySet() {
init();
if (readOnly) {
if (isReadOnly()) {
return Collections.unmodifiableSet(map.entrySet());
}
return modifyListening ? new ModifyEntrySet<>(this, map.entrySet()) : map.entrySet();
@@ -268,7 +268,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
@Override
public Set<K> keySet() {
init();
if (readOnly) {
if (isReadOnly()) {
return Collections.unmodifiableSet(map.keySet());
}
return modifyListening ? new ModifyKeySet<>(this, map.keySet()) : map.keySet();
@@ -339,7 +339,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
@Override
public Collection<E> values() {
init();
if (readOnly) {
if (isReadOnly()) {
return Collections.unmodifiableCollection(map.values());
}
return modifyListening ? new ModifyCollection<>(this, map.values()) : map.values();
@@ -9,7 +9,7 @@ import java.util.LinkedHashSet;
import java.util.Set;
/**
* Set capable of lazy loading and modification aware.
* Set capable of lazy loading.
*/
public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E>, BeanCollectionAdd {
@@ -210,27 +210,27 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
// -----------------------------------------------------//
@Override
public boolean add(E bean) {
public boolean add(E o) {
checkReadOnly();
init();
if (modifyListening) {
if (set.add(bean)) {
modifyAddition(bean);
if (set.add(o)) {
modifyAddition(o);
return true;
} else {
return false;
}
}
return set.add(bean);
return set.add(o);
}
@Override
public boolean addAll(Collection<? extends E> beans) {
public boolean addAll(Collection<? extends E> addCollection) {
checkReadOnly();
init();
if (modifyListening) {
boolean changed = false;
for (E bean : beans) {
for (E bean : addCollection) {
if (set.add(bean)) {
// register the addition of the bean
modifyAddition(bean);
@@ -239,7 +239,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
}
return changed;
}
return set.addAll(beans);
return set.addAll(addCollection);
}
@Override
@@ -255,15 +255,15 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
}
@Override
public boolean contains(Object bean) {
public boolean contains(Object o) {
init();
return set.contains(bean);
return set.contains(o);
}
@Override
public boolean containsAll(Collection<?> beans) {
public boolean containsAll(Collection<?> c) {
init();
return set.containsAll(beans);
return set.containsAll(c);
}
@Override
@@ -275,7 +275,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
@Override
public Iterator<E> iterator() {
init();
if (readOnly) {
if (isReadOnly()) {
return new ReadOnlyIterator<>(set.iterator());
}
if (modifyListening) {
@@ -285,17 +285,17 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
}
@Override
public boolean remove(Object bean) {
public boolean remove(Object o) {
checkReadOnly();
init();
if (modifyListening) {
if (set.remove(bean)) {
modifyRemoval(bean);
if (set.remove(o)) {
modifyRemoval(o);
return true;
}
return false;
}
return set.remove(bean);
return set.remove(o);
}
@Override
@@ -349,13 +349,13 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
}
@Override
public <T> T[] toArray(T[] array) {
public <T> T[] toArray(T[] a) {
init();
//noinspection SuspiciousToArrayCall
return set.toArray(array);
return set.toArray(a);
}
private static final class ReadOnlyIterator<E> implements Iterator<E>, Serializable {
private static class ReadOnlyIterator<E> implements Iterator<E>, Serializable {
private static final long serialVersionUID = 2577697326745352605L;
@@ -237,7 +237,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
}
buffer.append(rhsTableName);
int maxTableNameLength = databasePlatform.maxTableNameLength();
int maxTableNameLength = databasePlatform.getMaxTableNameLength();
// maxConstraintNameLength is used as the max table name length.
if (buffer.length() > maxTableNameLength) {
@@ -6,10 +6,6 @@ import java.util.concurrent.Callable;
* BackgroundExecutorWrapper that can be used to wrap tasks that are sent to background (i.e. another thread).
* It should copy all necessary thread-local variables. See {@link MdcBackgroundExecutorWrapper} for implementation details.
*
* Note: only tasks that are executed immediately (submit, execute) are wrapped. Periodic or scheduled tasks are not wrapped,
* as these may keep copied variables in memory either forever or until the scheduled task is finished.
* The caller is responsible to handle these cases.
*
* @author Roland Praml, FOCONIS AG
*/
public interface BackgroundExecutorWrapper {
@@ -16,7 +16,6 @@ import io.ebean.event.changelog.ChangeLogPrepare;
import io.ebean.event.changelog.ChangeLogRegister;
import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.meta.MetricNamingMatch;
import io.ebean.util.StringHelper;
import javax.persistence.EnumType;
@@ -25,18 +24,19 @@ import java.time.Clock;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
/**
* The configuration used for creating a Database.
* <p>
* Used to programmatically construct an Database and optionally register it
* with the DB singleton.
* </p>
* <p>
* If you just use DB thout this programmatic configuration Ebean will read
* the application.properties file and take the configuration from there. This usually
* includes searching the class path and automatically registering any entity
* classes and listeners etc.
* </p>
* <pre>{@code
*
* DatabaseConfig config = new DatabaseConfig();
@@ -56,6 +56,7 @@ import java.util.function.Function;
* <p>
* Note that DatabaseConfigProvider provides a standard Java ServiceLoader mechanism that can
* be used to apply configuration to the DatabaseConfig.
* </p>
*
* @author emcgreal
* @author rbygrave
@@ -114,19 +115,19 @@ public class DatabaseConfig {
private TenantCatalogProvider tenantCatalogProvider;
/**
* When true will load entity classes via EntityClassRegister.
* When true will load entity classes via ModuleInfoLoader.
* <p>
* NB: EntityClassRegister implementations are generated by querybean generator.
* NB: ModuleInfoLoader implementations are generated by querybean generator.
* Having this on and registering entity classes means we don't need to manually
* write that code or use classpath scanning to find entity classes.
*/
private boolean loadModuleInfo = true;
/**
* Interesting classes such as entities, embedded, ScalarTypes,
* Listeners, Finders, Controllers, AttributeConverters etc.
* List of interesting classes such as entities, embedded, ScalarTypes,
* Listeners, Finders, Controllers etc.
*/
private Set<Class<?>> classes = new HashSet<>();
private List<Class<?>> classes = new ArrayList<>();
/**
* The packages that are searched for interesting classes. Only used when
@@ -545,8 +546,6 @@ public class DatabaseConfig {
private String dumpMetricsOptions;
private Function<String, String> metricNaming = MetricNamingMatch.INSTANCE;
/**
* Construct a Database Configuration for programmatically creating an Database.
*/
@@ -612,7 +611,7 @@ public class DatabaseConfig {
}
/**
* Put a service object into configuration such that it can be used by ebean or a plugin.
* Put a service object into configuration such that it can be passed to a plugin.
* <p>
* For example, put IgniteConfiguration in to be passed to the Ignite plugin.
*/
@@ -620,23 +619,6 @@ public class DatabaseConfig {
serviceObject.put(key, configObject);
}
/**
* Put a service object into configuration such that it can be used by ebean or a plugin.
* <p>
* For example, put IgniteConfiguration in to be passed to the Ignite plugin.
* You can also override some SPI objects that should be used for that Database. Currently, the following
* objects are possible.
* <ul>
* <li>DataSourceAlertFactory (e.g. add different alert factories for different ebean instances)</li>
* <li>DocStoreFactory</li>
* <li>SlowQueryListener (e.g. add custom query listener for a certain ebean instance)</li>
* <li>ServerCacheNotifyPlugin</li>
* </ul>
*/
public <T> void putServiceObject(Class<T> iface, T configObject) {
serviceObject.put(serviceObjectKey(iface), configObject);
}
/**
* Return the service object given the key.
*/
@@ -645,7 +627,7 @@ public class DatabaseConfig {
}
/**
* Put a service object into configuration such that it can be used by ebean or a plugin.
* Put a service object into configuration such that it can be passed to a plugin.
*
* <pre>{@code
*
@@ -670,7 +652,7 @@ public class DatabaseConfig {
}
/**
* Used by ebean or plugins to obtain service objects.
* Used by plugins to obtain service objects.
*
* <pre>{@code
*
@@ -2320,7 +2302,8 @@ public class DatabaseConfig {
}
/**
* Programmatically add classes (typically entities) that this server should use.
* Programmatically add classes (typically entities) that this server should
* use.
* <p>
* The class can be an Entity, Embedded type, ScalarType, BeanPersistListener,
* BeanFinder or BeanPersistController.
@@ -2330,7 +2313,8 @@ public class DatabaseConfig {
* <p>
* Alternatively the classes can be added via {@link #setClasses(List)}.
*
* @param cls the entity type (or other type) that should be registered by this database.
* @param cls the entity type (or other type) that should be registered by this
* database.
*/
public void addClass(Class<?> cls) {
classes.add(cls);
@@ -2339,7 +2323,7 @@ public class DatabaseConfig {
/**
* Register all the classes (typically entity classes).
*/
public void addAll(Collection<Class<?>> classList) {
public void addAll(List<Class<?>> classList) {
if (classList != null && !classList.isEmpty()) {
classes.addAll(classList);
}
@@ -2381,26 +2365,15 @@ public class DatabaseConfig {
* <p>
* Alternatively the classes can contain added via {@link #addClass(Class)}.
*/
public void setClasses(Collection<Class<?>> classes) {
this.classes = new HashSet<>(classes);
public void setClasses(List<Class<?>> classes) {
this.classes = classes;
}
/**
* Return the classes registered for this database. Typically, this includes
* Return the classes registered for this database. Typically this includes
* entities and perhaps listeners.
*/
public Set<Class<?>> classes() {
return classes;
}
/**
* Deprecated - migrate to classes().
* <p>
* Sorry if returning Set rather than List breaks code but it feels safer to
* do that than a subtle change to return a shallow copy which you will not detect.
*/
@Deprecated
public Set<Class<?>> getClasses() {
public List<Class<?>> getClasses() {
return classes;
}
@@ -2769,6 +2742,8 @@ public class DatabaseConfig {
this.classLoadConfig = classLoadConfig;
}
/**
* Load settings from application.properties, application.yaml and other sources.
* <p>
@@ -2913,7 +2888,7 @@ public class DatabaseConfig {
serverCachePlugin = p.createInstance(ServerCachePlugin.class, "serverCachePlugin", serverCachePlugin);
String packagesProp = p.get("search.packages", p.get("packages", null));
packages = searchList(packagesProp, packages);
packages = getSearchList(packagesProp, packages);
skipCacheAfterWrite = p.getBoolean("skipCacheAfterWrite", skipCacheAfterWrite);
updateAllPropertiesInBatch = p.getBoolean("updateAllPropertiesInBatch", updateAllPropertiesInBatch);
@@ -2989,10 +2964,10 @@ public class DatabaseConfig {
tenantCatalogProvider = p.createInstance(TenantCatalogProvider.class, "tenant.catalogProvider", tenantCatalogProvider);
tenantSchemaProvider = p.createInstance(TenantSchemaProvider.class, "tenant.schemaProvider", tenantSchemaProvider);
tenantPartitionColumn = p.get("tenant.partitionColumn", tenantPartitionColumn);
classes = readClasses(p);
classes = getClasses(p);
String mappingsProp = p.get("mappingLocations", null);
mappingLocations = searchList(mappingsProp, mappingLocations);
mappingLocations = getSearchList(mappingsProp, mappingLocations);
}
private NamingConvention createNamingConvention(PropertiesWrapper properties, NamingConvention namingConvention) {
@@ -3006,13 +2981,13 @@ public class DatabaseConfig {
* @param properties the properties
* @return the classes
*/
private Set<Class<?>> readClasses(PropertiesWrapper properties) {
private List<Class<?>> getClasses(PropertiesWrapper properties) {
String classNames = properties.get("classes", null);
if (classNames == null) {
return classes;
}
Set<Class<?>> classList = new HashSet<>();
List<Class<?>> classList = new ArrayList<>();
String[] split = StringHelper.splitNames(classNames);
for (String cn : split) {
if (!"class".equalsIgnoreCase(cn)) {
@@ -3027,7 +3002,7 @@ public class DatabaseConfig {
return classList;
}
private List<String> searchList(String searchNames, List<String> defaultValue) {
private List<String> getSearchList(String searchNames, List<String> defaultValue) {
if (searchNames != null) {
String[] entries = StringHelper.splitNames(searchNames);
List<String> hitList = new ArrayList<>(entries.length);
@@ -3045,7 +3020,7 @@ public class DatabaseConfig {
public PersistBatch appliedPersistBatchOnCascade() {
if (persistBatchOnCascade == PersistBatch.INHERIT) {
// use the platform default (ALL except SQL Server which has NONE)
return databasePlatform.persistBatchOnCascade();
return databasePlatform.getPersistBatchOnCascade();
}
return persistBatchOnCascade;
}
@@ -3401,21 +3376,13 @@ public class DatabaseConfig {
}
/**
* Return true if entity classes should be loaded and registered via EntityClassRegister.
* Return true if entity classes should be loaded and registered via ModuleInfoLoader.
* <p>
* When false we either register entity classes via application code or use classpath
* scanning to find and register entity classes.
*/
public boolean isLoadModuleInfo() {
return loadModuleInfo;
}
/**
* Deprecated - migrate to isLoadModuleInfo().
*/
@Deprecated
public boolean isAutoLoadModuleInfo() {
return loadModuleInfo;
return loadModuleInfo && classes.isEmpty();
}
/**
@@ -3429,20 +3396,6 @@ public class DatabaseConfig {
this.loadModuleInfo = loadModuleInfo;
}
/**
* Return the naming convention to apply to metrics names.
*/
public Function<String, String> getMetricNaming() {
return metricNaming;
}
/**
* Set the naming convention to apply to metrics names.
*/
public void setMetricNaming(Function<String, String> metricNaming) {
this.metricNaming = metricNaming;
}
public enum UuidVersion {
VERSION4,
VERSION1,
@@ -5,7 +5,7 @@ import java.util.List;
/**
* Loads and returns entity classes to register with Ebean databases.
*/
public interface EntityClassRegister {
public interface ModuleInfoLoader {
/**
* Return entity classes to register for a named DB (not default DB).
@@ -1,26 +1,49 @@
package io.ebean.config.dbplatform;
import io.ebean.BackgroundExecutor;
import io.ebean.EbeanVersion;
import io.ebean.Query;
import io.ebean.annotation.PartitionMode;
import io.ebean.annotation.PersistBatch;
import io.ebean.annotation.Platform;
import io.ebean.config.CustomDbTypeMapping;
import io.ebean.config.PlatformConfig;
import io.ebean.util.JdbcClose;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
import java.sql.*;
import static java.lang.System.Logger.Level.*;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
/**
* Database platform specific settings.
*/
public class DatabasePlatform {
private static final System.Logger log = EbeanVersion.log;
private static final Logger log = LoggerFactory.getLogger("io.ebean");
/**
* Behavior used when ending a query only transaction (at read committed isolation level).
*/
public enum OnQueryOnly {
/**
* Rollback the transaction.
*/
ROLLBACK,
/**
* Commit the transaction
*/
COMMIT
}
/**
* Set to true for MySql, no other jdbc drivers need this workaround.
@@ -37,11 +60,16 @@ public class DatabasePlatform {
* Can we use native java time API objects in
* {@link ResultSet#getObject(int, Class)} and
* {@link PreparedStatement#setObject(int, Object)}.
* <p>
*
* Not all drivers (DB2 e.g.) will support this.
*/
protected boolean supportsNativeJavaTime = true;
/**
* The behaviour used when ending a read only transaction at read committed isolation level.
*/
protected OnQueryOnly onQueryOnly = OnQueryOnly.COMMIT;
/**
* The open quote used by quoted identifiers.
*/
@@ -118,6 +146,11 @@ public class DatabasePlatform {
*/
protected int clobDbType = Types.CLOB;
/**
* For Oracle treat empty strings as null.
*/
protected boolean treatEmptyStringsAsNull;
/**
* The database platform name.
*/
@@ -132,7 +165,7 @@ public class DatabasePlatform {
* want to use quoted identifiers for. The backticks get converted to the
* appropriate characters in convertQuotedIdentifiers
*/
private static final char[] QUOTED_IDENTIFIERS = new char[]{'"', '\'', '[', ']', '`'};
private static final char[] QUOTED_IDENTIFIERS = new char[] { '"', '\'', '[', ']', '`' };
/**
* The non-escaped like clause (to stop slash being escaped on some platforms).
@@ -266,7 +299,7 @@ public class DatabasePlatform {
/**
* Return the platform key.
*/
public Platform platform() {
public Platform getPlatform() {
return platform;
}
@@ -276,14 +309,14 @@ public class DatabasePlatform {
* "generic" is returned when no specific database platform has been set or found.
* </p>
*/
public String name() {
public String getName() {
return platform.name().toLowerCase();
}
/**
* Return true if we are using Sequence batch mode rather than STEP.
*/
public boolean sequenceBatchMode() {
public boolean isSequenceBatchMode() {
return sequenceBatchMode;
}
@@ -297,52 +330,52 @@ public class DatabasePlatform {
/**
* Return true if this database platform supports native ILIKE expression.
*/
public boolean supportsNativeIlike() {
public boolean isSupportsNativeIlike() {
return supportsNativeIlike;
}
/**
* Return true if the platform supports delete statements with table alias.
*/
public boolean supportsDeleteTableAlias() {
public boolean isSupportsDeleteTableAlias() {
return supportsDeleteTableAlias;
}
/**
* Return true if the collation is case-sensitive.
* Return true if the collation is case sensitive.
* <p>
* This is expected to be used for testing only.
* </p>
*/
public boolean caseSensitiveCollation() {
public boolean isCaseSensitiveCollation() {
return caseSensitiveCollation;
}
/**
* Return true if the platform supports SavepointId values.
*/
public boolean supportsSavepointId() {
public boolean isSupportsSavepointId() {
return supportsSavepointId;
}
/**
* Return true if migrations should use stored procedures.
*/
public boolean useMigrationStoredProcedures() {
public boolean isUseMigrationStoredProcedures() {
return useMigrationStoredProcedures;
}
/**
* Return true if the platform supports LIMIT with sql update.
*/
public boolean inlineSqlUpdateLimit() {
public boolean isInlineSqlUpdateLimit() {
return inlineSqlUpdateLimit;
}
/**
* Return the maximum number of bind values this database platform allows or zero for no limit.
*/
public int maxInBinding() {
public int getMaxInBinding() {
return maxInBinding;
}
@@ -352,14 +385,14 @@ public class DatabasePlatform {
* This is used when deriving names of intersection tables.
* </p>
*/
public int maxTableNameLength() {
public int getMaxTableNameLength() {
return maxTableNameLength;
}
/**
* Return the maximum constraint name allowed for the platform.
*/
public int maxConstraintNameLength() {
public int getMaxConstraintNameLength() {
return maxConstraintNameLength;
}
@@ -387,10 +420,24 @@ public class DatabasePlatform {
return null;
}
/**
* Return the behaviour to use when ending a read only transaction.
*/
public OnQueryOnly getOnQueryOnly() {
return onQueryOnly;
}
/**
* Set the behaviour to use when ending a read only transaction.
*/
public void setOnQueryOnly(OnQueryOnly onQueryOnly) {
this.onQueryOnly = onQueryOnly;
}
/**
* Return the DbEncrypt handler for this DB platform.
*/
public DbEncrypt dbEncrypt() {
public DbEncrypt getDbEncrypt() {
return dbEncrypt;
}
@@ -404,7 +451,7 @@ public class DatabasePlatform {
/**
* Return the history support for this database platform.
*/
public DbHistorySupport historySupport() {
public DbHistorySupport getHistorySupport() {
return historySupport;
}
@@ -418,14 +465,14 @@ public class DatabasePlatform {
/**
* So no except for Postgres and CockroachDB.
*/
public boolean nativeArrayType() {
public boolean isNativeArrayType() {
return false;
}
/**
* Return true if the DB supports native UUID.
*/
public boolean nativeUuidType() {
public boolean isNativeUuidType() {
return nativeUuidType;
}
@@ -434,21 +481,21 @@ public class DatabasePlatform {
*
* @return the db type map
*/
public DbPlatformTypeMapping dbTypeMap() {
public DbPlatformTypeMapping getDbTypeMap() {
return dbTypeMap;
}
/**
* Return the mapping for DB column default values.
*/
public DbDefaultValue dbDefaultValue() {
public DbDefaultValue getDbDefaultValue() {
return dbDefaultValue;
}
/**
* Return the column alias prefix.
*/
public String columnAliasPrefix() {
public String getColumnAliasPrefix() {
return columnAliasPrefix;
}
@@ -462,21 +509,21 @@ public class DatabasePlatform {
/**
* Return the close quote for quoted identifiers.
*/
public String closeQuote() {
public String getCloseQuote() {
return closeQuote;
}
/**
* Return the open quote for quoted identifiers.
*/
public String openQuote() {
public String getOpenQuote() {
return openQuote;
}
/**
* Return the JDBC type used to store booleans.
*/
public int booleanDbType() {
public int getBooleanDbType() {
return booleanDbType;
}
@@ -487,7 +534,7 @@ public class DatabasePlatform {
* example.
* </p>
*/
public int blobDbType() {
public int getBlobDbType() {
return blobDbType;
}
@@ -497,16 +544,25 @@ public class DatabasePlatform {
* This is typically Types.CLOB but for Postgres is Types.VARCHAR.
* </p>
*/
public int clobDbType() {
public int getClobDbType() {
return clobDbType;
}
/**
* Return true if empty strings should be treated as null.
*
* @return true, if checks if is treat empty strings as null
*/
public boolean isTreatEmptyStringsAsNull() {
return treatEmptyStringsAsNull;
}
/**
* Return true if a compound ID in (...) type expression needs to be in
* expanded form of (a=? and b=?) or (a=? and b=?) or ... rather than (a,b) in
* ((?,?),(?,?),...);
*/
public boolean idInExpandedForm() {
public boolean isIdInExpandedForm() {
return idInExpandedForm;
}
@@ -517,7 +573,7 @@ public class DatabasePlatform {
* This specifically is required for MySql when processing large results.
* </p>
*/
public boolean forwardOnlyHintOnFindIterate() {
public boolean isForwardOnlyHintOnFindIterate() {
return forwardOnlyHintOnFindIterate;
}
@@ -535,7 +591,7 @@ public class DatabasePlatform {
* This specifically is required for Hana which doesn't support CONCUR_UPDATABLE
* </p>
*/
public boolean supportsResultSetConcurrencyModeUpdatable() {
public boolean isSupportsResultSetConcurrencyModeUpdatable() {
return supportsResultSetConcurrencyModeUpdatable;
}
@@ -555,7 +611,7 @@ public class DatabasePlatform {
*
* @return the db identity
*/
public DbIdentity dbIdentity() {
public DbIdentity getDbIdentity() {
return dbIdentity;
}
@@ -568,14 +624,14 @@ public class DatabasePlatform {
*
* @return the sql limiter
*/
public SqlLimiter sqlLimiter() {
public SqlLimiter getSqlLimiter() {
return sqlLimiter;
}
/**
* Return the BasicSqlLimiter for limit/offset of SqlQuery queries.
*/
public BasicSqlLimiter basicSqlLimiter() {
public BasicSqlLimiter getBasicSqlLimiter() {
return basicSqlLimiter;
}
@@ -610,7 +666,7 @@ public class DatabasePlatform {
if (isQuote(dbName.charAt(dbName.length() - 1))) {
return openQuote + dbName.substring(1, dbName.length() - 1) + closeQuote;
} else {
log.log(ERROR, "Missing backquote on [" + dbName + "]");
log.error("Missing backquote on [" + dbName + "]");
}
} else if (allQuotedIdentifiers) {
return openQuote + dbName + closeQuote;
@@ -620,8 +676,8 @@ public class DatabasePlatform {
}
private boolean isQuote(char ch) {
for (char identifier : QUOTED_IDENTIFIERS) {
if (identifier == ch) {
for (char identifer : QUOTED_IDENTIFIERS) {
if (identifer == ch) {
return true;
}
}
@@ -644,14 +700,14 @@ public class DatabasePlatform {
/**
* Set to true if select count against anonymous view requires an alias.
*/
public boolean selectCountWithAlias() {
public boolean isSelectCountWithAlias() {
return selectCountWithAlias;
}
/**
* Return true if select count with subquery needs column alias (SQL Server).
*/
public boolean selectCountWithColumnAlias() {
public boolean isSelectCountWithColumnAlias() {
return selectCountWithColumnAlias;
}
@@ -673,7 +729,7 @@ public class DatabasePlatform {
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
// silently assume the database does not support the "for update" clause.
log.log(INFO, "it seems your database does not support the 'for update' clause");
log.info("it seems your database does not support the 'for update' clause");
return sql;
}
@@ -682,14 +738,14 @@ public class DatabasePlatform {
* <p>
* This may include an escape clause to disable a default escape character.
*/
public String likeClause(boolean rawLikeExpression) {
public String getLikeClause(boolean rawLikeExpression) {
return rawLikeExpression ? likeClauseRaw : likeClauseEscaped;
}
/**
* Return the platform default JDBC batch mode for persist cascade.
*/
public PersistBatch persistBatchOnCascade() {
public PersistBatch getPersistBatchOnCascade() {
return persistBatchOnCascade;
}
@@ -707,7 +763,7 @@ public class DatabasePlatform {
if (!schemaExists(dbSchema, connection)) {
Statement query = connection.createStatement();
try {
log.log(DEBUG, "create schema:{0}", dbSchema);
log.debug("create schema:{}", dbSchema);
query.executeUpdate("create schema " + dbSchema);
} finally {
JdbcClose.close(query);
@@ -733,6 +789,33 @@ public class DatabasePlatform {
return false;
}
/**
* Return true if the table exists.
*/
public boolean tableExists(Connection connection, String catalog, String schema, String table) throws SQLException {
DatabaseMetaData metaData = connection.getMetaData();
ResultSet tables = metaData.getTables(catalog, schema, table, null);
try {
return tables.next();
} finally {
JdbcClose.close(tables);
}
}
/**
* Return true if partitions exist for the given table.
*/
public boolean tablePartitionsExist(Connection connection, String table) throws SQLException {
return true;
}
/**
* Return the SQL to create an initial partition for the given table.
*/
public String tablePartitionInit(String tableName, PartitionMode mode, String property, String singlePrimaryKey) {
return null;
}
/**
* Escapes the like string for this DB-Platform
*/
@@ -3,25 +3,42 @@ package io.ebean.config.dbplatform;
/**
* Adds LIMIT OFFSET clauses to a SQL query.
*/
public final class LimitOffsetSqlLimiter implements SqlLimiter {
public class LimitOffsetSqlLimiter implements SqlLimiter {
/**
* LIMIT keyword.
*/
private static final String LIMIT = "limit";
/**
* OFFSET keyword.
*/
private static final String OFFSET = "offset";
@Override
public SqlLimitResponse limit(SqlLimitRequest request) {
String dbSql = request.getDbSql();
StringBuilder sb = new StringBuilder(50 + dbSql.length());
sb.append("select ");
if (request.isDistinct()) {
sb.append("distinct ");
}
sb.append(dbSql);
int maxRows = request.getMaxRows();
if (maxRows > 0) {
sb.append(" limit ").append(maxRows);
}
int firstRow = request.getFirstRow();
if (firstRow > 0) {
sb.append(" offset ").append(firstRow);
int maxRows = request.getMaxRows();
if (maxRows > 0 || firstRow > 0) {
sb.append(" ").append(LIMIT).append(" ").append(maxRows);
if (firstRow > 0) {
sb.append(" ").append(OFFSET).append(" ");
sb.append(firstRow);
}
}
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
return new SqlLimitResponse(sql);
}
@@ -1,9 +1,10 @@
package io.ebean.config.dbplatform;
import io.avaje.applog.AppLog;
import io.ebean.BackgroundExecutor;
import io.ebean.Transaction;
import io.ebean.util.JdbcClose;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
@@ -18,15 +19,12 @@ import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.ERROR;
/**
* Database sequence based IdGenerator.
*/
public abstract class SequenceIdGenerator implements PlatformIdGenerator {
protected static final System.Logger log = AppLog.getLogger("io.ebean.SEQ");
protected static final Logger log = LoggerFactory.getLogger("io.ebean.SEQ");
private final ReentrantLock lock = new ReentrantLock();
protected final String seqName;
@@ -122,7 +120,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
protected void loadInBackground(final int requestSize) {
if (currentlyBackgroundLoading.get()) {
// skip as already background loading
log.log(DEBUG, "... skip background sequence load (another load in progress)");
log.debug("... skip background sequence load (another load in progress)");
return;
}
currentlyBackgroundLoading.set(true);
@@ -154,6 +152,9 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
resultSet = statement.executeQuery();
List<Long> newIds = readIds(resultSet, requestSize);
if (log.isTraceEnabled()) {
log.trace("seq:{} loaded:{} sql:{}", seqName, newIds.size(), sql);
}
if (newIds.isEmpty()) {
throw new PersistenceException("Always expecting more than 1 row from " + sql);
}
@@ -163,7 +164,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
} catch (SQLException e) {
if (e.getMessage().contains("Database is already closed")) {
String msg = "Error getting SEQ when DB shutting down " + e.getMessage();
log.log(ERROR, msg);
log.error(msg);
System.out.println(msg);
return Collections.emptyList();
} else {
@@ -32,12 +32,7 @@ public class SqlCodeTranslator implements SqlExceptionTranslator {
}
private DataErrorType getErrorType(SQLException e) {
String sqlState = e.getSQLState();
while (sqlState == null && e.getCause() instanceof SQLException) {
e = (SQLException)e.getCause();
sqlState = e.getSQLState();
}
DataErrorType errorType = map.get(sqlState);
DataErrorType errorType = map.get(e.getSQLState());
if (errorType == null) {
// fall back to error code
errorType = map.get(String.valueOf(e.getErrorCode()));
@@ -5,6 +5,14 @@ package io.ebean.config.dbplatform;
*/
public interface SqlLimiter {
/**
* the new line character used.
* <p>
* Note that this is removed for logging sql to the transaction log.
* </p>
*/
char NEW_LINE = '\n';
/**
* Add the SQL limiting statements around the query.
*/
@@ -1,8 +1,9 @@
package io.ebean.event;
import io.ebean.Database;
import io.ebean.EbeanVersion;
import io.ebean.service.SpiContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Driver;
import java.sql.DriverManager;
@@ -12,8 +13,6 @@ import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import static java.lang.System.Logger.Level.*;
/**
* Manages the shutdown of Ebean.
* <p>
@@ -21,14 +20,13 @@ import static java.lang.System.Logger.Level.*;
*/
public final class ShutdownManager {
private static final System.Logger log = EbeanVersion.log;
private static final Logger log = LoggerFactory.getLogger("io.ebean");
private static final ReentrantLock lock = new ReentrantLock();
private static final List<Database> databases = new ArrayList<>();
private static final ShutdownHook shutdownHook = new ShutdownHook();
private static boolean stopping;
private static SpiContainer container;
static {
// Register the Shutdown hook
registerShutdownHook();
@@ -122,7 +120,9 @@ public final class ShutdownManager {
// Already run shutdown...
return;
}
log.log(DEBUG, "Ebean shutting down");
if (log.isDebugEnabled()) {
log.debug("Ebean shutting down");
}
stopping = true;
deregisterShutdownHook();
@@ -133,7 +133,7 @@ public final class ShutdownManager {
Runnable r = (Runnable) ClassUtil.newInstance(shutdownRunner);
r.run();
} catch (Exception e) {
log.log(ERROR, "Error running custom shutdown runnable", e);
log.error("Error running custom shutdown runnable", e);
}
}
@@ -147,7 +147,7 @@ public final class ShutdownManager {
try {
server.shutdown();
} catch (Exception ex) {
log.log(ERROR, "Error executing shutdown runnable", ex);
log.error("Error executing shutdown runnable", ex);
ex.printStackTrace();
}
}
@@ -165,10 +165,10 @@ public final class ShutdownManager {
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
try {
log.log(INFO, "De-registering jdbc driver: " + driver);
log.info("De-registering jdbc driver: " + driver);
DriverManager.deregisterDriver(driver);
} catch (SQLException e) {
log.log(ERROR, "Error de-registering driver " + driver, e);
log.error("Error de-registering driver " + driver, e);
}
}
}
@@ -204,7 +204,6 @@ public final class ShutdownManager {
private ShutdownHook() {
super("EbeanHook");
}
@Override
public void run() {
ShutdownManager.shutdown();
@@ -2,57 +2,28 @@ package io.ebean.meta;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
/**
* A simple MetricVisitor that can collect the desired metrics into lists.
*/
public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerMetrics {
private final String name;
private final Function<String,String> naming;
private final List<MetaTimedMetric> timed = new ArrayList<>();
private final List<MetaQueryMetric> query = new ArrayList<>();
private final List<MetaCountMetric> count = new ArrayList<>();
public BasicMetricVisitor() {
this("db", MetricNamingMatch.INSTANCE);
}
/**
* Construct to reset and collect everything.
*/
public BasicMetricVisitor(String name, Function<String,String> naming) {
this(name, naming, true, true, true, true);
public BasicMetricVisitor() {
super(true, true, true, true);
}
/**
* Construct specifying reset and what to collect.
*/
public BasicMetricVisitor(String name, Function<String,String> naming, boolean reset, boolean collectTransactionMetrics, boolean collectQueryMetrics, boolean collectL2Metrics) {
public BasicMetricVisitor(boolean reset, boolean collectTransactionMetrics, boolean collectQueryMetrics, boolean collectL2Metrics) {
super(reset, collectTransactionMetrics, collectQueryMetrics, collectL2Metrics);
this.name = name;
this.naming = naming;
}
@Override
public String name() {
return name;
}
@Override
public Function<String, String> namingConvention() {
return naming;
}
@Override
public ServerMetricsAsJson asJson() {
return new MetricsAsJson(this);
}
@Override
public List<MetricData> asData() {
return new MetricsAsData(this).data();
}
@Override
@@ -17,20 +17,21 @@ public interface MetaInfoManager {
ServerMetrics collectMetrics();
/**
* Deprecated migrate to collectMetrics().asJson().
* Collect the metrics in raw JSON form.
* <pre>{@code
*
* String metricsJson = database.getMetaInfoManager()
* .collectMetricsAsJson()
* .json();
*
* }</pre>
*/
@Deprecated
default ServerMetricsAsJson collectMetricsAsJson() {
return collectMetrics().asJson();
}
ServerMetricsAsJson collectMetricsAsJson();
/**
* Deprecated migrate to collectMetrics().asData().
* Return the metrics as a list of MetricData.
*/
@Deprecated
default List<MetricData> collectMetricsAsData() {
return collectMetrics().asData();
}
List<MetricData> collectMetricsAsData();
/**
* Visit the metrics resetting and collecting/reporting as desired.
@@ -1,16 +0,0 @@
package io.ebean.meta;
import java.util.function.Function;
/**
* Metric naming convention that is exact match.
*/
public final class MetricNamingMatch implements Function<String, String> {
public static final Function<String, String> INSTANCE = new MetricNamingMatch();
@Override
public String apply(String name) {
return name;
}
}
@@ -1,17 +1,10 @@
package io.ebean.meta;
import java.util.function.Function;
/**
* Defines visitor to read and report the transaction and query metrics.
*/
public interface MetricVisitor {
/**
* Return the naming convention that should be applied to the reported metric names.
*/
Function<String, String> namingConvention();
/**
* Return true if the metrics should be reset.
*/
@@ -7,21 +7,6 @@ import java.util.List;
*/
public interface ServerMetrics {
/**
* Return the name of the database these metrics were obtained for.
*/
String name();
/**
* Return ServerMetricsAsJson to build the metrics as JSON content.
*/
ServerMetricsAsJson asJson();
/**
* Return the metrics as a list of MetricData.
*/
List<MetricData> asData();
/**
* Return timed metrics for Transactions, labelled SqlQuery, labelled SqlUpdate.
*/
@@ -39,6 +39,18 @@ public interface ExpressionPath {
*/
StringParser stringParser();
/**
* For DateTime capable scalar types convert the long systemTimeMillis into
* an appropriate java time (Date,Timestamp,Time,Calendar, JODA type etc).
*/
Object parseDateTime(long systemTimeMillis);
/**
* Return true if the last type is "DateTime capable" - can support
* {@link #parseDateTime(long)}.
*/
boolean isDateTimeCapable();
/**
* Return the underlying JDBC type or 0 if this is not a scalar type.
*/
@@ -13,16 +13,9 @@ public interface SpiProfileLocationFactory {
ProfileLocation create();
/**
* Create a profile location with line numbering.
* Create a profile location with a line number.
*/
ProfileLocation createWithLine();
/**
* Create with a given label - used only with {@code @Transaction}.
*
* @param label the label for the transaction
*/
ProfileLocation create(String label);
ProfileLocation create(int lineNumber, String label);
/**
* Create a known location.
@@ -6,7 +6,6 @@ package io.ebean.text;
* Basic interface to support CSV, JSON and XML processing.
* </p>
*/
@FunctionalInterface
public interface StringFormatter {
/**
@@ -5,7 +5,6 @@ package io.ebean.text;
* <p>
* Basic interface to support CSV, JSON and XML processing.
*/
@FunctionalInterface
public interface StringParser {
/**
@@ -1,6 +1,4 @@
package io.ebean.csv.reader;
import io.ebean.text.StringParser;
package io.ebean.text;
import java.sql.Time;
@@ -1,4 +1,4 @@
package io.ebean.csv.reader;
package io.ebean.text.csv;
import io.ebean.Database;
@@ -0,0 +1,171 @@
package io.ebean.text.csv;
import io.ebean.text.StringParser;
import java.io.Reader;
import java.util.Locale;
/**
* Reads CSV data turning it into object graphs that you can be saved (inserted)
* or processed yourself.
* <p>
* This first example doesn't use a {@link CsvCallback} and this means it will
* automatically create a transaction, save the customers and commit the
* transaction when successful.
* </p>
*
* <pre>{@code
* try {
* File f = new File("src/test/resources/test1.csv");
*
* FileReader reader = new FileReader(f, encoding);
*
* CsvReader<Customer> csvReader = DB.createCsvReader(Customer.class);
*
* csvReader.setPersistBatchSize(20);
*
* csvReader.addProperty("status");
* // ignore the next property
* csvReader.addIgnore();
* csvReader.addProperty("name");
* csvReader.addDateTime("anniversary", "dd-MMM-yyyy");
* csvReader.addProperty("billingAddress.line1");
* csvReader.addProperty("billingAddress.city");
*
* csvReader.process(reader);
*
* } catch (Exception e) {
* throw new RuntimeException(e);
* }
* }</pre>
*
* @param <T> the entity bean type
*/
public interface CsvReader<T> {
/**
* Explicitly set the default Locale.
*/
void setDefaultLocale(Locale defaultLocale);
/**
* Set the default format to use for Time types.
*/
void setDefaultTimeFormat(String defaultTimeFormat);
/**
* Set the default format to use for Date types.
*/
void setDefaultDateFormat(String defaultDateFormat);
/**
* Set the default format to use for Timestamp types.
*/
void setDefaultTimestampFormat(String defaultTimestampFormat);
/**
* Set the batch size for using JDBC statement batching.
* <p>
* By default this is set to 20 and setting this to 1 will disable the use of
* JDBC statement batching.
* </p>
*/
void setPersistBatchSize(int persistBatchSize);
/**
* Set to true if there is a header row that should be ignored.
* <p>
* If addPropertiesFromHeader is true then all the properties are added using
* the default time,date and timestamp formats.
* <p>
* If you have a mix of dateTime formats you can not use this method and must
* add the properties yourself.
* </p>
*/
void setHasHeader(boolean hasHeader, boolean addPropertiesFromHeader);
/**
* Same as setHasHeader(true,true);
* <p>
* This will use a header to define all the properties to load using the
* default formats for time, date and datetime types.
* </p>
*/
void setAddPropertiesFromHeader();
/**
* Same as setHasHeader(true, false);
* <p>
* This indicates that there is a header but that it should be ignored.
* </p>
*/
void setIgnoreHeader();
/**
* Set the frequency with which a INFO message will be logged showing the
* progress of the processing. You might set this to 1000 or 10000 etc.
* <p>
* If this is not set then no INFO messages will be logged.
* </p>
*/
void setLogInfoFrequency(int logInfoFrequency);
/**
* Ignore the next column of data.
*/
void addIgnore();
/**
* Define the property which will be loaded from the next column of data.
* <p>
* This takes into account the data type of the property and handles the
* String to object conversion automatically.
* </p>
*/
void addProperty(String propertyName);
/**
* Define the next property and use a custom StringParser to convert the
* string content into the appropriate type for the property.
*/
void addProperty(String propertyName, StringParser parser);
/**
* Add a property with a custom Date/Time/Timestamp format using the default
* Locale. This will convert the string into the appropriate java type for the
* given property (Date, Calendar, SQL Date, Time, Timestamp, JODA etc).
*/
void addDateTime(String propertyName, String dateTimeFormat);
/**
* Add a property with a custom Date/Time/Timestamp format. This will convert
* the string into the appropriate java type for the given property (Date,
* Calendar, SQL Date, Time, Timestamp, JODA etc).
*/
void addDateTime(String propertyName, String dateTimeFormat, Locale locale);
/**
* Automatically create a transaction if required to process all the CSV
* content from the reader.
* <p>
* This will check for a current transaction. If there is no current
* transaction then one is started and will commit (or rollback) at the end of
* processing. This will also set the persistBatchSize on the transaction.
* </p>
*/
void process(Reader reader) throws Exception;
/**
* Process the CSV content passing the bean to the CsvCallback after each row.
* <p>
* This provides you with the ability to modify and process the bean.
* </p>
* <p>
* When using a CsvCallback the reader WILL NOT create a transaction or save
* the bean(s) for you. If you want to insert the processed beans you must
* create your own transaction and save the bean(s) yourself.
* </p>
*/
void process(Reader reader, CsvCallback<T> callback) throws Exception;
}
@@ -1,11 +1,9 @@
package io.ebean.csv.reader;
package io.ebean.text.csv;
import io.ebean.Database;
import io.ebean.EbeanVersion;
import io.ebean.Transaction;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.INFO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Provides the default implementation of CsvCallback.
@@ -22,7 +20,7 @@ import static java.lang.System.Logger.Level.INFO;
*/
public class DefaultCsvCallback<T> implements CsvCallback<T> {
private static final System.Logger log = EbeanVersion.log;
private static final Logger log = LoggerFactory.getLogger(DefaultCsvCallback.class);
/**
* The transaction to use (if not using CsvCallback).
@@ -49,7 +47,6 @@ public class DefaultCsvCallback<T> implements CsvCallback<T> {
*/
protected final int persistBatchSize;
protected boolean getGeneratedKeys = true;
/**
* The time the process started.
*/
@@ -131,7 +128,7 @@ public class DefaultCsvCallback<T> implements CsvCallback<T> {
// related beans (e.g. customer -> customer.billingAddress
server.save(bean, transaction);
if (logInfoFrequency > 0 && (row % logInfoFrequency == 0)) {
log.log(DEBUG, "processed {0} rows", row);
log.debug("processed {} rows", row);
}
}
@@ -142,7 +139,7 @@ public class DefaultCsvCallback<T> implements CsvCallback<T> {
public void end(int row) {
commitTransactionIfCreated();
exeTime = System.currentTimeMillis() - startTime;
log.log(INFO, "Csv finished, rows[{0}] exeMillis[{1}]", row, exeTime);
log.info("Csv finished, rows[{}] exeMillis[{}]", row, exeTime);
}
/**
@@ -163,13 +160,15 @@ public class DefaultCsvCallback<T> implements CsvCallback<T> {
transaction = server.beginTransaction();
createdTransaction = true;
if (persistBatchSize > 1) {
log.debug("Creating transaction, batchSize[{}]", persistBatchSize);
transaction.setBatchMode(true);
transaction.setBatchSize(persistBatchSize);
transaction.setGetGeneratedKeys(getGeneratedKeys);
transaction.setGetGeneratedKeys(false);
} else {
// explicitly turn off JDBC batching in case
// is has been turned on globally
transaction.setBatchMode(false);
log.debug("Creating transaction with no JDBC batching");
}
}
}
@@ -181,6 +180,7 @@ public class DefaultCsvCallback<T> implements CsvCallback<T> {
protected void commitTransactionIfCreated() {
if (createdTransaction) {
transaction.commit();
log.debug("Committed transaction");
}
}
@@ -191,6 +191,7 @@ public class DefaultCsvCallback<T> implements CsvCallback<T> {
protected void rollbackTransactionIfCreated(Throwable e) {
if (createdTransaction) {
transaction.rollback(e);
log.debug("Rolled back transaction");
}
}
@@ -0,0 +1,4 @@
/**
* CSV processing objects.
*/
package io.ebean.text.csv;
@@ -1,20 +1,19 @@
package io.ebean.util;
import io.ebean.EbeanVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import static java.lang.System.Logger.Level.WARNING;
/**
* Utility for closing raw Jdbc resources.
*/
public final class JdbcClose {
private static final System.Logger log = EbeanVersion.log;
private static final Logger log = LoggerFactory.getLogger("io.ebean");
/**
* Close the resultSet logging if an error occurs.
@@ -25,7 +24,7 @@ public final class JdbcClose {
statement.close();
}
} catch (SQLException e) {
log.log(WARNING, "Error closing statement", e);
log.warn("Error closing statement", e);
}
}
@@ -38,7 +37,7 @@ public final class JdbcClose {
resultSet.close();
}
} catch (SQLException e) {
log.log(WARNING, "Error closing resultSet", e);
log.warn("Error closing resultSet", e);
}
}
@@ -51,7 +50,7 @@ public final class JdbcClose {
connection.close();
}
} catch (SQLException e) {
log.log(WARNING, "Error closing connection", e);
log.warn("Error closing connection", e);
}
}
@@ -64,7 +63,7 @@ public final class JdbcClose {
connection.rollback();
}
} catch (SQLException e) {
log.log(WARNING, "Error on connection rollback", e);
log.warn("Error on connection rollback", e);
}
}
@@ -77,7 +76,7 @@ public final class JdbcClose {
stmt.cancel();
}
} catch (SQLException e) {
log.log(WARNING, "Error on cancelling statement", e);
log.warn("Error on cancelling statement", e);
}
}
}
@@ -63,6 +63,7 @@ public final class SplitName {
}
private static String[] split(String name, boolean last) {
int pos = last ? name.lastIndexOf('.') : name.indexOf('.');
if (pos == -1) {
if (last) {
@@ -1,28 +0,0 @@
package io.ebean.util;
import java.util.function.Predicate;
/**
* Provides a stack filter that excludes ebean and jdk code.
*/
public final class StackWalkFilter {
private static final Filter FILTER = new Filter();
/**
* Return a stack filter that excludes ebean and jdk code.
*/
public static Predicate<StackWalker.StackFrame> filter() {
return FILTER;
}
private static class Filter implements Predicate<StackWalker.StackFrame> {
@Override
public boolean test(StackWalker.StackFrame stackFrame) {
return !stackFrame.getClassName().startsWith("io.ebean")
&& !stackFrame.getClassName().startsWith("jdk.")
&& !stackFrame.getMethodName().startsWith("_ebean_");
}
}
}
+2 -2
View File
@@ -15,9 +15,8 @@ module io.ebean.api {
requires transitive persistence.api;
requires transitive io.ebean.annotation;
requires transitive io.ebean.datasource.api;
requires transitive io.avaje.applog;
requires transitive org.slf4j;
requires static org.slf4j;
requires static io.ebean.types;
requires static com.fasterxml.jackson.core;
requires static com.fasterxml.jackson.databind;
@@ -40,6 +39,7 @@ module io.ebean.api {
exports io.ebean.service;
exports io.ebean.text;
exports io.ebean.text.json;
exports io.ebean.text.csv;
exports io.ebean.util;
}
@@ -1 +0,0 @@
${project.version}
@@ -1 +0,0 @@
ebean-version: 143
@@ -1,78 +0,0 @@
package io.ebean;
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
import static io.ebean.StdOperators.*;
import static org.assertj.core.api.Assertions.assertThat;
class StdOperatorsTest {
final Query.Property<Number> amount = Query.Property.of("amount");
final Query.Property<String> foo = Query.Property.of("foo");
final Query.Property<String> bar = Query.Property.of("bar");
@Test
void testAvg() {
assertThat(avg(foo).toString()).isEqualTo("avg(foo)");
}
@Test
void testCount() {
assertThat(count(foo).toString()).isEqualTo("count(foo)");
}
@Test
void testMax() {
assertThat(max(foo).toString()).isEqualTo("max(foo)");
}
@Test
void testMin() {
assertThat(min(foo).toString()).isEqualTo("min(foo)");
}
@Test
void testSum() {
assertThat(sum(amount).toString()).isEqualTo("sum(amount)");
}
@Test
void testLower() {
assertThat(lower(foo).toString()).isEqualTo("lower(foo)");
}
@Test
void testUpper() {
assertThat(upper(foo).toString()).isEqualTo("upper(foo)");
}
@Test
void testConcat() {
assertThat(concat(foo, "+").toString()).isEqualTo("concat(foo,'+')");
assertThat(concat(foo, 42).toString()).isEqualTo("concat(foo,'42')");
assertThat(concat(foo, LocalDate.of(2022, 9, 1)).toString()).isEqualTo("concat(foo,'2022-09-01')");
assertThat(concat(foo, bar).toString()).isEqualTo("concat(foo,bar)");
assertThat(concat(foo, ":", 42, bar).toString()).isEqualTo("concat(foo,':','42',bar)");
}
@Test
void testCoalesce() {
assertThat(coalesce(foo, bar).toString()).isEqualTo("coalesce(foo,bar)");
assertThat(coalesce(foo, 42).toString()).isEqualTo("coalesce(foo,42)");
assertThat(coalesce(foo, 0).toString()).isEqualTo("coalesce(foo,0)");
assertThat(coalesce(foo, "apple").toString()).isEqualTo("coalesce(foo,'apple')");
assertThat(coalesce(foo, "banana").toString()).isEqualTo("coalesce(foo,'banana')");
}
@Test
void testCoalesceWithQuoted() {
assertThat(coalesce(foo, "ba'nana").toString()).isEqualTo("coalesce(foo,'ba''nana')");
}
@Test
void testConcatWithQuoted() {
assertThat(concat(foo, "ba'nana").toString()).isEqualTo("concat(foo,'ba''nana')");
}
}
@@ -3,6 +3,10 @@ package io.ebean.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.ebean.annotation.MutationDetection;
import io.ebean.annotation.PersistBatch;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.JsonConfig;
import io.ebean.config.MatchingNamingConvention;
import io.ebean.config.PlatformConfig;
import io.ebean.config.dbplatform.IdType;
import io.ebean.datasource.DataSourceConfig;
import org.junit.jupiter.api.Assertions;
@@ -89,7 +93,6 @@ class DatabaseConfigTest {
assertTrue(config.isDbOffline());
assertTrue(config.isAutoReadOnlyDataSource());
assertTrue(config.isAutoLoadModuleInfo());
assertTrue(config.isLoadModuleInfo());
assertTrue(config.skipDataSourceCheck());
assertTrue(config.isIdGeneratorAutomatic());
@@ -162,7 +165,6 @@ class DatabaseConfigTest {
assertEquals(MutationDetection.HASH, config.getJsonMutationDetection());
assertTrue(config.getPlatformConfig().isCaseSensitiveCollation());
assertTrue(config.isAutoLoadModuleInfo());
assertTrue(config.isLoadModuleInfo());
assertFalse(config.isQueryPlanEnable());
assertEquals(Long.MAX_VALUE, config.getQueryPlanThresholdMicros());
@@ -173,7 +175,6 @@ class DatabaseConfigTest {
config.setLoadModuleInfo(false);
assertFalse(config.isAutoLoadModuleInfo());
assertFalse(config.isLoadModuleInfo());
config.setAutoPersistUpdates(true);
assertTrue(config.isAutoPersistUpdates());
config.setSkipDataSourceCheck(true);
+5 -19
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -26,31 +26,17 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- JAVAX-DEPENDENCY-START -->
<!-- needed for java 11+ -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.6</version>
<scope>provided</scope>
</dependency>
<!-- JAVAX-DEPENDENCY-END -->
<!-- JAKARTA-DEPENDENCY-START ___
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>4.0.0</version>
<scope>runtime</scope>
</dependency>
____ JAKARTA-DEPENDENCY-END -->
<dependency>
<groupId>io.ebean</groupId>
@@ -69,7 +55,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-platform-h2</artifactId>
<version>13.15.0</version>
<version>13.6.2-SNAPSHOT</version>
<scope>test</scope>
</dependency>
@@ -84,7 +70,7 @@
<extensions>true</extensions>
<configuration>
<tiles>
<tile>io.ebean.tile:enhancement:13.12.0</tile>
<tile>io.ebean.tile:enhancement:13.3.0</tile>
</tiles>
</configuration>
</plugin>
@@ -143,12 +143,11 @@ public class BaseQueryTuner {
switch (type) {
case COUNT:
case ATTRIBUTE:
case ATTRIBUTE_SET:
case ID_LIST:
case UPDATE:
case DELETE:
case SQ_EXISTS:
case SQ_EX:
case SQ_IN:
return false;
default:
// not using autoTune when explicitly loading the l2 bean cache
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.autotune.service;
import io.avaje.applog.AppLog;
import io.ebean.config.AutoTuneConfig;
import io.ebean.config.DatabaseConfig;
import io.ebeaninternal.api.SpiEbeanServer;
@@ -8,6 +7,8 @@ import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.autotune.AutoTuneService;
import io.ebeaninternal.server.autotune.model.Autotune;
import io.ebeaninternal.server.autotune.model.Origin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
@@ -15,14 +16,12 @@ import java.io.InputStream;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import static java.lang.System.Logger.Level.*;
/**
* Implementation of the AutoTuneService which is comprised of profiling and query tuning.
*/
public class DefaultAutoTuneService implements AutoTuneService {
private static final System.Logger logger = AppLog.getLogger(DefaultAutoTuneService.class);
private static final Logger logger = LoggerFactory.getLogger(DefaultAutoTuneService.class);
private final ReentrantLock lock = new ReentrantLock();
@@ -112,7 +111,7 @@ public class DefaultAutoTuneService implements AutoTuneService {
if (stream != null) {
loadAutoTuneProfiling(AutoTuneXmlReader.read(stream));
} else {
logger.log(WARNING, "AutoTune file {0} not found - no initial automatic query tuning", tuningFile);
logger.warn("AutoTune file {} not found - no initial automatic query tuning", tuningFile);
}
} catch (IOException e) {
throw new IllegalStateException("Error on auto close of " + tuningFile, e);
@@ -121,7 +120,7 @@ public class DefaultAutoTuneService implements AutoTuneService {
}
private void loadAutoTuneProfiling(Autotune profiling) {
logger.log(INFO, "AutoTune loading {0} tuning entries", profiling.getOrigin().size());
logger.info("AutoTune loading {} tuning entries", profiling.getOrigin().size());
for (Origin origin : profiling.getOrigin()) {
queryTuner.put(origin);
}
@@ -142,17 +141,17 @@ public class DefaultAutoTuneService implements AutoTuneService {
event.process();
if (event.isEmpty()) {
long exeMillis = System.currentTimeMillis() - start;
logger.log(DEBUG, "No query tuning updates for server:{0} executionMillis:{1}", serverName, exeMillis);
logger.debug("No query tuning updates for server:{} executionMillis:{}", serverName, exeMillis);
} else {
// report the query tuning changes that have been made
runtimeChangeCount += event.getChangeCount();
event.writeFile(profilingFile + "-" + serverName + "-update");
long exeMillis = System.currentTimeMillis() - start;
logger.log(INFO, "query tuning updates - new:{0} diff:{1} for server:{2} executionMillis:{3}", event.getNewCount(), event.getDiffCount(), serverName, exeMillis);
logger.info("query tuning updates - new:{} diff:{} for server:{} executionMillis:{}", event.getNewCount(), event.getDiffCount(), serverName, exeMillis);
}
} catch (Throwable e) {
logger.log(ERROR, "Error collecting or applying automatic query tuning", e);
logger.error("Error collecting or applying automatic query tuning", e);
}
} finally {
lock.unlock();
@@ -173,11 +172,11 @@ public class DefaultAutoTuneService implements AutoTuneService {
AutoTuneDiffCollection event = new AutoTuneDiffCollection(profiling, queryTuner, false);
event.process();
if (event.isEmpty()) {
logger.log(INFO, "No new or diff entries for profiling server:{0}", serverName);
logger.info("No new or diff entries for profiling server:{}", serverName);
} else {
event.writeFile(profilingFile + "-" + serverName);
logger.log(INFO, "writing new:{0} diff:{1} profiling entries for server:{2}", event.getNewCount(), event.getDiffCount(), serverName);
logger.info("writing new:{} diff:{} profiling entries for server:{}", event.getNewCount(), event.getDiffCount(), serverName);
}
}
} finally {
@@ -197,7 +196,7 @@ public class DefaultAutoTuneService implements AutoTuneService {
private void outputAllTuning() {
if (runtimeChangeCount == 0) {
logger.log(INFO, "no runtime query tuning changes for server:{0}", serverName);
logger.info("no runtime query tuning changes for server:{}", serverName);
} else {
AutoTuneAllCollection event = new AutoTuneAllCollection(queryTuner);
@@ -206,12 +205,12 @@ public class DefaultAutoTuneService implements AutoTuneService {
if (existingTuning.exists()) {
// rename the existing autotune.xml file (appending 'now')
if (!existingTuning.renameTo(new File(tuningFile + "." + AutoTuneXmlWriter.now()))) {
logger.log(WARNING, "Failed to rename autotune file [{0}]", tuningFile);
logger.warn("Failed to rename autotune file [{}]", tuningFile);
}
}
event.writeFile(tuningFile, false);
logger.log(INFO, "query tuning detected [{0}] changes, writing all [{1}] tuning entries for server:{2}", runtimeChangeCount, size, serverName);
logger.info("query tuning detected [{}] changes, writing all [{}] tuning entries for server:{}", runtimeChangeCount, size, serverName);
}
}
@@ -280,7 +279,7 @@ public class DefaultAutoTuneService implements AutoTuneService {
} catch (InterruptedException e) {
// restore the interrupted status
Thread.currentThread().interrupt();
logger.log(WARNING, "Error while sleeping after System.gc() request.", e);
logger.warn("Error while sleeping after System.gc() request.", e);
}
}
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.autotune.service;
import io.avaje.applog.AppLog;
import io.ebean.bean.NodeUsageCollector;
import io.ebean.text.PathProperties;
import io.ebean.util.SplitName;
@@ -8,19 +7,19 @@ import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssoc;
import io.ebeaninternal.server.el.ElPropertyValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import static java.lang.System.Logger.Level.WARNING;
/**
* Collects usages statistics for a given node in the object graph.
*/
public class ProfileOriginNodeUsage {
private static final System.Logger logger = AppLog.getLogger(ProfileOriginNodeUsage.class);
private static final Logger logger = LoggerFactory.getLogger(ProfileOriginNodeUsage.class);
private final ReentrantLock lock = new ReentrantLock();
@@ -46,7 +45,7 @@ public class ProfileOriginNodeUsage {
if (path != null) {
ElPropertyValue elGetValue = rootDesc.elGetValue(path);
if (elGetValue == null) {
logger.log(WARNING, "AutoTune: Can't find join for path[" + path + "] for " + rootDesc.name());
logger.warn("AutoTune: Can't find join for path[" + path + "] for " + rootDesc.name());
return;
} else {
BeanProperty beanProperty = elGetValue.beanProperty();
@@ -62,7 +61,7 @@ public class ProfileOriginNodeUsage {
for (String propName : aggregateUsed) {
BeanProperty beanProp = desc.findPropertyFromPath(propName);
if (beanProp == null) {
logger.log(WARNING, "AutoTune: Can't find property[" + propName + "] for " + desc.name());
logger.warn("AutoTune: Can't find property[" + propName + "] for " + desc.name());
} else {
if (beanProp.isId()) {

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