Compare commits

...
Author SHA1 Message Date
Rob Bygrave ea7b4e8162 [maven-release-plugin] prepare release ebean-parent-12.13.0 2021-11-04 11:19:25 +13:00
Rob Bygrave 43742fdc0b Bump version to 12.13.0-SNAPSHOT 2021-11-04 11:16:50 +13:00
Rob Bygrave 8ef71bd451 Bump version to 12.13.0-SNAPSHOT 2021-11-04 11:02:45 +13:00
Rob Bygrave 0f60e2240c Bump version to 12.13.0-SNAPSHOT 2021-11-04 10:57:48 +13:00
Rob Bygrave 2cbb161ed5 Follow up to #2437 - Rename internal "dead/alive" to "replaced" 2021-11-04 10:40:04 +13:00
Rob BygraveandGitHub a47caec85b Merge pull request #2437 from FOCONIS/fix-persistence-context
FIX: Subsequent findEach / findList does not work reliable [Fixes regression in 12.3.3]
2021-11-04 09:59:31 +13:00
Roland Praml fd1b5f58bc FIX: Subsequent findEach / findList does not work reliable (Regression of #2411) 2021-11-03 11:34:04 +01:00
Rob Bygrave 0bb7d79015 Tidy build.yml 2021-10-28 22:40:10 +13:00
Rob BygraveandGitHub 9907cffe6e Update README.md 2021-10-28 22:38:48 +13:00
Rob Bygrave 704a138ff0 Tidy build.yml and TestExtraScalarTypes 2021-10-28 22:34:55 +13:00
Rob Bygrave f3cab4ee10 Merge branch 'master' of github.com:ebean-orm/ebean 2021-10-28 22:33:48 +13:00
Rob Bygrave d507452d63 Fix test TestExtraScalarTypes for github workflows build 2021-10-28 22:33:28 +13:00
Rob BygraveandGitHub 893aa6cb1a Update build.yml 2021-10-28 22:26:13 +13:00
Rob BygraveandGitHub e92fd2ef06 Add github workflows build.yml 2021-10-28 22:19:24 +13:00
Rob BygraveandGitHub bdad8b258a Merge pull request #2427 from FOCONIS/bug-reload-fails-on-partial-beans
FIX: When a bean is modified in persistence context and searched again, it will loose the change
2021-10-22 16:17:31 +13:00
Rob Bygrave a6cdf8d6dc Turn off nexus.staging.autoReleaseAfterClose 2021-10-22 10:52:16 +13:00
Rob Bygrave e232c724c0 maven.deploy.skip test modules and fix agent versions 2021-10-22 10:49:57 +13:00
Roland Praml d55023dbc7 FIX: When a bean is modified in persistence context and searched again, it will loose the change 2021-10-21 16:50:53 +02:00
Rob Bygrave fa4e013692 [maven-release-plugin] prepare for next development iteration 2021-10-21 21:36:29 +13:00
Rob Bygrave 08502d7315 [maven-release-plugin] prepare release ebean-parent-12.12.3 2021-10-21 21:36:21 +13:00
Rob Bygrave 6f4bc0ac2c Prepare release, comment out extra test modules 2021-10-21 21:33:16 +13:00
Rob Bygrave 5585866e82 Prepare release, comment out extra test modules 2021-10-21 14:07:27 +13:00
Rob Bygrave f21f6d9592 Prepare release, comment out extra test modules 2021-10-21 13:54:39 +13:00
Rob Bygrave 03e0519951 Refactor tidy internals for DefaultServer, rename descriptorManager 2021-10-21 13:41:58 +13:00
Rob Bygrave bc23d5829c Refactor tidy internals for DefaultPersister, BeanDescriptorManager etc 2021-10-21 13:30:32 +13:00
Rob Bygrave 64108aac40 #2424 Preserve using PersistenceException when transaction register(Callback) called with no active transaction 2021-10-21 12:12:02 +13:00
Rob Bygrave fcda419abb #2424 Preserve using PersistenceException when transaction register(Callback) called with no active transaction 2021-10-21 12:06:45 +13:00
Rob Bygrave 4d34c9e868 #2424 Change error for transaction register(Callback) when no active transaction from PersistenceException to NullPointerException
Ah ok, so in being more strict on null for currentTransaction() that shows up the code that registers transaction callbacks as checking for null and throwing PersistenceException. This is inconsistent with LOTS of other methods that use currentTransaction() and would result in NPE.

The concept here is that PersistenceException for this case isn't better than NPE and NPE is actually more consistence wrt using currentTransaction().
2021-10-21 12:02:42 +13:00
Rob Bygrave 5178b76431 Update internals migrate from deprecated methods baseTable() 2021-10-20 20:07:54 +13:00
Rob Bygrave 8fb02662e6 #2423 Add @Nullable on single bean publish and restore by id 2021-10-20 20:06:59 +13:00
Rob Bygrave 1aac63771d #2423 Tidy up DefaultServer internals getting descriptor 2021-10-20 19:58:11 +13:00
Rob Bygrave 3a138c3462 Tidy internals only - improve DefaultServer parameter names 2021-10-20 16:07:43 +13:00
Rob Bygrave 30088f4de7 #2423 Tidy up DefaultServer internals with Objects.requireNonNull() 2021-10-20 15:53:50 +13:00
Rob BygraveandGitHub cc272bb950 Merge pull request #2423 from ebean-orm/feature/nonNullApi
Use @NonNullApi to explicitly reflect non-null return types and params by default
2021-10-20 15:47:44 +13:00
Rob Bygrave b3ee982b64 Use @NonNullApi to explicitly reflect non-null return types and params by default 2021-10-20 15:45:20 +13:00
Rob Bygrave 92a13ad265 Remove pom releaseBackup files that should not be there 2021-10-20 09:52:06 +13:00
Rob Bygrave a445557ec3 #2422 - Remove extraneous jsr 305 @Nonnull 2021-10-19 17:59:25 +13:00
Rob Bygrave c7bb027c7d #2422 - Remove extraneous jsr 305 @Nonnull 2021-10-19 17:33:23 +13:00
Rob Bygrave 709eb369c9 #2419 - Add explicit @Nullable on findOne() methods 2021-10-19 12:12:11 +13:00
Rob Bygrave 5a4924b6cb #2421 - Change database.diff() to return empty map rather than null with null bean argument 2021-10-19 11:58:29 +13:00
Rob Bygrave a61c73c62a #2418 #2420 BeanState.loadErrors() returns empty map
Change Database.beanState() to throw IllegalArgumentException when bean isn't an entity bean
2021-10-19 11:52:36 +13:00
Rob Bygrave 7862648b83 #2419 - Add explicit @Nullable on findOne() methods 2021-10-19 11:50:22 +13:00
Rob Bygrave fa252a1fe4 Javadoc for #2303 - bump to pgjdbc 42.3.0 2021-10-19 11:23:26 +13:00
Rob Bygrave add7a8c4ba Javadoc for #2303 - bump to pgjdbc 42.2.25
Noting that this version of pgjdbc has not been released yet. Guessing that this is the next release number.
2021-10-14 14:49:15 +13:00
Rob Bygrave 834c04bd33 Update Postgres test dependency only (#2303) 2021-10-13 09:45:00 +13:00
Rob Bygrave 9bda4ab5c7 #2303 - Add javadoc for notes on Postgres with "allQuotedIdentifiers = true" 2021-10-13 09:37:40 +13:00
Rob Bygrave d1ca7a30dc Merge branch 'FOCONIS-tidy-remove-readjson-resetContext' 2021-10-12 15:11:35 +13:00
Rob Bygrave cb67dd0f29 Merge branch 'tidy-remove-readjson-resetContext' of https://github.com/FOCONIS/ebean into FOCONIS-tidy-remove-readjson-resetContext 2021-10-12 15:11:23 +13:00
Rob Bygrave e173f6e9a9 Tidy only DefaultPersistenceContext after merge of #2411 2021-10-12 15:10:36 +13:00
Rob BygraveandGitHub 349cd01921 Merge pull request #2411 from ebean-orm/feature/weak-reference-persistence-context
Weak reference based persistence context for streaming queries
2021-10-12 14:39:47 +13:00
Rob BygraveandGitHub 8fa7fa6af3 Merge pull request #2413 from FOCONIS/feature/weak-reference-persistence-context
Change DefaultPersistenceContect to use beginIterate / endIterate
2021-10-12 14:34:05 +13:00
Rob Bygrave caf18565a0 [maven-release-plugin] prepare for next development iteration 2021-10-12 12:46:15 +13:00
Rob Bygrave c89d39ec2d [maven-release-plugin] prepare release ebean-parent-12.12.2 2021-10-12 12:46:08 +13:00
Rob Bygrave 556557276c Bump ebean-agent version 2021-10-12 12:38:08 +13:00
Roland Praml 2f277938e5 Remove LoadContext.resetPersistenceContext 2021-10-11 17:48:09 +02:00
Roland Praml 5322ab3e7e Remove: ReadJson.resetContext as it is not used 2021-10-11 17:22:33 +02:00
Roland Praml 100832ddd9 Changed test to test pc.beginIterate / endIterate 2021-10-11 17:16:34 +02:00
Roland Praml 3f5009aa91 Use WeakReferences when in iterate query mode 2021-10-11 16:25:21 +02:00
Roland Praml 8dbd290119 Remove: ReadJson.resetContext as it is not used 2021-10-11 13:40:03 +02:00
Rob Bygrave ea3fb833a4 Weak reference based PersistenceContext for streaming queries 2021-10-11 22:48:18 +13:00
Rob Bygrave 0273e1c2c8 Modify test TestUpdate to ensure basic test data is loaded first 2021-10-11 12:13:02 +13:00
Rob Bygrave 8440a13b0f Refactor rename internal method DefaultPersistenceContext.classContext() 2021-10-11 11:36:38 +13:00
Rob Bygrave c5e940733c #2408 Followup refactor BindParamsParser extract methods 2021-10-11 11:21:28 +13:00
Rob BygraveandGitHub ac73031bec Merge pull request #2408 from FOCONIS/pr/bugfix/reuse_update_collection_parameters
Fix reuse of io.ebean.Update when using setParameter with Collection
2021-10-11 11:01:23 +13:00
Rob Bygrave a65ff8a650 Tidy test only - TestOneToManyCorrectGrouping 2021-10-08 12:55:50 +13:00
Rob Bygrave f904fea104 Tidy, remove unnecessary --add-opens test clause for eban-querybean testing 2021-10-08 12:55:22 +13:00
Rob Bygrave 2549eace09 #2406 - Memory leak in Query.findEach 2021-10-08 11:20:54 +13:00
Jonas Pöhler a592717c77 Merge remote-tracking branch 'ebean/master' into pr/bugfix/reuse_update_collection_parameters 2021-10-06 11:57:50 +02:00
Jonas Pöhler db6f93e383 FIX: Reuse of io.ebean.Update with collection parameters did not work correctly 2021-10-06 11:57:09 +02:00
Rob Bygrave 0a0d67585c [maven-release-plugin] prepare for next development iteration 2021-10-05 10:50:00 +13:00
Rob Bygrave db2f8cd811 [maven-release-plugin] prepare release ebean-parent-12.12.1 2021-10-05 10:49:53 +13:00
Rob Bygrave b6e524f879 Disable test modules for release 2021-10-05 10:47:23 +13:00
Rob Bygrave 40492f487c #2404 - Initializing @OneToMany with mutableListOf() in Kotlin results in ClassCastException 2021-10-05 10:17:44 +13:00
Rob Bygrave 2cee03bc4b #172 Bump ebean-agent via maven plugin
The associated ebean-agent has the fix for the kotlin specific #172 issue.
2021-10-04 22:57:24 +13:00
Rob BygraveandGitHub e2c6125501 Merge pull request #2402 from ebean-orm/feature/ebean-agent-min-version
Modify EbeanVersion to check for minimum ebean-agent version
2021-09-30 10:42:33 +13:00
Rob Bygrave b53221fc0e Modify EbeanVersion to check for minimum ebean-agent version 2021-09-29 12:20:27 +13:00
Rob Bygrave b23551ce43 #2401 - Fix EbeanVersion for use in module-path (reads local ebean-api pom.properties) 2021-09-29 11:14:26 +13:00
Rob Bygrave 3971ccea1a Merge branch 'master' of github.com:ebean-orm/ebean 2021-09-29 11:11:55 +13:00
Rob BygraveandGitHub 35b1f835c5 Merge pull request #2400 from focbenz/patch-1
Update README.md typo fix Maven central
2021-09-29 09:47:28 +13:00
Michael BenzandGitHub ef5e3a796d Update README.md typo fix Maven central
typo fix Maven central
2021-09-28 20:02:12 +02:00
Rob Bygrave d3dbde4e79 Add a dummy placeholder so that we can sync to maven central
The sync needs javadoc and sources so adding a dummy class. Note that I think we only just got this due to the multi-version jar but not sure.
2021-09-24 21:42:23 +12:00
Rob Bygrave 033c579984 #2398 - Fix compiler warning for annotation processing query bean generators 2021-09-24 17:51:36 +12:00
Rob Bygrave 1a34a56351 [maven-release-plugin] prepare for next development iteration 2021-09-24 10:12:14 +12:00
112 changed files with 1291 additions and 1301 deletions
+36
View File
@@ -0,0 +1,36 @@
name: Build
on: [push, pull_request]
jobs:
build:
runs-on: ${{ matrix.os }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
java_version: [8]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- 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
+2 -2
View File
@@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.org/ebean-orm/ebean.svg?branch=master)](https://travis-ci.org/ebean-orm/ebean)
[![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)
# Sponsors
@@ -36,7 +36,7 @@ Post questions or issues to the Ebean google group - https://groups.google.com/f
Goto [https://ebean.io/docs/](https://ebean.io/docs/)
## Maven cental links:
## Maven central links:
[Maven central - ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.ebean%22%20AND%20a%3A%22ebean%22 "maven central ebean")
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects")
+3 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.0</version>
<version>12.13.0</version>
</parent>
<name>ebean api</name>
@@ -36,9 +36,8 @@
-->
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-jsr305</artifactId>
<version>1.1</version>
<scope>provided</scope>
<artifactId>avaje-lang</artifactId>
<version>1.0</version>
</dependency>
<dependency>
@@ -1,5 +1,7 @@
package io.ebean;
import io.avaje.lang.NonNullApi;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
@@ -18,6 +20,7 @@ import java.util.concurrent.TimeUnit;
* This also propagates MDC context from the current thread to the
* background task if defined.
*/
@NonNullApi
public interface BackgroundExecutor {
/**
@@ -1,7 +1,7 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import java.util.List;
import java.util.Optional;
@@ -27,10 +27,10 @@ import java.util.Optional;
* @param <I> The ID type
* @param <T> The Bean type
*/
@NonNullApi
public abstract class BeanFinder<I,T> {
protected final Database server;
protected final Class<T> type;
/**
@@ -81,7 +81,6 @@ public abstract class BeanFinder<I,T> {
* <p>
* Equivalent to {@link Database#reference(Class, Object)}
*/
@Nonnull
public T ref(I id) {
return db().reference(type, id);
}
@@ -97,7 +96,6 @@ public abstract class BeanFinder<I,T> {
/**
* Find an entity by ID returning an Optional.
*/
@Nullable
public Optional<T> findByIdOrEmpty(I id) {
return db().find(type).setId(id).findOneOrEmpty();
}
@@ -112,7 +110,6 @@ public abstract class BeanFinder<I,T> {
/**
* Retrieves all entities of the given type.
*/
@Nonnull
public List<T> findAll() {
return query().findList();
}
@@ -1,5 +1,6 @@
package io.ebean;
import io.avaje.lang.NonNullApi;
import io.ebean.bean.EntityBean;
import java.util.Collection;
@@ -31,6 +32,7 @@ import java.util.Collection;
* @param <I> The ID type
* @param <T> The Bean type
*/
@NonNullApi
public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
/**
@@ -1,6 +1,5 @@
package io.ebean;
import javax.annotation.Nullable;
import java.util.Map;
import java.util.Set;
@@ -138,7 +137,6 @@ public interface BeanState {
/**
* Returns a map with load errors.
*/
@Nullable
Map<String, Exception> loadErrors();
/**
+4 -81
View File
@@ -1,13 +1,13 @@
package io.ebean;
import io.avaje.lang.NonNullApi;
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.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import java.util.Collection;
@@ -60,6 +60,7 @@ import java.util.concurrent.Callable;
*
* }</pre>
*/
@NonNullApi
public final class DB {
private static final DbContext context = DbContext.getInstance();
@@ -523,15 +524,13 @@ public final class DB {
* @param bean The entity bean to check uniqueness on
* @return a set of Properties if constraint validation was detected or empty list.
*/
@Nonnull
public static Set<Property> checkUniqueness(Object bean) {
return getDefault().checkUniqueness(bean);
}
/**
* Same as {@link #checkUniqueness(Object)}. but with given transaction.
* Same as {@link #checkUniqueness(Object)} but with given transaction.
*/
@Nonnull
public static Set<Property> checkUniqueness(Object bean, Transaction transaction) {
return getDefault().checkUniqueness(bean, transaction);
}
@@ -851,7 +850,6 @@ public final class DB {
* }</pre>
*/
public static <T> Update<T> createUpdate(Class<T> beanType, String ormUpdate) {
return getDefault().createUpdate(beanType, ormUpdate);
}
@@ -859,7 +857,6 @@ public final class DB {
* Create a CsvReader for a given beanType.
*/
public static <T> CsvReader<T> createCsvReader(Class<T> beanType) {
return getDefault().createCsvReader(beanType);
}
@@ -897,7 +894,6 @@ public final class DB {
* @return A ORM Query for this beanType
*/
public static <T> Query<T> createQuery(Class<T> beanType) {
return getDefault().createQuery(beanType);
}
@@ -935,7 +931,6 @@ public final class DB {
* @return The query with expressions defined as per the parsed query statement
*/
public static <T> Query<T> createQuery(Class<T> beanType, String eql) {
return getDefault().createQuery(beanType, eql);
}
@@ -951,7 +946,6 @@ public final class DB {
* @return A ORM Query object for this beanType
*/
public static <T> Query<T> find(Class<T> beanType) {
return getDefault().find(beanType);
}
@@ -1030,77 +1024,6 @@ public final class DB {
return getDefault().filter(beanType);
}
// /**
// * Execute a Sql Update Delete or Insert statement. This returns the number of
// * rows that where updated, deleted or inserted. If is executed in batch then
// * this returns -1. You can get the actual rowCount after commit() from
// * updateSql.getRowCount().
// * <p>
// * If you wish to execute a Sql Select natively then you should use the
// * FindByNativeSql object.
// * </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>
// * <pre>{@code
// *
// * // example that uses 'named' parameters
// * String s = "UPDATE f_topic set post_count = :count where id = :id"
// *
// * SqlUpdate update = DB.createSqlUpdate(s);
// *
// * update.setParameter("id", 1);
// * update.setParameter("count", 50);
// *
// * int modifiedCount = DB.execute(update);
// *
// * String msg = "There where " + modifiedCount + "rows updated";
// *
// * }</pre>
// *
// * @param sqlUpdate the update sql potentially with bind values
// * @return the number of rows updated or deleted. -1 if executed in batch.
// * @see SqlUpdate
// * @see CallableSql
// * @see DB#execute(CallableSql)
// */
// public static int execute(SqlUpdate sqlUpdate) {
// return defaultDatabase().execute(sqlUpdate);
// }
//
// /**
// * For making calls to stored procedures.
// * <p>
// * Example:
// * </p>
// * <pre>{@code
// *
// * String sql = "{call sp_order_modify(?,?,?)}";
// *
// * CallableSql cs = DB.createCallableSql(sql);
// * cs.setParameter(1, 27);
// * cs.setParameter(2, "SHIPPED");
// * cs.registerOut(3, Types.INTEGER);
// *
// * DB.execute(cs);
// *
// * // read the out parameter
// * Integer returnValue = (Integer) cs.getObject(3);
// *
// * }</pre>
// *
// * @see CallableSql
// * @see Ebean#execute(SqlUpdate)
// */
// public static int execute(CallableSql callableSql) {
// return defaultDatabase().execute(callableSql);
// }
/**
* Execute a TxRunnable in a Transaction with an explicit scope.
* <p>
+10 -7
View File
@@ -1,5 +1,7 @@
package io.ebean;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.annotation.Platform;
import io.ebean.annotation.TxIsolation;
import io.ebean.cache.ServerCacheManager;
@@ -10,8 +12,6 @@ import io.ebean.plugin.SpiServer;
import io.ebean.text.csv.CsvReader;
import io.ebean.text.json.JsonContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
@@ -92,6 +92,7 @@ import java.util.concurrent.Callable;
* @see DatabaseFactory
* @see DatabaseConfig
*/
@NonNullApi
public interface Database {
/**
@@ -575,8 +576,8 @@ public interface Database {
<T> DtoQuery<T> createNamedDtoQuery(Class<T> dtoType, String namedQuery);
/**
* Look to execute a native sql query that does not returns beans but instead
* returns SqlRow or direct access to ResultSet (see {@link SqlQuery#findList(RowMapper)}.
* Look to execute a native sql query that does not return beans but instead
* returns SqlRow or direct access to ResultSet.
*
* <p>
* Refer to {@link DtoQuery} for native sql queries returning DTO beans.
@@ -949,7 +950,6 @@ public interface Database {
* @param beanType the type of entity bean
* @param id the id value
*/
@Nonnull
<T> T reference(Class<T> beanType, Object id);
/**
@@ -1236,6 +1236,7 @@ public interface Database {
* @param id the bean id value
* @param transaction the transaction to use (can be null)
*/
@Nullable
<T> T find(Class<T> beanType, Object id, Transaction transaction);
/**
@@ -1294,13 +1295,11 @@ public interface Database {
* @param bean The entity bean to check uniqueness on
* @return a set of Properties if constraint validation was detected or empty list.
*/
@Nonnull
Set<Property> checkUniqueness(Object bean);
/**
* Same as {@link #checkUniqueness(Object)}. but with given transaction.
*/
@Nonnull
Set<Property> checkUniqueness(Object bean, Transaction transaction);
/**
@@ -1614,6 +1613,7 @@ public interface Database {
* @param id the id of the entity bean
* @param transaction the transaction the publish process should use (can be null)
*/
@Nullable
<T> T publish(Class<T> beanType, Object id, Transaction transaction);
/**
@@ -1627,6 +1627,7 @@ public interface Database {
* @param beanType the type of the entity bean
* @param id the id of the entity bean
*/
@Nullable
<T> T publish(Class<T> beanType, Object id);
/**
@@ -1665,6 +1666,7 @@ public interface Database {
* @param id the id of the entity bean to restore
* @param transaction the transaction the restore process should use (can be null)
*/
@Nullable
<T> T draftRestore(Class<T> beanType, Object id, Transaction transaction);
/**
@@ -1678,6 +1680,7 @@ public interface Database {
* @param beanType the type of the entity bean
* @param id the id of the entity bean to restore
*/
@Nullable
<T> T draftRestore(Class<T> beanType, Object id);
/**
@@ -1,9 +1,10 @@
package io.ebean;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.docstore.DocQueryContext;
import io.ebean.docstore.RawDoc;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@@ -13,6 +14,7 @@ import java.util.function.Predicate;
/**
* Document storage operations.
*/
@NonNullApi
public interface DocumentStore {
/**
@@ -1,7 +1,7 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
@@ -38,12 +38,12 @@ import java.util.stream.Stream;
*
* }</pre>
*/
@NonNullApi
public interface DtoQuery<T> extends CancelableQuery {
/**
* Execute the query returning a list.
*/
@Nonnull
List<T> findList();
/**
@@ -53,7 +53,6 @@ public interface DtoQuery<T> extends CancelableQuery {
* resultSet and potentially connection and MUST be closed. We should use
* QueryIterator in a <em>try with resource block</em>.
*/
@Nonnull
QueryIterator<T> findIterate();
/**
@@ -63,7 +62,6 @@ public interface DtoQuery<T> extends CancelableQuery {
* resultSet and potentially connection and MUST be closed. We should use
* the Stream in a <em>try with resource block</em>.
*/
@Nonnull
Stream<T> findStream();
/**
@@ -105,7 +103,6 @@ public interface DtoQuery<T> extends CancelableQuery {
/**
* Execute the query returning an optional bean.
*/
@Nonnull
Optional<T> findOneOrEmpty();
/**
+1 -4
View File
@@ -1,13 +1,12 @@
package io.ebean;
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.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import java.util.Collection;
@@ -506,7 +505,6 @@ public final class Ebean {
* @param bean The entity bean to check uniqueness on
* @return a set of Properties if constraint validation was detected or empty list.
*/
@Nonnull
public static Set<Property> checkUniqueness(Object bean) {
return getDefault().checkUniqueness(bean);
}
@@ -514,7 +512,6 @@ public final class Ebean {
/**
* Same as {@link #checkUniqueness(Object)}. but with given transaction.
*/
@Nonnull
public static Set<Property> checkUniqueness(Object bean, Transaction transaction) {
return getDefault().checkUniqueness(bean, transaction);
}
@@ -16,15 +16,22 @@ public class EbeanVersion {
private static final Logger log = LoggerFactory.getLogger("io.ebean");
/**
* Maintain the minimum ebean-agent version manually based on required ebean-agent bug fixes.
*/
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();
}
private static void readVersion() {
try {
Properties prop = new Properties();
try (InputStream in = DB.class.getResourceAsStream("/META-INF/maven/io.ebean/ebean/pom.properties")) {
try (InputStream in = ClassLoader.getSystemResourceAsStream("META-INF/maven/io.ebean/ebean-api/pom.properties")) {
if (in != null) {
prop.load(in);
in.close();
version = prop.getProperty("version");
version = readVersion(in);
}
}
log.info("ebean version: {}", version);
@@ -33,6 +40,49 @@ public class EbeanVersion {
}
}
private static void checkAgentVersion() {
try {
try (InputStream in = ClassLoader.getSystemResourceAsStream("META-INF/maven/io.ebean/ebean-agent/pom.properties")) {
// often we only have ebean-agent during development (with build time enhancement), null is expected
if (in != null) {
String agentVersion = readVersion(in);
if (agentVersion != null) {
if (checkMinAgentVersion(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.warn("Could not check minimum ebean-agent version {}.{}.0 required due to - {}", MIN_AGENT_MAJOR_VERSION, MIN_AGENT_MINOR_VERSION, e.getMessage());
}
}
/**
* Return true if ebean-agent is NOT at our minimum version.
*/
static boolean checkMinAgentVersion(String agentVersion) {
String[] versionSegments = agentVersion.split("\\.");
if (versionSegments.length != 3) {
return true;
} else {
int major = Integer.parseInt(versionSegments[0]);
int minor = Integer.parseInt(versionSegments[1]);
if (major < MIN_AGENT_MAJOR_VERSION) {
return true;
} else {
return major == MIN_AGENT_MAJOR_VERSION && minor < MIN_AGENT_MINOR_VERSION;
}
}
}
private static String readVersion(InputStream in) throws IOException {
Properties prop = new Properties();
prop.load(in);
in.close();
return prop.getProperty("version");
}
private EbeanVersion() {
// hide
}
@@ -1,6 +1,5 @@
package io.ebean;
import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Future;
@@ -25,13 +24,11 @@ public class EmptyPagedList<T> implements PagedList<T> {
// do nothing
}
@Nonnull
@Override
public Future<Integer> getFutureCount() {
return null;
}
@Nonnull
@Override
public List<T> getList() {
return Collections.emptyList();
@@ -1,21 +1,13 @@
package io.ebean;
import io.ebean.search.Match;
import io.ebean.search.MultiMatch;
import io.ebean.search.TextCommonTerms;
import io.ebean.search.TextQueryString;
import io.ebean.search.TextSimple;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.search.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.NonUniqueResultException;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -39,6 +31,7 @@ import java.util.function.Predicate;
*
* @see Query#where()
*/
@NonNullApi
public interface ExpressionList<T> {
/**
@@ -327,7 +320,6 @@ public interface ExpressionList<T> {
*
* @see Query#findList()
*/
@Nonnull
List<T> findList();
/**
@@ -335,7 +327,6 @@ public interface ExpressionList<T> {
*
* @see Query#findIds()
*/
@Nonnull
<A> List<A> findIds();
/**
@@ -351,7 +342,6 @@ public interface ExpressionList<T> {
*
* @see Query#findSet()
*/
@Nonnull
Set<T> findSet();
/**
@@ -359,7 +349,6 @@ public interface ExpressionList<T> {
*
* @see Query#findMap()
*/
@Nonnull
<K> Map<K, T> findMap();
/**
@@ -392,7 +381,6 @@ public interface ExpressionList<T> {
*
* @return the list of values for the selected property
*/
@Nonnull
<A> List<A> findSingleAttributeList();
/**
@@ -429,7 +417,6 @@ public interface ExpressionList<T> {
/**
* Execute the query returning an optional bean.
*/
@Nonnull
Optional<T> findOneOrEmpty();
/**
@@ -442,7 +429,6 @@ public interface ExpressionList<T> {
*
* @return a Future object for the row count query
*/
@Nonnull
FutureRowCount<T> findFutureCount();
/**
@@ -455,7 +441,6 @@ public interface ExpressionList<T> {
*
* @return a Future object for the list of Id's
*/
@Nonnull
FutureIds<T> findFutureIds();
/**
@@ -468,7 +453,6 @@ public interface ExpressionList<T> {
*
* @return a Future object for the list result of the query
*/
@Nonnull
FutureList<T> findFutureList();
/**
@@ -499,7 +483,6 @@ public interface ExpressionList<T> {
* @return The PagedList
* @see Query#findPagedList()
*/
@Nonnull
PagedList<T> findPagedList();
/**
@@ -509,7 +492,6 @@ public interface ExpressionList<T> {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
List<Version<T>> findVersions();
/**
@@ -519,13 +501,11 @@ public interface ExpressionList<T> {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
/**
* Add some filter predicate expressions to the many property.
*/
@Nonnull
ExpressionList<T> filterMany(String manyProperty);
/**
@@ -1,7 +1,7 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.avaje.lang.Nullable;
import javax.persistence.NonUniqueResultException;
import java.time.Clock;
import java.util.List;
@@ -82,7 +82,6 @@ public interface ExtendedServer {
*
* @see Query#findIds()
*/
@Nonnull
<A, T> List<A> findIds(Query<T> query, Transaction transaction);
/**
@@ -100,7 +99,6 @@ public interface ExtendedServer {
* @see Query#findEach(Consumer)
* @see Query#findEachWhile(Predicate)
*/
@Nonnull
<T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction);
/**
@@ -112,7 +110,6 @@ public interface ExtendedServer {
* Note that the stream needs to be closed so use with try with resources.
* </p>
*/
@Nonnull
<T> Stream<T> findStream(Query<T> query, Transaction transaction);
/**
@@ -125,7 +122,6 @@ public interface ExtendedServer {
* <p>
* Note that the stream needs to be closed so use with try with resources.
*/
@Nonnull
@Deprecated
<T> Stream<T> findLargeStream(Query<T> query, Transaction transaction);
@@ -210,7 +206,6 @@ public interface ExtendedServer {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
<T> List<Version<T>> findVersions(Query<T> query, Transaction transaction);
/**
@@ -235,7 +230,6 @@ public interface ExtendedServer {
* @return the list of fetched beans.
* @see Query#findList()
*/
@Nonnull
<T> List<T> findList(Query<T> query, Transaction transaction);
/**
@@ -251,7 +245,6 @@ public interface ExtendedServer {
* @return a Future object for the row count query
* @see Query#findFutureCount()
*/
@Nonnull
<T> FutureRowCount<T> findFutureCount(Query<T> query, Transaction transaction);
/**
@@ -267,7 +260,6 @@ public interface ExtendedServer {
* @return a Future object for the list of Id's
* @see Query#findFutureIds()
*/
@Nonnull
<T> FutureIds<T> findFutureIds(Query<T> query, Transaction transaction);
/**
@@ -284,7 +276,6 @@ public interface ExtendedServer {
* @return a Future object for the list result of the query
* @see Query#findFutureList()
*/
@Nonnull
<T> FutureList<T> findFutureList(Query<T> query, Transaction transaction);
/**
@@ -316,7 +307,6 @@ public interface ExtendedServer {
* @return The PagedList
* @see Query#findPagedList()
*/
@Nonnull
<T> PagedList<T> findPagedList(Query<T> query, Transaction transaction);
/**
@@ -341,7 +331,6 @@ public interface ExtendedServer {
* @return the set of fetched beans.
* @see Query#findSet()
*/
@Nonnull
<T> Set<T> findSet(Query<T> query, Transaction transaction);
/**
@@ -358,7 +347,6 @@ public interface ExtendedServer {
* @return the map of fetched beans.
* @see Query#findMap()
*/
@Nonnull
<K, T> Map<K, T> findMap(Query<T> query, Transaction transaction);
/**
@@ -391,7 +379,6 @@ public interface ExtendedServer {
* @return the list of values for the selected property
* @see Query#findSingleAttributeList()
*/
@Nonnull
<A, T> List<A> findSingleAttributeList(Query<T> query, Transaction transaction);
/**
@@ -419,7 +406,6 @@ public interface ExtendedServer {
/**
* Similar to findOne() but returns an Optional (rather than nullable).
*/
@Nonnull
<T> Optional<T> findOneOrEmpty(Query<T> query, Transaction transaction);
/**
@@ -463,7 +449,6 @@ public interface ExtendedServer {
* @return the list of fetched MapBean.
* @see SqlQuery#findList()
*/
@Nonnull
List<SqlRow> findList(SqlQuery query, Transaction transaction);
/**
@@ -1,9 +1,8 @@
package io.ebean;
import io.avaje.lang.NonNullApi;
import io.ebean.service.SpiFetchGroupQuery;
import javax.annotation.Nonnull;
/**
* Defines what part of the object graph to load (select and fetch clauses).
* <p>
@@ -62,6 +61,7 @@ import javax.annotation.Nonnull;
*
* @param <T> The bean type the Fetch group can be applied to
*/
@NonNullApi
public interface FetchGroup<T> {
/**
@@ -83,7 +83,6 @@ public interface FetchGroup<T> {
*
* @return The FetchGroup with the given select clause
*/
@Nonnull
static <T> FetchGroup<T> of(Class<T> cls, String select) {
return XServiceProvider.fetchGroupOf(cls, select);
}
@@ -108,7 +107,6 @@ public interface FetchGroup<T> {
*
* @return The FetchGroupBuilder with the given select clause which we will add fetch clauses to
*/
@Nonnull
static <T> FetchGroupBuilder<T> of(Class<T> cls) {
return XServiceProvider.fetchGroupOf(cls);
}
@@ -1,6 +1,6 @@
package io.ebean;
import javax.annotation.Nonnull;
import io.avaje.lang.NonNullApi;
/**
* Builds a FetchGroup by adding fetch clauses.
@@ -23,85 +23,73 @@ import javax.annotation.Nonnull;
*
* }</pre>
*/
@NonNullApi
public interface FetchGroupBuilder<T> {
/**
* Specify specific properties to select (top level properties).
*/
@Nonnull
FetchGroupBuilder<T> select(String select);
/**
* Fetch all the properties at the given path.
*/
@Nonnull
FetchGroupBuilder<T> fetch(String path);
/**
* Fetch the path with the nested fetch group.
*/
@Nonnull
FetchGroupBuilder<T> fetch(String path, FetchGroup<?> nestedGroup);
/**
* Fetch the path using a query join with the nested fetch group.
*/
@Nonnull
FetchGroupBuilder<T> fetchQuery(String path, FetchGroup<?> nestedGroup);
/**
* Fetch the path lazily with the nested fetch group.
*/
@Nonnull
FetchGroupBuilder<T> fetchLazy(String path, FetchGroup<?> nestedGroup);
/**
* Fetch the path including specified properties.
*/
@Nonnull
FetchGroupBuilder<T> fetch(String path, String properties);
/**
* Fetch the path including all its properties using a query join.
*/
@Nonnull
FetchGroupBuilder<T> fetchQuery(String path);
/**
* Fetch the path including all its properties using L2 cache.
* Cache misses fallback to fetchQuery().
*/
@Nonnull
FetchGroupBuilder<T> fetchCache(String path);
/**
* Fetch the path including specified properties using a query join.
*/
@Nonnull
FetchGroupBuilder<T> fetchQuery(String path, String properties);
/**
* Fetch the path including specified properties using L2 cache.
* Cache misses fallback to fetchQuery().
*/
@Nonnull
FetchGroupBuilder<T> fetchCache(String path, String properties);
/**
* Fetch the path including all its properties lazily.
*/
@Nonnull
FetchGroupBuilder<T> fetchLazy(String path);
/**
* Fetch the path including specified properties lazily.
*/
@Nonnull
FetchGroupBuilder<T> fetchLazy(String path, String properties);
/**
* Build and return the FetchGroup.
*/
@Nonnull
FetchGroup<T> build();
}
@@ -1,5 +1,7 @@
package io.ebean;
import io.avaje.lang.NonNullApi;
import java.util.List;
import java.util.Set;
@@ -77,6 +79,7 @@ import java.util.Set;
*
* @param <T> the entity bean type
*/
@NonNullApi
public interface Filter<T> {
/**
+3 -4
View File
@@ -1,7 +1,7 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import java.util.List;
/**
@@ -55,6 +55,7 @@ import java.util.List;
* }</pre>
*
*/
@NonNullApi
public class Finder<I, T> {
/**
@@ -139,7 +140,6 @@ public class Finder<I, T> {
* <p>
* Equivalent to {@link Database#reference(Class, Object)}
*/
@Nonnull
public T ref(I id) {
return db().reference(type, id);
}
@@ -166,7 +166,6 @@ public class Finder<I, T> {
/**
* Retrieves all entities of the given type.
*/
@Nonnull
public List<T> all() {
return query().findList();
}
@@ -113,9 +113,9 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
*/
SHOULD("should", "", true);
private String prefix;
private String literal;
private boolean text;
private final String prefix;
private final String literal;
private final boolean text;
Type(String literal, String prefix, boolean text) {
this.literal = literal;
@@ -1,6 +1,5 @@
package io.ebean;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.Future;
@@ -116,13 +115,11 @@ public interface PagedList<T> {
*
* }</pre>
*/
@Nonnull
Future<Integer> getFutureCount();
/**
* Return the list of entities for this page.
*/
@Nonnull
List<T> getList();
/**
+3 -17
View File
@@ -1,7 +1,7 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import javax.persistence.NonUniqueResultException;
import java.sql.Connection;
import java.sql.Timestamp;
@@ -177,6 +177,7 @@ import java.util.stream.Stream;
*
* @param <T> the type of Entity bean this query will fetch.
*/
@NonNullApi
public interface Query<T> extends CancelableQuery {
/**
@@ -689,7 +690,6 @@ public interface Query<T> extends CancelableQuery {
* This query will execute against the Database that was used to create it.
* </p>
*/
@Nonnull
<A> List<A> findIds();
/**
@@ -727,7 +727,6 @@ public interface Query<T> extends CancelableQuery {
*
* }</pre>
*/
@Nonnull
QueryIterator<T> findIterate();
/**
@@ -749,7 +748,6 @@ public interface Query<T> extends CancelableQuery {
*
* }</pre>
*/
@Nonnull
Stream<T> findStream();
/**
@@ -772,7 +770,6 @@ public interface Query<T> extends CancelableQuery {
*
* }</pre>
*/
@Nonnull
@Deprecated
Stream<T> findLargeStream();
@@ -882,7 +879,6 @@ public interface Query<T> extends CancelableQuery {
*
* }</pre>
*/
@Nonnull
List<T> findList();
/**
@@ -898,7 +894,6 @@ public interface Query<T> extends CancelableQuery {
*
* }</pre>
*/
@Nonnull
Set<T> findSet();
/**
@@ -918,7 +913,6 @@ public interface Query<T> extends CancelableQuery {
*
* }</pre>
*/
@Nonnull
<K> Map<K, T> findMap();
/**
@@ -951,7 +945,6 @@ public interface Query<T> extends CancelableQuery {
*
* @return the list of values for the selected property
*/
@Nonnull
<A> List<A> findSingleAttributeList();
/**
@@ -1049,7 +1042,6 @@ public interface Query<T> extends CancelableQuery {
/**
* Execute the query returning an optional bean.
*/
@Nonnull
Optional<T> findOneOrEmpty();
/**
@@ -1064,7 +1056,6 @@ public interface Query<T> extends CancelableQuery {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
List<Version<T>> findVersions();
/**
@@ -1074,7 +1065,6 @@ public interface Query<T> extends CancelableQuery {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
/**
@@ -1132,7 +1122,6 @@ public interface Query<T> extends CancelableQuery {
*
* @return a Future object for the row count query
*/
@Nonnull
FutureRowCount<T> findFutureCount();
/**
@@ -1145,7 +1134,6 @@ public interface Query<T> extends CancelableQuery {
*
* @return a Future object for the list of Id's
*/
@Nonnull
FutureIds<T> findFutureIds();
/**
@@ -1157,7 +1145,6 @@ public interface Query<T> extends CancelableQuery {
*
* @return a Future object for the list result of the query
*/
@Nonnull
FutureList<T> findFutureList();
/**
@@ -1187,7 +1174,6 @@ public interface Query<T> extends CancelableQuery {
*
* @return The PagedList
*/
@Nonnull
PagedList<T> findPagedList();
/**
@@ -1,7 +1,7 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
@@ -37,12 +37,12 @@ import java.util.function.Predicate;
*
* }</pre>
*/
@NonNullApi
public interface SqlQuery extends Serializable, CancelableQuery {
/**
* Execute the query returning a list.
*/
@Nonnull
List<SqlRow> findList();
/**
@@ -119,7 +119,6 @@ public interface SqlQuery extends Serializable, CancelableQuery {
/**
* Execute the query returning an optional row.
*/
@Nonnull
Optional<SqlRow> findOneOrEmpty();
/**
@@ -354,6 +353,7 @@ public interface SqlQuery extends Serializable, CancelableQuery {
/**
* Return the single value.
*/
@Nullable
T findOne();
/**
@@ -9,11 +9,7 @@ import javax.persistence.PersistenceException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.net.URL;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -1164,7 +1160,7 @@ public final class EntityBeanIntercept implements Serializable {
*/
public Map<String, Exception> getLoadErrors() {
if (loadErrors == null) {
return null;
return Collections.emptyMap();
}
Map<String, Exception> ret = null;
int len = getPropertyLength();
@@ -60,21 +60,15 @@ public interface PersistenceContext {
int size(Class<?> rootType);
/**
* Return a copy of the Persistence context to use for large query iteration.
* Signalizes the PersistenceContext, the begin for large query iteration.
*/
PersistenceContext forIterate();
void beginIterate();
/**
* Return a new Persistence context during iteration of large query result.
* Signalizes the PersistenceContext, the end for large query iteration.
*/
PersistenceContext forIterateReset();
/**
* Return true if the persistence context has grown and hit the 'reset limit'
* during large query iteration.
*/
boolean resetLimit();
void endIterate();
/**
* Wrapper on a bean to also indicate if a bean has been deleted.
* <p>
@@ -1547,6 +1547,9 @@ public class DatabaseConfig {
/**
* Set to true if all DB column and table names should use quoted identifiers.
* <p>
* For Postgres pgjdbc version 42.3.0 should be used with datasource property
* <em>quoteReturningIdentifiers</em> set to <em>false</em> (refer #2303).
*/
public void setAllQuotedIdentifiers(boolean allQuotedIdentifiers) {
platformConfig.setAllQuotedIdentifiers(allQuotedIdentifiers);
@@ -117,6 +117,9 @@ public class PlatformConfig {
/**
* Set to true if all DB column and table names should use quoted identifiers.
* <p>
* For Postgres pgjdbc version 42.3.0 should be used with datasource property
* <em>quoteReturningIdentifiers</em> set to <em>false</em> (refer #2303).
*/
public void setAllQuotedIdentifiers(boolean allQuotedIdentifiers) {
this.allQuotedIdentifiers = allQuotedIdentifiers;
@@ -8,7 +8,6 @@ import io.ebean.event.BeanPersistController;
import io.ebean.event.BeanPersistListener;
import io.ebean.event.BeanQueryAdapter;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
@@ -21,7 +20,6 @@ public interface BeanType<T> {
/**
* Return the short name of the bean type.
*/
@Nonnull
String name();
/**
@@ -35,7 +33,6 @@ public interface BeanType<T> {
/**
* Return the full name of the bean type.
*/
@Nonnull
String fullName();
/**
@@ -49,7 +46,6 @@ public interface BeanType<T> {
/**
* Return the class type this BeanDescriptor describes.
*/
@Nonnull
Class<T> type();
/**
@@ -76,7 +72,6 @@ public interface BeanType<T> {
/**
* Return all the properties for this bean type.
*/
@Nonnull
Collection<? extends Property> allProperties();
/**
@@ -1,7 +1,5 @@
package io.ebean.plugin;
import javax.annotation.Nonnull;
/**
* Property of a entity bean that can be read.
*/
@@ -10,7 +8,6 @@ public interface Property {
/**
* Return the name of the property.
*/
@Nonnull
String name();
/**
@@ -24,7 +21,6 @@ public interface Property {
/**
* Return the type of the property.
*/
@Nonnull
Class<?> type();
/**
@@ -20,7 +20,7 @@ public interface JsonBeanReader<T> {
/**
* Create a new reader taking the context from the existing one but using a new JsonParser.
*/
JsonBeanReader<T> forJson(JsonParser moreJson, boolean resetContext);
JsonBeanReader<T> forJson(JsonParser moreJson);
/**
* Add a bean explicitly to the persistence context.
@@ -0,0 +1,31 @@
package io.ebean;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class EbeanVersionTest {
@Test
void checkMinAgentVersion_ok() {
assertFalse(EbeanVersion.checkMinAgentVersion("12.12.0"));
assertFalse(EbeanVersion.checkMinAgentVersion("12.12.99"));
assertFalse(EbeanVersion.checkMinAgentVersion("13.1.0"));
}
@Test
void checkMinAgentVersion_agentTooOld() {
assertTrue(EbeanVersion.checkMinAgentVersion("11.13.0"));
assertTrue(EbeanVersion.checkMinAgentVersion("12.11.0"));
assertTrue(EbeanVersion.checkMinAgentVersion("12.11.99"));
}
@Test
void checkMinAgentVersion_unexpectedAgentVersion() {
assertTrue(EbeanVersion.checkMinAgentVersion("13.13"));
assertTrue(EbeanVersion.checkMinAgentVersion("13"));
assertTrue(EbeanVersion.checkMinAgentVersion(""));
}
}
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.0</version>
<version>12.13.0</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.12.0</tag>
<tag>ebean-parent-12.13.0</tag>
</scm>
<name>ebean autotune</name>
@@ -26,7 +26,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>provided</scope>
</dependency>
+15 -15
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.0</version>
<version>12.13.0</version>
</parent>
<name>ebean bom</name>
@@ -71,88 +71,88 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.0</version>
<version>12.13.0</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
+6 -6
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.0</version>
<version>12.13.0</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -15,7 +15,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.12.0</tag>
<tag>ebean-parent-12.13.0</tag>
</scm>
<dependencies>
@@ -41,19 +41,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
@@ -136,7 +136,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.20</version>
<version>42.2.24</version>
<optional>true</optional>
</dependency>
@@ -285,12 +285,17 @@ public final class BindParams implements Serializable {
*/
public boolean isSameBindHash() {
if (bindHash == null) {
bindHash = calcQueryPlanHash();
return false;
}
String oldPlan = bindHash;
String newHash = calcQueryPlanHash();
return bindHash.equals(newHash);
}
/**
* Updates the hash.
*/
public void updateHash() {
bindHash = calcQueryPlanHash();
return bindHash.equals(oldPlan);
}
/**
@@ -36,14 +36,6 @@ public interface LoadContext {
*/
PersistenceContext getPersistenceContext();
/**
* Set the persistence context used by this query and future lazy loading.
* <p>
* Used by query iterator when processing large result sets.
* </p>
*/
void resetPersistenceContext(PersistenceContext persistenceContext);
/**
* Register a Bean for lazy loading.
*/
@@ -16,6 +16,7 @@ import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.query.CQuery;
import io.ebeaninternal.server.transaction.RemoteTransactionEvent;
import javax.annotation.Nullable;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -141,7 +142,7 @@ public interface SpiEbeanServer extends SpiServer, ExtendedServer, EbeanServer,
/**
* Compile a query.
*/
<T> CQuery<T> compileQuery(Type type, Query<T> query, Transaction t);
<T> CQuery<T> compileQuery(Type type, Query<T> query, Transaction transaction);
/**
* Execute the findId's query but without copying the query.
@@ -150,12 +151,12 @@ public interface SpiEbeanServer extends SpiServer, ExtendedServer, EbeanServer,
* the query has finished (if executing in a background thread).
* </p>
*/
<A, T> List<A> findIdsWithCopy(Query<T> query, Transaction t);
<A, T> List<A> findIdsWithCopy(Query<T> query, Transaction transaction);
/**
* Execute the findCount query but without copying the query.
*/
<T> int findCountWithCopy(Query<T> query, Transaction t);
<T> int findCountWithCopy(Query<T> query, Transaction transaction);
/**
* Load a batch of Associated One Beans.
@@ -257,6 +258,7 @@ public interface SpiEbeanServer extends SpiServer, ExtendedServer, EbeanServer,
/**
* DTO findOne query.
*/
@Nullable
<T> T findDtoOne(SpiDtoQuery<T> query);
/**
@@ -14,7 +14,7 @@ public interface SpiJsonReader {
PersistenceContext getPersistenceContext();
SpiJsonReader forJson(JsonParser moreJson, boolean resetContext);
SpiJsonReader forJson(JsonParser moreJson);
<T> void persistenceContextPut(Object beanId, T currentBean);
File diff suppressed because it is too large Load Diff
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.core;
import io.ebean.*;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.bean.PersistenceContext;
import io.ebean.cache.QueryCacheEntry;
import io.ebean.common.BeanList;
@@ -201,14 +200,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
return persistenceContext;
}
/**
* Add the bean to the persistence context.
*/
public void persistenceContextAdd(EntityBean bean) {
Object id = beanDescriptor.getId(bean);
beanDescriptor.contextPut(persistenceContext, id, bean);
}
/**
* This will create a local (readOnly) transaction if no current transaction
* exists.
@@ -233,6 +224,9 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
createdTransaction = true;
}
persistenceContext = persistenceContext(query, transaction);
if (Type.ITERATE == query.getType()) {
persistenceContext.beginIterate();
}
loadContext = new DLoadContext(this, secondaryQueries);
}
@@ -241,6 +235,9 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
*/
@Override
public void rollbackTransIfRequired() {
if (Type.ITERATE == query.getType()) {
persistenceContext.endIterate();
}
if (createdTransaction) {
try {
transaction.end();
@@ -271,20 +268,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
return jsonRead;
}
/**
* For iterate queries reset the persistenceContext and loadContext.
*/
public void flushPersistenceContextOnIterate() {
if (persistenceContext.resetLimit()) {
persistenceContext = persistenceContext.forIterateReset();
loadContext.resetPersistenceContext(persistenceContext);
if (jsonRead != null) {
jsonRead.setPersistenceContext(persistenceContext);
jsonRead.setLoadContext(loadContext);
}
}
}
/**
* Get the TransactionContext either explicitly set on the query or
* transaction scoped.
@@ -300,11 +283,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
if (scope == PersistenceContextScope.QUERY || t == null) {
return new DefaultPersistenceContext();
}
if (Type.ITERATE == query.getType()) {
return t.getPersistenceContext().forIterate();
} else {
return t.getPersistenceContext();
}
return t.getPersistenceContext();
}
/**
@@ -314,6 +293,9 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
*/
@Override
public void endTransIfRequired() {
if (Type.ITERATE == query.getType()) {
persistenceContext.endIterate();
}
if (createdTransaction && transaction.isActive()) {
transaction.commit();
if (query.getType().isUpdate()) {
@@ -590,7 +572,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
private ElPropertyValue mapProperty() {
ElPropertyValue property = beanDescriptor.elGetValue(query.getMapKey());
if (property == null) {
throw new IllegalStateException("Unknown map key property "+query.getMapKey());
throw new IllegalStateException("Unknown map key property " + query.getMapKey());
}
return property;
}
@@ -56,7 +56,6 @@ import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
import io.ebeanservice.docstore.api.mapping.DocumentMapping;
import org.slf4j.Logger;
import javax.annotation.Nonnull;
import javax.persistence.PersistenceException;
import java.io.IOException;
import java.io.StringWriter;
@@ -1961,7 +1960,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
* Return the class type this BeanDescriptor describes.
*/
@Override
@Nonnull
public Class<T> type() {
return beanType;
}
@@ -1973,7 +1971,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
* instead.
*/
@Override
@Nonnull
public String fullName() {
return fullName;
}
@@ -1982,7 +1979,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
* Return the short name of the entity bean.
*/
@Override
@Nonnull
public String name() {
return name;
}
@@ -2936,7 +2932,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
}
@Override
@Nonnull
public Collection<? extends Property> allProperties() {
return propertiesAll();
}
@@ -90,7 +90,7 @@ final class BeanDescriptorJsonHelp<T> {
return null;
}
JsonParser newParser = node.traverse();
SpiJsonReader newReader = jsonRead.forJson(newParser, false);
SpiJsonReader newReader = jsonRead.forJson(newParser);
// check for the discriminator value to determine the correct sub type
String discColumn = inheritInfo.getRoot().getDiscriminatorColumn();
@@ -349,10 +349,10 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
builder = RawSqlBuilder.unparsed(sql.getQuery());
}
for (Map.Entry<String,String> columnMapping : sql.getColumnMapping().entrySet()) {
for (Map.Entry<String, String> columnMapping : sql.getColumnMapping().entrySet()) {
builder.columnMapping(columnMapping.getKey(), columnMapping.getValue());
}
for (Map.Entry<String,String> aliasMapping : sql.getAliasMapping().entrySet()) {
for (Map.Entry<String, String> aliasMapping : sql.getAliasMapping().entrySet()) {
builder.tableAliasMapping(aliasMapping.getKey(), aliasMapping.getValue());
}
info.addRawSql(sql.getName(), builder.create());
@@ -410,7 +410,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
@Override
public boolean isTableManaged(String tableName) {
return tableToDescMap.get(tableName.toLowerCase()) != null
|| tableToViewDescMap.get(tableName.toLowerCase()) != null;
|| tableToViewDescMap.get(tableName.toLowerCase()) != null;
}
/**
@@ -618,7 +618,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
DeployBeanInfo<?> info = createDeployBeanInfo(entityClass);
deployInfoMap.put(entityClass, info);
Class<?> embeddedIdType = info.getEmbeddedIdType();
if (embeddedIdType != null){
if (embeddedIdType != null) {
embeddedIdTypes.add(embeddedIdType);
}
}
@@ -788,8 +788,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
Class<?> targetType = prop.getTargetType();
DeployBeanInfo<?> info = deployInfoMap.get(targetType);
if (info == null) {
String msg = "Can not find descriptor [" + targetType + "] for " + prop.getFullBeanName();
throw new PersistenceException(msg);
throw new PersistenceException("Can not find descriptor [" + targetType + "] for " + prop.getFullBeanName());
}
return info.getDescriptor();
}
@@ -901,21 +900,17 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
Class<?> owningType = oneToMany.getOwningType();
if (!oneToMany.getCascadeInfo().isSave()) {
// The property MUST have persist cascading so that inserts work.
Class<?> targetType = oneToMany.getTargetType();
String msg = "Error on " + oneToMany.getFullBeanName() + ". @OneToMany MUST have ";
msg += "Cascade.PERSIST or Cascade.ALL because this is a unidirectional ";
msg += "relationship. That is, there is no property of type " + owningType + " on " + targetType;
throw new PersistenceException(msg);
}
// mark this property as unidirectional
oneToMany.setUnidirectional();
// specify table and table alias...
BeanTable beanTable = beanTable(owningType);
// define the TableJoin
DeployTableJoin oneToManyJoin = oneToMany.getTableJoin();
if (!oneToManyJoin.hasJoinColumns()) {
@@ -951,27 +946,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
String mappedBy = prop.getMappedBy();
// get the mappedBy property
DeployBeanDescriptor<?> targetDesc = targetDescriptor(prop);
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
if (mappedProp == null) {
String m = "Error on " + prop.getFullBeanName();
m += " Can not find mappedBy property [" + targetDesc + "." + mappedBy + "] ";
throw new PersistenceException(m);
}
if (!(mappedProp instanceof DeployBeanPropertyAssocOne<?>)) {
String m = "Error on " + prop.getFullBeanName();
m += ". mappedBy property [" + targetDesc + "." + mappedBy + "]is not a OneToOne?";
throw new PersistenceException(m);
}
DeployBeanPropertyAssocOne<?> mappedAssocOne = (DeployBeanPropertyAssocOne<?>) mappedProp;
if (!mappedAssocOne.isOneToOne()) {
String m = "Error on " + prop.getFullBeanName();
m += ". mappedBy property [" + targetDesc + "." + mappedBy + "]is not a OneToOne?";
throw new PersistenceException(m);
}
DeployBeanPropertyAssocOne<?> mappedAssocOne = mappedOneToOne(prop, mappedBy, targetDesc);
DeployTableJoin tableJoin = prop.getTableJoin();
if (!tableJoin.hasJoinColumns()) {
// define Join as the inverse of the mappedBy property
@@ -987,6 +962,21 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
}
}
private DeployBeanPropertyAssocOne<?> mappedOneToOne(DeployBeanPropertyAssocOne<?> prop, String mappedBy, DeployBeanDescriptor<?> targetDesc) {
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
if (mappedProp == null) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + " Can not find mappedBy property [" + targetDesc + "." + mappedBy + "]");
}
if (!(mappedProp instanceof DeployBeanPropertyAssocOne<?>)) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + ". mappedBy property [" + targetDesc + "." + mappedBy + "]is not a OneToOne?");
}
DeployBeanPropertyAssocOne<?> mappedAssocOne = (DeployBeanPropertyAssocOne<?>) mappedProp;
if (!mappedAssocOne.isOneToOne()) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + ". mappedBy property [" + targetDesc + "." + mappedBy + "]is not a OneToOne?");
}
return mappedAssocOne;
}
private void checkUniDirectionalPrimaryKeyJoin(DeployBeanPropertyAssocOne<?> prop) {
if (prop.isPrimaryKeyJoin()) {
// uni-directional PrimaryKeyJoin ...
@@ -1008,7 +998,6 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
return;
}
DeployBeanDescriptor<?> targetDesc = targetDescriptor(prop);
if (targetDesc.isDraftableElement()) {
// automatically turning on orphan removal and CascadeType.ALL
prop.setModifyListenMode(BeanCollection.ModifyListenMode.REMOVALS);
@@ -1040,23 +1029,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
String mappedBy = prop.getMappedBy();
// get the mappedBy property
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
if (mappedProp == null) {
String m = "Error on " + prop.getFullBeanName();
m += " Can not find mappedBy property [" + mappedBy + "] ";
m += "in [" + targetDesc + "]";
throw new PersistenceException(m);
}
if (!(mappedProp instanceof DeployBeanPropertyAssocOne<?>)) {
String m = "Error on " + prop.getFullBeanName();
m += ". mappedBy property [" + mappedBy + "]is not a ManyToOne?";
m += "in [" + targetDesc + "]";
throw new PersistenceException(m);
}
DeployBeanPropertyAssocOne<?> mappedAssocOne = (DeployBeanPropertyAssocOne<?>) mappedProp;
DeployBeanPropertyAssocOne<?> mappedAssocOne = mappedManyToOne(prop, targetDesc, mappedBy);
DeployTableJoin tableJoin = prop.getTableJoin();
if (!tableJoin.hasJoinColumns()) {
// define Join as the inverse of the mappedBy property
@@ -1079,6 +1052,17 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
}
}
private DeployBeanPropertyAssocOne<?> mappedManyToOne(DeployBeanPropertyAssocMany<?> prop, DeployBeanDescriptor<?> targetDesc, String mappedBy) {
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
if (mappedProp == null) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + " Can not find mappedBy property [" + mappedBy + "] " + "in [" + targetDesc + "]");
}
if (!(mappedProp instanceof DeployBeanPropertyAssocOne<?>)) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + ". mappedBy property [" + mappedBy + "]is not a ManyToOne?" + "in [" + targetDesc + "]");
}
return (DeployBeanPropertyAssocOne<?>) mappedProp;
}
/**
* For mappedBy copy the joins from the other side.
*/
@@ -1094,33 +1078,10 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
// get the mappedBy property
DeployBeanDescriptor<?> targetDesc = targetDescriptor(prop);
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
if (mappedProp == null) {
String m = "Error on " + prop.getFullBeanName();
m += " Can not find mappedBy property [" + mappedBy + "] ";
m += "in [" + targetDesc + "]";
throw new PersistenceException(m);
}
if (!(mappedProp instanceof DeployBeanPropertyAssocMany<?>)) {
String m = "Error on " + prop.getFullBeanName();
m += ". mappedBy property [" + targetDesc + "." + mappedBy + "] is not a ManyToMany?";
throw new PersistenceException(m);
}
DeployBeanPropertyAssocMany<?> mappedAssocMany = (DeployBeanPropertyAssocMany<?>) mappedProp;
if (!mappedAssocMany.isManyToMany()) {
String m = "Error on " + prop.getFullBeanName();
m += ". mappedBy property [" + targetDesc + "." + mappedBy + "] is not a ManyToMany?";
throw new PersistenceException(m);
}
DeployBeanPropertyAssocMany<?> mappedAssocMany = mappedManyToMany(prop, mappedBy, targetDesc);
// define the relationships/joins on this side as the
// reverse of the other mappedBy side ...
// DeployTableJoin mappedJoin = mappedAssocMany.getTableJoin();
DeployTableJoin mappedIntJoin = mappedAssocMany.getIntersectionJoin();
DeployTableJoin mappendInverseJoin = mappedAssocMany.getInverseJoin();
@@ -1142,6 +1103,22 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
}
}
private DeployBeanPropertyAssocMany<?> mappedManyToMany(DeployBeanPropertyAssocMany<?> prop, String mappedBy, DeployBeanDescriptor<?> targetDesc) {
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
if (mappedProp == null) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + " Can not find mappedBy property [" + mappedBy + "] " + "in [" + targetDesc + "]");
}
if (!(mappedProp instanceof DeployBeanPropertyAssocMany<?>)) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + ". mappedBy property [" + targetDesc + "." + mappedBy + "] is not a ManyToMany?");
}
DeployBeanPropertyAssocMany<?> mappedAssocMany = (DeployBeanPropertyAssocMany<?>) mappedProp;
if (!mappedAssocMany.isManyToMany()) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + ". mappedBy property [" + targetDesc + "." + mappedBy + "] is not a ManyToMany?");
}
return mappedAssocMany;
}
private <T> void setBeanControllerFinderListener(DeployBeanDescriptor<T> descriptor) {
persistControllerManager.addPersistControllers(descriptor);
postLoadManager.addPostLoad(descriptor);
@@ -40,7 +40,6 @@ import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
import io.ebeanservice.docstore.api.mapping.DocPropertyOptions;
import io.ebeanservice.docstore.api.support.DocStructure;
import javax.annotation.Nonnull;
import javax.persistence.PersistenceException;
import java.io.DataInput;
import java.io.DataOutput;
@@ -813,7 +812,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
* Return the name of the property.
*/
@Override
@Nonnull
public String name() {
return name;
}
@@ -1299,7 +1297,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
* Return the property type.
*/
@Override
@Nonnull
public Class<?> type() {
return propertyType;
}
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.el;
import io.avaje.lang.NonNullApi;
import io.ebean.Filter;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -11,6 +12,7 @@ import java.util.regex.Pattern;
/**
* Default implementation of the Filter interface.
*/
@NonNullApi
public final class ElFilter<T> implements Filter<T> {
private final BeanDescriptor<T> beanDescriptor;
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.executor;
import io.avaje.lang.NonNullApi;
import io.ebeaninternal.api.SpiBackgroundExecutor;
import org.slf4j.MDC;
@@ -13,6 +14,7 @@ import java.util.concurrent.TimeUnit;
/**
* The default implementation of the BackgroundExecutor.
*/
@NonNullApi
public final class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
private final ScheduledExecutorService executor;
@@ -1,5 +1,7 @@
package io.ebeaninternal.server.expression;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.CacheMode;
import io.ebean.CountDistinctOrder;
import io.ebean.DtoQuery;
@@ -51,6 +53,7 @@ import java.util.function.Predicate;
/**
* Default implementation of ExpressionList.
*/
@NonNullApi
public class DefaultExpressionList<T> implements SpiExpressionList<T> {
private static final String AND = " and ";
@@ -469,6 +472,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return query.exists();
}
@Nullable
@Override
public T findOne() {
return query.findOne();
@@ -1,23 +1,15 @@
package io.ebeaninternal.server.expression;
import io.ebean.ExpressionFactory;
import io.ebean.ExpressionList;
import io.ebean.FutureIds;
import io.ebean.FutureList;
import io.ebean.FutureRowCount;
import io.ebean.Junction;
import io.ebean.OrderBy;
import io.ebean.Query;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.*;
import io.ebeaninternal.api.SpiExpressionList;
import io.ebeaninternal.api.SpiQuery;
import javax.persistence.PersistenceException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
@NonNullApi
public final class FilterExpressionList<T> extends DefaultExpressionList<T> {
private static final String notAllowedMessage = "This method is not allowed on a filter";
@@ -92,6 +84,7 @@ public final class FilterExpressionList<T> extends DefaultExpressionList<T> {
return rootQuery.findSet();
}
@Nullable
@Override
public T findOne() {
return rootQuery.findOne();
@@ -1,5 +1,7 @@
package io.ebeaninternal.server.expression;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.CacheMode;
import io.ebean.CountDistinctOrder;
import io.ebean.DtoQuery;
@@ -48,6 +50,7 @@ import java.util.function.Predicate;
/**
* Junction implementation.
*/
@NonNullApi
final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, ExpressionList<T> {
DefaultExpressionList<T> exprList;
@@ -476,6 +479,7 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
return exprList.findSet();
}
@Nullable
@Override
public T findOne() {
return exprList.findOne();
@@ -136,7 +136,7 @@ abstract class EqlWhereListener<T> extends EQLBaseListener {
}
}
@SuppressWarnings("unchecked")
@SuppressWarnings({"unchecked", "rawtypes"})
private List<Object> toList(Object value) {
if (value == null) return null;
if (value instanceof List) {
@@ -46,7 +46,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
/**
* Reset the buffers after a query iterator reset.
*/
public void clear() {
private void clear() {
if (bufferList != null) {
bufferList.clear();
}
@@ -57,7 +57,7 @@ public final class DLoadContext implements LoadContext {
private final ProfileLocation profileLocation;
private final ProfilingListener profilingListener;
private final Map<String, ObjectGraphNode> nodePathMap = new HashMap<>();
private PersistenceContext persistenceContext;
private final PersistenceContext persistenceContext;
private List<OrmQueryProperties> secQuery;
private Object tenantId;
@@ -251,19 +251,6 @@ public final class DLoadContext implements LoadContext {
return persistenceContext;
}
@Override
public void resetPersistenceContext(PersistenceContext persistenceContext) {
this.persistenceContext = persistenceContext;
// clear the load contexts for beans and beanCollections
for (DLoadBeanContext beanContext : beanMap.values()) {
beanContext.clear();
}
for (DLoadManyContext manyContext : manyMap.values()) {
manyContext.clear();
}
this.rootBeanContext.clear();
}
@Override
public void register(String path, EntityBeanIntercept ebi) {
getBeanContext(path).register(ebi);
@@ -48,7 +48,7 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
/**
* Reset the buffers for a query iterator reset.
*/
public void clear() {
private void clear() {
if (bufferList != null) {
bufferList.clear();
}
@@ -118,7 +118,11 @@ public final class Binder {
bindLog.append(value);
}
}
if (value == null) {
if (value instanceof Collection) {
for (Object entry: (Collection<?>) value) {
bindObject(dataBind, entry);
}
} else if (value == null) {
// this doesn't work for query predicates
bindObject(dataBind, null, param.getType());
} else {
@@ -1,11 +1,6 @@
package io.ebeaninternal.server.persist;
import io.ebean.CallableSql;
import io.ebean.MergeOptions;
import io.ebean.Query;
import io.ebean.SqlUpdate;
import io.ebean.Transaction;
import io.ebean.Update;
import io.ebean.*;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanCollection.ModifyListenMode;
import io.ebean.bean.EntityBean;
@@ -13,30 +8,15 @@ import io.ebean.bean.PersistenceContext;
import io.ebean.event.BeanPersistController;
import io.ebean.meta.MetricVisitor;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.core.PersistRequest;
import io.ebeaninternal.server.core.*;
import io.ebeaninternal.server.core.PersistRequest.Type;
import io.ebeaninternal.server.core.PersistRequestBean;
import io.ebeaninternal.server.core.PersistRequestCallableSql;
import io.ebeaninternal.server.core.PersistRequestOrmUpdate;
import io.ebeaninternal.server.core.PersistRequestUpdateSql;
import io.ebeaninternal.server.core.Persister;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanDescriptorManager;
import io.ebeaninternal.server.deploy.BeanManager;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import io.ebeaninternal.server.deploy.IntersectionRow;
import io.ebeaninternal.server.deploy.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* Persister implementation using DML.
@@ -82,7 +62,6 @@ public final class DefaultPersister implements Persister {
*/
@Override
public int executeCallable(CallableSql callSql, Transaction t) {
return executeOrQueue(new PersistRequestCallableSql(server, callSql, (SpiTransaction) t, persistExecute));
}
@@ -91,16 +70,8 @@ public final class DefaultPersister implements Persister {
*/
@Override
public int executeOrmUpdate(Update<?> update, Transaction t) {
SpiUpdate<?> ormUpdate = (SpiUpdate<?>) update;
BeanManager<?> mgr = beanDescriptorManager.beanManager(ormUpdate.getBeanType());
if (mgr == null) {
String msg = "No BeanManager found for type [" + ormUpdate.getBeanType() + "]. Is it an entity?";
throw new PersistenceException(msg);
}
BeanManager<?> mgr = beanManager(ormUpdate.getBeanType());
return executeOrQueue(new PersistRequestOrmUpdate(server, mgr, ormUpdate, (SpiTransaction) t, persistExecute));
}
@@ -169,10 +140,8 @@ public final class DefaultPersister implements Persister {
*/
@Override
public <T> List<T> draftRestore(Query<T> query, Transaction transaction) {
Class<T> beanType = query.getBeanType();
BeanDescriptor<T> desc = server.descriptor(beanType);
DraftHandler<T> draftHandler = new DraftHandler<>(desc, transaction);
List<T> liveBeans = draftHandler.fetchSourceBeans(query, false);
@@ -182,7 +151,6 @@ public final class DefaultPersister implements Persister {
}
draftHandler.fetchDestinationBeans(liveBeans, true);
BeanManager<T> mgr = beanDescriptorManager.beanManager(beanType);
for (T liveBean : liveBeans) {
@@ -214,10 +182,8 @@ public final class DefaultPersister implements Persister {
*/
@Override
public <T> List<T> publish(Query<T> query, Transaction transaction) {
Class<T> beanType = query.getBeanType();
BeanDescriptor<T> desc = server.descriptor(beanType);
DraftHandler<T> draftHandler = new DraftHandler<>(desc, transaction);
List<T> draftBeans = draftHandler.fetchSourceBeans(query, true);
@@ -227,7 +193,6 @@ public final class DefaultPersister implements Persister {
}
draftHandler.fetchDestinationBeans(draftBeans, false);
BeanManager<T> mgr = beanDescriptorManager.beanManager(beanType);
List<T> livePublish = new ArrayList<>(draftBeans.size());
@@ -251,7 +216,6 @@ public final class DefaultPersister implements Persister {
}
draftHandler.updateDrafts(transaction, mgr);
PUB.debug("publish - complete for [{}]", desc.name());
return livePublish;
}
@@ -330,9 +294,7 @@ public final class DefaultPersister implements Persister {
* Fetch the destination beans that will be published to.
*/
void fetchDestinationBeans(List<T> sourceBeans, boolean asDraft) {
List<Object> ids = getBeanIds(desc, sourceBeans);
Query<T> destQuery = server.find(desc.type()).where().idIn(ids).query();
if (asDraft) {
destQuery.asDraft();
@@ -376,7 +338,6 @@ public final class DefaultPersister implements Persister {
@Override
public int merge(BeanDescriptor<?> desc, EntityBean bean, MergeOptions options, SpiTransaction transaction) {
MergeHandler merge = new MergeHandler(server, desc, bean, options, transaction);
List<EntityBean> deleteBeans = merge.merge();
if (!deleteBeans.isEmpty()) {
@@ -385,13 +346,11 @@ public final class DefaultPersister implements Persister {
delete(deleteBean, transaction, options.isDeletePermanent());
}
}
// cascade save as normal with forceUpdate flags set
PersistRequestBean<?> request = createRequestRecurse(bean, transaction, null, Flags.MERGE);
request.checkBatchEscalationOnCascade();
saveRecurse(request);
request.flushBatchOnCascade();
// lambda expects a return
return 0;
}
@@ -443,7 +402,6 @@ public final class DefaultPersister implements Persister {
*/
@Override
public void insert(EntityBean bean, Transaction t) {
PersistRequestBean<?> req = createRequest(bean, t, PersistRequest.Type.INSERT);
if (req.isSkipReference()) {
// skip insert on reference bean
@@ -465,7 +423,6 @@ public final class DefaultPersister implements Persister {
}
void saveRecurse(EntityBean bean, Transaction t, Object parentBean, int flags) {
// determine insert or update taking into account stateless updates
saveRecurse(createRequestRecurse(bean, t, parentBean, flags));
}
@@ -493,7 +450,6 @@ public final class DefaultPersister implements Persister {
* Insert the bean.
*/
private void insert(PersistRequestBean<?> request) {
if (request.isRegisteredBean()) {
// skip as already inserted/updated in this request (recursive cascading)
return;
@@ -520,7 +476,6 @@ public final class DefaultPersister implements Persister {
* Update the bean.
*/
private void update(PersistRequestBean<?> request) {
if (request.isRegisteredBean()) {
// skip as already inserted/updated in this request (recursive cascading)
return;
@@ -531,21 +486,16 @@ public final class DefaultPersister implements Persister {
// save associated One beans recursively first
saveAssocOne(request);
}
if (request.isDirty()) {
request.executeOrQueue();
} else if (log.isDebugEnabled()) {
log.debug("Update skipped as bean is unchanged: {}", request.bean());
}
if (request.isPersistCascade()) {
// save all the beans in assocMany's after
saveAssocMany(request);
}
request.completeUpdate();
} finally {
request.unRegisterBean();
}
@@ -557,7 +507,6 @@ public final class DefaultPersister implements Persister {
*/
@Override
public int delete(EntityBean bean, Transaction t, boolean permanent) {
Type deleteType = permanent ? Type.DELETE_PERMANENT : Type.DELETE;
PersistRequestBean<EntityBean> originalRequest = createDeleteRequest(bean, t, deleteType);
if (originalRequest.isHardDeleteDraft()) {
@@ -601,7 +550,6 @@ public final class DefaultPersister implements Persister {
}
req.commitTransIfRequired();
req.flushBatchOnCascade();
return rows;
} catch (RuntimeException ex) {
@@ -631,23 +579,19 @@ public final class DefaultPersister implements Persister {
*/
@Override
public int deleteMany(Class<?> beanType, Collection<?> ids, Transaction transaction, boolean permanent) {
if (ids == null || ids.isEmpty()) {
return 0;
}
BeanDescriptor<?> descriptor = beanDescriptorManager.descriptor(beanType);
DeleteMode deleteMode = (permanent || !descriptor.isSoftDelete()) ? DeleteMode.HARD : DeleteMode.SOFT;
if (descriptor.isMultiTenant()) {
return deleteAsBeans(ids, transaction, deleteMode, descriptor);
}
ArrayList<Object> idList = new ArrayList<>(ids.size());
for (Object id : ids) {
// convert to appropriate type if required
idList.add(descriptor.convertId(id));
}
return delete(descriptor, null, idList, transaction, deleteMode);
}
@@ -698,7 +642,6 @@ public final class DefaultPersister implements Persister {
* Delete by Id or a List of Id's.
*/
private int delete(BeanDescriptor<?> descriptor, Object id, List<Object> idList, Transaction transaction, DeleteMode deleteMode) {
SpiTransaction t = (SpiTransaction) transaction;
if (t.isPersistCascade()) {
BeanPropertyAssocOne<?>[] propImportDelete = descriptor.propertiesOneImportedDelete();
@@ -818,7 +761,6 @@ public final class DefaultPersister implements Persister {
}
private void notifyDeleteById(BeanDescriptor<?> descriptor, Object id, List<Object> idList, Transaction transaction) {
BeanPersistController controller = descriptor.persistController();
if (controller != null) {
DeleteIdRequest request = new DeleteIdRequest(server, transaction, descriptor.type(), id);
@@ -838,7 +780,6 @@ public final class DefaultPersister implements Persister {
* the delete cascades to them (foreign keys).
*/
private Query<?> deleteRequiresQuery(BeanDescriptor<?> desc, BeanPropertyAssocOne<?>[] propImportDelete, DeleteMode deleteMode) {
Query<?> q = server.createQuery(desc.type());
StringBuilder sb = new StringBuilder(30);
for (BeanPropertyAssocOne<?> aPropImportDelete : propImportDelete) {
@@ -860,9 +801,7 @@ public final class DefaultPersister implements Persister {
* </p>
*/
private int delete(PersistRequestBean<?> request) {
DeleteUnloadedForeignKeys unloadedForeignKeys = null;
if (request.isPersistCascade()) {
// delete children first ... register the
// bean to handle bi-directional cascading
@@ -879,16 +818,13 @@ public final class DefaultPersister implements Persister {
int count = request.executeOrQueue();
request.removeFromPersistenceContext();
if (request.isPersistCascade()) {
deleteAssocOne(request);
if (unloadedForeignKeys != null) {
unloadedForeignKeys.deleteCascade();
}
}
request.complete();
// return true if using JDBC batch (as we can't tell until the batch is flushed)
return count;
}
@@ -901,11 +837,9 @@ public final class DefaultPersister implements Persister {
* </p>
*/
private void saveAssocMany(PersistRequestBean<?> request) {
EntityBean parentBean = request.entityBean();
BeanDescriptor<?> desc = request.descriptor();
SpiTransaction t = request.transaction();
EntityBean orphanForRemoval = request.importedOrphanForRemoval();
if (orphanForRemoval != null) {
delete(orphanForRemoval, request.transaction(), true);
@@ -972,7 +906,6 @@ public final class DefaultPersister implements Persister {
* </p>
*/
private void deleteAssocMany(PersistRequestBean<?> request) {
SpiTransaction t = request.transaction();
t.depth(-1);
@@ -1014,7 +947,6 @@ public final class DefaultPersister implements Persister {
deleteManyIntersection(parentBean, many, t, request.isPublish(), false);
}
} else {
if (ModifyListenMode.REMOVALS == many.modifyListenMode()) {
// PrivateOwned ...
// if soft delete then check target also supports soft delete
@@ -1023,7 +955,6 @@ public final class DefaultPersister implements Persister {
if (details instanceof BeanCollection<?>) {
Set<?> modifyRemovals = ((BeanCollection<?>) details).getModifyRemovals();
if (modifyRemovals != null && !modifyRemovals.isEmpty()) {
// delete the orphans that have been removed from the collection
for (Object detail : modifyRemovals) {
EntityBean detailBean = (EntityBean) detail;
@@ -1035,11 +966,9 @@ public final class DefaultPersister implements Persister {
}
}
}
deleteManyDetails(t, desc, parentBean, many, null, deleteMode);
}
}
// restore the depth
t.depth(+1);
}
@@ -1054,7 +983,6 @@ public final class DefaultPersister implements Persister {
*/
void deleteManyDetails(SpiTransaction t, BeanDescriptor<?> desc, EntityBean parentBean,
BeanPropertyAssocMany<?> many, List<Object> excludeDetailIds, DeleteMode deleteMode) {
if (many.cascadeInfo().isDelete()) {
// cascade delete the beans in the collection
BeanDescriptor<?> targetDesc = many.targetDescriptor();
@@ -1083,7 +1011,6 @@ public final class DefaultPersister implements Persister {
* Will use delete by object if the child entity has manyToMany relationships.
*/
private void deleteChildrenById(SpiTransaction t, BeanDescriptor<?> targetDesc, List<Object> childIds, DeleteMode deleteMode) {
if (!targetDesc.isDeleteByBulk()) {
// convert into a list of reference objects and perform delete by object
List<Object> refList = new ArrayList<>(childIds.size());
@@ -1091,7 +1018,6 @@ public final class DefaultPersister implements Persister {
refList.add(targetDesc.createReference(id, null));
}
deleteList(refList, t, deleteMode, true);
} else {
// perform delete by statement if possible
delete(targetDesc, null, childIds, t, deleteMode);
@@ -1102,16 +1028,13 @@ public final class DefaultPersister implements Persister {
* Save any associated one beans.
*/
private void saveAssocOne(PersistRequestBean<?> request) {
BeanDescriptor<?> desc = request.descriptor();
// imported ones with save cascade
for (BeanPropertyAssocOne<?> prop : desc.propertiesOneImportedSave()) {
// check for partial objects
if (prop.isOrphanRemoval() && request.isDirtyProperty(prop)) {
request.setImportedOrphanForRemoval(prop);
}
if (request.isLoadedProperty(prop)) {
EntityBean detailBean = prop.getValueAsEntityBean(request.entityBean());
if (detailBean != null
@@ -1125,7 +1048,6 @@ public final class DefaultPersister implements Persister {
}
}
}
for (BeanPropertyAssocOne<?> prop : desc.propertiesOneExportedSave()) {
if (prop.isOrphanRemoval() && request.isDirtyProperty(prop)) {
deleteOrphan(request, prop);
@@ -1145,9 +1067,7 @@ public final class DefaultPersister implements Persister {
* loaded but required for Delete cascade.
*/
private DeleteUnloadedForeignKeys getDeleteUnloadedForeignKeys(PersistRequestBean<?> request) {
DeleteUnloadedForeignKeys fkeys = null;
for (BeanPropertyAssocOne<?> one : request.descriptor().propertiesOneImportedDelete()) {
if (!request.isLoadedProperty(one)) {
// we have cascade Delete on a partially populated bean and
@@ -1158,7 +1078,6 @@ public final class DefaultPersister implements Persister {
fkeys.add(one);
}
}
return fkeys;
}
@@ -1166,9 +1085,7 @@ public final class DefaultPersister implements Persister {
* Delete any associated one beans.
*/
private void deleteAssocOne(PersistRequestBean<?> request) {
DeleteMode deleteMode = request.deleteMode();
for (BeanPropertyAssocOne<?> prop : request.descriptor().propertiesOneImportedDelete()) {
if (deleteMode.isHard() || prop.isTargetSoftDelete()) {
if (request.isLoadedProperty(prop)) {
@@ -1196,7 +1113,7 @@ public final class DefaultPersister implements Persister {
* Create the Persist Request Object additionally specifying the publish status.
*/
private <T> PersistRequestBean<T> createRequestInternal(T bean, Transaction t, PersistRequest.Type type) {
BeanManager<T> mgr = getBeanManager(bean);
BeanManager<T> mgr = beanManager(bean.getClass());
return createRequest(bean, t, null, mgr, type, Flags.ZERO);
}
@@ -1206,7 +1123,7 @@ public final class DefaultPersister implements Persister {
* This call determines the PersistRequest.Type based on bean state and the insert flag (root persist type).
*/
private <T> PersistRequestBean<T> createRequestRecurse(T bean, Transaction t, Object parentBean, int flags) {
BeanManager<T> mgr = getBeanManager(bean);
BeanManager<T> mgr = beanManager(bean.getClass());
BeanDescriptor<T> desc = mgr.getBeanDescriptor();
EntityBean entityBean = (EntityBean) bean;
PersistRequest.Type type;
@@ -1225,7 +1142,7 @@ public final class DefaultPersister implements Persister {
* Create the Persist Request Object that wraps all the objects used to
* perform an insert, update or delete.
*/
@SuppressWarnings({"unchecked"})
@SuppressWarnings({"unchecked", "rawtypes"})
private <T> PersistRequestBean<T> createRequest(T bean, Transaction t, Object parentBean, BeanManager<?> mgr,
PersistRequest.Type type, int flags) {
// no delete requests come here
@@ -1242,7 +1159,7 @@ public final class DefaultPersister implements Persister {
@SuppressWarnings({"unchecked"})
private <T> PersistRequestBean<T> createDeleteRequest(Object bean, Transaction t, PersistRequest.Type type, int flags) {
BeanManager<T> mgr = getBeanManager(bean);
BeanManager<T> mgr = beanManager(bean.getClass());
if (type == Type.DELETE_PERMANENT) {
type = Type.DELETE;
} else if (type == Type.DELETE && mgr.getBeanDescriptor().isSoftDelete()) {
@@ -1256,9 +1173,8 @@ public final class DefaultPersister implements Persister {
}
private String errNotRegistered(Class<?> beanClass) {
String msg = "The type [" + beanClass + "] is not a registered entity?";
msg += " If you don't explicitly list the entity classes to use Ebean will search for them in the classpath.";
return msg;
return "The type [" + beanClass + "] is not a registered entity?"
+ " If you don't explicitly list the entity classes to use Ebean will search for them in the classpath.";
}
/**
@@ -1269,10 +1185,10 @@ public final class DefaultPersister implements Persister {
* </p>
*/
@SuppressWarnings("unchecked")
private <T> BeanManager<T> getBeanManager(Object bean) {
BeanManager<T> mgr = (BeanManager<T>) beanDescriptorManager.beanManager(bean.getClass());
private <T> BeanManager<T> beanManager(Class<?> cls) {
BeanManager<T> mgr = (BeanManager<T>)beanDescriptorManager.beanManager(cls);
if (mgr == null) {
throw new PersistenceException(errNotRegistered(bean.getClass()));
throw new PersistenceException(errNotRegistered(cls));
}
return mgr;
}
@@ -416,7 +416,6 @@ public final class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfi
} else {
// nextBean set to previously read currentBean
nextBean = currentBean;
request.persistenceContextAdd(nextBean);
// check the current row we have just moved to
if (checkForDifferentBean()) {
return true;
@@ -26,7 +26,6 @@ final class CQueryIteratorSimple<T> implements QueryIterator<T> {
public boolean hasNext() {
boolean ret = false;
try {
request.flushPersistenceContextOnIterate();
ret = cquery.hasNext();
return ret;
} catch (SQLException e) {
@@ -35,8 +35,6 @@ final class CQueryIteratorWithBuffer<T> implements QueryIterator<T> {
try {
if (buffer.isEmpty() && moreToLoad) {
// load buffer
request.flushPersistenceContextOnIterate();
int i = -1;
while (moreToLoad && ++i < bufferSize) {
if (cquery.hasNext()) {
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.query;
import io.avaje.lang.NonNullApi;
import io.ebean.FetchConfig;
import io.ebean.FetchGroup;
import io.ebean.FetchGroupBuilder;
@@ -9,14 +10,12 @@ import io.ebeaninternal.server.querydefn.SpiFetchGroup;
/**
* Default implementation of the FetchGroupBuilder.
*/
@NonNullApi
final class DFetchGroupBuilder<T> implements FetchGroupBuilder<T> {
private static final FetchConfig DEFAULT_FETCH = FetchConfig.ofDefault();
private static final FetchConfig FETCH_CACHE = FetchConfig.ofCache();
private static final FetchConfig FETCH_QUERY = FetchConfig.ofQuery();
private static final FetchConfig FETCH_LAZY = FetchConfig.ofLazy();
private final OrmQueryDetail detail;
@@ -38,22 +37,22 @@ final class DFetchGroupBuilder<T> implements FetchGroupBuilder<T> {
}
@Override
public FetchGroupBuilder<T> fetch(String path, FetchGroup nestedGroup) {
public FetchGroupBuilder<T> fetch(String path, FetchGroup<?> nestedGroup) {
return fetchNested(path, nestedGroup, DEFAULT_FETCH);
}
@Override
public FetchGroupBuilder<T> fetchQuery(String path, FetchGroup nestedGroup) {
public FetchGroupBuilder<T> fetchQuery(String path, FetchGroup<?> nestedGroup) {
return fetchNested(path, nestedGroup, FETCH_QUERY);
}
@Override
public FetchGroupBuilder<T> fetchLazy(String path, FetchGroup nestedGroup) {
public FetchGroupBuilder<T> fetchLazy(String path, FetchGroup<?> nestedGroup) {
return fetchNested(path, nestedGroup, FETCH_LAZY);
}
private FetchGroupBuilder<T> fetchNested(String path, FetchGroup nestedGroup, FetchConfig fetchConfig) {
OrmQueryDetail nestedDetail = ((SpiFetchGroup) nestedGroup).underlying();
private FetchGroupBuilder<T> fetchNested(String path, FetchGroup<?> nestedGroup, FetchConfig fetchConfig) {
OrmQueryDetail nestedDetail = ((SpiFetchGroup<?>) nestedGroup).underlying();
detail.addNested(path, nestedDetail, fetchConfig);
return this;
}
@@ -1,5 +1,7 @@
package io.ebeaninternal.server.query;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.CacheMode;
import io.ebean.CountDistinctOrder;
import io.ebean.Database;
@@ -29,8 +31,6 @@ import io.ebeaninternal.api.SpiQueryFetch;
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
import io.ebeaninternal.server.querydefn.SpiFetchGroup;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.List;
@@ -44,6 +44,7 @@ import java.util.stream.Stream;
/**
* Implementation of FetchGroup query for use to create FetchGroup via query beans.
*/
@NonNullApi
final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQueryFetch {
private static final FetchConfig FETCH_CACHE = FetchConfig.ofCache();
@@ -65,6 +66,7 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
return this;
}
@SuppressWarnings("rawtypes")
@Override
public Query<T> select(FetchGroup fetchGroup) {
this.detail = ((SpiFetchGroup) fetchGroup).detail();
@@ -117,7 +119,7 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
}
@Override
public Query<T> fetch(String property, String columns, FetchConfig config) {
public Query<T> fetch(String property, @Nullable String columns, @Nullable FetchConfig config) {
detail.fetch(property, columns, config);
return this;
}
@@ -234,25 +236,21 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public <A> List<A> findIds() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public QueryIterator<T> findIterate() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public Stream<T> findStream() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public Stream<T> findLargeStream() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
@@ -273,25 +271,21 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public List<T> findList() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public Set<T> findSet() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public <K> Map<K, T> findMap() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public <A> List<A> findSingleAttributeList() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
@@ -318,19 +312,16 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public Optional<T> findOneOrEmpty() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public List<Version<T>> findVersions() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end) {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
@@ -361,25 +352,21 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public FutureRowCount<T> findFutureCount() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public FutureIds<T> findFutureIds() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public FutureList<T> findFutureList() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public PagedList<T> findPagedList() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
@@ -268,9 +268,16 @@ class SqlTreeNodeBean implements SqlTreeNode {
contextBean = localBean;
} else {
// bean already exists in persistenceContext
if (isLoadContextBeanNeeded(queryMode, contextBean)) {
// refresh it anyway (lazy loading for example)
if (queryMode.isLoadContextBean()) {
// if explicitly set loadContextBean to true, then reload
localBean = contextBean;
} else if (!contextBean._ebean_getIntercept().isFullyLoadedBean()) {
// reload if contextBean is partial object
localBean = contextBean;
// and switch to lazyLoad query mode in order not to overwrite
// existing properties in SqlBeanLoad::load
queryMode = Mode.LAZYLOAD_BEAN;
} else {
// ignore the DB data...
localBean = null;
@@ -683,14 +690,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
return "SqlTreeNodeBean: " + desc;
}
private boolean isLoadContextBeanNeeded(Mode queryMode, EntityBean contextBean) {
// if explicitly set loadContextBean to true, then reload
if (queryMode.isLoadContextBean()) {
return true;
}
// reload if contextBean is partial object
return !contextBean._ebean_getIntercept().isFullyLoadedBean();
}
@Override
public boolean hasMany() {
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.querydefn;
import io.avaje.lang.NonNullApi;
import io.ebean.DtoQuery;
import io.ebean.ProfileLocation;
import io.ebean.QueryIterator;
@@ -12,6 +13,7 @@ import io.ebeaninternal.server.dto.DtoBeanDescriptor;
import io.ebeaninternal.server.dto.DtoMappingRequest;
import io.ebeaninternal.server.dto.DtoQueryPlan;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
@@ -21,6 +23,7 @@ import java.util.stream.Stream;
/**
* Default implementation of DtoQuery.
*/
@NonNullApi
public final class DefaultDtoQuery<T> extends AbstractQuery implements SpiDtoQuery<T> {
private final SpiEbeanServer server;
@@ -114,6 +117,7 @@ public final class DefaultDtoQuery<T> extends AbstractQuery implements SpiDtoQue
return server.findDtoList(this);
}
@Nullable
@Override
public T findOne() {
return server.findDtoOne(this);
@@ -206,6 +210,7 @@ public final class DefaultDtoQuery<T> extends AbstractQuery implements SpiDtoQue
return label;
}
@Nullable
@Override
public String getPlanLabel() {
if (label != null) {
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.querydefn;
import io.avaje.lang.NonNullApi;
import io.ebean.*;
import io.ebean.OrderBy.Property;
import io.ebean.bean.CallOrigin;
@@ -30,6 +31,7 @@ import java.util.stream.Stream;
/**
* Default implementation of an Object Relational query.
*/
@NonNullApi
public final class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
private static final String DEFAULT_QUERY_NAME = "default";
@@ -1,5 +1,7 @@
package io.ebeaninternal.server.querydefn;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.RowConsumer;
import io.ebean.RowMapper;
import io.ebean.SqlQuery;
@@ -17,6 +19,7 @@ import java.util.function.Predicate;
/**
* Default implementation of SQuery - SQL Query.
*/
@NonNullApi
public final class DefaultRelationalQuery extends AbstractQuery implements SpiSqlQuery {
private static final long serialVersionUID = -1098305779779591068L;
@@ -263,6 +266,7 @@ public final class DefaultRelationalQuery extends AbstractQuery implements SpiSq
this.mapper = mapper;
}
@Nullable
@Override
public T findOne() {
return mapperFindOne(mapper);
@@ -45,7 +45,7 @@ public final class DJsonBeanReader<T> implements JsonBeanReader<T> {
}
@Override
public JsonBeanReader<T> forJson(JsonParser moreJson, boolean resetContext) {
return new DJsonBeanReader<>(desc, readJson.forJson(moreJson, resetContext));
public JsonBeanReader<T> forJson(JsonParser moreJson) {
return new DJsonBeanReader<>(desc, readJson.forJson(moreJson));
}
}
@@ -50,22 +50,14 @@ public final class ReadJson implements SpiJsonReader {
/**
* Construct when transferring load context, persistence context, object mapper etc to a new ReadJson instance.
*/
private ReadJson(JsonParser moreJson, ReadJson source, boolean resetContext) {
private ReadJson(JsonParser moreJson, ReadJson source) {
this.parser = moreJson;
this.rootDesc = source.rootDesc;
this.pathStack = source.pathStack;
this.visitorMap = source.visitorMap;
this.objectMapper = source.objectMapper;
if (resetContext) {
this.persistenceContext = new DefaultPersistenceContext();
this.loadContext = source.loadContext;
if (loadContext != null) {
loadContext.resetPersistenceContext(persistenceContext);
}
} else {
this.persistenceContext = source.persistenceContext;
this.loadContext = source.loadContext;
}
this.persistenceContext = source.persistenceContext;
this.loadContext = source.loadContext;
}
private LoadContext initLoadContext(BeanDescriptor<?> desc, JsonReadOptions readOptions) {
@@ -96,8 +88,8 @@ public final class ReadJson implements SpiJsonReader {
* Return a new instance of ReadJson using the existing context but with a new JsonParser.
*/
@Override
public SpiJsonReader forJson(JsonParser moreJson, boolean resetContext) {
return new ReadJson(moreJson, this, resetContext);
public SpiJsonReader forJson(JsonParser moreJson) {
return new ReadJson(moreJson, this);
}
/**
@@ -1,11 +1,13 @@
package io.ebeaninternal.server.transaction;
import io.ebean.bean.EntityBean;
import io.ebean.bean.PersistenceContext;
import io.ebeaninternal.api.SpiBeanType;
import io.ebeaninternal.api.SpiBeanTypeManager;
import io.ebeaninternal.api.SpiPersistenceContext;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
@@ -25,14 +27,16 @@ import java.util.concurrent.locks.ReentrantLock;
*/
public final class DefaultPersistenceContext implements SpiPersistenceContext {
/**
* Map used hold caches. One cache per bean type.
*/
private final HashMap<Class<?>, ClassContext> typeCache = new HashMap<>();
private final ReentrantLock lock = new ReentrantLock();
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
private int putCount;
/**
* When we are inside an iterate loop, we will add only WeakReferences. This
* allows the JVM GC to collect beans, which are not referenced elsewhere. In
* normal operation, we will use hard references, to avoid performance impact
*/
private int iterateDepth;
/**
* Create a new PersistenceContext.
@@ -40,60 +44,33 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
public DefaultPersistenceContext() {
}
/**
* Create as a shallow copy with initial or types that have not been added to.
*/
private DefaultPersistenceContext(DefaultPersistenceContext parent, boolean initial) {
for (Map.Entry<Class<?>, ClassContext> entry : parent.typeCache.entrySet()) {
typeCache.put(entry.getKey(), entry.getValue().copy(initial));
}
}
/**
* Return the initial shallow copy with each ClassContext noting it's initialSize (to detect additions).
*/
@Override
public PersistenceContext forIterate() {
return new DefaultPersistenceContext(this, true);
}
/**
* Return a shallow copy including each ClassContext that has had no additions (still at initialSize).
*/
@Override
public PersistenceContext forIterateReset() {
return new DefaultPersistenceContext(this, false);
}
@Override
public boolean resetLimit() {
public void beginIterate() {
lock.lock();
try {
if (putCount < 100) {
return false;
}
putCount = 0;
for (ClassContext value : typeCache.values()) {
if (value.resetLimit()) {
return true;
}
}
// checking after another 100 puts
return false;
iterateDepth++;
} finally {
lock.unlock();
}
}
@Override
public void endIterate() {
lock.lock();
try {
iterateDepth--;
expungeStaleEntries(); // when leaving the iterator, cleanup.
} finally {
lock.unlock();
}
}
/**
* Set an object into the PersistenceContext.
*/
@Override
public void put(Class<?> rootType, Object id, Object bean) {
lock.lock();
try {
putCount++;
getClassContext(rootType).put(id, bean);
expungeStaleEntries();
classContext(rootType).useReferences(iterateDepth > 0).put(id, bean);
} finally {
lock.unlock();
}
@@ -103,8 +80,8 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
public Object putIfAbsent(Class<?> rootType, Object id, Object bean) {
lock.lock();
try {
putCount++;
return getClassContext(rootType).putIfAbsent(id, bean);
expungeStaleEntries();
return classContext(rootType).useReferences(iterateDepth > 0).putIfAbsent(id, bean);
} finally {
lock.unlock();
}
@@ -117,7 +94,8 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
public Object get(Class<?> rootType, Object id) {
lock.lock();
try {
return getClassContext(rootType).get(id);
expungeStaleEntries();
return classContext(rootType).get(id);
} finally {
lock.unlock();
}
@@ -127,19 +105,18 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
public WithOption getWithOption(Class<?> rootType, Object id) {
lock.lock();
try {
return getClassContext(rootType).getWithOption(id);
expungeStaleEntries();
return classContext(rootType).getWithOption(id);
} finally {
lock.unlock();
}
}
/**
* Return the number of beans of the given type in the persistence context.
*/
@Override
public int size(Class<?> rootType) {
lock.lock();
try {
expungeStaleEntries();
ClassContext classMap = typeCache.get(rootType);
return classMap == null ? 0 : classMap.size();
} finally {
@@ -147,14 +124,12 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
}
}
/**
* Clear the PersistenceContext.
*/
@Override
public void clear() {
lock.lock();
try {
typeCache.clear();
expungeStaleEntries();
} finally {
lock.unlock();
}
@@ -168,6 +143,7 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
if (classMap != null) {
classMap.clear();
}
expungeStaleEntries();
} finally {
lock.unlock();
}
@@ -181,6 +157,7 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
if (classMap != null && id != null) {
classMap.deleted(id);
}
expungeStaleEntries();
} finally {
lock.unlock();
}
@@ -194,6 +171,7 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
if (classMap != null && id != null) {
classMap.remove(id);
}
expungeStaleEntries();
} finally {
lock.unlock();
}
@@ -203,6 +181,7 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
public List<Object> dirtyBeans(SpiBeanTypeManager manager) {
lock.lock();
try {
expungeStaleEntries();
List<Object> list = new ArrayList<>();
for (ClassContext classContext : typeCache.values()) {
classContext.dirtyBeans(manager, list);
@@ -213,80 +192,68 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
}
}
/**
* When there is a queue, poll it to remove stale entries from the map. Note:
* This is always done AFTER <code>useReferences</code> was called with
* <code>true</code>. Polling an empty queue has no performance impact.
*/
private void expungeStaleEntries() {
Reference<?> ref;
while ((ref = queue.poll()) != null) {
((BeanRef) ref).expunge();
}
}
@Override
public String toString() {
lock.lock();
try {
expungeStaleEntries();
return typeCache.toString();
} finally {
lock.unlock();
}
}
private ClassContext getClassContext(Class<?> rootType) {
return typeCache.computeIfAbsent(rootType, k -> new ClassContext(rootType));
private ClassContext classContext(Class<?> rootType) {
return typeCache.computeIfAbsent(rootType, k -> new ClassContext(k, queue));
}
private static class ClassContext {
private final Map<Object, Object> map = new HashMap<>();
private final Class<?> rootType;
private final ReferenceQueue<Object> queue;
private Set<Object> deleteSet;
private int initialSize;
private ClassContext parent;
private boolean useReferences;
private int weakCount;
private ClassContext(Class<?> rootType) {
private ClassContext(Class<?> rootType, ReferenceQueue<Object> queue) {
this.rootType = rootType;
this.queue = queue;
}
/**
* Create as a shallow copy.
* When called with "true", initialize referenceQueue and store BeanRefs instead
* of real object references.
*/
private ClassContext(ClassContext source, boolean initial) {
this.rootType = source.rootType;
if (initial || source.isTransfer()) {
parent = source.transferParent();
initialSize = parent.size();
if (source.deleteSet != null) {
deleteSet = new HashSet<>(source.deleteSet);
}
}
}
/**
* True if this should be transferred to a new iterator persistence context.
*/
private boolean isTransfer() {
// map not added to and has some original/parent beans
return map.isEmpty() && initialSize > 0;
}
private ClassContext transferParent() {
return (parent != null) ? parent : this;
}
/**
* Return a shallow copy if initial copy or it has not grown (still at initialSize).
*/
private ClassContext copy(boolean initial) {
return new ClassContext(this, initial);
}
/**
* Return true if grown above the reset limit size of 1000.
*/
private boolean resetLimit() {
return map.size() > 1000;
private ClassContext useReferences(boolean useReferences) {
this.useReferences = useReferences;
return this;
}
@Override
public String toString() {
return "size:" + map.size();
return "size:" + map.size() + " (" + weakCount + " weak)";
}
private Object get(Object id) {
Object bean = (parent == null) ? null : parent.get(id);
return bean != null ? bean : map.get(id);
Object ret = map.get(id);
if (ret instanceof BeanRef) {
return ((BeanRef) ret).get();
} else {
return ret;
}
}
private WithOption getWithOption(Object id) {
@@ -304,24 +271,39 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
return existingValue;
}
// put the new value and return null indicating the put was successful
map.put(id, bean);
put(id, bean);
return null;
}
private void put(Object id, Object b) {
map.put(id, b);
private void put(Object id, Object bean) {
Object existing;
if (useReferences) {
weakCount++;
existing = map.put(id, new BeanRef(this, id, bean, queue));
} else {
existing = map.put(id, bean);
}
if (existing instanceof BeanRef) {
// when a BeanRef is replaced, its expunge() must NOT remove an entry
((BeanRef) existing).setReplaced();
weakCount--;
}
}
private int size() {
return map.size() + initialSize;
return map.size();
}
private void clear() {
map.clear();
weakCount = 0;
}
private void remove(Object id) {
map.remove(id);
Object ret = map.remove(id);
if (ret instanceof BeanRef) {
weakCount--;
}
}
private void deleted(Object id) {
@@ -329,7 +311,7 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
deleteSet = new HashSet<>();
}
deleteSet.add(id);
map.remove(id);
remove(id);
}
/**
@@ -338,6 +320,10 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
void dirtyBeans(SpiBeanTypeManager manager, List<Object> list) {
final SpiBeanType beanType = manager.beanType(rootType);
for (Object value : map.values()) {
if (value instanceof BeanRef) {
value = ((BeanRef) value).get();
if (value == null) continue;
}
EntityBean bean = (EntityBean) value;
if (bean._ebean_getIntercept().isDirty() || beanType.isToManyDirty(bean)) {
list.add(value);
@@ -346,4 +332,27 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
}
}
private static class BeanRef extends WeakReference<Object> {
private final ClassContext classContext;
private final Object key;
private boolean replaced;
private BeanRef(ClassContext classContext, Object key, Object referent, ReferenceQueue<? super Object> q) {
super(referent, q);
this.classContext = classContext;
this.key = key;
}
private void setReplaced() {
replaced = true;
}
private void expunge() {
if (!replaced) {
classContext.remove(key);
}
}
}
}
@@ -60,7 +60,6 @@ public final class BindParamsParser {
* </p>
*/
private String parseSql() {
if (params.isSameBindHash()) {
String preparedSql = params.getPreparedSql();
if (preparedSql != null && !preparedSql.isEmpty()) {
@@ -68,114 +67,121 @@ public final class BindParamsParser {
return preparedSql;
}
}
String preparedSql = prepareSql();
params.setPreparedSql(preparedSql);
params.updateHash();
return preparedSql;
}
String preparedSql;
if (params.requiresNamedParamsPrepare()) {
private String prepareSql() {
if (!params.requiresNamedParamsPrepare()) {
return sql;
} else {
// convert named parameters into ordered list
OrderedList orderedList = params.createOrderedList();
parseNamedParams(orderedList);
preparedSql = orderedList.getPreparedSql();
} else {
preparedSql = sql;
return orderedList.getPreparedSql();
}
params.setPreparedSql(preparedSql);
return preparedSql;
}
/**
* Named parameters need to be parsed and replaced with ?.
*/
private void parseNamedParams(OrderedList orderedList) {
parseNamedParams(0, orderedList);
}
private void parseNamedParams(int startPos, OrderedList orderedList) {
if (sql == null) {
throw new PersistenceException("query does not contain any named bind parameters?");
}
if (startPos > sql.length()) {
return;
}
// search for quotes and named params... in order...
// search for quotes and named params in order
int beginQuotePos = sql.indexOf(quote, startPos);
int nameParamStart = findNameStart(sql, startPos);
if (beginQuotePos > 0 && beginQuotePos < nameParamStart) {
// the quote precedes the named parameter...
// find and add up to the end quote
int endQuotePos = sql.indexOf(quote, beginQuotePos + 1);
String sub = sql.substring(startPos, endQuotePos + 1);
orderedList.appendSql(sub);
// start again after the end quote
parseNamedParams(endQuotePos + 1, orderedList);
addNamedParam(startPos, orderedList, beginQuotePos);
} else {
if (nameParamStart < 0) {
// no more params, add the rest
String sub = sql.substring(startPos, sql.length());
orderedList.appendSql(sub);
orderedList.appendSql(sql.substring(startPos));
} else {
// find the end of the parameter name
int endOfParam = nameParamStart + 1;
do {
char c = sql.charAt(endOfParam);
if (c != '_' && !Character.isLetterOrDigit(c)) {
break;
}
endOfParam++;
} while (endOfParam < sql.length());
int endOfParam = findEndOfParam(nameParamStart);
// add the named parameter value to bindList
String paramName = sql.substring(nameParamStart + 1, endOfParam);
Param param = extractNamedParam(paramName);
Param param;
if (paramName.startsWith(ENCRYPTKEY_PREFIX)) {
param = addEncryptKeyParam(paramName);
} else {
param = params.getParameter(paramName);
}
if (param == null) {
String msg = "Bind value is not set or null for [" + paramName + "] in [" + sql + "]";
throw new PersistenceException(msg);
}
String sub = sql.substring(startPos, nameParamStart);
orderedList.appendSql(sub);
// check if inValue is a Collection type...
orderedList.appendSql(sql.substring(startPos, nameParamStart));
Object inValue = param.getInValue();
if (inValue instanceof Collection<?>) {
// Chop up Collection parameter into a number
// of individual parameters and add each one individually
Collection<?> collection = (Collection<?>) inValue;
int c = 0;
for (Object elVal : collection) {
if (++c > 1) {
orderedList.appendSql(",");
}
orderedList.appendSql("?");
BindParams.Param elParam = new BindParams.Param();
elParam.setInValue(elVal);
orderedList.add(elParam);
}
addCollectionParams(orderedList, param, (Collection<?>) inValue);
} else {
// its a normal scalar value parameter...
orderedList.add(param);
orderedList.appendSql("?");
addScalarParam(orderedList, param);
}
// continue on after the end of the parameter
parseNamedParams(endOfParam, orderedList);
}
}
}
private void addScalarParam(OrderedList orderedList, Param param) {
orderedList.add(param);
orderedList.appendSql("?");
}
private Param extractNamedParam(String paramName) {
Param param;
if (paramName.startsWith(ENCRYPTKEY_PREFIX)) {
param = addEncryptKeyParam(paramName);
} else {
param = params.getParameter(paramName);
}
if (param == null) {
throw new PersistenceException("Bind value is not set or null for [" + paramName + "] in [" + sql + "]");
}
return param;
}
private int findEndOfParam(int nameParamStart) {
int endOfParam = nameParamStart + 1;
do {
char c = sql.charAt(endOfParam);
if (c != '_' && !Character.isLetterOrDigit(c)) {
break;
}
endOfParam++;
} while (endOfParam < sql.length());
return endOfParam;
}
private void addNamedParam(int startPos, OrderedList orderedList, int beginQuotePos) {
// the quote precedes the named parameter...
// find and add up to the end quote
int endQuotePos = sql.indexOf(quote, beginQuotePos + 1);
String sub = sql.substring(startPos, endQuotePos + 1);
orderedList.appendSql(sub);
// start again after the end quote
parseNamedParams(endQuotePos + 1, orderedList);
}
private void addCollectionParams(OrderedList orderedList, Param param, Collection<?> inValue) {
// Chop up Collection parameter into a number of individual parameters
Collection<?> collection = inValue;
for (int c = 0; c < collection.size(); c++) {
if (c > 0) {
orderedList.appendSql(",");
}
orderedList.appendSql("?");
}
orderedList.add(param);
}
/**
* Find the next named parameter start position (based on colon).
*/
@@ -200,15 +206,11 @@ public final class BindParamsParser {
* Add an encryption key bind parameter.
*/
private Param addEncryptKeyParam(String keyNamedParam) {
int pos = keyNamedParam.indexOf(ENCRYPTKEY_GAP, ENCRYPTKEY_PREFIX_LEN);
String tableName = keyNamedParam.substring(ENCRYPTKEY_PREFIX_LEN, pos);
String columnName = keyNamedParam.substring(pos + ENCRYPTKEY_GAP_LEN);
EncryptKey key = beanDescriptor.encryptKey(tableName, columnName);
String strKey = key.getStringValue();
return params.setEncryptionKey(keyNamedParam, strKey);
}
@@ -1,5 +1,6 @@
package io.ebeanservice.docstore.none;
import io.avaje.lang.NonNullApi;
import io.ebean.DocStoreQueueEntry;
import io.ebean.DocumentStore;
import io.ebean.PagedList;
@@ -16,6 +17,7 @@ import java.util.function.Predicate;
/**
* DocumentStore that barfs it is used.
*/
@NonNullApi
public final class NoneDocStore implements DocumentStore {
public static IllegalStateException implementationNotInClassPath() {
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.0</version>
<version>12.13.0</version>
</parent>
<name>ebean ddl generation</name>
@@ -28,14 +28,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>provided</scope>
</dependency>
@@ -243,11 +243,11 @@ public class ModelBuildContext {
*/
public FkeyBuilder addForeignKey(BeanDescriptor<?> desc, TableJoin tableJoin, boolean direction) {
String baseTable = ctx.normaliseTable(desc.getBaseTable());
String baseTable = ctx.normaliseTable(desc.baseTable());
String fkName = ctx.foreignKeyConstraintName(tableName, baseTable, count.incrementAndGet());
String fkIndex = ctx.foreignKeyIndexName(tableName, baseTable, count.get());
MCompoundForeignKey foreignKey = new MCompoundForeignKey(fkName, desc.getBaseTable(), fkIndex);
MCompoundForeignKey foreignKey = new MCompoundForeignKey(fkName, desc.baseTable(), fkIndex);
for (TableJoinColumn column : tableJoin.columns()) {
String localCol = direction ? column.getForeignDbColumn() : column.getLocalDbColumn();
@@ -203,10 +203,10 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
if (columns.length == 1) {
if (p.hasForeignKeyConstraint() && !importedProperty.descriptor().suppressForeignKey()) {
// single references column (put it on the column)
String refTable = importedProperty.descriptor().getBaseTable();
String refTable = importedProperty.descriptor().baseTable();
if (refTable == null) {
// odd case where an EmbeddedId only has 1 property
refTable = p.targetDescriptor().getBaseTable();
refTable = p.targetDescriptor().baseTable();
}
col.setReferences(refTable + "." + refColumn);
col.setForeignKeyName(foreignKeyConstraintName(col.getName()));
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.0</version>
<version>12.13.0</version>
</parent>
<name>ebean external mapping api</name>
+5 -5
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.0</version>
<version>12.13.0</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -14,7 +14,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-parent-12.12.0</tag>
<tag>ebean-parent-12.13.0</tag>
</scm>
<name>ebean external mapping xml</name>
@@ -33,7 +33,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
@@ -59,14 +59,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>test</scope>
</dependency>
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.0</version>
<version>12.13.0</version>
</parent>
<name>ebean postgis</name>
@@ -23,7 +23,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>provided</scope>
</dependency>
@@ -44,7 +44,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.8</version>
<version>42.2.24</version>
<scope>provided</scope>
</dependency>
@@ -74,7 +74,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>test</scope>
</dependency>
+7 -16
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.0</version>
<version>12.13.0</version>
</parent>
<name>ebean querybean</name>
@@ -17,7 +17,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>provided</scope>
</dependency>
@@ -27,9 +27,8 @@
-->
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-jsr305</artifactId>
<version>1.1</version>
<scope>provided</scope>
<artifactId>avaje-lang</artifactId>
<version>1.0</version>
</dependency>
<dependency>
@@ -57,21 +56,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>test</scope>
</dependency>
@@ -93,14 +92,6 @@
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
--add-opens io.ebean.querybean/org.querytest=io.ebean.core
</argLine>
</configuration>
</plugin>
<!-- Enhancement -->
<plugin>
<groupId>io.repaint.maven</groupId>
@@ -1,24 +1,8 @@
package io.ebean.typequery;
import io.ebean.CacheMode;
import io.ebean.DB;
import io.ebean.Database;
import io.ebean.DtoQuery;
import io.ebean.ExpressionList;
import io.ebean.FetchConfig;
import io.ebean.FetchGroup;
import io.ebean.FutureIds;
import io.ebean.FutureList;
import io.ebean.FutureRowCount;
import io.ebean.PagedList;
import io.ebean.PersistenceContextScope;
import io.ebean.ProfileLocation;
import io.ebean.Query;
import io.ebean.QueryIterator;
import io.ebean.RawSql;
import io.ebean.Transaction;
import io.ebean.UpdateQuery;
import io.ebean.Version;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.*;
import io.ebean.search.MultiMatch;
import io.ebean.search.TextCommonTerms;
import io.ebean.search.TextQueryString;
@@ -28,16 +12,9 @@ import io.ebean.text.PathProperties;
import io.ebeaninternal.api.SpiQueryFetch;
import io.ebeaninternal.server.util.ArrayStack;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -81,6 +58,7 @@ import java.util.stream.Stream;
* @param <T> the entity bean type (normal entity bean type e.g. Customer)
* @param <R> the specific root query bean type (e.g. QCustomer)
*/
@NonNullApi
public abstract class TQRootBean<T, R> {
/**
@@ -177,7 +155,6 @@ public abstract class TQRootBean<T, R> {
* the find methods available on this 'root query bean' instance like findList().
* </p>
*/
@Nonnull
public Query<T> query() {
return query;
}
@@ -1621,7 +1598,6 @@ public abstract class TQRootBean<T, R> {
/**
* Execute the query returning an optional bean.
*/
@Nonnull
public Optional<T> findOneOrEmpty() {
return query.findOneOrEmpty();
}
@@ -1643,7 +1619,6 @@ public abstract class TQRootBean<T, R> {
*
* @see Query#findList()
*/
@Nonnull
public List<T> findList() {
return query.findList();
}
@@ -1667,7 +1642,6 @@ public abstract class TQRootBean<T, R> {
*
* }</pre>
*/
@Nonnull
public Stream<T> findStream() {
return query.findStream();
}
@@ -1697,7 +1671,6 @@ public abstract class TQRootBean<T, R> {
*
* @see Query#findSet()
*/
@Nonnull
public Set<T> findSet() {
return query.findSet();
}
@@ -1710,7 +1683,6 @@ public abstract class TQRootBean<T, R> {
*
* @see Query#findIds()
*/
@Nonnull
public <A> List<A> findIds() {
return query.findIds();
}
@@ -1736,7 +1708,6 @@ public abstract class TQRootBean<T, R> {
*
* @see Query#findMap()
*/
@Nonnull
public <K> Map<K, T> findMap() {
return query.findMap();
}
@@ -1777,7 +1748,6 @@ public abstract class TQRootBean<T, R> {
*
* }</pre>
*/
@Nonnull
public QueryIterator<T> findIterate() {
return query.findIterate();
}
@@ -1798,7 +1768,6 @@ public abstract class TQRootBean<T, R> {
*
* @return the list of values for the selected property
*/
@Nonnull
public <A> List<A> findSingleAttributeList() {
return query.findSingleAttributeList();
}
@@ -1913,7 +1882,6 @@ public abstract class TQRootBean<T, R> {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
public List<Version<T>> findVersions() {
return query.findVersions();
}
@@ -1925,7 +1893,6 @@ public abstract class TQRootBean<T, R> {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
public List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end) {
return query.findVersionsBetween(start, end);
}
@@ -1936,7 +1903,6 @@ public abstract class TQRootBean<T, R> {
* This is the number of 'top level' or 'root level' entities.
* </p>
*/
@Nonnull
public int findCount() {
return query.findCount();
}
@@ -1951,7 +1917,6 @@ public abstract class TQRootBean<T, R> {
*
* @return a Future object for the row count query
*/
@Nonnull
public FutureRowCount<T> findFutureCount() {
return query.findFutureCount();
}
@@ -1966,7 +1931,6 @@ public abstract class TQRootBean<T, R> {
*
* @return a Future object for the list of Id's
*/
@Nonnull
public FutureIds<T> findFutureIds() {
return query.findFutureIds();
}
@@ -1980,7 +1944,6 @@ public abstract class TQRootBean<T, R> {
*
* @return a Future object for the list result of the query
*/
@Nonnull
public FutureList<T> findFutureList() {
return query.findFutureList();
}
@@ -2014,7 +1977,6 @@ public abstract class TQRootBean<T, R> {
*
* @return The PagedList
*/
@Nonnull
public PagedList<T> findPagedList() {
return query.findPagedList();
}
@@ -2047,7 +2009,6 @@ public abstract class TQRootBean<T, R> {
/**
* Return the type of beans being queried.
*/
@Nonnull
public Class<T> getBeanType() {
return query.getBeanType();
}
@@ -2055,7 +2016,6 @@ public abstract class TQRootBean<T, R> {
/**
* Return the expression list that has been built for this query.
*/
@Nonnull
public ExpressionList<T> getExpressionList() {
return query.where();
}
@@ -1,19 +1,9 @@
package org.querytest;
import io.ebean.DB;
import io.ebean.Database;
import io.ebean.PagedList;
import io.ebean.Query;
import io.ebean.QueryIterator;
import io.ebean.Transaction;
import io.ebean.*;
import io.ebean.annotation.Transactional;
import io.ebean.types.Inet;
import org.example.domain.ACat;
import org.example.domain.ADog;
import org.example.domain.Address;
import org.example.domain.Animal;
import org.example.domain.Country;
import org.example.domain.Customer;
import org.example.domain.*;
import org.example.domain.otherpackage.PhoneNumber;
import org.example.domain.otherpackage.ValidEmail;
import org.example.domain.query.QAnimal;
@@ -26,15 +16,7 @@ import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
@@ -155,23 +137,21 @@ public class QCustomerTest {
assertThat(ids).isNotEmpty();
Map<List, Customer> map = new QCustomer()
Map<Long, Customer> map = new QCustomer()
.status.equalTo(Customer.Status.GOOD)
.findMap();
assertThat(map.size()).isEqualTo(ids.size());
QueryIterator<Customer> iterate = new QCustomer()
.status.equalTo(Customer.Status.GOOD)
.findIterate();
try (QueryIterator<Customer> iterate =
new QCustomer()
.status.equalTo(Customer.Status.GOOD)
.findIterate()) {
try {
while (iterate.hasNext()) {
Customer customer = iterate.next();
assertThat(customer.getName()).isNotNull();
}
} finally {
iterate.close();
}
}
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.0</version>
<version>12.13.0</version>
</parent>
<artifactId>ebean-redis</artifactId>
@@ -22,35 +22,35 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>test</scope>
</dependency>
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.0</version>
<version>12.13.0</version>
</parent>
<name>ebean test</name>
@@ -29,14 +29,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
@@ -147,7 +147,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.23</version>
<version>42.2.24</version>
<exclusions>
<exclusion>
<groupId>org.checkerframework</groupId>
@@ -47,7 +47,7 @@ public class JsonBeanReaderTest extends BaseTestCase {
beanReader.read();
JsonParser more = getParser();
JsonBeanReader<Customer> moreReader = beanReader.forJson(more, true);
JsonBeanReader<Customer> moreReader = beanReader.forJson(more);
Customer customer = moreReader.read();
assertThat(customer.getId()).isEqualTo(42);
@@ -19,17 +19,19 @@ public class BindParamsTest {
BindParams.Param param = bindParams.getParameter("ids");
assertEquals(3, param.queryBindCount());
assertFalse(bindParams.isSameBindHash());
bindParams.updateHash();
List<String> ids2 = Arrays.asList("1", "2", "3", "4");
bindParams.setParameter("ids", ids2);
assertEquals(4, param.queryBindCount());
assertFalse(bindParams.isSameBindHash());
bindParams.updateHash();
List<String> ids3 = Arrays.asList("2", "99", "44");
bindParams.setParameter("ids", ids3);
assertEquals(3, param.queryBindCount());
assertFalse(bindParams.isSameBindHash());
bindParams.updateHash();
List<String> ids4 = Arrays.asList("4545", "3499", "3444");
bindParams.setParameter("ids", ids4);
@@ -1,5 +1,6 @@
package io.ebeaninternal.api;
import io.avaje.lang.NonNullApi;
import io.ebean.*;
import io.ebean.annotation.Platform;
import io.ebean.annotation.TxIsolation;
@@ -37,6 +38,7 @@ import java.util.stream.Stream;
/**
* Test double for SpiEbeanServer.
*/
@NonNullApi
public class TDSpiEbeanServer extends TDSpiServer implements SpiEbeanServer {
String name;
@@ -1,5 +1,6 @@
package io.ebeaninternal.api;
import io.avaje.lang.NonNullApi;
import io.ebean.*;
import io.ebean.annotation.Platform;
import io.ebean.annotation.TxIsolation;
@@ -15,7 +16,6 @@ import io.ebean.plugin.SpiServer;
import io.ebean.text.csv.CsvReader;
import io.ebean.text.json.JsonContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
@@ -26,6 +26,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
@NonNullApi
public class TDSpiServer implements SpiServer {
@Override
public void shutdown() {
@@ -267,7 +268,6 @@ public class TDSpiServer implements SpiServer {
return null;
}
@Nonnull
@Override
public <T> T reference(Class<T> beanType, Object id) {
return null;
@@ -413,13 +413,11 @@ public class TDSpiServer implements SpiServer {
return 0;
}
@Nonnull
@Override
public Set<Property> checkUniqueness(Object bean) {
return null;
}
@Nonnull
@Override
public Set<Property> checkUniqueness(Object bean, Transaction transaction) {
return null;
@@ -15,6 +15,7 @@ import io.ebeaninternal.server.transaction.RemoteTransactionEvent;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.Customer;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
@@ -99,8 +100,9 @@ public class BinaryTransactionEventReadWriteTest extends BaseTestCase {
}
class TDEbeanServer extends TDSpiEbeanServer {
@Nonnull
@Override
public BeanDescriptor<?> descriptorById(String descriptorId) {
public BeanDescriptor<?> descriptorById(@Nonnull String descriptorId) {
return customerBeanDescriptor;
}
}
@@ -16,9 +16,10 @@ import java.sql.Timestamp;
import java.util.Map;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
public class TestDiffHelpSimple extends BaseTestCase {
class TestDiffHelpSimple extends BaseTestCase {
long firstTime = System.currentTimeMillis() - 10000;
long secondTime = System.currentTimeMillis();
@@ -26,7 +27,7 @@ public class TestDiffHelpSimple extends BaseTestCase {
Database server;
BeanDescriptor<Order> orderDesc;
public TestDiffHelpSimple() {
TestDiffHelpSimple() {
server = DB.getDefault();
SpiEbeanServer spiServer = (SpiEbeanServer) server;
orderDesc = spiServer.descriptor(Order.class);
@@ -44,9 +45,12 @@ public class TestDiffHelpSimple extends BaseTestCase {
}
@Test
public void testBasicChanges() {
void diffWhenNull_expect_empty() {
assertThat(DB.diff(null, null)).isEmpty();
}
@Test
void testBasicChanges() {
Order order1 = createBaseOrder(server);
Order order2 = new Order();
@@ -70,9 +74,7 @@ public class TestDiffHelpSimple extends BaseTestCase {
}
@Test
public void testBasicChanges_given_flatMode() {
void testBasicChanges_given_flatMode() {
Order order1 = createBaseOrder(server);
Order order2 = new Order();
@@ -98,8 +100,7 @@ public class TestDiffHelpSimple extends BaseTestCase {
}
@Test
public void testIdIgnored() {
void testIdIgnored() {
Order order1 = createBaseOrder(server);
Order order2 = createBaseOrder(server);
order2.setId(14);
@@ -110,8 +111,7 @@ public class TestDiffHelpSimple extends BaseTestCase {
}
@Test
public void testSecondValueNull() {
void testSecondValueNull() {
Order order1 = createBaseOrder(server);
Order order2 = createBaseOrder(server);
@@ -134,10 +134,8 @@ public class TestDiffHelpSimple extends BaseTestCase {
assertNull(shipDatePair.getOldValue());
}
@Test
public void testFirstValueNull() {
void testFirstValueNull() {
Order order1 = createBaseOrder(server);
order1.setShipDate(null);
@@ -157,8 +155,7 @@ public class TestDiffHelpSimple extends BaseTestCase {
}
@Test
public void testBothNull() {
void testBothNull() {
Order order1 = createBaseOrder(server);
order1.setShipDate(null);
@@ -6,16 +6,13 @@ import org.junit.jupiter.api.Test;
import org.tests.model.basic.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class DefaultPersistenceContextTest {
class DefaultPersistenceContextTest {
private final Customer customer42;
private final Car car1;
public DefaultPersistenceContextTest() {
DefaultPersistenceContextTest() {
customer42 = new Customer();
customer42.setId(42);
car1 = new Car();
@@ -37,8 +34,7 @@ public class DefaultPersistenceContextTest {
}
@Test
public void put_get_withInheritance() {
void put_get_withInheritance() {
PersistenceContext pc = pc();
pc.put(root(Vehicle.class), 1, car1);
@@ -47,8 +43,7 @@ public class DefaultPersistenceContextTest {
}
@Test
public void put_get() {
void put_get() {
PersistenceContext pc = pc();
pc.put(Customer.class, customer42.getId(), customer42);
@@ -57,8 +52,7 @@ public class DefaultPersistenceContextTest {
}
@Test
public void putIfAbsent_when_absent() {
void putIfAbsent_when_absent() {
PersistenceContext pc = pc();
Object existing = pc.putIfAbsent(Customer.class, customer42.getId(), customer42);
@@ -66,8 +60,7 @@ public class DefaultPersistenceContextTest {
}
@Test
public void putIfAbsent_when_notAbsent() {
void putIfAbsent_when_notAbsent() {
PersistenceContext pc = pcWith42();
Object existing = pc.putIfAbsent(Customer.class, customer42.getId(), new Customer());
@@ -75,30 +68,28 @@ public class DefaultPersistenceContextTest {
}
@Test
public void get_when_empty() {
void get_when_empty() {
PersistenceContext pc = pc();
Object found = pc.get(Customer.class, 42);
assertThat(found).isNull();
}
@Test
public void get_when_there() {
void get_when_there() {
PersistenceContext pc = pcWith42();
Object found = pc.get(Customer.class, 42);
assertThat(found).isSameAs(customer42);
}
@Test
public void getWithOption_when_empty() {
void getWithOption_when_empty() {
PersistenceContext pc = pc();
PersistenceContext.WithOption withOption = pc.getWithOption(Customer.class, 42);
assertThat(withOption).isNull();
}
@Test
public void getWithOption_when_there() {
void getWithOption_when_there() {
PersistenceContext pc = pcWith42();
PersistenceContext.WithOption withOption = pc.getWithOption(Customer.class, 42);
@@ -106,8 +97,7 @@ public class DefaultPersistenceContextTest {
}
@Test
public void getWithOption_when_deleted() {
void getWithOption_when_deleted() {
PersistenceContext pc = pcWith42();
pc.deleted(Customer.class, 42);
@@ -117,38 +107,33 @@ public class DefaultPersistenceContextTest {
}
@Test
public void size_when_empty() {
void size_when_empty() {
PersistenceContext pc = pc();
assertThat(pc.size(Customer.class)).isEqualTo(0);
}
@Test
public void size_when_some() {
void size_when_some() {
PersistenceContext pc = pcWith42();
assertThat(pc.size(Customer.class)).isEqualTo(1);
}
@Test
public void clear() {
void clear() {
PersistenceContext pc = pcWith42();
pc.clear();
assertThat(pc.size(Customer.class)).isEqualTo(0);
}
@Test
public void clearClass() {
void clearClass() {
PersistenceContext pc = pcWith42();
pc.clear(Customer.class);
assertThat(pc.size(Customer.class)).isEqualTo(0);
}
@Test
public void clearClassAndId() {
void clearClassAndId() {
PersistenceContext pc = pcWith42();
pc.put(Customer.class, 43, new Customer());
@@ -160,24 +145,24 @@ public class DefaultPersistenceContextTest {
}
@Test
public void forIterate() {
void beginIterate() {
final DefaultPersistenceContext pc = pcWith42();
final Object origCustomer42 = pc.get(Customer.class, 42);
// act
final PersistenceContext pcIterate = pc.forIterate();
assertThat(pc).isNotSameAs(pcIterate);
assertThat(pcIterate.size(Customer.class)).isEqualTo(1);
pc.beginIterate();
assertThat(pc.size(Customer.class)).isEqualTo(1);
// assert same instance (bean effectively transferred to iterator persistence context
final Object customer42 = pcIterate.get(Customer.class, 42);
final Object customer42 = pc.get(Customer.class, 42);
assertThat(customer42).isSameAs(origCustomer42);
final PersistenceContext.WithOption option = pcIterate.getWithOption(Customer.class, 42);
final PersistenceContext.WithOption option = pc.getWithOption(Customer.class, 42);
assertThat(option.getBean()).isSameAs(origCustomer42);
pc.endIterate();
}
@Test
public void forIterate_many() {
void beginIterate_many() throws InterruptedException {
DefaultPersistenceContext pc = new DefaultPersistenceContext();
addCustomers(pc, 1, 100);
addContacts(pc, 1, 1010);
@@ -185,50 +170,26 @@ public class DefaultPersistenceContextTest {
assertThat(pc.size(Contact.class)).isEqualTo(1010);
// act
final PersistenceContext pcIterate = pc.forIterate();
assertThat(pcIterate.size(Customer.class)).isEqualTo(100);
assertThat(pcIterate.size(Contact.class)).isEqualTo(1010);
pc.beginIterate();
assertThat(pc.size(Customer.class)).isEqualTo(100);
assertThat(pc.size(Contact.class)).isEqualTo(1010);
addCustomers(pc, 200, 100);
addContacts(pc, 2000, 1010);
assertThat(pc.size(Customer.class)).isEqualTo(200);
assertThat(pc.size(Contact.class)).isEqualTo(2020);
pc.endIterate();
System.gc();
Thread.sleep(50); // give the GC some time
assertThat(pc.size(Customer.class)).isEqualTo(100);
assertThat(pc.size(Contact.class)).isEqualTo(1010);
}
@Test
public void forIterate_resetLimit_forIterateReset() {
DefaultPersistenceContext initialPc = new DefaultPersistenceContext();
addCustomers(initialPc, 1, 100);
addContacts(initialPc, 1, 1010);
final PersistenceContext pcIterate = initialPc.forIterate();
assertFalse(pcIterate.resetLimit());
// added 900 NEW contact beans
addContacts(pcIterate, 2000, 900);
assertThat(pcIterate.size(Contact.class)).isEqualTo(1910);
assertFalse(pcIterate.resetLimit());
// boundary, added 1000 NEW contact beans (still false)
addContacts(pcIterate, 3000, 100);
assertFalse(pcIterate.resetLimit());
addContacts(pcIterate, 4000, 1);
addProducts(pcIterate, 1, 100);
// ACT - over 1000 added beans boundary for contacts so returns true
assertTrue(pcIterate.resetLimit());
assertThat(pcIterate.size(Contact.class)).isEqualTo(2011);
assertThat(pcIterate.size(Customer.class)).isEqualTo(100);
assertThat(pcIterate.size(Product.class)).isEqualTo(100);
// ACT - obtain new PC forIterateReset
PersistenceContext pcReset = pcIterate.forIterateReset();
// keeps original customer beans as no new added beans there
assertThat(pcReset.size(Customer.class)).isEqualTo(100); // customers didn't change
// added beans to contacts and products so those where reset
assertThat(pcReset.size(Contact.class)).isEqualTo(0);
assertThat(pcReset.size(Product.class)).isEqualTo(0);
}
@Test
public void toString_sillyTest() {
void toString_sillyTest() {
DefaultPersistenceContext pc = pcWith42();
assertThat(pc.toString()).contains("org.tests.model.basic.Customer");
}
@@ -248,12 +209,4 @@ public class DefaultPersistenceContextTest {
pc.put(Contact.class, i, bean);
}
}
private void addProducts(PersistenceContext pc, int start, int loop) {
for (int i = start; i < start + loop; i++) {
Product bean = new Product();
bean.setId(i);
pc.put(Product.class, i, bean);
}
}
}
@@ -2,37 +2,52 @@ package org.tests.basic;
import io.ebean.BaseTestCase;
import io.ebean.DB;
import io.ebean.Transaction;
import io.ebeaninternal.api.SpiPersistenceContext;
import io.ebeaninternal.api.SpiTransaction;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.ContactNote;
import org.tests.model.basic.Customer;
import org.tests.model.basic.Order;
import org.tests.model.basic.ResetBasicData;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.ArrayList;
import java.util.List;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public class TestPersistenceContext extends BaseTestCase {
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
class TestPersistenceContext extends BaseTestCase {
@Test
public void test() {
void testReload() {
ResetBasicData.reset();
try (Transaction txn = DB.beginTransaction()) {
List<ContactNote> notes = new ArrayList<>();
DB.find(ContactNote.class).findEach(notes::add);
notes.get(0).setTitle("FooBar");
DB.find(ContactNote.class).findList();
assertThat(notes.get(0).getTitle()).isEqualTo("FooBar");
}
}
@Test
void test() {
ResetBasicData.reset();
// implicit transaction with its own
// persistence context
// implicit transaction with its own persistence context
Order oBefore = DB.find(Order.class, 1);
Order order = null;
// start a persistence context
DB.beginTransaction();
Order order;
try {
order = DB.find(Order.class, 1);
// not the same instance ...as a different
// persistence context
assertTrue(order != oBefore);
// not the same instance ...as a different persistence context
assertNotSame(order, oBefore);
// finds an existing bean in the persistence context
// ... so doesn't even execute a query
@@ -40,19 +55,17 @@ public class TestPersistenceContext extends BaseTestCase {
Order o3 = DB.reference(Order.class, 1);
// all the same instance
assertTrue(order == o2);
assertTrue(order == o3);
assertSame(order, o2);
assertSame(order, o3);
} finally {
DB.endTransaction();
}
// implicit transaction with its own
// persistence context
// implicit transaction with its own persistence context
Order oAfter = DB.find(Order.class, 1);
assertTrue(oAfter != oBefore);
assertTrue(oAfter != order);
assertNotSame(oAfter, oBefore);
assertNotSame(oAfter, order);
// start a persistence context
DB.beginTransaction();
@@ -65,17 +78,142 @@ public class TestPersistenceContext extends BaseTestCase {
.setUseCache(false)
.setId(id)
.findOne();
assert customer != null;
System.gc();
Order order2 = DB.find(Order.class, orderId);
assert order2 != null;
Customer customer2 = order2.getCustomer();
assert customer2 != null;
assertEquals(customer.getId(), customer2.getId());
assertTrue(customer == customer2);
assertSame(customer, customer2);
} finally {
DB.endTransaction();
}
}
@Disabled
@Test
void findWithGcTest() {
for (int j = 0; j < 20; j++) {
for (int i = 0; i < 500; i++) {
Customer c = new Customer();
c.setName("Customer #" + i);
DB.save(c);
}
int customerCount = DB.find(Customer.class).findCount();
AtomicInteger count = new AtomicInteger(customerCount);
WeakHashMap<Customer, Integer> customers = new WeakHashMap<>();
DB.find(Customer.class).fetch("orders").findEach(customer -> {
customers.put(customer, customer.getId());
if (count.decrementAndGet() == 0) {
// Trigger garbage collection on last iteration and check if beans disappear from memory
System.gc();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
customers.size(); // expunge stale entries
System.out.println("Total instances: " + customerCount + ", instances left in memory: " + customers.size());
}
});
}
}
@Disabled // run manually
@Test
void testPcScopes_with_weakReferences() throws InterruptedException {
for (int i = 0; i < 5000; i++) {
Customer c = new Customer();
c.setName("Customer #" + i);
DB.save(c);
Order o = new Order();
o.setCustomer(c);
DB.save(o);
}
try (Transaction txn = DB.beginTransaction()) {
List<Customer> first100 = DB.find(Customer.class).where().le("id", 100).findList();
assertEquals(100, first100.size());
for (Customer c : first100) {
c.setSmallnote("one of the first 100");
}
// use lastBean to hold onto a weak reference bean
Customer[] lastBean = new Customer[1];
// findEach switches on use of weak reference in persistence context
DB.find(Customer.class).setLazyLoadBatchSize(1).findEach(customer -> {
if (customer.getId() <= 100) {
assertEquals("one of the first 100", customer.getSmallnote());
// nested finds
DB.find(Order.class).where().eq("customer", customer).findEach(20, consumer -> {
});
} else {
assertNotEquals("one of the first 100", customer.getSmallnote());
}
lastBean[0] = customer;
});
SpiPersistenceContext pc = ((SpiTransaction) txn).getPersistenceContext();
// the first 100 customers using strong references
assertThat(pc.toString()).contains("Customer=size:5000 (4900 weak)");
assertThat(pc.toString()).contains("Order=size:100 (100 weak)");
System.gc();
Thread.sleep(100);
pc.get(Customer.class, 1); // trigger expungeStaleEntries
// pc.get(Order.class, 1);
assertThat(pc.toString()).contains("Customer=size:101 (1 weak)");
assertThat(pc.toString()).contains("Order=size:0 (0 weak)");
first100 = DB.find(Customer.class).where().le("id", 100).findList();
for (Customer c : first100) {
assertEquals("one of the first 100", c.getSmallnote());
}
Customer lastBeanFromDb = DB.find(Customer.class).setId(lastBean[0].getId()).findOne();
assertSame(lastBeanFromDb, lastBean[0]);
// read 200
DB.find(Customer.class).where().le("id", 200).findList();
assertThat(pc.toString()).contains("Customer=size:201 (1 weak)");
lastBean[0] = null; // allow GC on this one
lastBeanFromDb = null;
System.gc();
Thread.sleep(100);
assertThat(pc.toString()).contains("Customer=size:200 (0 weak)");
}
}
@Disabled // run manually
@Test
void testPcScopes_with_findEachFindList() {
for (int i = 0; i < 5000; i++) {
Customer c = new Customer();
c.setName("Customer #" + i);
DB.save(c);
Order o = new Order();
o.setCustomer(c);
DB.save(o);
}
for (int i = 0; i < 1000; i++) {
try (Transaction txn = DB.beginTransaction()) {
List<Customer> customers = new ArrayList<>();
DB.find(Customer.class).select("id").findEach(customers::add);
SpiPersistenceContext pc = ((SpiTransaction) txn).getPersistenceContext();
assertThat(pc.toString()).contains("Customer=size:5000 (5000 weak)");
customers.clear();
customers = DB.find(Customer.class).select("id").findList();
assertThat(pc.toString()).contains("Customer=size:5000"); // We expect ALWAYS 5000 entries in the PC
}
}
}
}
@@ -0,0 +1,70 @@
package org.tests.basic;
import io.ebean.BaseTestCase;
import io.ebean.DB;
import io.ebean.Update;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.Customer;
import org.tests.model.basic.ResetBasicData;
import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Testcase identified a bug when collections are used as bind parameters
*
* @author Roland Praml, FOCONIS AG
*/
public class TestUpdate extends BaseTestCase {
@BeforeEach
public void createCustomers() {
ResetBasicData.reset();
for (int i = 1; i <= 3; i++) {
Customer cust = new Customer();
cust.setName("testUpdate" + i);
DB.save(cust);
}
}
@AfterEach
public void deleteCustomers() {
DB.createUpdate(Customer.class, "delete from customer where name like 'testUpdate%'").execute();
}
@Test
public void testNormal() {
for (int i = 1; i <= 3; i++) {
Update<Customer> update = DB.createUpdate(Customer.class,
"update customer set smallnote = :smallnote where name in (:name)");
update.setParameter("name", Arrays.asList("testUpdate" + i)).setParameter("smallnote", "Note #" + i).execute();
}
Customer cust = DB.find(Customer.class).where().eq("name", "testUpdate3").findOne();
assertThat(cust.getSmallnote()).isEqualTo("Note #3");
}
@Test
public void testReuse() {
Update<Customer> update = DB.createUpdate(Customer.class,
"update customer set smallnote = :smallnote where name in (:name)");
for (int i = 1; i <= 3; i++) {
update.setParameter("name", Arrays.asList("testUpdate" + i)).setParameter("smallnote", "Note #" + i).execute();
}
Customer cust = DB.find(Customer.class).where().eq("name", "testUpdate3").findOne();
assertThat(cust.getSmallnote()).isEqualTo("Note #3");
}
@Test
public void testReuseNoArray() {
Update<Customer> update = DB.createUpdate(Customer.class,
"update customer set smallnote = :smallnote where name = :name");
for (int i = 1; i <= 3; i++) {
update.setParameter("name", "testUpdate" + i).setParameter("smallnote", "Note #" + i).execute();
}
Customer cust = DB.find(Customer.class).where().eq("name", "testUpdate3").findOne();
assertThat(cust.getSmallnote()).isEqualTo("Note #3");
}
}
@@ -10,16 +10,16 @@ import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TestExtraScalarTypes extends BaseTestCase {
class TestExtraScalarTypes extends BaseTestCase {
@Test
public void test() {
void test() {
Locale locale = Locale.getDefault();
Currency currency = Currency.getInstance(locale);
Locale locale = Locale.ENGLISH;
Currency currency = Currency.getInstance(Locale.US);
TimeZone tz = TimeZone.getDefault();
ESomeType e = new ESomeType();
@@ -29,20 +29,20 @@ public class TestExtraScalarTypes extends BaseTestCase {
DB.save(e);
ESomeType e2 = DB.find(ESomeType.class).setAutoTune(false).setId(e.getId()).findOne();
ESomeType e2 = DB.find(ESomeType.class).setId(e.getId()).findOne();
assertNotNull(e2.getCurrency());
assertNotNull(e2.getLocale());
assertNotNull(e2.getTimeZone());
List<ESomeType> list = DB.find(ESomeType.class)
.setAutoTune(false).where()
.where()
.eq("locale", locale)
.eq("timeZone", tz.getID())
.eq("currency", currency)
.findList();
assertTrue(!list.isEmpty());
assertThat(list).isNotEmpty();
}
}
@@ -16,11 +16,24 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
public class TestBeanState extends BaseTestCase {
class TestBeanState extends BaseTestCase {
@Test
public void test() {
void invalid() {
assertThrows(IllegalArgumentException.class, () -> DB.beanState(new Object()));
}
@Test
void loadErrors_when_empty() {
ResetBasicData.reset();
Customer one = DB.find(Customer.class).setMaxRows(1).findOne();
BeanState beanState = DB.beanState(one);
assertThat(beanState.loadErrors()).isEmpty();
}
@Test
void test() {
ResetBasicData.reset();
List<Customer> custs = DB.find(Customer.class).findList();
@@ -55,8 +68,7 @@ public class TestBeanState extends BaseTestCase {
}
@Test
public void setDisableLazyLoad_expect_lazyLoadingDisabled() {
void setDisableLazyLoad_expect_lazyLoadingDisabled() {
ResetBasicData.reset();
List<Customer> custs = DB.find(Customer.class).order("id").findList();
@@ -73,8 +85,7 @@ public class TestBeanState extends BaseTestCase {
}
@Test
public void getChangedProps_when_setManyProperty() {
void changedProps_when_setManyProperty() {
ResetBasicData.reset();
Customer customer = DB.find(Customer.class).order("id").setMaxRows(1).findOne();
@@ -87,8 +98,7 @@ public class TestBeanState extends BaseTestCase {
}
@Test
public void getChangedProps_when_setManyProperty_onNewBean() {
void changedProps_when_setManyProperty_onNewBean() {
Customer customer = new Customer();
BeanState beanState = DB.beanState(customer);
@@ -107,7 +117,7 @@ public class TestBeanState extends BaseTestCase {
}
@Test
public void readOnly_when_setManyProperty() {
void readOnly_when_setManyProperty() {
Customer customer = new Customer();
customer.setContacts(new ArrayList<>());
@@ -120,7 +130,7 @@ public class TestBeanState extends BaseTestCase {
}
@Test
public void readOnly_when_setProperty() {
void readOnly_when_setProperty() {
Customer customer = new Customer();
customer.setName("a");
@@ -0,0 +1,29 @@
package org.tests.o2m;
import io.ebean.BaseTestCase;
import io.ebean.common.BeanList;
import org.junit.jupiter.api.Test;
import org.tests.model.json.EBasicJsonMap;
import org.tests.o2m.lazy.OmlBaz;
import org.tests.o2m.lazy.OmlFoo;
import static org.assertj.core.api.Assertions.assertThat;
class TestOneToManyEnhancement extends BaseTestCase {
@Test
void test_when_constructorAddsEntry() {
OmlFoo foo = new OmlFoo(new OmlBaz());
assertThat(foo.getBazList()).isInstanceOf(BeanList.class);
assertThat(foo.getBazList()).isNotEmpty();
}
@Test
void test_commonCase() {
EBasicJsonMap bean = new EBasicJsonMap();
assertThat(bean.getDetails()).isInstanceOf(BeanList.class);
assertThat(bean.getDetails()).isEmpty();
}
}
@@ -15,7 +15,12 @@ public class OmlFoo {
private OmlBar bar;
@OneToMany(mappedBy = "foo", cascade = CascadeType.ALL)
private List<OmlBaz> bazList = new ArrayList<OmlBaz>();
private List<OmlBaz> bazList = new ArrayList<>();
public OmlFoo(OmlBaz baz) {
bazList.add(baz);
baz.setFoo(this);
}
public Long getId() {
return id;
@@ -13,11 +13,9 @@ public class TestLazyManyViaPath extends BaseTestCase {
@Test
public void test() {
OmlBar bar = new OmlBar();
List<OmlFoo> fooList = new ArrayList<>();
fooList.add(createNewFooWithBar(bar));
bar.setFooList(fooList);
DB.save(bar);
@@ -30,26 +28,24 @@ public class TestLazyManyViaPath extends BaseTestCase {
// This works
List<OmlFoo> foosList = fooFromDb.getBar().getFooList();
assertThat(fooList.size()).isEqualTo(1);
assertThat(foosList).hasSize(1);
assertThat(fooList).hasSize(1);
OmlBaz bazFromDb = DB
.find(OmlBaz.class)
.where()
.eq("id", bar.getFooList().get(0).getBazList().get(0).getId())
.findOne();
assert bazFromDb != null;
// This does not work and gives the exception
List<OmlFoo> foosList1 = bazFromDb.getFoo().getBar().getFooList();
assertThat(foosList1.size()).isEqualTo(1);
}
private static OmlFoo createNewFooWithBar(OmlBar bar) {
OmlFoo foo = new OmlFoo();
OmlFoo foo = new OmlFoo(new OmlBaz());
foo.setBar(bar);
OmlBaz baz = new OmlBaz();
baz.setFoo(foo);
foo.getBazList().add(baz);
return foo;
}
@@ -12,17 +12,16 @@ import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestOneToManyCorrectGrouping extends BaseTestCase {
class TestOneToManyCorrectGrouping extends BaseTestCase {
public static final int EXPECTED_ITERATIONS = 2;
static final int EXPECTED_ITERATIONS = 4;
@Test
public void test() {
void test() {
ResetBasicData.reset();
Query<Customer> customerQuery = DB.find(Customer.class)
.fetch("orders")
.where().le("id", 2)
.where().le("id", 4)
.query();
final AtomicInteger count = new AtomicInteger();
@@ -1,6 +1,5 @@
package org.tests.query.cache;
import javax.annotation.Nonnull;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@@ -17,7 +16,6 @@ public class Contract {
private List<Position> positions;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "container", fetch = FetchType.LAZY)
@Nonnull
private List<AclContainerRelation> aclEntries = new ArrayList<>();
public Long getId() {
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.0</version>
<version>12.13.0</version>
</parent>
<name>ebean composite</name>
@@ -22,20 +22,20 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
<!-- Technically optional but most expected to use query beans -->
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.12.0</version>
<version>12.13.0</version>
</dependency>
</dependencies>
@@ -0,0 +1,7 @@
package io.ebean.assembly;
/**
* Nothing interesting here - look at ebean-api.
*/
public class Assembly {
}

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