mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
153
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbf46bb0ec | ||
|
|
6aa4337b27 | ||
|
|
99d7a4e4b4 | ||
|
|
b7da2cbd97 | ||
|
|
b4ae721998 | ||
|
|
3bb4126e26 | ||
|
|
de439e7695 | ||
|
|
e5ec72df5c | ||
|
|
98a89156bf | ||
|
|
dc65475dbb | ||
|
|
cc64ff5f10 | ||
|
|
ab87174e5b | ||
|
|
a6fdc42934 | ||
|
|
4c16b85e85 | ||
|
|
9e3d6c6a08 | ||
|
|
d567872813 | ||
|
|
7069d3f600 | ||
|
|
b2f8b7c711 | ||
|
|
4092ea307e | ||
|
|
01f64ef9f9 | ||
|
|
f1a48b182e | ||
|
|
8ac5467856 | ||
|
|
758f84f573 | ||
|
|
2073fefc92 | ||
|
|
5b98d8d9c2 | ||
|
|
8e59e72983 | ||
|
|
b56d68dac7 | ||
|
|
e0c3a92b60 | ||
|
|
213562fcf1 | ||
|
|
d3a09b93c0 | ||
|
|
536ea57369 | ||
|
|
ac1dd4cbab | ||
|
|
bc33e05906 | ||
|
|
8ecc407cb0 | ||
|
|
2672dff512 | ||
|
|
74d907bbce | ||
|
|
53aacabce7 | ||
|
|
ab9cdd8f5b | ||
|
|
b3d439ed11 | ||
|
|
d57657c209 | ||
|
|
dd080c5933 | ||
|
|
0be98d7989 | ||
|
|
fca54dbbe3 | ||
|
|
7ec5fe6a85 | ||
|
|
9ea5505214 | ||
|
|
75d3b566a7 | ||
|
|
e38059f52c | ||
|
|
72331aa945 | ||
|
|
e497c54f82 | ||
|
|
b44091ff3a | ||
|
|
2ab889f889 | ||
|
|
23541e661e | ||
|
|
6778e37652 | ||
|
|
5eac31283d | ||
|
|
38016773d4 | ||
|
|
ad80eb267f | ||
|
|
449e0832e0 | ||
|
|
f28f5c9a01 | ||
|
|
9dd28d8879 | ||
|
|
b47eec99a5 | ||
|
|
99bb55efa0 | ||
|
|
4408eb618a | ||
|
|
9ccd1b1b27 | ||
|
|
0c1657fef5 | ||
|
|
ee393c6485 | ||
|
|
7f68b9d846 | ||
|
|
2035a3344e | ||
|
|
ade36582a0 | ||
|
|
a4b8be61e3 | ||
|
|
b7feb62ecd | ||
|
|
7e48f7c8eb | ||
|
|
501f8111fe | ||
|
|
d8f4503d98 | ||
|
|
0d83978c58 | ||
|
|
69e56be459 | ||
|
|
35a721039d | ||
|
|
98b4ac5029 | ||
|
|
fe874c946d | ||
|
|
53386e9bf4 | ||
|
|
5435055f5c | ||
|
|
583e10f5c6 | ||
|
|
5393d709a3 | ||
|
|
fc1c9392aa | ||
|
|
6b2c48d4f6 | ||
|
|
400ae3cf4b | ||
|
|
f22a322104 | ||
|
|
e98ff952bf | ||
|
|
573e1b553c | ||
|
|
a674d0d696 | ||
|
|
5393161c16 | ||
|
|
1bdc6d8f7f | ||
|
|
e9081a176f | ||
|
|
3e7db2887f | ||
|
|
fcf14ac222 | ||
|
|
55324653a5 | ||
|
|
a132f09b03 | ||
|
|
48eac84930 | ||
|
|
948619a125 | ||
|
|
0cd0741f18 | ||
|
|
01a3455ecb | ||
|
|
610f7db1cb | ||
|
|
373ef6d1eb | ||
|
|
f1b1cee2fd | ||
|
|
a73e4f23ff | ||
|
|
9a5d3498c1 | ||
|
|
0b24d635ad | ||
|
|
b623e19dae | ||
|
|
7389a8b344 | ||
|
|
d68f477e8e | ||
|
|
dbe273bb56 | ||
|
|
1a4377da29 | ||
|
|
c3cdecaa60 | ||
|
|
9d706056c6 | ||
|
|
cb0100f02a | ||
|
|
9c6dd0989a | ||
|
|
a23a179bbf | ||
|
|
365b7c4600 | ||
|
|
ed2455f460 | ||
|
|
046033627a | ||
|
|
786444a6b9 | ||
|
|
9ab26cfb9d | ||
|
|
aa1e3ea1bc | ||
|
|
c66875449b | ||
|
|
f6c4024ae5 | ||
|
|
2c8cc793ab | ||
|
|
66454d2e61 | ||
|
|
e7b13cf2d9 | ||
|
|
04cd520719 | ||
|
|
838af0478e | ||
|
|
9064e96b90 | ||
|
|
8e91268979 | ||
|
|
cc637d56e1 | ||
|
|
9846ebd65d | ||
|
|
b568e2efc7 | ||
|
|
20fc74219a | ||
|
|
92a4bfb38e | ||
|
|
5c34b0daa5 | ||
|
|
f4ea674d60 | ||
|
|
21f43dc395 | ||
|
|
5082ce4280 | ||
|
|
ed061fb3b1 | ||
|
|
247e96f5db | ||
|
|
ce60eac583 | ||
|
|
c34fcdf7b7 | ||
|
|
dcfada0b52 | ||
|
|
fb3fd439bb | ||
|
|
6226672d27 | ||
|
|
bf72794a4c | ||
|
|
30a00cb092 | ||
|
|
0bfb6895ad | ||
|
|
29345c823e | ||
|
|
e71cb4f2ff | ||
|
|
c044bc52f7 |
+1
-4
@@ -1,6 +1,4 @@
|
||||
*.autofetch
|
||||
*create-all.sql
|
||||
*drop-all.sql
|
||||
*.orig
|
||||
.classpath
|
||||
.project
|
||||
@@ -12,7 +10,6 @@ ebean-autotune.xml
|
||||
ebean-profiling*.xml
|
||||
/db
|
||||
/mydb.db
|
||||
!src/test/ddl-review/*.sql
|
||||
profiling/
|
||||
|
||||
# Intellij project files
|
||||
@@ -20,4 +17,4 @@ profiling/
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
*uuid.state
|
||||
*uuid.state
|
||||
|
||||
+1
-1
@@ -293,6 +293,6 @@ ebean.tenant.schemaProvider
|
||||
ebean.updateAllPropertiesInBatch
|
||||
ebean.updateChangesOnly
|
||||
ebean.updatesDeleteMissingChildren
|
||||
ebean.useJavaxValidationNotNull
|
||||
ebean.useValidationNotNull
|
||||
ebean.useJtaTransactionManager
|
||||
|
||||
|
||||
+5
-18
@@ -4,18 +4,13 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean api</name>
|
||||
<description>ebean api</description>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
|
||||
<properties>
|
||||
<jackson-core.version>2.11.3</jackson-core.version>
|
||||
<jackson-databind.version>2.11.3</jackson-databind.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!--
|
||||
@@ -32,7 +27,7 @@
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>avaje-config</artifactId>
|
||||
<version>1.2</version>
|
||||
<version>1.3</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
@@ -55,7 +50,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>6.13</version>
|
||||
<version>6.15</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -74,7 +69,7 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson-core.version}</version>
|
||||
<version>${jackson.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
@@ -82,7 +77,7 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson-databind.version}</version>
|
||||
<version>${jackson.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
@@ -102,14 +97,6 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope to read validation annotations Size etc -->
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
<version>1.1.0.Final</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
|
||||
@@ -1,33 +1,43 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Background thread pool service for executing of tasks asynchronously.
|
||||
* Background executor service for executing of tasks asynchronously.
|
||||
* <p>
|
||||
* This service is used internally by Ebean for executing background tasks such
|
||||
* as the {@link Query#findFutureList()} and also for executing background tasks
|
||||
* periodically.
|
||||
* </p>
|
||||
* This service can be used to execute tasks in the background.
|
||||
* <p>
|
||||
* This service has been made available so you can use it for your application
|
||||
* code if you want. It can be useful for some server caching implementations
|
||||
* (background population and trimming of the cache etc).
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
* This service is managed by Ebean and will perform a clean shutdown
|
||||
* waiting for background tasks to complete with a default 30 second
|
||||
* timeout. Shutdown occurs prior to DataSource shutdown.
|
||||
* <p>
|
||||
* This also propagates MDC context from the current thread to the
|
||||
* background task if defined.
|
||||
*/
|
||||
public interface BackgroundExecutor {
|
||||
|
||||
/**
|
||||
* Execute a task in the background.
|
||||
* Execute a callable task in the background returning the Future.
|
||||
*/
|
||||
void execute(Runnable r);
|
||||
<T> Future<T> submit(Callable<T> task);
|
||||
|
||||
/**
|
||||
* Execute a runnable task in the background returning the Future.
|
||||
*/
|
||||
Future<?> submit(Runnable task);
|
||||
|
||||
/**
|
||||
* Execute a task in the background. Effectively the same as
|
||||
* {@link BackgroundExecutor#submit(Runnable)} but returns void.
|
||||
*/
|
||||
void execute(Runnable task);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to scheduleWithFixedDelay().
|
||||
* Execute a task periodically with a fixed delay between each execution.
|
||||
* <p>
|
||||
* For example, execute a runnable every minute.
|
||||
@@ -36,27 +46,64 @@ public interface BackgroundExecutor {
|
||||
* That is, this method has the same behaviour characteristics as
|
||||
* {@link ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit)}
|
||||
*/
|
||||
void executePeriodically(Runnable r, long delay, TimeUnit unit);
|
||||
@Deprecated
|
||||
void executePeriodically(Runnable task, long delay, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to scheduleWithFixedDelay().
|
||||
* Execute a task periodically additionally with an initial delay different from delay.
|
||||
*/
|
||||
void executePeriodically(Runnable r, long initialDelay, long delay, TimeUnit unit);
|
||||
@Deprecated
|
||||
void executePeriodically(Runnable task, long initialDelay, long delay, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Execute a task periodically with a given delay.
|
||||
*
|
||||
* @param task the task to execute
|
||||
* @param initialDelay the time to delay first execution
|
||||
* @param delay the delay between the termination of one
|
||||
* execution and the commencement of the next
|
||||
* @param unit the time unit of the initialDelay and delay parameters
|
||||
* @return a ScheduledFuture representing pending completion of
|
||||
* the series of repeated tasks. The future's {@link
|
||||
* Future#get() get()} method will never return normally,
|
||||
* and will throw an exception upon task cancellation or
|
||||
* abnormal termination of a task execution.
|
||||
*/
|
||||
ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Execute a task periodically with a given period.
|
||||
*
|
||||
* <p>If any execution of this task takes longer than its period, then
|
||||
* subsequent executions may start late, but will not concurrently
|
||||
* execute.
|
||||
*
|
||||
* @param task the task to execute
|
||||
* @param initialDelay the time to delay first execution
|
||||
* @param period the period between successive executions
|
||||
* @param unit the time unit of the initialDelay and period parameters
|
||||
* @return a ScheduledFuture representing pending completion of
|
||||
* the series of repeated tasks. The future's {@link
|
||||
* Future#get() get()} method will never return normally,
|
||||
* and will throw an exception upon task cancellation or
|
||||
* abnormal termination of a task execution.
|
||||
*/
|
||||
ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Schedules a Runnable for one-shot action that becomes enabled after the given delay.
|
||||
*
|
||||
* @return a ScheduledFuture representing pending completion of the task and
|
||||
* whose get() method will return null upon completion
|
||||
* whose get() method will return null upon completion
|
||||
*/
|
||||
ScheduledFuture<?> schedule(Runnable r, long delay, TimeUnit unit);
|
||||
ScheduledFuture<?> schedule(Runnable task, long delay, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Schedules a Callable for one-shot action that becomes enabled after the given delay.
|
||||
*
|
||||
* @return a ScheduledFuture that can be used to extract result or cancel
|
||||
*/
|
||||
<V> ScheduledFuture<V> schedule(Callable<V> c, long delay, TimeUnit unit);
|
||||
|
||||
<V> ScheduledFuture<V> schedule(Callable<V> task, long delay, TimeUnit unit);
|
||||
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
public class DatabaseFactory {
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock(false);
|
||||
private static final ReentrantLock lock = new ReentrantLock();
|
||||
private static SpiContainer container;
|
||||
|
||||
static {
|
||||
|
||||
@@ -27,7 +27,7 @@ final class DbContext {
|
||||
|
||||
private final HashMap<String, Database> syncMap = new HashMap<>();
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* The 'default' Database.
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
class DbPrimary {
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock(false);
|
||||
private static final ReentrantLock lock = new ReentrantLock();
|
||||
private static String defaultServerName;
|
||||
private static boolean skip;
|
||||
|
||||
|
||||
@@ -169,6 +169,28 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
UpdateQuery<T> asUpdate();
|
||||
|
||||
/**
|
||||
* Execute the query with the given lock type and WAIT.
|
||||
* <p>
|
||||
* Note that <code>forUpdate()</code> is the same as
|
||||
* <code>withLock(LockType.UPDATE)</code>.
|
||||
* <p>
|
||||
* Provides us with the ability to explicitly use Postgres
|
||||
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
|
||||
*/
|
||||
Query<T> withLock(Query.LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute the query with the given lock type and lock wait.
|
||||
* <p>
|
||||
* Note that <code>forUpdateNoWait()</code> is the same as
|
||||
* <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
|
||||
* <p>
|
||||
* Provides us with the ability to explicitly use Postgres
|
||||
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
|
||||
*/
|
||||
Query<T> withLock(Query.LockType lockType, Query.LockWait lockWait);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause which results in the DB locking the record.
|
||||
*/
|
||||
|
||||
@@ -3,30 +3,13 @@ package io.ebean;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Defines the configuration options for a "query fetch" or a
|
||||
* "lazy loading fetch". This gives you the ability to use multiple smaller
|
||||
* queries to populate an object graph as opposed to a single large query.
|
||||
* <p>
|
||||
* The primary goal is to provide efficient ways of loading complex object
|
||||
* graphs avoiding SQL Cartesian product and issues around populating object
|
||||
* graphs that have multiple *ToMany relationships.
|
||||
* </p>
|
||||
* <p>
|
||||
* It also provides the ability to control the lazy loading queries (batch size,
|
||||
* selected properties and fetches) to avoid N+1 queries etc.
|
||||
* <p>
|
||||
* There can also be cases loading across a single OneToMany where 2 SQL queries
|
||||
* using Ebean FetchConfig.query() can be more efficient than one SQL query.
|
||||
* When the "One" side is wide (lots of columns) and the cardinality difference
|
||||
* is high (a lot of "Many" beans per "One" bean) then this can be more
|
||||
* efficient loaded as 2 SQL queries.
|
||||
* </p>
|
||||
* Defines how a relationship is fetched via either normal SQL join,
|
||||
* a eager secondary query, via lazy loading or via eagerly hitting L2 cache.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
* // Normal fetch join results in a single SQL query
|
||||
* List<Order> list = DB.find(Order.class).fetch("details").findList();
|
||||
*
|
||||
* // Find Orders join details using a single SQL query
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL queries
|
||||
@@ -37,103 +20,13 @@ import java.io.Serializable;
|
||||
* // This will use 2 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* DB.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .fetch("details", FetchConfig.ofQuery())
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using 2 "query joins"
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* DB.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .fetch("customer", new FetchConfig().queryFirst(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
|
||||
* // query 3) find customer where id in (?,?,?,?,?) // first 5 customers
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using "query joins" and partial objects
|
||||
* </p>
|
||||
* <p>
|
||||
*
|
||||
* <pre>{@code
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* DB.find(Order.class)
|
||||
* .select("status, shipDate")
|
||||
* .fetch("details", "quantity, price", new FetchConfig().query())
|
||||
* .fetch("details.product", "sku, name")
|
||||
* .fetch("customer", "name", new FetchConfig().queryFirst(5))
|
||||
* .fetch("customer.contacts")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order (status, shipDate)
|
||||
* // query 2) find orderDetail (quantity, price) fetch product (sku, name) where
|
||||
* // order.id in (?,? ...)
|
||||
* // query 3) find customer (name) fetch contacts (*) fetch shippingAddress (*)
|
||||
* // where id in (?,?,?,?,?)
|
||||
*
|
||||
* // Note: the fetch of "details.product" is automatically included into the
|
||||
* // fetch of "details"
|
||||
* //
|
||||
* // Note: the fetch of "customer.contacts" and "customer.shippingAddress"
|
||||
* // are automatically included in the fetch of "customer"
|
||||
* }</pre>
|
||||
* <p>
|
||||
* You can use query() and lazy together on a single join. The query is executed
|
||||
* immediately and the lazy defines the batch size to use for further lazy
|
||||
* loading (if lazy loading is invoked).
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> list =
|
||||
* DB.find(Order.class)
|
||||
* .fetch("customer", new FetchConfig().query(10).lazy(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find customer where id in (?,?,?,?,?,?,?,?,?,?) // first 10 customers
|
||||
* // .. then if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <p>
|
||||
* Example of controlling the lazy loading query:
|
||||
* </p>
|
||||
* <p>
|
||||
* This gives us the ability to optimise the lazy loading query for a given use
|
||||
* case.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<Order> list = DB.find(Order.class)
|
||||
* .fetch("customer","name", new FetchConfig().lazy(5))
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .where().eq("status",Order.Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order where status = Order.Status.NEW
|
||||
* //
|
||||
* // .. if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @author mario
|
||||
* @author rbygrave
|
||||
@@ -142,66 +35,122 @@ public class FetchConfig implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int lazyBatchSize = -1;
|
||||
private static final int JOIN_MODE = 0;
|
||||
private static final int QUERY_MODE = 1;
|
||||
private static final int LAZY_MODE = 2;
|
||||
private static final int CACHE_MODE = 3;
|
||||
|
||||
private int queryBatchSize = -1;
|
||||
|
||||
private boolean queryAll;
|
||||
|
||||
private boolean cache;
|
||||
private int mode;
|
||||
private int batchSize;
|
||||
private int hashCode;
|
||||
|
||||
/**
|
||||
* Construct the fetch configuration object.
|
||||
*/
|
||||
public FetchConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this path should be lazy loaded using the default batch load
|
||||
* size.
|
||||
*/
|
||||
public FetchConfig lazy() {
|
||||
this.lazyBatchSize = 0;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that this path should be lazy loaded with a specified batch size.
|
||||
* Deprecated - migrate to one of the static factory methods like {@link FetchConfig#ofQuery()}
|
||||
*
|
||||
* @param lazyBatchSize the batch size for lazy loading
|
||||
* Construct using default JOIN mode.
|
||||
*/
|
||||
public FetchConfig lazy(int lazyBatchSize) {
|
||||
this.lazyBatchSize = lazyBatchSize;
|
||||
this.queryAll = false;
|
||||
@Deprecated
|
||||
public FetchConfig() {
|
||||
//this.mode = JOIN_MODE;
|
||||
this.batchSize = 100;
|
||||
this.hashCode = 1000;
|
||||
}
|
||||
|
||||
private FetchConfig(int mode, int batchSize) {
|
||||
this.mode = mode;
|
||||
this.batchSize = batchSize;
|
||||
this.hashCode = mode + 10 * batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to eagerly fetch the relationship using L2 cache.
|
||||
* <p>
|
||||
* Any cache misses will be loaded by secondary query to the database.
|
||||
*/
|
||||
public static FetchConfig ofCache() {
|
||||
return new FetchConfig(CACHE_MODE, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to eagerly fetch the relationship using a secondary query.
|
||||
*/
|
||||
public static FetchConfig ofQuery() {
|
||||
return new FetchConfig(QUERY_MODE, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to eagerly fetch the relationship using a secondary with a given batch size.
|
||||
*/
|
||||
public static FetchConfig ofQuery(int batchSize) {
|
||||
return new FetchConfig(QUERY_MODE, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to lazily load the relationship.
|
||||
*/
|
||||
public static FetchConfig ofLazy() {
|
||||
return new FetchConfig(LAZY_MODE, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to lazily load the relationship specifying the batch size.
|
||||
*/
|
||||
public static FetchConfig ofLazy(int batchSize) {
|
||||
return new FetchConfig(LAZY_MODE, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return FetchConfig to fetch the relationship using SQL join.
|
||||
*/
|
||||
public static FetchConfig ofDefault() {
|
||||
return new FetchConfig(JOIN_MODE, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* We want to migrate away from mutating FetchConfig to a fully immutable FetchConfig.
|
||||
*/
|
||||
private FetchConfig mutate(int mode, int batchSize) {
|
||||
if (batchSize < 1) {
|
||||
throw new IllegalArgumentException("batch size "+batchSize+" must be > 0");
|
||||
}
|
||||
this.mode = mode;
|
||||
this.batchSize = batchSize;
|
||||
this.hashCode = mode + 10 * batchSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to FetchConfig.ofLazy().
|
||||
*/
|
||||
@Deprecated
|
||||
public FetchConfig lazy() {
|
||||
return mutate(LAZY_MODE, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to FetchConfig.ofLazy(batchSize).
|
||||
*/
|
||||
@Deprecated
|
||||
public FetchConfig lazy(int batchSize) {
|
||||
return mutate(LAZY_MODE, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to FetchConfig.ofQuery().
|
||||
*
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
* <p>
|
||||
* This will use the default batch size for separate query which is 100.
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
public FetchConfig query() {
|
||||
this.queryBatchSize = 0;
|
||||
this.queryAll = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly fetch the beans fetching the beans from the L2 bean cache
|
||||
* and using the DB for beans not in the cache.
|
||||
*/
|
||||
public FetchConfig cache() {
|
||||
this.cache = true;
|
||||
this.queryBatchSize = 0;
|
||||
this.queryAll = true;
|
||||
return this;
|
||||
return mutate(QUERY_MODE, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to FetchConfig.ofQuery(batchSize).
|
||||
*
|
||||
* Eagerly fetch the beans in this path as a separate query (rather than as
|
||||
* part of the main query).
|
||||
* <p>
|
||||
@@ -213,16 +162,16 @@ public class FetchConfig implements Serializable {
|
||||
* is also used.
|
||||
* </p>
|
||||
*
|
||||
* @param queryBatchSize the batch size used to load beans on this path
|
||||
* @param batchSize the batch size used to load beans on this path
|
||||
*/
|
||||
public FetchConfig query(int queryBatchSize) {
|
||||
this.queryBatchSize = queryBatchSize;
|
||||
// queryAll true as long as a lazy batch size has not already been set
|
||||
this.queryAll = (lazyBatchSize == -1);
|
||||
return this;
|
||||
@Deprecated
|
||||
public FetchConfig query(int batchSize) {
|
||||
return mutate(QUERY_MODE, batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to FetchConfig.ofQuery(batchSize).
|
||||
*
|
||||
* Eagerly fetch the first batch of beans on this path.
|
||||
* This is similar to {@link #query(int)} but only fetches the first batch.
|
||||
* <p>
|
||||
@@ -230,61 +179,68 @@ public class FetchConfig implements Serializable {
|
||||
* loaded eagerly but instead use lazy loading.
|
||||
* </p>
|
||||
*
|
||||
* @param queryBatchSize the number of parent beans this path is populated for
|
||||
* @param batchSize the number of parent beans this path is populated for
|
||||
*/
|
||||
public FetchConfig queryFirst(int queryBatchSize) {
|
||||
this.queryBatchSize = queryBatchSize;
|
||||
this.queryAll = false;
|
||||
return this;
|
||||
@Deprecated
|
||||
public FetchConfig queryFirst(int batchSize) {
|
||||
return query(batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size for lazy loading.
|
||||
* Deprecated - migrate to FetchConfig.ofCache().
|
||||
*
|
||||
* Eagerly fetch the beans fetching the beans from the L2 bean cache
|
||||
* and using the DB for beans not in the cache.
|
||||
*/
|
||||
public int getLazyBatchSize() {
|
||||
return lazyBatchSize;
|
||||
@Deprecated
|
||||
public FetchConfig cache() {
|
||||
return mutate(CACHE_MODE, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size for separate query load.
|
||||
* Return the batch size for fetching.
|
||||
*/
|
||||
public int getQueryBatchSize() {
|
||||
return queryBatchSize;
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the query fetch should fetch 'all' rather than just the
|
||||
* 'first' batch.
|
||||
*/
|
||||
public boolean isQueryAll() {
|
||||
return queryAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this uses L2 bean cache.
|
||||
* Return true if the fetch should use the L2 cache.
|
||||
*/
|
||||
public boolean isCache() {
|
||||
return cache;
|
||||
return mode == CACHE_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the fetch should be a eager secondary query.
|
||||
*/
|
||||
public boolean isQuery() {
|
||||
return mode == QUERY_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the fetch should be a lazy query.
|
||||
*/
|
||||
public boolean isLazy() {
|
||||
return mode == LAZY_MODE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the fetch should try to use SQL join.
|
||||
*/
|
||||
public boolean isJoin() {
|
||||
return mode == JOIN_MODE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
FetchConfig that = (FetchConfig) o;
|
||||
if (lazyBatchSize != that.lazyBatchSize) return false;
|
||||
if (queryBatchSize != that.queryBatchSize) return false;
|
||||
if (cache != that.cache) return false;
|
||||
return queryAll == that.queryAll;
|
||||
return (hashCode == ((FetchConfig) o).hashCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = lazyBatchSize;
|
||||
result = 92821 * result + queryBatchSize;
|
||||
result = 92821 * result + (queryAll ? 1 : 0);
|
||||
result = 92821 * result + (cache ? 1 : 0);
|
||||
return result;
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-10
@@ -1,11 +1,9 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import java.io.Serializable;
|
||||
package io.ebean;
|
||||
|
||||
/**
|
||||
* Owner object notified when a modification is detected.
|
||||
*/
|
||||
public interface ModifyAwareOwner extends Serializable {
|
||||
public interface ModifyAwareType {
|
||||
|
||||
/**
|
||||
* Return true if the value is considered dirty.
|
||||
@@ -16,11 +14,6 @@ public interface ModifyAwareOwner extends Serializable {
|
||||
/**
|
||||
* Marks the object as modified.
|
||||
*/
|
||||
void markAsModified();
|
||||
|
||||
/**
|
||||
* Reset the dirty state to clean.
|
||||
*/
|
||||
void resetMarkedDirty();
|
||||
void setMarkedDirty(boolean markedDirty);
|
||||
|
||||
}
|
||||
@@ -180,13 +180,44 @@ import java.util.stream.Stream;
|
||||
public interface Query<T> {
|
||||
|
||||
/**
|
||||
* For update mode.
|
||||
* The lock type (strength) to use with query FOR UPDATE row locking.
|
||||
*/
|
||||
enum ForUpdate {
|
||||
enum LockType {
|
||||
/**
|
||||
* The default lock type being either UPDATE or NO_KEY_UPDATE based on
|
||||
* PlatformConfig.forUpdateNoKey configuration (Postgres option).
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/**
|
||||
* FOR UPDATE.
|
||||
*/
|
||||
UPDATE,
|
||||
|
||||
/**
|
||||
* FOR NO KEY UPDATE (Postgres only).
|
||||
*/
|
||||
NO_KEY_UPDATE,
|
||||
|
||||
/**
|
||||
* FOR SHARE (Postgres only).
|
||||
*/
|
||||
SHARE,
|
||||
|
||||
/**
|
||||
* FOR KEY SHARE (Postgres only).
|
||||
*/
|
||||
KEY_SHARE
|
||||
}
|
||||
|
||||
/**
|
||||
* FOR UPDATE wait mode.
|
||||
*/
|
||||
enum LockWait {
|
||||
/**
|
||||
* Standard For update clause.
|
||||
*/
|
||||
BASE,
|
||||
WAIT,
|
||||
|
||||
/**
|
||||
* For update with No Wait option.
|
||||
@@ -483,7 +514,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, fetchProperties, new FetchConfig().query())
|
||||
* fetch(path, fetchProperties, FetchConfig.ofQuery())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -517,7 +548,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, fetchProperties, new FetchConfig().lazy())
|
||||
* fetch(path, fetchProperties, FetchConfig.ofLazy())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -542,7 +573,7 @@ public interface Query<T> {
|
||||
* // fetch customers (their id, name and status)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* .select("name, status")
|
||||
* .fetch("contacts", "firstName,lastName,email", new FetchConfig().lazy(10))
|
||||
* .fetch("contacts", "firstName,lastName,email", FetchConfig.ofLazy(10))
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
@@ -579,7 +610,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, new FetchConfig().query())
|
||||
* fetch(path, FetchConfig.ofQuery())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -608,7 +639,7 @@ public interface Query<T> {
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* fetch(path, new FetchConfig().lazy())
|
||||
* fetch(path, FetchConfig.ofLazy())
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -631,7 +662,7 @@ public interface Query<T> {
|
||||
* // fetch customers (their id, name and status)
|
||||
* List<Customer> customers = DB.find(Customer.class)
|
||||
* // lazy fetch contacts with a batch size of 100
|
||||
* .fetch("contacts", new FetchConfig().lazy(100))
|
||||
* .fetch("contacts", FetchConfig.ofLazy(100))
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
@@ -813,7 +844,7 @@ public interface Query<T> {
|
||||
* <pre>{@code
|
||||
*
|
||||
* DB.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .fetch("contacts", FetchConfig.ofQuery(2))
|
||||
* .where().eq("status", Status.NEW)
|
||||
* .order().asc("id")
|
||||
* .setMaxRows(2000)
|
||||
@@ -1613,8 +1644,32 @@ public interface Query<T> {
|
||||
*/
|
||||
String getGeneratedSql();
|
||||
|
||||
/**
|
||||
* Execute the query with the given lock type and WAIT.
|
||||
* <p>
|
||||
* Note that <code>forUpdate()</code> is the same as
|
||||
* <code>withLock(LockType.UPDATE)</code>.
|
||||
* <p>
|
||||
* Provides us with the ability to explicitly use Postgres
|
||||
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
|
||||
*/
|
||||
Query<T> withLock(LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute the query with the given lock type and lock wait.
|
||||
* <p>
|
||||
* Note that <code>forUpdateNoWait()</code> is the same as
|
||||
* <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
|
||||
* <p>
|
||||
* Provides us with the ability to explicitly use Postgres
|
||||
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
|
||||
*/
|
||||
Query<T> withLock(LockType lockType, LockWait lockWait);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause which results in the DB locking the record.
|
||||
* <p>
|
||||
* The same as <code>withLock(LockType.UPDATE, LockWait.WAIT)</code>.
|
||||
*/
|
||||
Query<T> forUpdate();
|
||||
|
||||
@@ -1622,7 +1677,8 @@ public interface Query<T> {
|
||||
* Execute using "for update" clause with "no wait" option.
|
||||
* <p>
|
||||
* This is typically a Postgres and Oracle only option at this stage.
|
||||
* </p>
|
||||
* <p>
|
||||
* The same as <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
|
||||
*/
|
||||
Query<T> forUpdateNoWait();
|
||||
|
||||
@@ -1630,7 +1686,8 @@ public interface Query<T> {
|
||||
* Execute using "for update" clause with "skip locked" option.
|
||||
* <p>
|
||||
* This is typically a Postgres and Oracle only option at this stage.
|
||||
* </p>
|
||||
* <p>
|
||||
* The same as <code>withLock(LockType.UPDATE, LockWait.SKIPLOCKED)</code>.
|
||||
*/
|
||||
Query<T> forUpdateSkipLocked();
|
||||
|
||||
@@ -1640,9 +1697,14 @@ public interface Query<T> {
|
||||
boolean isForUpdate();
|
||||
|
||||
/**
|
||||
* Return the "for update" mode to use.
|
||||
* Return the "for update" wait mode to use.
|
||||
*/
|
||||
ForUpdate getForUpdateMode();
|
||||
LockWait getForUpdateLockWait();
|
||||
|
||||
/**
|
||||
* Return the lock type (strength) to use with "for update".
|
||||
*/
|
||||
LockType getForUpdateLockType();
|
||||
|
||||
/**
|
||||
* Set root table alias.
|
||||
|
||||
@@ -107,7 +107,7 @@ package io.ebean;
|
||||
*
|
||||
* List<OrderAggregate> orders = DB.find(OrderAggregate.class)
|
||||
* .setRawSql(rawSql)
|
||||
* .fetch("order", "status,orderDate", new FetchConfig().query())
|
||||
* .fetch("order", "status,orderDate", FetchConfig.ofQuery())
|
||||
* .fetch("order.customer", "name")
|
||||
* .where().gt("order.id", 0)
|
||||
* .having().gt("totalAmount", 20)
|
||||
|
||||
@@ -519,11 +519,11 @@ public interface Transaction extends AutoCloseable {
|
||||
void flush() throws PersistenceException;
|
||||
|
||||
/**
|
||||
* This is a synonym for flush() and will be deprecated.
|
||||
* Deprecated - migrate to flush().
|
||||
* <p>
|
||||
* flush() is preferred as it matches the JPA flush() method.
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
void flushBatch() throws PersistenceException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,7 +32,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
private static final int STATE_REFERENCE = 1;
|
||||
private static final int STATE_LOADED = 2;
|
||||
|
||||
private transient final ReentrantLock lock = new ReentrantLock(false);
|
||||
private transient final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private transient NodeUsageCollector nodeUsageCollector;
|
||||
|
||||
@@ -931,10 +931,14 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* OneToMany and ManyToMany only set loaded state.
|
||||
*/
|
||||
public void preSetterMany(boolean interceptField, int propertyIndex, Object oldValue, Object newValue) {
|
||||
if (readOnly) {
|
||||
throw new IllegalStateException("This bean is readOnly");
|
||||
if (state == STATE_NEW) {
|
||||
setLoadedProperty(propertyIndex);
|
||||
} else {
|
||||
if (readOnly) {
|
||||
throw new IllegalStateException("This bean is readOnly");
|
||||
}
|
||||
setChangedProperty(propertyIndex);
|
||||
}
|
||||
setLoadedProperty(propertyIndex);
|
||||
}
|
||||
|
||||
private void setChangedPropertyValue(int propertyIndex, boolean setDirtyState, Object origValue) {
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
public abstract class SingleBeanLoader implements BeanLoader {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
protected final Database database;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
private static final long serialVersionUID = 3365725236140187588L;
|
||||
|
||||
protected final ReentrantLock lock = new ReentrantLock(false);
|
||||
protected final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
protected boolean readOnly;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ public final class CopyOnFirstWriteList<E> extends AbstractList<E> implements Li
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* The underlying List implementation.
|
||||
|
||||
@@ -40,6 +40,13 @@ public class ClassLoadConfig {
|
||||
return isPresent("javax.validation.constraints.NotNull");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if jakarta validation annotations like Size and NotNull are present.
|
||||
*/
|
||||
public boolean isJakartaValidationAnnotationsPresent() {
|
||||
return isPresent("jakarta.validation.constraints.NotNull");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if javax PostConstruct annotation is present (maybe not in java9).
|
||||
* If not we don't support PostConstruct lifecycle events.
|
||||
|
||||
@@ -489,7 +489,7 @@ public class DatabaseConfig {
|
||||
* Should the javax.validation.constraints.NotNull enforce a notNull column in DB.
|
||||
* If set to false, use io.ebean.annotation.NotNull or Column(nullable=true).
|
||||
*/
|
||||
private boolean useJavaxValidationNotNull = true;
|
||||
private boolean useValidationNotNull = true;
|
||||
|
||||
/**
|
||||
* Generally we want to perform L2 cache notification in the background and not impact
|
||||
@@ -2809,7 +2809,7 @@ public class DatabaseConfig {
|
||||
enabledL2Regions = p.get("enabledL2Regions", enabledL2Regions);
|
||||
notifyL2CacheInForeground = p.getBoolean("notifyL2CacheInForeground", notifyL2CacheInForeground);
|
||||
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager);
|
||||
useJavaxValidationNotNull = p.getBoolean("useJavaxValidationNotNull", useJavaxValidationNotNull);
|
||||
useValidationNotNull = p.getBoolean("useValidationNotNull", useValidationNotNull);
|
||||
autoReadOnlyDataSource = p.getBoolean("autoReadOnlyDataSource", autoReadOnlyDataSource);
|
||||
idGeneratorAutomatic = p.getBoolean("idGeneratorAutomatic", idGeneratorAutomatic);
|
||||
|
||||
@@ -3056,20 +3056,21 @@ public class DatabaseConfig {
|
||||
/**
|
||||
* Returns if we use javax.validation.constraints.NotNull
|
||||
*/
|
||||
public boolean isUseJavaxValidationNotNull() {
|
||||
return useJavaxValidationNotNull;
|
||||
public boolean isUseValidationNotNull() {
|
||||
return useValidationNotNull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls if Ebean should ignore <code>&x64;javax.validation.contstraints.NotNull</code>
|
||||
* Controls if Ebean should ignore <code>&x64;javax.validation.contstraints.NotNull</code> or
|
||||
* <code>&x64;jakarta.validation.contstraints.NotNull</code>
|
||||
* with respect to generating a <code>NOT NULL</code> column.
|
||||
* <p>
|
||||
* Normally when Ebean sees javax NotNull annotation it means that column is defined as NOT NULL.
|
||||
* Set this to <code>false</code> and the javax NotNull annotation is effectively ignored (and
|
||||
* we instead use Ebean's own NotNull annotation or JPA Column(nullable=false) annotation.
|
||||
*/
|
||||
public void setUseJavaxValidationNotNull(boolean useJavaxValidationNotNull) {
|
||||
this.useJavaxValidationNotNull = useJavaxValidationNotNull;
|
||||
public void setUseValidationNotNull(boolean useValidationNotNull) {
|
||||
this.useValidationNotNull = useValidationNotNull;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,11 @@ public class PlatformConfig {
|
||||
|
||||
private boolean allQuotedIdentifiers;
|
||||
|
||||
/**
|
||||
* Set this to true for Postgres FOR UPDATE to use NO KEY option.
|
||||
*/
|
||||
private boolean forUpdateNoKey;
|
||||
|
||||
private DbConstraintNaming constraintNaming;
|
||||
|
||||
/**
|
||||
@@ -77,6 +82,7 @@ public class PlatformConfig {
|
||||
* Construct based on given config - typically for DbMigration generation with many platforms.
|
||||
*/
|
||||
public PlatformConfig(PlatformConfig platformConfig) {
|
||||
this.forUpdateNoKey = platformConfig.forUpdateNoKey;
|
||||
this.databaseBooleanFalse = platformConfig.databaseBooleanFalse;
|
||||
this.databaseBooleanTrue = platformConfig.databaseBooleanTrue;
|
||||
this.databaseSequenceBatchSize = platformConfig.databaseSequenceBatchSize;
|
||||
@@ -133,14 +139,26 @@ public class PlatformConfig {
|
||||
this.caseSensitiveCollation = caseSensitiveCollation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Postgres FOR UPDATE should use the NO KEY option.
|
||||
*/
|
||||
public boolean isForUpdateNoKey() {
|
||||
return forUpdateNoKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true such that Postgres FOR UPDATE should use the NO KEY option.
|
||||
*/
|
||||
public void setForUpdateNoKey(boolean forUpdateNoKey) {
|
||||
this.forUpdateNoKey = forUpdateNoKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a value used to represent TRUE in the database.
|
||||
* <p>
|
||||
* This is used for databases that do not support boolean natively.
|
||||
* </p>
|
||||
* <p>
|
||||
* The value returned is either a Integer or a String (e.g. "1", or "T").
|
||||
* </p>
|
||||
*/
|
||||
public String getDatabaseBooleanTrue() {
|
||||
return databaseBooleanTrue;
|
||||
@@ -150,10 +168,8 @@ public class PlatformConfig {
|
||||
* Set the value to represent TRUE in the database.
|
||||
* <p>
|
||||
* This is used for databases that do not support boolean natively.
|
||||
* </p>
|
||||
* <p>
|
||||
* The value set is either a Integer or a String (e.g. "1", or "T").
|
||||
* </p>
|
||||
*/
|
||||
public void setDatabaseBooleanTrue(String databaseBooleanTrue) {
|
||||
this.databaseBooleanTrue = databaseBooleanTrue;
|
||||
@@ -245,7 +261,6 @@ public class PlatformConfig {
|
||||
|
||||
/**
|
||||
* Add a custom type mapping.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set the default mapping for BigDecimal.class/decimal
|
||||
@@ -266,7 +281,6 @@ public class PlatformConfig {
|
||||
|
||||
/**
|
||||
* Add a custom type mapping that applies to all platforms.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set the default mapping for BigDecimal/decimal
|
||||
@@ -294,6 +308,7 @@ public class PlatformConfig {
|
||||
public void loadSettings(PropertiesWrapper p) {
|
||||
|
||||
idType = p.getEnum(IdType.class, "idType", idType);
|
||||
forUpdateNoKey = p.getBoolean("forUpdateNoKey", forUpdateNoKey);
|
||||
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
|
||||
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
|
||||
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
|
||||
@@ -334,7 +349,6 @@ public class PlatformConfig {
|
||||
*/
|
||||
public enum DbUuid {
|
||||
|
||||
|
||||
/**
|
||||
* Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40).
|
||||
*/
|
||||
|
||||
@@ -679,21 +679,20 @@ public class DatabasePlatform {
|
||||
|
||||
public String completeSql(String sql, Query<?> query) {
|
||||
if (query.isForUpdate()) {
|
||||
sql = withForUpdate(sql, query.getForUpdateMode());
|
||||
sql = withForUpdate(sql, query.getForUpdateLockWait(), query.getForUpdateLockType());
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* For update hint on the FROM clause (SQL server only).
|
||||
*/
|
||||
public String fromForUpdate(Query.ForUpdate forUpdateMode) {
|
||||
public String fromForUpdate(Query.LockWait lockWait) {
|
||||
// return null except for sql server
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
// silently assume the database does not support the "for update" clause.
|
||||
logger.info("it seems your database does not support the 'for update' clause");
|
||||
return sql;
|
||||
|
||||
@@ -26,9 +26,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger("io.ebean.SEQ");
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private final ReentrantLock loadLock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* The actual sequence name.
|
||||
|
||||
@@ -51,7 +51,7 @@ public class H2Platform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
// NOWAIT and SKIP LOCKED currently not supported with H2
|
||||
return sql + " for update";
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebean.config.dbplatform.hana;
|
||||
|
||||
import io.ebean.Query.ForUpdate;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.Query.LockWait;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.PlatformConfig;
|
||||
@@ -68,16 +69,16 @@ public class HanaPlatform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
case BASE:
|
||||
protected String withForUpdate(String sql, LockWait lockWait, Query.LockType lockType) {
|
||||
switch (lockWait) {
|
||||
case WAIT:
|
||||
return sql + " for update";
|
||||
case NOWAIT:
|
||||
return sql + " for update nowait";
|
||||
case SKIPLOCKED:
|
||||
return sql + " for update ignore locked";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown update mode: " + forUpdateMode.name());
|
||||
throw new IllegalArgumentException("Unknown update mode: " + lockWait);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ public abstract class BaseMySqlPlatform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
// NOWAIT and SKIP LOCKED currently not supported with MySQL
|
||||
return sql + " for update";
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@ public class NuoDbPlatform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
switch (lockWait) {
|
||||
case NOWAIT:
|
||||
return sql + " for update nowait";
|
||||
case SKIPLOCKED:
|
||||
|
||||
@@ -79,8 +79,8 @@ public class OraclePlatform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
switch (lockWait) {
|
||||
case SKIPLOCKED:
|
||||
return sql + " for update skip locked";
|
||||
case NOWAIT:
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.annotation.PartitionMode;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.PlatformConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
@@ -25,6 +26,15 @@ import java.sql.Types;
|
||||
*/
|
||||
public class PostgresPlatform extends DatabasePlatform {
|
||||
|
||||
private static final String SKIP_LOCKED = " skip locked";
|
||||
private static final String NO_WAIT = " nowait";
|
||||
private static final String FOR_UPDATE = " for update";
|
||||
private static final String FOR_NO_KEY_UPDATE = " for no key update";
|
||||
private static final String FOR_SHARE = " for share";
|
||||
private static final String FOR_KEY_SHARE = " for key share";
|
||||
|
||||
private boolean forUpdateNoKey;
|
||||
|
||||
public PostgresPlatform() {
|
||||
super();
|
||||
this.platform = Platform.POSTGRES;
|
||||
@@ -81,6 +91,12 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
dbTypeMap.put(DbType.LONGVARCHAR, dbTypeText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(PlatformConfig config) {
|
||||
super.configure(config);
|
||||
forUpdateNoKey = config.isForUpdateNoKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addGeoTypes(int srid) {
|
||||
dbTypeMap.put(DbType.POINT, geoType("point", srid));
|
||||
@@ -108,22 +124,32 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
*/
|
||||
@Override
|
||||
public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) {
|
||||
|
||||
return new PostgresSequenceIdGenerator(be, ds, seqName, sequenceBatchSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
switch (lockWait) {
|
||||
case SKIPLOCKED:
|
||||
return sql + " for update skip locked";
|
||||
return sql + lock(lockType) + SKIP_LOCKED;
|
||||
case NOWAIT:
|
||||
return sql + " for update nowait";
|
||||
return sql + lock(lockType) + NO_WAIT;
|
||||
default:
|
||||
return sql + " for update";
|
||||
return sql + lock(lockType);
|
||||
}
|
||||
}
|
||||
|
||||
private String lock(Query.LockType lockType) {
|
||||
switch (lockType) {
|
||||
case UPDATE: return FOR_UPDATE;
|
||||
case NO_KEY_UPDATE: return FOR_NO_KEY_UPDATE;
|
||||
case SHARE: return FOR_SHARE;
|
||||
case KEY_SHARE: return FOR_KEY_SHARE;
|
||||
case DEFAULT: return forUpdateNoKey ? FOR_NO_KEY_UPDATE : FOR_UPDATE;
|
||||
}
|
||||
return FOR_UPDATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tablePartitionsExist(Connection connection, String table) throws SQLException {
|
||||
try (PreparedStatement statement = connection.prepareStatement("select count(*) from pg_inherits i WHERE i.inhparent = ?::regclass")) {
|
||||
|
||||
+3
-3
@@ -105,8 +105,8 @@ abstract class SqlServerBasePlatform extends DatabasePlatform {
|
||||
* For update is part of the FROM clause on the base table for sql server.
|
||||
*/
|
||||
@Override
|
||||
public String fromForUpdate(Query.ForUpdate forUpdateMode) {
|
||||
switch (forUpdateMode) {
|
||||
public String fromForUpdate(Query.LockWait lockWait) {
|
||||
switch (lockWait) {
|
||||
case SKIPLOCKED:
|
||||
return "with (updlock,readpast)";
|
||||
case NOWAIT:
|
||||
@@ -117,7 +117,7 @@ abstract class SqlServerBasePlatform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
|
||||
protected String withForUpdate(String sql, Query.LockWait lockWait, Query.LockType lockType) {
|
||||
// for update are hints on from clause of base table
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public final class ShutdownManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ShutdownManager.class);
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock(false);
|
||||
private static final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private static final List<Database> databases = new ArrayList<>();
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</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.6.0</tag>
|
||||
<tag>ebean-parent-12.7.1</tag>
|
||||
</scm>
|
||||
|
||||
<name>ebean autotune</name>
|
||||
@@ -26,7 +26,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -59,12 +59,12 @@
|
||||
<plugin>
|
||||
<groupId>io.repaint.maven</groupId>
|
||||
<artifactId>tiles-maven-plugin</artifactId>
|
||||
<version>2.18</version>
|
||||
<version>2.19</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<tiles>
|
||||
<!-- other tiles ... -->
|
||||
<tile>io.ebean.tile:enhancement:12.5.0</tile>
|
||||
<tile>io.ebean.tile:enhancement:12.6.0</tile>
|
||||
</tiles>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ public class DefaultAutoTuneService implements AutoTuneService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultAutoTuneService.class);
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final SpiEbeanServer server;
|
||||
|
||||
@@ -77,7 +77,7 @@ public class DefaultAutoTuneService implements AutoTuneService {
|
||||
loadTuningFile();
|
||||
if (isRuntimeTuningUpdates()) {
|
||||
// periodically gather and update query tuning
|
||||
server.getBackgroundExecutor().executePeriodically(new ProfilingUpdate(), profilingUpdateFrequency, TimeUnit.SECONDS);
|
||||
server.getBackgroundExecutor().scheduleWithFixedDelay(new ProfilingUpdate(), profilingUpdateFrequency, profilingUpdateFrequency, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
public class ProfileManager implements ProfilingListener {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final boolean queryTuningAddVersion;
|
||||
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class ProfileOrigin {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private static final long RESET_COUNT = -1000000000L;
|
||||
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ public class ProfileOriginNodeUsage {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProfileOriginNodeUsage.class);
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final String path;
|
||||
|
||||
|
||||
+6
-9
@@ -11,12 +11,9 @@ import org.tests.model.basic.Order;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
//import org.tests.model.basic.ResetBasicData;
|
||||
|
||||
public class ProfileOriginTest extends BaseTestCase {
|
||||
|
||||
|
||||
private BeanDescriptor<Order> desc = getBeanDescriptor(Order.class);
|
||||
private final BeanDescriptor<Order> desc = getBeanDescriptor(Order.class);
|
||||
|
||||
@Test
|
||||
public void buildDetail() {
|
||||
@@ -30,7 +27,7 @@ public class ProfileOriginTest extends BaseTestCase {
|
||||
|
||||
OrmQueryDetail detail = po.buildDetail(desc);
|
||||
|
||||
assertThat(detail.asString().trim()).isEqualTo("fetch customer (name)");
|
||||
assertThat(detail.asStringDebug().trim()).isEqualTo("fetch customer (name)");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -49,7 +46,7 @@ public class ProfileOriginTest extends BaseTestCase {
|
||||
|
||||
OrmQueryDetail detail = po.buildDetail(desc);
|
||||
|
||||
assertThat(detail.asString()).isEqualTo("select (orderDate) fetch customer (name)");
|
||||
assertThat(detail.asStringDebug()).isEqualTo("select (orderDate) fetch customer (name)");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -67,7 +64,7 @@ public class ProfileOriginTest extends BaseTestCase {
|
||||
|
||||
OrmQueryDetail detail = po.buildDetail(desc);
|
||||
|
||||
assertThat(detail.asString().trim()).isEqualTo("select (orderDate,customer)");
|
||||
assertThat(detail.asStringDebug().trim()).isEqualTo("select (orderDate,customer)");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -90,7 +87,7 @@ public class ProfileOriginTest extends BaseTestCase {
|
||||
|
||||
OrmQueryDetail detail = po.buildDetail(desc);
|
||||
|
||||
assertThat(detail.asString()).isEqualTo("select (orderDate) fetch customer (billingAddress)");
|
||||
assertThat(detail.asStringDebug()).isEqualTo("select (orderDate) fetch customer (billingAddress)");
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +116,7 @@ public class ProfileOriginTest extends BaseTestCase {
|
||||
po.collectUsageInfo(c);
|
||||
|
||||
OrmQueryDetail detail = po.buildDetail(desc);
|
||||
assertThat(detail.asString()).isEqualTo("fetch customer (name,note) fetch customer.billingAddress (line1)");
|
||||
assertThat(detail.asStringDebug()).isEqualTo("fetch customer (name,note) fetch customer.billingAddress (line1)");
|
||||
}
|
||||
|
||||
private NodeUsageCollector node(String path) {
|
||||
|
||||
+34
-16
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean bom</name>
|
||||
@@ -15,11 +15,11 @@
|
||||
<properties>
|
||||
<ebean-ddl-runner.version>1.0</ebean-ddl-runner.version>
|
||||
<ebean-migration-auto.version>1.0</ebean-migration-auto.version>
|
||||
<ebean-migration.version>12.2.0</ebean-migration.version>
|
||||
<ebean-test-docker.version>4.0</ebean-test-docker.version>
|
||||
<ebean-migration.version>12.4.0</ebean-migration.version>
|
||||
<ebean-test-docker.version>4.1</ebean-test-docker.version>
|
||||
<ebean-datasource.version>7.0</ebean-datasource.version>
|
||||
<ebean-agent.version>12.6.0</ebean-agent.version>
|
||||
<ebean-maven-plugin.version>12.6.0</ebean-maven-plugin.version>
|
||||
<ebean-agent.version>12.6.6</ebean-agent.version>
|
||||
<ebean-maven-plugin.version>12.6.6</ebean-maven-plugin.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -81,72 +81,90 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-xml</artifactId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-autotune</artifactId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>kotlin-querybean-generator</artifactId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-postgis</artifactId>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-redis</artifactId>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</dependencyManagement>
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.7.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<name>ebean core type</name>
|
||||
<description>ebean scalar types api</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,166 @@
|
||||
package io.ebean.core.type;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Data binder for ScalarTypes generally to an underlying PreparedStatement.
|
||||
*/
|
||||
public interface DataBinder {
|
||||
|
||||
/**
|
||||
* Add something to the binding log.
|
||||
*/
|
||||
StringBuilder append(Object entry);
|
||||
|
||||
/**
|
||||
* Return the binding log.
|
||||
*/
|
||||
StringBuilder log();
|
||||
|
||||
/**
|
||||
* Close the underlying prepared statement.
|
||||
*/
|
||||
void close() throws SQLException;
|
||||
|
||||
/**
|
||||
* Return the current position. Effectively column binding position.
|
||||
*/
|
||||
int currentPos();
|
||||
|
||||
/**
|
||||
* Return the next position.
|
||||
*/
|
||||
int nextPos();
|
||||
|
||||
/**
|
||||
* Decrement the position.
|
||||
*/
|
||||
void decrementPos();
|
||||
|
||||
/**
|
||||
* Execute as a dml statement.
|
||||
*/
|
||||
int executeUpdate() throws SQLException;
|
||||
|
||||
/**
|
||||
* Return the underlying PreparedStatement.
|
||||
*/
|
||||
PreparedStatement getPstmt();
|
||||
|
||||
/**
|
||||
* Return any inputStreams that have been bound (and should be closed).
|
||||
* This is used for batched statement execution only.
|
||||
*/
|
||||
List<InputStream> getInputStreams();
|
||||
|
||||
/**
|
||||
* Bind an object.
|
||||
*/
|
||||
void setObject(Object value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind an object with given sql type.
|
||||
*/
|
||||
void setObject(Object value, int sqlType) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind null.
|
||||
*/
|
||||
void setNull(int jdbcType) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a string value.
|
||||
*/
|
||||
void setString(String value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a int value.
|
||||
*/
|
||||
void setInt(int value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a long value.
|
||||
*/
|
||||
void setLong(long value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a short value.
|
||||
*/
|
||||
void setShort(short value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a float value.
|
||||
*/
|
||||
void setFloat(float value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a double value.
|
||||
*/
|
||||
void setDouble(double value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a BigDecimal value.
|
||||
*/
|
||||
void setBigDecimal(BigDecimal value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a date value.
|
||||
*/
|
||||
void setDate(java.sql.Date value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a timestamp value.
|
||||
*/
|
||||
void setTimestamp(Timestamp value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a time value.
|
||||
*/
|
||||
void setTime(Time value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a boolean value.
|
||||
*/
|
||||
void setBoolean(boolean value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a byte array value.
|
||||
*/
|
||||
void setBytes(byte[] value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a byte value.
|
||||
*/
|
||||
void setByte(byte value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a char value.
|
||||
*/
|
||||
void setChar(char value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a InputStream value.
|
||||
*/
|
||||
void setBinaryStream(InputStream inputStream, long length) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a byte array value.
|
||||
*/
|
||||
void setBlob(byte[] bytes) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind a string clob value.
|
||||
*/
|
||||
void setClob(String content) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind an array value.
|
||||
*/
|
||||
void setArray(String arrayType, Object[] elements) throws SQLException;
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
package io.ebean.core.type;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.ebeanservice.docstore.api.mapping;
|
||||
package io.ebean.core.type;
|
||||
|
||||
/**
|
||||
* Types as defined for document store property types.
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
package io.ebeaninternal.api;
|
||||
package io.ebean.core.type;
|
||||
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
package io.ebean.core.type;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
@@ -10,6 +10,6 @@ public interface ScalarDataReader<T> {
|
||||
/**
|
||||
* Read and return the appropriate value from the dataReader.
|
||||
*/
|
||||
T read(DataReader dataReader) throws SQLException;
|
||||
T read(DataReader reader) throws SQLException;
|
||||
|
||||
}
|
||||
+2
-3
@@ -1,10 +1,9 @@
|
||||
package io.ebeaninternal.server.type;
|
||||
package io.ebean.core.type;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import io.ebean.text.StringFormatter;
|
||||
import io.ebean.text.StringParser;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
@@ -112,7 +111,7 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
|
||||
* JDBC type.
|
||||
* </p>
|
||||
*/
|
||||
void bind(DataBind bind, T value) throws SQLException;
|
||||
void bind(DataBinder binder, T value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Convert the value as necessary to the JDBC type.
|
||||
+23
-16
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core</artifactId>
|
||||
@@ -15,14 +15,9 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-parent-12.6.0</tag>
|
||||
<tag>ebean-parent-12.7.1</tag>
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<jackson-core.version>2.11.3</jackson-core.version>
|
||||
<jackson-databind.version>2.11.3</jackson-databind.version>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<!-- Note: to use this profile, you need to download manually the db2jcc4 driver.
|
||||
@@ -70,14 +65,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>12.2.0</version>
|
||||
<version>12.4.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddlgen</artifactId>
|
||||
<version>12.5.2A</version>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -92,13 +87,19 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
<version>12.6.0</version>
|
||||
<version>12.7.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -132,6 +133,12 @@
|
||||
<version>1.1.0.Final</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
@@ -151,14 +158,14 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson-core.version}</version>
|
||||
<version>${jackson.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson-databind.version}</version>
|
||||
<version>${jackson.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
@@ -196,7 +203,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test-docker</artifactId>
|
||||
<version>4.0</version>
|
||||
<version>4.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -295,7 +302,7 @@
|
||||
<plugin>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>12.5.0</version>
|
||||
<version>12.6.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
|
||||
@@ -20,6 +20,7 @@ import io.ebeaninternal.server.deploy.TableJoin;
|
||||
import io.ebeaninternal.server.query.CancelableQuery;
|
||||
import io.ebeaninternal.server.querydefn.NaturalKeyBindParam;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
import io.ebeaninternal.server.querydefn.OrmUpdateProperties;
|
||||
import io.ebeaninternal.server.rawsql.SpiRawSql;
|
||||
|
||||
@@ -30,7 +31,7 @@ import java.util.Set;
|
||||
/**
|
||||
* Object Relational query - Internal extension to Query object.
|
||||
*/
|
||||
public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
|
||||
public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCodes {
|
||||
|
||||
enum Mode {
|
||||
NORMAL(false), LAZYLOAD_MANY(false), LAZYLOAD_BEAN(true), REFRESH_BEAN(true);
|
||||
@@ -237,7 +238,7 @@ public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
|
||||
* Return the ForUpdate mode.
|
||||
*/
|
||||
@Override
|
||||
ForUpdate getForUpdateMode();
|
||||
LockWait getForUpdateLockWait();
|
||||
|
||||
/**
|
||||
* Return the bean descriptor for this query.
|
||||
@@ -289,6 +290,16 @@ public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
|
||||
*/
|
||||
boolean selectAllForLazyLoadProperty();
|
||||
|
||||
/**
|
||||
* Set the select properties.
|
||||
*/
|
||||
void selectProperties(OrmQueryProperties other);
|
||||
|
||||
/**
|
||||
* Set the fetch properties for the given path.
|
||||
*/
|
||||
void fetchProperties(String path, OrmQueryProperties other);
|
||||
|
||||
/**
|
||||
* Set the on a secondary query given the label, relativePath and profile location of the parent query.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.FetchConfig;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Query select and fetch properties (that avoids parsing).
|
||||
*/
|
||||
public interface SpiQueryFetch {
|
||||
|
||||
/**
|
||||
* Specify the select properties.
|
||||
*/
|
||||
void selectProperties(Set<String> properties);
|
||||
|
||||
/**
|
||||
* Specify the fetch properties for the given path.
|
||||
*/
|
||||
void fetchProperties(String name, Set<String> properties, FetchConfig config);
|
||||
|
||||
}
|
||||
@@ -318,4 +318,20 @@ public interface SpiTransaction extends Transaction {
|
||||
* Return true if explicitly set to skip cache (ignores skipOnWrite).
|
||||
*/
|
||||
boolean isSkipCacheExplicit();
|
||||
|
||||
/**
|
||||
* Fire pre commit processing/listeners.
|
||||
*/
|
||||
void preCommit();
|
||||
|
||||
/**
|
||||
* Fire post commit events and listeners.
|
||||
*/
|
||||
void postCommit();
|
||||
|
||||
/**
|
||||
* Fire post rollback events and listeners.
|
||||
*/
|
||||
void postRollback(Throwable cause);
|
||||
|
||||
}
|
||||
|
||||
@@ -418,4 +418,18 @@ public abstract class SpiTransactionProxy implements SpiTransaction {
|
||||
transaction.flushBatchOnCollection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preCommit() {
|
||||
transaction.preCommit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postCommit() {
|
||||
transaction.postCommit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postRollback(Throwable cause) {
|
||||
transaction.postRollback(cause);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebeaninternal.json;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
@@ -145,7 +146,7 @@ class EJsonReader {
|
||||
currentContext = stack.pop(currentContext);
|
||||
}
|
||||
if (modifyAwareOwner != null) {
|
||||
modifyAwareOwner.resetMarkedDirty();
|
||||
modifyAwareOwner.setMarkedDirty(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,7 +297,7 @@ class EJsonReader {
|
||||
map = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
ObjectContext(ModifyAwareOwner owner) {
|
||||
ObjectContext(ModifyAwareType owner) {
|
||||
map = new ModifyAwareMap<>(owner, new LinkedHashMap<>());
|
||||
}
|
||||
|
||||
@@ -334,7 +335,7 @@ class EJsonReader {
|
||||
values = new ArrayList<>();
|
||||
}
|
||||
|
||||
ArrayContext(ModifyAwareOwner owner) {
|
||||
ArrayContext(ModifyAwareType owner) {
|
||||
values = new ModifyAwareList<>(owner, new ArrayList<>());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,26 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Detects when content has been modified and as such needs to be persisted (included in an update).
|
||||
*/
|
||||
public class ModifyAwareFlag implements ModifyAwareOwner {
|
||||
public class ModifyAwareFlag implements ModifyAwareType, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
boolean dirty;
|
||||
private boolean markedDirty;
|
||||
|
||||
@Override
|
||||
public boolean isMarkedDirty() {
|
||||
if (!dirty) return false;
|
||||
dirty = false;
|
||||
return true;
|
||||
return markedDirty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsModified() {
|
||||
dirty = true;
|
||||
public void setMarkedDirty(boolean markedDirty) {
|
||||
this.markedDirty = markedDirty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetMarkedDirty() {
|
||||
dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
@@ -7,7 +9,7 @@ import java.util.Iterator;
|
||||
*/
|
||||
public class ModifyAwareIterator<E> implements Iterator<E> {
|
||||
|
||||
private final ModifyAwareOwner owner;
|
||||
private final ModifyAwareType owner;
|
||||
|
||||
private final Iterator<E> it;
|
||||
|
||||
@@ -17,7 +19,7 @@ public class ModifyAwareIterator<E> implements Iterator<E> {
|
||||
* The owner is notified of the removals.
|
||||
* </p>
|
||||
*/
|
||||
public ModifyAwareIterator(ModifyAwareOwner owner, Iterator<E> it) {
|
||||
public ModifyAwareIterator(ModifyAwareType owner, Iterator<E> it) {
|
||||
this.owner = owner;
|
||||
this.it = it;
|
||||
}
|
||||
@@ -34,7 +36,7 @@ public class ModifyAwareIterator<E> implements Iterator<E> {
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
owner.markAsModified();
|
||||
owner.setMarkedDirty(true);
|
||||
it.remove();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -10,20 +13,20 @@ import java.util.Objects;
|
||||
/**
|
||||
* Modify aware wrapper of a list.
|
||||
*/
|
||||
public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
|
||||
public class ModifyAwareList<E> implements List<E>, ModifyAwareType, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
final List<E> list;
|
||||
|
||||
final ModifyAwareOwner owner;
|
||||
final ModifyAwareType owner;
|
||||
|
||||
public ModifyAwareList(List<E> list) {
|
||||
this.list = list;
|
||||
this.owner = new ModifyAwareFlag();
|
||||
}
|
||||
|
||||
public ModifyAwareList(ModifyAwareOwner owner, List<E> list) {
|
||||
public ModifyAwareList(ModifyAwareType owner, List<E> list) {
|
||||
this.list = list;
|
||||
this.owner = owner;
|
||||
}
|
||||
@@ -56,13 +59,12 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsModified() {
|
||||
owner.markAsModified();
|
||||
public void setMarkedDirty(boolean markedDirty) {
|
||||
owner.setMarkedDirty(markedDirty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetMarkedDirty() {
|
||||
owner.resetMarkedDirty();
|
||||
private void markAsDirty() {
|
||||
owner.setMarkedDirty(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,13 +100,13 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
|
||||
|
||||
@Override
|
||||
public boolean add(E e) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.add(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.remove(o);
|
||||
}
|
||||
|
||||
@@ -115,31 +117,31 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends E> c) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.addAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(int index, Collection<? extends E> c) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.addAll(index, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.removeAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.retainAll(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
list.clear();
|
||||
}
|
||||
|
||||
@@ -150,19 +152,19 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
|
||||
|
||||
@Override
|
||||
public E set(int index, E element) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.set(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int index, E element) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
list.add(index, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public E remove(int index) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return list.remove(index);
|
||||
}
|
||||
|
||||
@@ -195,7 +197,6 @@ public class ModifyAwareList<E> implements List<E>, ModifyAwareOwner {
|
||||
* Create an return a modify aware Set.
|
||||
*/
|
||||
public ModifyAwareSet<E> asSet() {
|
||||
|
||||
return new ModifyAwareSet<>(owner, new LinkedHashSet<>(list));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
/**
|
||||
@@ -7,11 +9,11 @@ import java.util.ListIterator;
|
||||
*/
|
||||
public class ModifyAwareListIterator<E> implements ListIterator<E> {
|
||||
|
||||
final ModifyAwareOwner owner;
|
||||
final ModifyAwareType owner;
|
||||
|
||||
final ListIterator<E> iterator;
|
||||
|
||||
public ModifyAwareListIterator(ModifyAwareOwner owner, ListIterator<E> iterator) {
|
||||
public ModifyAwareListIterator(ModifyAwareType owner, ListIterator<E> iterator) {
|
||||
this.owner = owner;
|
||||
this.iterator = iterator;
|
||||
}
|
||||
@@ -48,19 +50,19 @@ public class ModifyAwareListIterator<E> implements ListIterator<E> {
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
owner.markAsModified();
|
||||
owner.setMarkedDirty(true);
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(E e) {
|
||||
owner.markAsModified();
|
||||
owner.setMarkedDirty(true);
|
||||
iterator.set(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(E e) {
|
||||
owner.markAsModified();
|
||||
owner.setMarkedDirty(true);
|
||||
iterator.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
@@ -9,11 +12,11 @@ import java.util.Set;
|
||||
/**
|
||||
* Map that is wraps an underlying map for the purpose of detecting changes.
|
||||
*/
|
||||
public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
|
||||
public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareType, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
final ModifyAwareOwner owner;
|
||||
final ModifyAwareType owner;
|
||||
|
||||
/**
|
||||
* The underlying map.
|
||||
@@ -25,7 +28,7 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
|
||||
this.owner = new ModifyAwareFlag();
|
||||
}
|
||||
|
||||
public ModifyAwareMap(ModifyAwareOwner owner, Map<K, V> underlying) {
|
||||
public ModifyAwareMap(ModifyAwareType owner, Map<K, V> underlying) {
|
||||
this.owner = owner;
|
||||
this.map = underlying;
|
||||
}
|
||||
@@ -58,13 +61,12 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsModified() {
|
||||
owner.markAsModified();
|
||||
public void setMarkedDirty(boolean markedDirty) {
|
||||
owner.setMarkedDirty(markedDirty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetMarkedDirty() {
|
||||
owner.resetMarkedDirty();
|
||||
private void markAsDirty() {
|
||||
owner.setMarkedDirty(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -94,7 +96,7 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
markAsModified();
|
||||
markAsDirty();
|
||||
return map.put(key, value);
|
||||
}
|
||||
|
||||
@@ -102,14 +104,14 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
|
||||
public V remove(Object key) {
|
||||
V value = map.remove(key);
|
||||
if (value != null) {
|
||||
markAsModified();
|
||||
markAsDirty();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
markAsModified();
|
||||
markAsDirty();
|
||||
map.putAll(m);
|
||||
}
|
||||
|
||||
@@ -117,7 +119,7 @@ public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareOwner {
|
||||
@Override
|
||||
public void clear() {
|
||||
if (!map.isEmpty()) {
|
||||
markAsModified();
|
||||
markAsDirty();
|
||||
}
|
||||
map.clear();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package io.ebeaninternal.json;
|
||||
|
||||
import io.ebean.ModifyAwareType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
@@ -8,11 +11,11 @@ import java.util.Set;
|
||||
/**
|
||||
* Wraps a Set for the purposes of detecting modifications.
|
||||
*/
|
||||
public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
public class ModifyAwareSet<E> implements Set<E>, ModifyAwareType, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
protected final ModifyAwareOwner owner;
|
||||
protected final ModifyAwareType owner;
|
||||
|
||||
protected final Set<E> set;
|
||||
|
||||
@@ -26,7 +29,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
/**
|
||||
* Create with an Owner that is notified of modifications.
|
||||
*/
|
||||
public ModifyAwareSet(ModifyAwareOwner owner, Set<E> underlying) {
|
||||
public ModifyAwareSet(ModifyAwareType owner, Set<E> underlying) {
|
||||
this.owner = owner;
|
||||
this.set = underlying;
|
||||
}
|
||||
@@ -37,16 +40,14 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsModified() {
|
||||
owner.markAsModified();
|
||||
public void setMarkedDirty(boolean markedDirty) {
|
||||
owner.setMarkedDirty(markedDirty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetMarkedDirty() {
|
||||
owner.resetMarkedDirty();
|
||||
private void markAsDirty() {
|
||||
owner.setMarkedDirty(true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return set.toString();
|
||||
@@ -72,7 +73,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
@Override
|
||||
public boolean add(E o) {
|
||||
if (set.add(o)) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -83,7 +84,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
boolean changed = false;
|
||||
for (E o : collection) {
|
||||
if (set.add(o)) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -93,7 +94,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
@Override
|
||||
public void clear() {
|
||||
if (!set.isEmpty()) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
}
|
||||
set.clear();
|
||||
}
|
||||
@@ -121,7 +122,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
if (set.remove(o)) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -132,7 +133,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
boolean changed = false;
|
||||
for (Object element : collection) {
|
||||
if (set.remove(element)) {
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -147,7 +148,7 @@ public class ModifyAwareSet<E> implements Set<E>, ModifyAwareOwner {
|
||||
Object o = it.next();
|
||||
if (!collection.contains(o)) {
|
||||
it.remove();
|
||||
owner.markAsModified();
|
||||
markAsDirty();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ class DefaultCacheHolder {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger("io.ebean.cache.ALL");
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final ConcurrentHashMap<String, ServerCache> allCaches = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<String, Set<String>> collectIdCaches = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ public class DefaultServerCache implements ServerCache {
|
||||
|
||||
// default to trimming the cache every 60 seconds
|
||||
long trimFreqSecs = (trimFrequency == 0) ? 60 : trimFrequency;
|
||||
executor.executePeriodically(trim, trimFreqSecs, TimeUnit.SECONDS);
|
||||
executor.scheduleWithFixedDelay(trim, trimFreqSecs, trimFreqSecs, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,7 @@ public class ClusterManager implements ServerLookup {
|
||||
|
||||
private static final Logger clusterLogger = LoggerFactory.getLogger("io.ebean.Cluster");
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final ConcurrentHashMap<String, EbeanServer> serverMap = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
+14
-22
@@ -27,7 +27,7 @@ public abstract class AbstractSqlQueryRequest {
|
||||
|
||||
protected final SpiEbeanServer server;
|
||||
|
||||
protected SpiTransaction trans;
|
||||
protected SpiTransaction transaction;
|
||||
|
||||
private boolean createdTransaction;
|
||||
|
||||
@@ -47,18 +47,18 @@ public abstract class AbstractSqlQueryRequest {
|
||||
AbstractSqlQueryRequest(SpiEbeanServer server, SpiSqlBinding query, Transaction t) {
|
||||
this.server = server;
|
||||
this.query = query;
|
||||
this.trans = (SpiTransaction) t;
|
||||
this.transaction = (SpiTransaction) t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a transaction if none currently exists.
|
||||
*/
|
||||
public void initTransIfRequired() {
|
||||
if (trans == null) {
|
||||
trans = server.currentServerTransaction();
|
||||
if (trans == null || !trans.isActive()) {
|
||||
if (transaction == null) {
|
||||
transaction = server.currentServerTransaction();
|
||||
if (transaction == null || !transaction.isActive()) {
|
||||
// create a local readOnly transaction
|
||||
trans = server.createReadOnlyTransaction(null);
|
||||
transaction = server.createReadOnlyTransaction(null);
|
||||
createdTransaction = true;
|
||||
}
|
||||
}
|
||||
@@ -69,20 +69,18 @@ public abstract class AbstractSqlQueryRequest {
|
||||
*/
|
||||
public void endTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
trans.commit();
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
|
||||
public EbeanServer getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public SpiTransaction getTransaction() {
|
||||
return trans;
|
||||
protected void flushJdbcBatchOnQuery() {
|
||||
if (transaction.isFlushOnQuery()) {
|
||||
transaction.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLogSql() {
|
||||
return trans.isLogSql();
|
||||
return transaction.isLogSql();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,7 +118,6 @@ public abstract class AbstractSqlQueryRequest {
|
||||
* Prepare the SQL taking into account named bind parameters.
|
||||
*/
|
||||
private void prepareSql() {
|
||||
|
||||
String sql = query.getQuery();
|
||||
BindParams bindParams = query.getBindParams();
|
||||
if (!bindParams.isEmpty()) {
|
||||
@@ -131,7 +128,6 @@ public abstract class AbstractSqlQueryRequest {
|
||||
}
|
||||
|
||||
private String limitOffset(String sql) {
|
||||
|
||||
int firstRow = query.getFirstRow();
|
||||
int maxRows = query.getMaxRows();
|
||||
if (firstRow > 0 || maxRows > 0) {
|
||||
@@ -149,10 +145,8 @@ public abstract class AbstractSqlQueryRequest {
|
||||
}
|
||||
|
||||
protected void executeAsSql(Binder binder) throws SQLException {
|
||||
|
||||
prepareSql();
|
||||
Connection conn = trans.getInternalConnection();
|
||||
|
||||
Connection conn = transaction.getInternalConnection();
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
if (query.getTimeout() > 0) {
|
||||
pstmt.setQueryTimeout(query.getTimeout());
|
||||
@@ -160,14 +154,12 @@ public abstract class AbstractSqlQueryRequest {
|
||||
if (query.getBufferFetchSizeHint() > 0) {
|
||||
pstmt.setFetchSize(query.getBufferFetchSizeHint());
|
||||
}
|
||||
|
||||
BindParams bindParams = query.getBindParams();
|
||||
if (!bindParams.isEmpty()) {
|
||||
this.bindLog = binder.bind(bindParams, pstmt, conn);
|
||||
}
|
||||
|
||||
if (isLogSql()) {
|
||||
trans.logSql(Str.add(TrimLogSql.trim(sql), "; --bind(", bindLog, ")"));
|
||||
transaction.logSql(Str.add(TrimLogSql.trim(sql), "; --bind(", bindLog, ")"));
|
||||
}
|
||||
|
||||
setResultSet(pstmt.executeQuery(), null);
|
||||
|
||||
@@ -131,19 +131,10 @@ public class DatabasePlatformFactory {
|
||||
* Use JDBC DatabaseMetaData to determine the platform.
|
||||
*/
|
||||
private DatabasePlatform byDataSource(DataSource dataSource) {
|
||||
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
DatabaseMetaData metaData = connection.getMetaData();
|
||||
|
||||
return byDatabaseMeta(metaData, connection);
|
||||
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
return byDatabaseMeta(connection.getMetaData(), connection);
|
||||
} catch (SQLException ex) {
|
||||
throw new PersistenceException(ex);
|
||||
|
||||
} finally {
|
||||
JdbcClose.close(connection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +148,7 @@ public class DatabasePlatformFactory {
|
||||
final int minorVersion = metaData.getDatabaseMinorVersion();
|
||||
|
||||
if (dbProductName.contains("oracle")) {
|
||||
return new OraclePlatform();
|
||||
return oracleVersion(majorVersion);
|
||||
} else if (dbProductName.contains("microsoft")) {
|
||||
throw new IllegalArgumentException("For SqlServer please explicitly choose either sqlserver16 or sqlserver17 as the platform via DatabaseConfig.setDatabasePlatformName. Refer to issue #1340 for more details");
|
||||
} else if (dbProductName.contains("h2")) {
|
||||
@@ -188,6 +179,10 @@ public class DatabasePlatformFactory {
|
||||
return new DatabasePlatform();
|
||||
}
|
||||
|
||||
private DatabasePlatform oracleVersion(int majorVersion) {
|
||||
return majorVersion < 12 ? new Oracle11Platform() : new OraclePlatform();
|
||||
}
|
||||
|
||||
private DatabasePlatform mysqlVersion(int majorVersion, int minorVersion) {
|
||||
if (majorVersion <= 5 && minorVersion <= 5) {
|
||||
return new MySql55Platform();
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import io.ebeaninternal.server.lib.DaemonExecutorService;
|
||||
import io.ebeaninternal.server.lib.DaemonScheduleThreadPool;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* The default implementation of the BackgroundExecutor.
|
||||
*/
|
||||
public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
private final DaemonScheduleThreadPool schedulePool;
|
||||
|
||||
private final DaemonExecutorService pool;
|
||||
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*/
|
||||
public DefaultBackgroundExecutor(int schedulePoolSize, int shutdownWaitSeconds, String namePrefix) {
|
||||
this.pool = new DaemonExecutorService(shutdownWaitSeconds, namePrefix);
|
||||
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix + "-periodic-");
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a Runnable using a background thread.
|
||||
*/
|
||||
@Override
|
||||
public void execute(Runnable r) {
|
||||
final Map<String, String> map = MDC.getCopyOfContextMap();
|
||||
if (map == null) {
|
||||
pool.execute(r);
|
||||
} else {
|
||||
pool.execute(() -> {
|
||||
MDC.setContextMap(map);
|
||||
try {
|
||||
r.run();
|
||||
} finally {
|
||||
MDC.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executePeriodically(Runnable r, long delay, TimeUnit unit) {
|
||||
executePeriodically(r, delay, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executePeriodically(Runnable r, long initialDelay, long delay, TimeUnit unit) {
|
||||
final Map<String, String> map = MDC.getCopyOfContextMap();
|
||||
if (map == null) {
|
||||
schedulePool.scheduleWithFixedDelay(r, initialDelay, delay, unit);
|
||||
} else {
|
||||
schedulePool.scheduleWithFixedDelay(() -> {
|
||||
MDC.setContextMap(map);
|
||||
try {
|
||||
r.run();
|
||||
} finally {
|
||||
MDC.clear();
|
||||
}
|
||||
}, initialDelay, delay, unit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> schedule(Runnable r, long delay, TimeUnit unit) {
|
||||
final Map<String, String> map = MDC.getCopyOfContextMap();
|
||||
if (map == null) {
|
||||
return schedulePool.schedule(r, delay, unit);
|
||||
} else {
|
||||
return schedulePool.schedule(() -> {
|
||||
MDC.setContextMap(map);
|
||||
try {
|
||||
r.run();
|
||||
} finally {
|
||||
MDC.clear();
|
||||
}
|
||||
}, delay, unit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> ScheduledFuture<V> schedule(Callable<V> c, long delay, TimeUnit unit) {
|
||||
final Map<String, String> map = MDC.getCopyOfContextMap();
|
||||
if (map == null) {
|
||||
return schedulePool.schedule(c, delay, unit);
|
||||
} else {
|
||||
return schedulePool.schedule(() -> {
|
||||
MDC.setContextMap(map);
|
||||
try {
|
||||
return c.call();
|
||||
} finally {
|
||||
MDC.clear();
|
||||
}
|
||||
}, delay, unit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
pool.shutdown();
|
||||
schedulePool.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -215,7 +215,6 @@ class DefaultBeanLoader {
|
||||
desc.contextPut(pc, id, bean);
|
||||
ebi.setPersistenceContext(pc);
|
||||
}
|
||||
|
||||
boolean draft = desc.isDraftInstance(bean);
|
||||
|
||||
if (embeddedOwnerIndex == -1) {
|
||||
@@ -245,7 +244,6 @@ class DefaultBeanLoader {
|
||||
// and put the data into the original bean
|
||||
query.setUsageProfiling(false);
|
||||
query.setPersistenceContext(pc);
|
||||
|
||||
query.setMode(mode);
|
||||
query.setId(id);
|
||||
|
||||
|
||||
@@ -10,14 +10,15 @@ import io.ebean.config.TenantMode;
|
||||
import io.ebean.config.UnderscoreNamingConvention;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.h2.H2Platform;
|
||||
import io.ebean.event.ShutdownManager;
|
||||
import io.ebean.service.SpiContainer;
|
||||
import io.ebeaninternal.api.DbOffline;
|
||||
import io.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.DbOffline;
|
||||
import io.ebeaninternal.server.cluster.ClusterManager;
|
||||
import io.ebeaninternal.server.core.bootup.BootupClassPathSearch;
|
||||
import io.ebeaninternal.server.core.bootup.BootupClasses;
|
||||
import io.ebean.event.ShutdownManager;
|
||||
import io.ebeaninternal.server.executor.DefaultBackgroundExecutor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -35,7 +36,7 @@ public class DefaultContainer implements SpiContainer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("io.ebean.internal.DefaultContainer");
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final ClusterManager clusterManager;
|
||||
|
||||
public DefaultContainer(ContainerConfig containerConfig) {
|
||||
|
||||
@@ -161,7 +161,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultServer.class);
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final DatabaseConfig config;
|
||||
private final String serverName;
|
||||
private final DatabasePlatform databasePlatform;
|
||||
@@ -451,16 +451,20 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
backgroundExecutor.shutdown();
|
||||
// shutdown DataSource (if its an Ebean one)
|
||||
transactionManager.shutdown(shutdownDataSource, deregisterDriver);
|
||||
dumpMetrics();
|
||||
shutdown = true;
|
||||
if (shutdownDataSource) {
|
||||
config.setDataSource(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void shutdownPlugins() {
|
||||
private void dumpMetrics() {
|
||||
if (config.isDumpMetricsOnShutdown()) {
|
||||
new DumpMetrics(this, config.getDumpMetricsOptions()).dump();
|
||||
}
|
||||
}
|
||||
|
||||
private void shutdownPlugins() {
|
||||
for (Plugin plugin : serverPlugins) {
|
||||
try {
|
||||
plugin.shutdown();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebeaninternal.api.SpiDtoQuery;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
@@ -8,7 +9,6 @@ import io.ebeaninternal.server.dto.DtoMappingRequest;
|
||||
import io.ebeaninternal.server.dto.DtoQueryPlan;
|
||||
import io.ebeaninternal.server.persist.Binder;
|
||||
import io.ebeaninternal.server.query.DtoQueryEngine;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebeaninternal.server.type.RsetDataReader;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
@@ -50,7 +50,7 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
|
||||
ormQuery.setManualId();
|
||||
|
||||
// execute the underlying ORM query returning the ResultSet
|
||||
SpiResultSet result = server.findResultSet(ormQuery, trans);
|
||||
SpiResultSet result = server.findResultSet(ormQuery, transaction);
|
||||
this.pstmt = result.getStatement();
|
||||
this.sql = ormQuery.getGeneratedSql();
|
||||
setResultSet(result.getResultSet(), ormQuery.getQueryPlanKey());
|
||||
@@ -88,14 +88,17 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
|
||||
}
|
||||
|
||||
public void findEach(Consumer<T> consumer) {
|
||||
flushJdbcBatchOnQuery();
|
||||
queryEngine.findEach(this, consumer);
|
||||
}
|
||||
|
||||
public void findEachWhile(Predicate<T> consumer) {
|
||||
flushJdbcBatchOnQuery();
|
||||
queryEngine.findEachWhile(this, consumer);
|
||||
}
|
||||
|
||||
public List<T> findList() {
|
||||
flushJdbcBatchOnQuery();
|
||||
return queryEngine.findList(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ public final class InternString {
|
||||
|
||||
private static final HashMap<String, String> map = new HashMap<>();
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock(false);
|
||||
private static final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* Return the shared instance of this string.
|
||||
|
||||
@@ -104,7 +104,6 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
|
||||
return transaction.isLogSummary();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if this persist request should use JDBC batch.
|
||||
*/
|
||||
@@ -119,23 +118,22 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
|
||||
return transaction.translate(e.getMessage(), e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the statement.
|
||||
*/
|
||||
int executeStatement() {
|
||||
return executeStatement(false);
|
||||
}
|
||||
|
||||
int executeStatement(boolean addBatch) {
|
||||
boolean batch = isBatchThisRequest();
|
||||
|
||||
try {
|
||||
int rows;
|
||||
BatchControl control = transaction.getBatchControl();
|
||||
if (control != null) {
|
||||
rows = control.executeStatementOrBatch(this, batch);
|
||||
rows = control.executeStatementOrBatch(this, batch, addBatch);
|
||||
|
||||
} else if (batch) {
|
||||
// need to create the BatchControl
|
||||
control = persistExecute.createBatchControl(transaction);
|
||||
rows = control.executeStatementOrBatch(this, true);
|
||||
rows = control.executeStatementOrBatch(this, true, addBatch);
|
||||
} else {
|
||||
rows = executeNow();
|
||||
}
|
||||
|
||||
@@ -388,7 +388,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
@Override
|
||||
public void preGetterTrigger(int propertyIndex) {
|
||||
if (flushBatchOnGetter(propertyIndex)) {
|
||||
transaction.flushBatch();
|
||||
transaction.flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ public final class PersistRequestUpdateSql extends PersistRequest {
|
||||
*/
|
||||
public int addBatch() {
|
||||
this.addBatch = true;
|
||||
return executeOrQueue();
|
||||
return executeStatement(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,13 +73,13 @@ public final class PersistRequestUpdateSql extends PersistRequest {
|
||||
/**
|
||||
* Add this request to BatchControl to flush later.
|
||||
*/
|
||||
public void addToFlushQueue(boolean early) {
|
||||
public void addToFlushQueue(int pos) {
|
||||
BatchControl control = transaction.getBatchControl();
|
||||
if (control == null) {
|
||||
control = persistExecute.createBatchControl(transaction);
|
||||
}
|
||||
flushQueue = true;
|
||||
control.addToFlushQueue(this, early);
|
||||
control.addToFlushQueue(this, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -104,18 +104,14 @@ public interface Persister {
|
||||
void executeOrQueue(SpiSqlUpdate update, SpiTransaction t, boolean queue);
|
||||
|
||||
/**
|
||||
* Queue the SqlUpdate for early execution (with JDBC batch).
|
||||
* Queue the SqlUpdate for execution with position 0, 1 or 2 defining
|
||||
* when it executes relative to the flush of beans .
|
||||
*/
|
||||
void addToFlushQueue(SpiSqlUpdate update, SpiTransaction t);
|
||||
void addToFlushQueue(SpiSqlUpdate update, SpiTransaction t, int pos);
|
||||
|
||||
/**
|
||||
* Queue the SqlUpdate for late execution (with JDBC batch).
|
||||
* Add the statement to JDBC batch for later execution via executeBatch.
|
||||
*/
|
||||
void addToFlushQueueLast(SpiSqlUpdate update, SpiTransaction t);
|
||||
|
||||
/**
|
||||
* Add the statement to JDBC batch for later execution via executeBatch.
|
||||
*/
|
||||
void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction);
|
||||
|
||||
/**
|
||||
|
||||
@@ -56,35 +56,43 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
|
||||
}
|
||||
|
||||
boolean findEachRow(RowConsumer mapper) {
|
||||
flushJdbcBatchOnQuery();
|
||||
queryEngine.findEachRow(this, mapper);
|
||||
return true;
|
||||
}
|
||||
|
||||
<T> List<T> findListMapper(RowMapper<T> mapper) {
|
||||
flushJdbcBatchOnQuery();
|
||||
return queryEngine.findListMapper(this, mapper);
|
||||
}
|
||||
|
||||
<T> T findOneMapper(RowMapper<T> mapper) {
|
||||
flushJdbcBatchOnQuery();
|
||||
return queryEngine.findOneMapper(this, mapper);
|
||||
}
|
||||
|
||||
public <T> List<T> findSingleAttributeList(Class<T> cls) {
|
||||
flushJdbcBatchOnQuery();
|
||||
return queryEngine.findSingleAttributeList(this, cls);
|
||||
}
|
||||
|
||||
public <T> T findSingleAttribute(Class<T> cls) {
|
||||
flushJdbcBatchOnQuery();
|
||||
return queryEngine.findSingleAttribute(this, cls);
|
||||
}
|
||||
|
||||
public void findEach(Consumer<SqlRow> consumer) {
|
||||
flushJdbcBatchOnQuery();
|
||||
queryEngine.findEach(this, consumer);
|
||||
}
|
||||
|
||||
public void findEachWhile(Predicate<SqlRow> consumer) {
|
||||
flushJdbcBatchOnQuery();
|
||||
queryEngine.findEach(this, consumer);
|
||||
}
|
||||
|
||||
public List<SqlRow> findList() {
|
||||
flushJdbcBatchOnQuery();
|
||||
return queryEngine.findList(this);
|
||||
}
|
||||
|
||||
@@ -92,9 +100,7 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
|
||||
* Build the list of property names.
|
||||
*/
|
||||
private String[] getPropertyNames() throws SQLException {
|
||||
|
||||
ResultSetMetaData metaData = resultSet.getMetaData();
|
||||
|
||||
int columnsPlusOne = metaData.getColumnCount() + 1;
|
||||
ArrayList<String> propNames = new ArrayList<>(columnsPlusOne - 1);
|
||||
for (int i = 1; i < columnsPlusOne; i++) {
|
||||
@@ -107,9 +113,7 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
|
||||
* Read and return the next SqlRow.
|
||||
*/
|
||||
public SqlRow createNewRow() throws SQLException {
|
||||
|
||||
rows++;
|
||||
|
||||
SqlRow sqlRow = queryEngine.createSqlRow(estimateCapacity);
|
||||
int index = 0;
|
||||
for (String propertyName : propertyNames) {
|
||||
@@ -121,9 +125,9 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
|
||||
}
|
||||
|
||||
public void logSummary() {
|
||||
if (trans.isLogSummary()) {
|
||||
if (transaction.isLogSummary()) {
|
||||
long micros = (System.nanoTime() - startNano) / 1000L;
|
||||
trans.logSummary("SqlQuery rows[" + rows + "] micros[" + micros + "] bind[" + bindLog + "]");
|
||||
transaction.logSummary("SqlQuery rows[" + rows + "] micros[" + micros + "] bind[" + bindLog + "]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +140,6 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
|
||||
}
|
||||
|
||||
public <T> List<T> mapList(RowMapper<T> mapper) throws SQLException {
|
||||
|
||||
List<T> list = new ArrayList<>();
|
||||
while (next()) {
|
||||
list.add(mapper.map(resultSet, rows++));
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.ebean.annotation.DocStore;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.IdGenerator;
|
||||
import io.ebean.config.ScalarTypeConverter;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.event.BeanFindController;
|
||||
import io.ebean.event.BeanPersistController;
|
||||
import io.ebean.event.BeanPersistListener;
|
||||
@@ -18,7 +19,6 @@ import io.ebean.event.changelog.ChangeLogRegister;
|
||||
import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.util.AnnotationUtil;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -223,12 +223,9 @@ public class BootupClasses implements ClassFilter {
|
||||
*/
|
||||
private <T> T create(Class<T> cls, boolean logOnException) {
|
||||
try {
|
||||
// instantiate via found class
|
||||
Constructor<T> constructor = cls.getConstructor();
|
||||
return constructor.newInstance();
|
||||
|
||||
return cls.getConstructor().newInstance();
|
||||
} catch (NoSuchMethodException e) {
|
||||
logger.debug("Ignore/expected - no default constructor", e);
|
||||
logger.debug("Ignore/expected - no default constructor: " +e.getMessage());
|
||||
return null;
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -2,8 +2,8 @@ package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebean.core.type.DataReader;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.EncryptKey;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.config.dbplatform.PlatformIdGenerator;
|
||||
import io.ebean.core.type.DocPropertyType;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.event.BeanFindController;
|
||||
import io.ebean.event.BeanPersistController;
|
||||
import io.ebean.event.BeanPersistListener;
|
||||
@@ -82,7 +84,6 @@ import io.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
import io.ebeaninternal.server.rawsql.SpiRawSql;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.util.SortByClause;
|
||||
import io.ebeaninternal.util.SortByClauseParser;
|
||||
import io.ebeanservice.docstore.api.DocStoreBeanAdapter;
|
||||
@@ -90,7 +91,6 @@ import io.ebeanservice.docstore.api.DocStoreUpdateContext;
|
||||
import io.ebeanservice.docstore.api.DocStoreUpdates;
|
||||
import io.ebeanservice.docstore.api.mapping.DocMappingBuilder;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import io.ebeanservice.docstore.api.mapping.DocumentMapping;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -522,7 +522,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return (EntityBean) beanType.newInstance();
|
||||
return (EntityBean) beanType.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Error trying to create the prototypeEntityBean for " + beanType, e);
|
||||
}
|
||||
@@ -814,7 +814,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
int propertyLength = toEbi.getPropertyLength();
|
||||
String[] names = getProperties();
|
||||
for (int i = 0; i < propertyLength; i++) {
|
||||
|
||||
if (fromEbi.isLoadedProperty(i)) {
|
||||
BeanProperty property = getBeanProperty(names[i]);
|
||||
if (!toEbi.isLoadedProperty(i)) {
|
||||
@@ -1865,17 +1864,23 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
}
|
||||
|
||||
/**
|
||||
* We actually need to do a query because we don't know the type without the discriminator
|
||||
* value, just select the id property and discriminator column (auto added)
|
||||
* We actually need to do a query because we don't know the type without the discriminator value.
|
||||
*/
|
||||
private T findReferenceBean(Object id, PersistenceContext pc) {
|
||||
DefaultOrmQuery<T> query = new DefaultOrmQuery<>(this, ebeanServer, ebeanServer.getExpressionFactory());
|
||||
query.setPersistenceContext(pc);
|
||||
return query
|
||||
// .select(getIdProperty().getName())
|
||||
// we do not select the id because we
|
||||
// probably have to load the entire bean
|
||||
.setId(id).findOne();
|
||||
return query.setId(id).findOne();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a reference with a check for the bean in the persistence context.
|
||||
*/
|
||||
public EntityBean createReference(Boolean readOnly, Object id, PersistenceContext pc) {
|
||||
Object refBean = contextGet(pc, id);
|
||||
if (refBean == null) {
|
||||
refBean = createReference(readOnly, false, id, pc);
|
||||
}
|
||||
return (EntityBean)refBean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2087,6 +2092,13 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the simple name of the entity bean.
|
||||
*/
|
||||
public String getSimpleName() {
|
||||
return beanType.getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Summary description.
|
||||
*/
|
||||
@@ -2271,8 +2283,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
*/
|
||||
public void lazyLoadRegister(String prefix, EntityBeanIntercept ebi, EntityBean bean, LoadContext loadContext) {
|
||||
// load the List/Set/Map proxy objects (deferred fetching of lists)
|
||||
BeanPropertyAssocMany<?>[] manys = propertiesMany();
|
||||
for (BeanPropertyAssocMany<?> many : manys) {
|
||||
for (BeanPropertyAssocMany<?> many : propertiesMany()) {
|
||||
if (!ebi.isLoadedProperty(many.getPropertyIndex())) {
|
||||
BeanCollection<?> ref = many.createReferenceIfNull(bean);
|
||||
if (ref != null && !ref.isRegisteredWithLoadContext()) {
|
||||
|
||||
+1
-42
@@ -89,7 +89,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
|
||||
BeanDescriptorCacheHelp(BeanDescriptor<T> desc, SpiCacheManager cacheManager, CacheOptions cacheOptions,
|
||||
boolean cacheSharableBeans, BeanPropertyAssocOne<?>[] propertiesOneImported) {
|
||||
|
||||
this.desc = desc;
|
||||
this.beanType = desc.rootBeanType;
|
||||
this.cacheName = beanType.getSimpleName();
|
||||
@@ -99,7 +98,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
this.cacheSharableBeans = cacheSharableBeans;
|
||||
this.propertiesOneImported = propertiesOneImported;
|
||||
this.naturalKey = cacheOptions.getNaturalKey();
|
||||
|
||||
if (!cacheOptions.isEnableQueryCache()) {
|
||||
this.queryCache = null;
|
||||
} else {
|
||||
@@ -133,7 +131,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
void deriveNotifyFlags() {
|
||||
cacheNotifyOnAll = (invalidateQueryCache || beanCache != null || queryCache != null);
|
||||
cacheNotifyOnDelete = !cacheNotifyOnAll && isNotifyOnDeletes();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
if (cacheNotifyOnAll || cacheNotifyOnDelete) {
|
||||
String notifyMode = cacheNotifyOnAll ? "All" : "Delete";
|
||||
@@ -292,7 +289,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
* Try to load the bean collection from cache return true if successful.
|
||||
*/
|
||||
boolean manyPropLoad(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, Object parentId, Boolean readOnly) {
|
||||
|
||||
if (many.isElementCollection()) {
|
||||
// held as part of the bean cache so skip
|
||||
return false;
|
||||
@@ -307,14 +303,12 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
EntityBean ownerBean = bc.getOwnerBean();
|
||||
EntityBeanIntercept ebi = ownerBean._ebean_getIntercept();
|
||||
PersistenceContext persistenceContext = ebi.getPersistenceContext();
|
||||
|
||||
BeanDescriptor<?> targetDescriptor = many.getTargetDescriptor();
|
||||
|
||||
List<Object> idList = entry.getIdList();
|
||||
bc.checkEmptyLazyLoad();
|
||||
for (Object id : idList) {
|
||||
Object refBean = targetDescriptor.createReference(readOnly, false, id, persistenceContext);
|
||||
many.add(bc, (EntityBean) refBean);
|
||||
many.add(bc, targetDescriptor.createReference(readOnly, id, persistenceContext));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -323,7 +317,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
* Put the beanCollection into the cache.
|
||||
*/
|
||||
void manyPropPut(BeanPropertyAssocMany<?> many, Object details, Object parentId) {
|
||||
|
||||
if (many.isElementCollection()) {
|
||||
CachedBeanData data = (CachedBeanData) beanCache.get(parentId);
|
||||
if (data != null) {
|
||||
@@ -351,7 +344,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
}
|
||||
|
||||
void cachePutManyIds(Object parentId, String manyName, CachedManyIds entry) {
|
||||
|
||||
ServerCache collectionIdsCache = cacheManager.getCollectionIdsCache(beanType, manyName);
|
||||
if (manyLog.isDebugEnabled()) {
|
||||
manyLog.debug(" PUT {}({}).{} - ids:{}", cacheName, parentId, manyName, entry);
|
||||
@@ -360,7 +352,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
}
|
||||
|
||||
private CachedManyIds createManyIds(BeanPropertyAssocMany<?> many, Object details) {
|
||||
|
||||
Collection<?> actualDetails = BeanCollectionUtil.getActualDetails(details);
|
||||
if (actualDetails == null) {
|
||||
return null;
|
||||
@@ -378,7 +369,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
* Hit the bean cache with the given ids returning the hits.
|
||||
*/
|
||||
BeanCacheResult<T> cacheIdLookup(PersistenceContext context, Collection<?> ids) {
|
||||
|
||||
Set<Object> keys = new HashSet<>(ids.size());
|
||||
for (Object id : ids) {
|
||||
keys.add(desc.cacheKey(id));
|
||||
@@ -395,7 +385,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
T bean = convertToBean(entry.getKey(), false, context, cachedBeanData);
|
||||
result.add(bean, desc.getBeanId(bean));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -403,14 +392,12 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
* Use natural keys to hit the bean cache and return resulting hits.
|
||||
*/
|
||||
BeanCacheResult<T> naturalKeyLookup(PersistenceContext context, Set<Object> keys) {
|
||||
|
||||
if (context == null) {
|
||||
context = new DefaultPersistenceContext();
|
||||
}
|
||||
|
||||
// naturalKey -> Id map
|
||||
Map<Object, Object> naturalKeyMap = naturalKeyCache.getAll(keys);
|
||||
|
||||
if (natLog.isTraceEnabled()) {
|
||||
natLog.trace(" MLOOKUP {}({}) - hits:{}", cacheName, keys, naturalKeyMap);
|
||||
}
|
||||
@@ -433,15 +420,12 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
}
|
||||
// process the hits into beans etc
|
||||
for (Map.Entry<Object, Object> entry : beanDataMap.entrySet()) {
|
||||
|
||||
Object id = entry.getKey();
|
||||
CachedBeanData cachedBeanData = (CachedBeanData) entry.getValue();
|
||||
|
||||
T bean = convertToBean(id, false, context, cachedBeanData);
|
||||
Object naturalKey = reverseMap.get(id);
|
||||
result.add(bean, naturalKey);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -452,7 +436,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
if (context == null) {
|
||||
context = new DefaultPersistenceContext();
|
||||
}
|
||||
|
||||
// Not using a loadContext for beans coming out of L2 cache
|
||||
// so that means no batch lazy loading for these beans
|
||||
EntityBean entityBean = (EntityBean) bean;
|
||||
@@ -522,7 +505,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
* Put a bean into the bean cache.
|
||||
*/
|
||||
void beanCachePut(EntityBean bean) {
|
||||
|
||||
if (desc.inheritInfo != null) {
|
||||
desc.descOf(bean.getClass()).cacheBeanPutDirect(bean);
|
||||
} else {
|
||||
@@ -531,7 +513,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
}
|
||||
|
||||
void beanCachePutAllDirect(Collection<EntityBean> beans) {
|
||||
|
||||
Map<Object, Object> natKeys = null;
|
||||
if (naturalKey != null) {
|
||||
natKeys = new LinkedHashMap<>();
|
||||
@@ -566,15 +547,12 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
* Put the bean into the bean cache.
|
||||
*/
|
||||
void beanCachePutDirect(EntityBean bean) {
|
||||
|
||||
CachedBeanData beanData = beanExtractData(desc, bean);
|
||||
|
||||
String key = desc.cacheKeyForBean(bean);
|
||||
if (beanLog.isDebugEnabled()) {
|
||||
beanLog.debug(" PUT {}({}) data:{}", cacheName, key, beanData);
|
||||
}
|
||||
getBeanCache().put(key, beanData);
|
||||
|
||||
if (naturalKey != null) {
|
||||
String naturalKey = calculateNaturalKey(beanData);
|
||||
if (naturalKey != null) {
|
||||
@@ -618,7 +596,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
* Return a bean from the bean cache.
|
||||
*/
|
||||
private T beanCacheGetInternal(String key, Boolean readOnly, PersistenceContext context) {
|
||||
|
||||
CachedBeanData data = (CachedBeanData) getBeanCache().get(key);
|
||||
if (data == null) {
|
||||
if (beanLog.isTraceEnabled()) {
|
||||
@@ -646,7 +623,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
return (T) bean;
|
||||
}
|
||||
}
|
||||
|
||||
return (T) loadBean(id, readOnly, data, context);
|
||||
}
|
||||
|
||||
@@ -654,7 +630,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
* Load the entity bean taking into account inheritance.
|
||||
*/
|
||||
private EntityBean loadBean(Object id, Boolean readOnly, CachedBeanData data, PersistenceContext context) {
|
||||
|
||||
String discValue = data.getDiscValue();
|
||||
if (discValue == null) {
|
||||
return loadBeanDirect(id, readOnly, data, context);
|
||||
@@ -674,7 +649,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
* Load the entity bean from cache data given this is the root bean type.
|
||||
*/
|
||||
EntityBean loadBeanDirect(Object id, Boolean readOnly, CachedBeanData data, PersistenceContext context) {
|
||||
|
||||
id = desc.convertId(id);
|
||||
EntityBean bean = null;
|
||||
if (context == null) {
|
||||
@@ -682,7 +656,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
} else {
|
||||
bean = (EntityBean) desc.contextGet(context, id);
|
||||
}
|
||||
|
||||
if (bean == null) {
|
||||
bean = desc.createEntityBean();
|
||||
desc.setId(id, bean);
|
||||
@@ -698,7 +671,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
}
|
||||
|
||||
CachedBeanDataToBean.load(desc, bean, data, context);
|
||||
|
||||
if (desc.isReadAuditing()) {
|
||||
desc.readAuditBean("l2", "", bean);
|
||||
}
|
||||
@@ -709,7 +681,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
* Load the embedded bean checking for inheritance.
|
||||
*/
|
||||
EntityBean embeddedBeanLoad(CachedBeanData data, PersistenceContext context) {
|
||||
|
||||
String discValue = data.getDiscValue();
|
||||
if (discValue == null) {
|
||||
return embeddedBeanLoadDirect(data, context);
|
||||
@@ -746,25 +717,20 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
* Load a batch of entities from L2 bean cache checking the lazy loaded property is loaded.
|
||||
*/
|
||||
Set<EntityBeanIntercept> beanCacheLoadAll(List<EntityBeanIntercept> list, PersistenceContext context, int lazyLoadProperty, String propertyName) {
|
||||
|
||||
Map<Object, EntityBeanIntercept> ebis = new HashMap<>();
|
||||
for (EntityBeanIntercept ebi : list) {
|
||||
ebis.put(desc.cacheKeyForBean(ebi.getOwner()), ebi);
|
||||
}
|
||||
|
||||
|
||||
Map<Object, Object> hits = getBeanCache().getAll(ebis.keySet());
|
||||
|
||||
if (beanLog.isTraceEnabled()) {
|
||||
beanLog.trace(" MLOAD {}({}) - got hits ({})", cacheName, ebis.keySet(), hits.size());
|
||||
}
|
||||
|
||||
Set<EntityBeanIntercept> loaded = new HashSet<>();
|
||||
|
||||
Iterator<Map.Entry<Object, Object>> iterator = hits.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<Object, Object> hit = iterator.next();
|
||||
|
||||
Object key = hit.getKey();
|
||||
EntityBeanIntercept ebi = ebis.remove(key);
|
||||
CachedBeanData cacheData = (CachedBeanData) hit.getValue();
|
||||
@@ -774,7 +740,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
beanLog.trace(" load {}({}) - cache miss on property({})", cacheName, key, propertyName);
|
||||
}
|
||||
iterator.remove();
|
||||
|
||||
} else {
|
||||
CachedBeanDataToBean.load(desc, ebi.getOwner(), cacheData, context);
|
||||
loaded.add(ebi);
|
||||
@@ -783,11 +748,9 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ebis.isEmpty() && beanLog.isTraceEnabled()) {
|
||||
beanLog.trace(" load {}({}) - cache miss", cacheName, ebis.keySet());
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
@@ -795,7 +758,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
* Returns true if it managed to populate/load the single bean from the cache.
|
||||
*/
|
||||
boolean beanCacheLoad(EntityBean bean, EntityBeanIntercept ebi, String key, PersistenceContext context) {
|
||||
|
||||
CachedBeanData cacheData = (CachedBeanData) getBeanCache().get(key);
|
||||
if (cacheData == null) {
|
||||
if (beanLog.isTraceEnabled()) {
|
||||
@@ -810,7 +772,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CachedBeanDataToBean.load(desc, bean, cacheData, context);
|
||||
if (beanLog.isDebugEnabled()) {
|
||||
beanLog.debug(" LOAD {}({}) - hit", cacheName, key);
|
||||
@@ -932,7 +893,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
* Apply changes to the bean cache entry.
|
||||
*/
|
||||
void cacheBeanUpdate(String key, Map<String, Object> changes, boolean updateNaturalKey, long version) {
|
||||
|
||||
ServerCache cache = getBeanCache();
|
||||
CachedBeanData existingData = (CachedBeanData) cache.get(key);
|
||||
if (existingData != null) {
|
||||
@@ -952,7 +912,6 @@ final class BeanDescriptorCacheHelp<T> {
|
||||
}
|
||||
cache.put(key, newData);
|
||||
}
|
||||
|
||||
if (updateNaturalKey) {
|
||||
Object oldKey = calculateNaturalKey(existingData);
|
||||
if (oldKey != null) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -14,13 +14,32 @@ import java.util.Arrays;
|
||||
*/
|
||||
abstract class BeanDescriptorElement<T> extends BeanDescriptor<T> {
|
||||
|
||||
private final String simpleName;
|
||||
|
||||
final ElementHelp elementHelp;
|
||||
|
||||
BeanDescriptorElement(BeanDescriptorMap owner, DeployBeanDescriptor<T> deploy, ElementHelp elementHelp) {
|
||||
super(owner, deploy);
|
||||
this.simpleName = shortName(deploy.getName());
|
||||
this.elementHelp = elementHelp;
|
||||
}
|
||||
|
||||
private String shortName(String name) {
|
||||
int pos = name.lastIndexOf('.');
|
||||
if (pos > 1) {
|
||||
pos = name.lastIndexOf('.', pos - 1);
|
||||
if (pos > 1) {
|
||||
return name.substring(pos + 1);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSimpleName() {
|
||||
return simpleName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJsonReadCollection() {
|
||||
return true;
|
||||
|
||||
+1
-2
@@ -1,12 +1,11 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.api.json.SpiJsonReader;
|
||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
+1
-1
@@ -5,10 +5,10 @@ import com.fasterxml.jackson.core.JsonToken;
|
||||
import io.ebean.PersistenceIOException;
|
||||
import io.ebean.SqlUpdate;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.api.json.SpiJsonReader;
|
||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
+1
-1
@@ -2,10 +2,10 @@ package io.ebeaninternal.server.deploy;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.api.json.SpiJsonReader;
|
||||
import io.ebeaninternal.api.json.SpiJsonWriter;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
+17
-108
@@ -16,6 +16,7 @@ import io.ebean.config.dbplatform.DbHistorySupport;
|
||||
import io.ebean.config.dbplatform.DbIdentity;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.config.dbplatform.PlatformIdGenerator;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.event.changelog.ChangeLogFilter;
|
||||
import io.ebean.event.changelog.ChangeLogListener;
|
||||
import io.ebean.event.changelog.ChangeLogPrepare;
|
||||
@@ -56,7 +57,6 @@ import io.ebeaninternal.server.persist.platform.MultiValueBind;
|
||||
import io.ebeaninternal.server.properties.BeanPropertiesReader;
|
||||
import io.ebeaninternal.server.properties.BeanPropertyAccess;
|
||||
import io.ebeaninternal.server.properties.EnhanceBeanPropertyAccess;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.ScalarTypeInteger;
|
||||
import io.ebeaninternal.server.type.TypeManager;
|
||||
import io.ebeaninternal.xmapping.api.XmapEbean;
|
||||
@@ -117,6 +117,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
private final TypeManager typeManager;
|
||||
private final BootupClasses bootupClasses;
|
||||
private final String serverName;
|
||||
private final List<BeanDescriptor<?>> elementDescriptors = new ArrayList<>();
|
||||
private final Map<Class<?>, BeanTable> beanTableMap = new HashMap<>();
|
||||
private final Map<String, BeanDescriptor<?>> descMap = new HashMap<>();
|
||||
private final Map<String, BeanDescriptor<?>> descQueueMap = new HashMap<>();
|
||||
@@ -202,7 +203,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Run periodic trim of query plans.
|
||||
*/
|
||||
public void scheduleBackgroundTrim() {
|
||||
backgroundExecutor.executePeriodically(this::trimQueryPlans, 117L, 60L, TimeUnit.SECONDS);
|
||||
backgroundExecutor.scheduleWithFixedDelay(this::trimQueryPlans, 117L, 60L, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void trimQueryPlans() {
|
||||
@@ -237,7 +238,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Return the versions between timestamp suffix based on the DbHistorySupport.
|
||||
*/
|
||||
private String getVersionsBetweenSuffix(DatabasePlatform databasePlatform, DatabaseConfig serverConfig) {
|
||||
|
||||
DbHistorySupport historySupport = databasePlatform.getHistorySupport();
|
||||
// with historySupport returns a simple view suffix or the sql2011 versions between timestamp suffix
|
||||
return (historySupport == null) ? serverConfig.getAsOfViewSuffix() : historySupport.getVersionsBetweenSuffix(serverConfig.getAsOfViewSuffix());
|
||||
@@ -361,7 +361,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void readEntityMapping(ClassLoader classLoader, XmapEntity entityDeploy) {
|
||||
|
||||
String entityClassName = entityDeploy.getClazz();
|
||||
Class<?> entityClass;
|
||||
try {
|
||||
@@ -411,7 +410,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* For SQL based modifications we need to invalidate appropriate parts of the cache.
|
||||
*/
|
||||
public void cacheNotify(TransactionEventTable.TableIUD tableIUD, CacheChangeSet changeSet) {
|
||||
|
||||
String tableName = tableIUD.getTableName().toLowerCase();
|
||||
List<BeanDescriptor<?>> normalBeanTypes = tableToDescMap.get(tableName);
|
||||
if (normalBeanTypes != null) {
|
||||
@@ -447,7 +445,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Invalidate entity beans based on views via their dependent tables.
|
||||
*/
|
||||
public void processViewInvalidation(Set<String> viewInvalidation) {
|
||||
|
||||
for (String depTable : viewInvalidation) {
|
||||
List<BeanDescriptor<?>> list = tableToViewDescMap.get(depTable.toLowerCase());
|
||||
if (list != null) {
|
||||
@@ -460,12 +457,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
/**
|
||||
* Build a map of table names to BeanDescriptors.
|
||||
* <p>
|
||||
* This is generally used to maintain caches from table names.
|
||||
* </p>
|
||||
*/
|
||||
private void readTableToDescriptor() {
|
||||
|
||||
for (BeanDescriptor<?> desc : descMap.values()) {
|
||||
String baseTable = desc.getBaseTable();
|
||||
if (baseTable != null) {
|
||||
@@ -489,7 +482,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void readForeignKeys() {
|
||||
|
||||
for (BeanDescriptor<?> d : descMap.values()) {
|
||||
d.initialiseFkeys();
|
||||
}
|
||||
@@ -500,18 +492,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* <p>
|
||||
* This occurs after all the BeanDescriptors have been created. This resolves
|
||||
* circular relationships between BeanDescriptors.
|
||||
* </p>
|
||||
* <p>
|
||||
* Also responsible for creating all the BeanManagers which contain the
|
||||
* persister, listener etc.
|
||||
* </p>
|
||||
*/
|
||||
private void initialiseAll() {
|
||||
|
||||
// now that all the BeanDescriptors are in their map
|
||||
// we can initialise them which sorts out circular
|
||||
// dependencies for OneToMany and ManyToOne etc
|
||||
|
||||
BeanDescriptorInitContext initContext = new BeanDescriptorInitContext(asOfTableMap, draftTableMap, asOfViewSuffix);
|
||||
|
||||
// PASS 1:
|
||||
@@ -569,7 +557,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void checkMissingHashCodeOrEquals(Exception source, Class<?> idType, Class<?> beanType) {
|
||||
|
||||
String msg = "SERIOUS ERROR: The hashCode() and equals() methods *MUST* be implemented ";
|
||||
msg += "on Embedded bean " + idType + " as it is used as an Id for " + beanType;
|
||||
throw new PersistenceException(msg, source);
|
||||
@@ -603,7 +590,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> BeanManager<T> getBeanManager(Class<T> entityType) {
|
||||
|
||||
return (BeanManager<T>) getBeanManager(entityType.getName());
|
||||
}
|
||||
|
||||
@@ -615,14 +601,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Create the BeanControllers, BeanFinders and BeanListeners.
|
||||
*/
|
||||
private void createListeners() {
|
||||
|
||||
int qa = beanQueryAdapterManager.getRegisterCount();
|
||||
int cc = persistControllerManager.getRegisterCount();
|
||||
int pl = postLoadManager.getRegisterCount();
|
||||
int pc = postConstructManager.getRegisterCount();
|
||||
int lc = persistListenerManager.getRegisterCount();
|
||||
int fc = beanFinderManager.getRegisterCount();
|
||||
|
||||
logger.debug("BeanPersistControllers[{}] BeanFinders[{}] BeanPersistListeners[{}] BeanQueryAdapters[{}] BeanPostLoaders[{}] BeanPostConstructors[{}]", cc, fc, lc, qa, pl, pc);
|
||||
}
|
||||
|
||||
@@ -639,11 +623,16 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void registerBeanDescriptor(DeployBeanInfo<?> info) {
|
||||
BeanDescriptor desc = new BeanDescriptor<>(this, info.getDescriptor());
|
||||
BeanDescriptor<?> desc = new BeanDescriptor<>(this, info.getDescriptor());
|
||||
descMap.put(desc.getBeanType().getName(), desc);
|
||||
if (desc.isDocStoreMapped()) {
|
||||
descQueueMap.put(desc.getDocStoreQueueId(), desc);
|
||||
}
|
||||
for (BeanPropertyAssocMany<?> many : desc.propertiesMany()) {
|
||||
if (many.isElementCollection()) {
|
||||
elementDescriptors.add(many.getElementDescriptor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -651,10 +640,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* <p>
|
||||
* This stops short of reading relationship meta data until after the
|
||||
* BeanTables have all been created.
|
||||
* </p>
|
||||
*/
|
||||
private void readEntityDeploymentInitial() {
|
||||
|
||||
for (Class<?> entityClass : bootupClasses.getEntities()) {
|
||||
DeployBeanInfo<?> info = createDeployBeanInfo(entityClass);
|
||||
deployInfoMap.put(entityClass, info);
|
||||
@@ -687,15 +674,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Create the BeanTable information which has the base table and id.
|
||||
* <p>
|
||||
* This is determined prior to resolving relationship information.
|
||||
* </p>
|
||||
*/
|
||||
private void readEntityBeanTable() {
|
||||
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
BeanTable beanTable = createBeanTable(info);
|
||||
beanTableMap.put(beanTable.getBeanType(), beanTable);
|
||||
}
|
||||
|
||||
// register non-id embedded beans (after bean tables are created)
|
||||
for (DeployBeanInfo<?> info : embeddedBeans) {
|
||||
registerEmbeddedBean(info);
|
||||
@@ -706,17 +690,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Create the BeanTable information which has the base table and id.
|
||||
* <p>
|
||||
* This is determined prior to resolving relationship information.
|
||||
* </p>
|
||||
*/
|
||||
private void readEntityDeploymentAssociations() {
|
||||
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
readDeployAssociations(info);
|
||||
}
|
||||
}
|
||||
|
||||
private void readInheritedIdGenerators() {
|
||||
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
DeployBeanDescriptor<?> descriptor = info.getDescriptor();
|
||||
InheritInfo inheritInfo = descriptor.getInheritInfo();
|
||||
@@ -734,17 +715,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Create the BeanTable from the deployment information gathered so far.
|
||||
*/
|
||||
private BeanTable createBeanTable(DeployBeanInfo<?> info) {
|
||||
|
||||
DeployBeanDescriptor<?> deployDescriptor = info.getDescriptor();
|
||||
DeployBeanTable beanTable = deployDescriptor.createDeployBeanTable();
|
||||
return new BeanTable(beanTable, this);
|
||||
}
|
||||
|
||||
private void readEntityRelationships() {
|
||||
|
||||
// We only perform 'circular' checks etc after we have
|
||||
// all the DeployBeanDescriptors created and in the map.
|
||||
|
||||
List<DeployBeanPropertyAssocOne<?>> primaryKeyJoinCheck = new ArrayList<>();
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
checkMappedBy(info, primaryKeyJoinCheck);
|
||||
@@ -752,15 +730,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
for (DeployBeanPropertyAssocOne<?> prop : primaryKeyJoinCheck) {
|
||||
checkUniDirectionalPrimaryKeyJoin(prop);
|
||||
}
|
||||
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
secondaryPropsJoins(info);
|
||||
}
|
||||
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
setInheritanceInfo(info);
|
||||
}
|
||||
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
if (!info.isEmbedded()) {
|
||||
registerBeanDescriptor(info);
|
||||
@@ -769,12 +744,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the inheritance info. ~EMG fix for join problem
|
||||
*
|
||||
* @param info the new inheritance info
|
||||
* Sets the inheritance info.
|
||||
*/
|
||||
private void setInheritanceInfo(DeployBeanInfo<?> info) {
|
||||
|
||||
for (DeployBeanPropertyAssocOne<?> oneProp : info.getDescriptor().propertiesAssocOne()) {
|
||||
if (!oneProp.isTransient()) {
|
||||
DeployBeanInfo<?> assoc = deployInfoMap.get(oneProp.getTargetType());
|
||||
@@ -783,7 +755,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (DeployBeanPropertyAssocMany<?> manyProp : info.getDescriptor().propertiesAssocMany()) {
|
||||
if (!manyProp.isTransient()) {
|
||||
DeployBeanInfo<?> assoc = deployInfoMap.get(manyProp.getTargetType());
|
||||
@@ -795,7 +766,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void secondaryPropsJoins(DeployBeanInfo<?> info) {
|
||||
|
||||
DeployBeanDescriptor<?> descriptor = info.getDescriptor();
|
||||
for (DeployBeanProperty prop : descriptor.propertiesBase()) {
|
||||
if (prop.isSecondaryTable()) {
|
||||
@@ -819,10 +789,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* This will read join information defined on the 'owning/other' side of the
|
||||
* relationship. It also does some extra work for unidirectional
|
||||
* relationships.
|
||||
* </p>
|
||||
*/
|
||||
private void checkMappedBy(DeployBeanInfo<?> info, List<DeployBeanPropertyAssocOne<?>> primaryKeyJoinCheck) {
|
||||
|
||||
for (DeployBeanPropertyAssocOne<?> oneProp : info.getDescriptor().propertiesAssocOne()) {
|
||||
if (!oneProp.isTransient()) {
|
||||
if (oneProp.getMappedBy() != null) {
|
||||
@@ -845,14 +813,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private DeployBeanDescriptor<?> getTargetDescriptor(DeployBeanPropertyAssoc<?> prop) {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return info.getDescriptor();
|
||||
}
|
||||
|
||||
@@ -861,10 +827,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* mark it as unidirectional.
|
||||
*/
|
||||
private boolean findMappedBy(DeployBeanPropertyAssocMany<?> prop) {
|
||||
|
||||
// this is the entity bean type - that owns this property
|
||||
Class<?> owningType = prop.getOwningType();
|
||||
|
||||
Set<String> matchSet = new HashSet<>();
|
||||
|
||||
// get the bean descriptor that holds the mappedBy property
|
||||
@@ -918,7 +882,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// multiple options so should specify mappedBy property
|
||||
@@ -930,12 +893,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void makeOrderColumn(DeployBeanPropertyAssocMany<?> oneToMany) {
|
||||
|
||||
DeployBeanDescriptor<?> targetDesc = getTargetDescriptor(oneToMany);
|
||||
|
||||
DeployOrderColumn orderColumn = oneToMany.getOrderColumn();
|
||||
DeployBeanProperty orderProperty = new DeployBeanProperty(targetDesc, Integer.class, ScalarTypeInteger.INSTANCE, null);
|
||||
|
||||
orderProperty.setName(DeployOrderColumn.LOGICAL_NAME);
|
||||
orderProperty.setDbColumn(orderColumn.getName());
|
||||
orderProperty.setNullable(orderColumn.isNullable());
|
||||
@@ -943,7 +903,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
orderProperty.setDbUpdateable(orderColumn.isUpdatable());
|
||||
orderProperty.setDbRead(true);
|
||||
orderProperty.setOwningType(targetDesc.getBeanType());
|
||||
|
||||
final InheritInfo targetInheritInfo = targetDesc.getInheritInfo();
|
||||
if (targetInheritInfo != null) {
|
||||
for (InheritInfo child : targetInheritInfo.getChildren()) {
|
||||
@@ -951,7 +910,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
childDescriptor.setOrderColumn(orderProperty);
|
||||
}
|
||||
}
|
||||
|
||||
targetDesc.setOrderColumn(orderProperty);
|
||||
}
|
||||
|
||||
@@ -960,19 +918,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* unidirectional.
|
||||
* <p>
|
||||
* This means that inserts MUST cascade for this property.
|
||||
* </p>
|
||||
* <p>
|
||||
* Create a "Shadow"/Unidirectional property on the target. It is used with
|
||||
* inserts to set the foreign key value (e.g. inserts the foreign key value
|
||||
* into the order_id column on the order_lines table).
|
||||
* </p>
|
||||
*/
|
||||
private void makeUnidirectional(DeployBeanPropertyAssocMany<?> oneToMany) {
|
||||
|
||||
DeployBeanDescriptor<?> targetDesc = getTargetDescriptor(oneToMany);
|
||||
|
||||
Class<?> owningType = oneToMany.getOwningType();
|
||||
|
||||
if (!oneToMany.getCascadeInfo().isSave()) {
|
||||
// The property MUST have persist cascading so that inserts work.
|
||||
|
||||
@@ -1020,11 +973,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void checkMappedByOneToOne(DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
// check that the mappedBy property is valid and read
|
||||
// its associated join information if it is available
|
||||
String mappedBy = prop.getMappedBy();
|
||||
|
||||
// get the mappedBy property
|
||||
DeployBeanDescriptor<?> targetDesc = getTargetDescriptor(prop);
|
||||
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
|
||||
@@ -1077,10 +1028,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* <p>
|
||||
* We can use the join information from the mappedBy property and reverse it
|
||||
* for using in the OneToMany direction.
|
||||
* </p>
|
||||
*/
|
||||
private void checkMappedByOneToMany(DeployBeanInfo<?> info, DeployBeanPropertyAssocMany<?> prop) {
|
||||
|
||||
if (prop.isElementCollection()) {
|
||||
// skip mapping check
|
||||
return;
|
||||
@@ -1161,7 +1110,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* For mappedBy copy the joins from the other side.
|
||||
*/
|
||||
private void checkMappedByManyToMany(DeployBeanPropertyAssocMany<?> prop) {
|
||||
|
||||
// get the bean descriptor that holds the mappedBy property
|
||||
String mappedBy = prop.getMappedBy();
|
||||
if (mappedBy == null) {
|
||||
@@ -1222,50 +1170,40 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private <T> void setBeanControllerFinderListener(DeployBeanDescriptor<T> descriptor) {
|
||||
|
||||
persistControllerManager.addPersistControllers(descriptor);
|
||||
postLoadManager.addPostLoad(descriptor);
|
||||
postConstructManager.addPostConstructListeners(descriptor);
|
||||
persistListenerManager.addPersistListeners(descriptor);
|
||||
beanQueryAdapterManager.addQueryAdapter(descriptor);
|
||||
beanFinderManager.addFindControllers(descriptor);
|
||||
|
||||
if (changeLogRegister != null) {
|
||||
ChangeLogFilter changeFilter = changeLogRegister.getChangeFilter(descriptor.getBeanType());
|
||||
if (changeFilter != null) {
|
||||
descriptor.setChangeLogFilter(changeFilter);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the initial deployment information for a given bean type.
|
||||
*/
|
||||
private <T> DeployBeanInfo<T> createDeployBeanInfo(Class<T> beanClass) {
|
||||
|
||||
DeployBeanDescriptor<T> desc = new DeployBeanDescriptor<>(this, beanClass, config);
|
||||
beanLifecycleAdapterFactory.addLifecycleMethods(desc);
|
||||
|
||||
// set bean controller, finder and listener
|
||||
setBeanControllerFinderListener(desc);
|
||||
deplyInherit.process(desc);
|
||||
desc.checkInheritanceMapping();
|
||||
|
||||
createProperties.createProperties(desc);
|
||||
|
||||
DeployBeanInfo<T> info = new DeployBeanInfo<>(deployUtil, desc);
|
||||
|
||||
readAnnotations.readInitial(info);
|
||||
return info;
|
||||
}
|
||||
|
||||
private <T> void readDeployAssociations(DeployBeanInfo<T> info) {
|
||||
|
||||
DeployBeanDescriptor<T> desc = info.getDescriptor();
|
||||
|
||||
readAnnotations.readAssociations(info, this);
|
||||
|
||||
if (EntityType.SQL == desc.getEntityType()) {
|
||||
desc.setBaseTable(null, null, null);
|
||||
}
|
||||
@@ -1273,15 +1211,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
// mark transient properties
|
||||
transientProperties.process(desc);
|
||||
setScalarType(desc);
|
||||
|
||||
if (!desc.isEmbedded()) {
|
||||
// Set IdGenerator or use DB Identity
|
||||
setIdGeneration(desc);
|
||||
|
||||
// find the appropriate default concurrency mode
|
||||
setConcurrencyMode(desc);
|
||||
}
|
||||
|
||||
// generate the byte code
|
||||
createByteCode(desc);
|
||||
}
|
||||
@@ -1290,7 +1225,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Set the Identity generation mechanism.
|
||||
*/
|
||||
private <T> void setIdGeneration(DeployBeanDescriptor<T> desc) {
|
||||
|
||||
if (desc.getIdGenerator() != null) {
|
||||
// already assigned (So custom or UUID)
|
||||
return;
|
||||
@@ -1298,7 +1232,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
if (desc.idProperty() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final DeployIdentityMode identityMode = desc.getIdentityMode();
|
||||
if (identityMode.isSequence() && !dbIdentity.isSupportsSequence()) {
|
||||
// explicit sequence but not supported by the DatabasePlatform
|
||||
@@ -1355,11 +1288,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void createByteCode(DeployBeanDescriptor<?> deploy) {
|
||||
|
||||
// check to see if the bean supports EntityBean interface
|
||||
// generate a subclass if required
|
||||
setEntityBeanClass(deploy);
|
||||
|
||||
// use Code generation or Standard reflection to support
|
||||
// getter and setter methods
|
||||
setBeanReflect(deploy);
|
||||
@@ -1373,10 +1304,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* <p>
|
||||
* Enums are treated a bit differently in that they always have a ScalarType
|
||||
* as one is built for them.
|
||||
* </p>
|
||||
*/
|
||||
private void setScalarType(DeployBeanDescriptor<?> deployDesc) {
|
||||
|
||||
for (DeployBeanProperty prop : deployDesc.propertiesAll()) {
|
||||
if (!(prop instanceof DeployBeanPropertyAssoc<?>)) {
|
||||
deployUtil.setScalarType(prop);
|
||||
@@ -1390,17 +1319,13 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* This sets the implementation of constructing entity beans and the setting
|
||||
* and getting of properties. It is generally faster to use code generation
|
||||
* rather than reflection to do this.
|
||||
* </p>
|
||||
*/
|
||||
private void setBeanReflect(DeployBeanDescriptor<?> desc) {
|
||||
|
||||
// Set the BeanReflectGetter and BeanReflectSetter that typically
|
||||
// use generated code. NB: Due to Bug 166 so now doing this for
|
||||
// abstract classes as well.
|
||||
|
||||
BeanPropertiesReader reflectProps = new BeanPropertiesReader(desc.getBeanType());
|
||||
desc.setProperties(reflectProps.getProperties());
|
||||
|
||||
for (DeployBeanProperty prop : desc.propertiesAll()) {
|
||||
String propName = prop.getName();
|
||||
Integer pos = reflectProps.getPropertyIndex(propName);
|
||||
@@ -1410,7 +1335,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
"If you are running in an IDE with enhancement plugin try a Build -> Rebuild Project to recompile and enhance all entity beans. " +
|
||||
"Error - property " + propName + " not found in " + reflectProps + " for type " + desc.getBeanType());
|
||||
}
|
||||
|
||||
} else {
|
||||
final int propertyIndex = pos;
|
||||
prop.setPropertyIndex(propertyIndex);
|
||||
@@ -1427,7 +1351,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Return true if this is a persistent field (not transient or static).
|
||||
*/
|
||||
private boolean isPersistentField(DeployBeanProperty prop) {
|
||||
|
||||
Field field = prop.getField();
|
||||
if (field == null) {
|
||||
return false;
|
||||
@@ -1442,12 +1365,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* which contain version properties.
|
||||
*/
|
||||
private void setConcurrencyMode(DeployBeanDescriptor<?> desc) {
|
||||
|
||||
if (desc.getConcurrencyMode() != null) {
|
||||
// concurrency mode explicitly set during deployment
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkForVersionProperties(desc)) {
|
||||
desc.setConcurrencyMode(ConcurrencyMode.VERSION);
|
||||
} else {
|
||||
@@ -1459,23 +1380,16 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Search for version properties also including embedded beans.
|
||||
*/
|
||||
private boolean checkForVersionProperties(DeployBeanDescriptor<?> desc) {
|
||||
|
||||
boolean hasVersionProperty = false;
|
||||
|
||||
List<DeployBeanProperty> props = desc.propertiesBase();
|
||||
for (DeployBeanProperty prop : props) {
|
||||
for (DeployBeanProperty prop : desc.propertiesBase()) {
|
||||
if (prop.isVersionColumn()) {
|
||||
hasVersionProperty = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return hasVersionProperty;
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasEntityBeanInterface(Class<?> beanClass) {
|
||||
|
||||
Class<?>[] interfaces = beanClass.getInterfaces();
|
||||
for (Class<?> anInterface : interfaces) {
|
||||
for (Class<?> anInterface : beanClass.getInterfaces()) {
|
||||
if (anInterface.equals(EntityBean.class)) {
|
||||
return true;
|
||||
}
|
||||
@@ -1487,18 +1401,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Test the bean type to see if it implements EntityBean interface already.
|
||||
*/
|
||||
private void setEntityBeanClass(DeployBeanDescriptor<?> desc) {
|
||||
|
||||
Class<?> beanClass = desc.getBeanType();
|
||||
|
||||
if (!hasEntityBeanInterface(beanClass)) {
|
||||
String msg = "Bean " + beanClass + " is not enhanced? Check packages specified in ebean.mf. If you are running in IDEA or " +
|
||||
"Eclipse check that the enhancement plugin is installed. See https://ebean.io/docs/trouble-shooting#not-enhanced";
|
||||
throw new BeanNotEnhancedException(msg);
|
||||
}
|
||||
|
||||
// the bean already implements EntityBean
|
||||
checkInheritedClasses(beanClass);
|
||||
|
||||
entityBeanCount++;
|
||||
}
|
||||
|
||||
@@ -1507,7 +1417,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* enhanced or all dynamically subclassed).
|
||||
*/
|
||||
private void checkInheritedClasses(Class<?> beanClass) {
|
||||
|
||||
Class<?> superclass = beanClass.getSuperclass();
|
||||
if (Object.class.equals(superclass)) {
|
||||
// we got to the top of the inheritance
|
||||
@@ -1566,10 +1475,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void addPrimaryKeyJoin(DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
String baseTable = prop.getDesc().getBaseTable();
|
||||
DeployTableJoin inverse = prop.getTableJoin().createInverse(baseTable);
|
||||
|
||||
TableJoin inverseJoin = new TableJoin(inverse, prop.getForeignKey());
|
||||
DeployBeanInfo<?> target = deployInfoMap.get(prop.getTargetType());
|
||||
target.setPrimaryKeyJoin(inverseJoin);
|
||||
@@ -1586,7 +1493,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Create a BeanDescriptor for an ElementCollection target.
|
||||
*/
|
||||
public <A> BeanDescriptor<A> createElementDescriptor(DeployBeanDescriptor<A> elementDescriptor, ManyType manyType, boolean scalar) {
|
||||
|
||||
ElementHelp elementHelp = elementHelper(manyType);
|
||||
if (manyType.isMap()) {
|
||||
if (scalar) {
|
||||
@@ -1619,6 +1525,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
for (BeanDescriptor<?> desc : immutableDescriptorList) {
|
||||
desc.visitMetrics(visitor);
|
||||
}
|
||||
for (BeanDescriptor<?> desc : elementDescriptors) {
|
||||
desc.visitMetrics(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
public List<MetaQueryPlan> queryPlanInit(QueryPlanInit request) {
|
||||
|
||||
@@ -3,10 +3,10 @@ package io.ebeaninternal.server.deploy;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.EncryptKey;
|
||||
import io.ebean.config.NamingConvention;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.cache.SpiCacheManager;
|
||||
import io.ebeaninternal.server.deploy.id.IdBinder;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeanservice.docstore.api.DocStoreBeanAdapter;
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,9 @@ import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.config.EncryptKey;
|
||||
import io.ebean.config.dbplatform.DbEncryptFunction;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebean.core.type.DocPropertyType;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.plugin.Property;
|
||||
import io.ebean.text.StringParser;
|
||||
import io.ebean.util.SplitName;
|
||||
@@ -28,9 +31,7 @@ import io.ebeaninternal.server.query.STreeProperty;
|
||||
import io.ebeaninternal.server.query.SqlBeanLoad;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebeaninternal.server.type.LocalEncryptedType;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.ScalarTypeBoolean;
|
||||
import io.ebeaninternal.server.type.ScalarTypeEnum;
|
||||
import io.ebeaninternal.server.type.ScalarTypeLogicalType;
|
||||
@@ -38,7 +39,6 @@ import io.ebeaninternal.util.ValueUtil;
|
||||
import io.ebeanservice.docstore.api.mapping.DocMappingBuilder;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyOptions;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import io.ebeanservice.docstore.api.support.DocStructure;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.Query;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.core.type.DocPropertyType;
|
||||
import io.ebean.text.PathProperties;
|
||||
import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
@@ -22,7 +23,6 @@ import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.querydefn.DefaultOrmQuery;
|
||||
import io.ebeanservice.docstore.api.mapping.DocMappingBuilder;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyType;
|
||||
import io.ebeanservice.docstore.api.support.DocStructure;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -262,10 +262,16 @@ public abstract class BeanPropertyAssoc<T> extends BeanProperty implements STree
|
||||
/**
|
||||
* Return true if the target side has soft delete.
|
||||
*/
|
||||
@Override
|
||||
public boolean isTargetSoftDelete() {
|
||||
return targetDescriptor.isSoftDelete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSoftDeletePredicate(String tableAlias) {
|
||||
return targetDescriptor.getSoftDeletePredicate(tableAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if REFRESH should cascade.
|
||||
*/
|
||||
|
||||
@@ -569,6 +569,13 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
|
||||
return elementCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the element bean descriptor (for an element collection only).
|
||||
*/
|
||||
public BeanDescriptor<T> getElementDescriptor() {
|
||||
return elementDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* ManyToMany only, join from local table to intersection table.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,9 @@ import io.ebean.ValuePair;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebean.core.type.ScalarDataReader;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.util.SplitName;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
@@ -23,9 +26,6 @@ import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
import io.ebeaninternal.server.query.STreePropertyAssocOne;
|
||||
import io.ebeaninternal.server.query.SqlBeanLoad;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebeaninternal.server.type.ScalarDataReader;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -4,9 +4,9 @@ import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.server.query.STreePropertyAssocMany;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.core.type.DataReader;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.query.SqlBeanLoad;
|
||||
import io.ebeaninternal.server.type.DataReader;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.query.STreeProperty;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.el.ElPropertyDeploy;
|
||||
import io.ebeaninternal.server.query.STreeProperty;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.deploy.id;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.api.SpiExpressionRequest;
|
||||
import io.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import io.ebeaninternal.server.core.InternString;
|
||||
@@ -10,7 +11,6 @@ import io.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import io.ebeaninternal.server.persist.MultiValueWrapper;
|
||||
import io.ebeaninternal.server.persist.platform.MultiValueBind;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
|
||||
+1
-11
@@ -17,6 +17,7 @@ import io.ebean.config.ScalarTypeConverter;
|
||||
import io.ebean.config.dbplatform.DbDefaultValue;
|
||||
import io.ebean.config.dbplatform.DbEncrypt;
|
||||
import io.ebean.config.dbplatform.DbEncryptFunction;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.util.AnnotationUtil;
|
||||
import io.ebeaninternal.server.core.InternString;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
@@ -26,7 +27,6 @@ import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
import io.ebeaninternal.server.properties.BeanPropertyGetter;
|
||||
import io.ebeaninternal.server.properties.BeanPropertySetter;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.ScalarTypeWrapper;
|
||||
import io.ebeanservice.docstore.api.mapping.DocPropertyOptions;
|
||||
|
||||
@@ -34,7 +34,6 @@ import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Version;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
@@ -1140,15 +1139,6 @@ public class DeployBeanProperty {
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<Size> getMetaAnnotationSize() {
|
||||
final List<Size> size = getMetaAnnotations(Size.class);
|
||||
final List<Size.List> lists = getMetaAnnotations(Size.List.class);
|
||||
for (Size.List list : lists) {
|
||||
Collections.addAll(size, list.value());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public Formula getMetaAnnotationFormula(Platform platform) {
|
||||
Formula fallback = null;
|
||||
for (Annotation ann : metaAnnotations) {
|
||||
|
||||
+5
@@ -176,4 +176,9 @@ public abstract class DeployBeanPropertyAssoc<T> extends DeployBeanProperty {
|
||||
public void setFetchPreference(int fetchPreference) {
|
||||
this.fetchPreference = fetchPreference;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setTargetType(Class<?> targetType) {
|
||||
this.targetType = (Class<T>)targetType;
|
||||
}
|
||||
}
|
||||
|
||||
-13
@@ -65,19 +65,6 @@ public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
|
||||
this.manyType = manyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* When generics is not used for manyType you can specify via annotations.
|
||||
* <p>
|
||||
* Really only expect this for Scala due to a Scala compiler bug at the moment.
|
||||
* Otherwise I'd probably not bother support this.
|
||||
* </p>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setTargetType(Class<?> cls) {
|
||||
this.targetType = (Class<T>) cls;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the many type.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package io.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import io.ebean.config.BeanNotRegisteredException;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import io.ebeaninternal.server.deploy.BeanTable;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
|
||||
abstract class AnnotationAssoc extends AnnotationParser {
|
||||
|
||||
final BeanDescriptorManager factory;
|
||||
|
||||
AnnotationAssoc(DeployBeanInfo<?> info, ReadAnnotationConfig readConfig, BeanDescriptorManager factory) {
|
||||
super(info, readConfig);
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
void setTargetType(Class<?> targetType, DeployBeanPropertyAssoc<?> prop) {
|
||||
if (!targetType.equals(void.class)) {
|
||||
prop.setTargetType(targetType);
|
||||
}
|
||||
}
|
||||
|
||||
void setBeanTable(DeployBeanPropertyAssoc<?> prop) {
|
||||
BeanTable assoc = getBeanTable(prop);
|
||||
if (assoc == null) {
|
||||
throw new BeanNotRegisteredException(errorMsgMissingBeanTable(prop.getTargetType(), prop.getFullBeanName()));
|
||||
}
|
||||
prop.setBeanTable(assoc);
|
||||
}
|
||||
|
||||
BeanTable getBeanTable(DeployBeanPropertyAssoc<?> prop) {
|
||||
return factory.getBeanTable(prop.getTargetType());
|
||||
}
|
||||
|
||||
private String errorMsgMissingBeanTable(Class<?> type, String from) {
|
||||
return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered? See https://ebean.io/docs/trouble-shooting#not-registered";
|
||||
}
|
||||
|
||||
}
|
||||
+11
-33
@@ -5,9 +5,9 @@ import io.ebean.annotation.FetchPreference;
|
||||
import io.ebean.annotation.HistoryExclude;
|
||||
import io.ebean.annotation.Where;
|
||||
import io.ebean.bean.BeanCollection.ModifyListenMode;
|
||||
import io.ebean.config.BeanNotRegisteredException;
|
||||
import io.ebean.config.NamingConvention;
|
||||
import io.ebean.config.TableName;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebean.util.CamelCaseHelper;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
@@ -21,7 +21,6 @@ import io.ebeaninternal.server.deploy.meta.DeployOrderColumn;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.CollectionTable;
|
||||
@@ -44,16 +43,10 @@ import static io.ebean.util.StringHelper.isNull;
|
||||
/**
|
||||
* Read the deployment annotation for Assoc Many beans.
|
||||
*/
|
||||
class AnnotationAssocManys extends AnnotationParser {
|
||||
class AnnotationAssocManys extends AnnotationAssoc {
|
||||
|
||||
private final BeanDescriptorManager factory;
|
||||
|
||||
/**
|
||||
* Create with the DeployInfo.
|
||||
*/
|
||||
AnnotationAssocManys(DeployBeanInfo<?> info, ReadAnnotationConfig readConfig, BeanDescriptorManager factory) {
|
||||
super(info, readConfig);
|
||||
this.factory = factory;
|
||||
super(info, readConfig, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,15 +139,15 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
JoinTable joinTable = get(prop, JoinTable.class);
|
||||
if (joinTable != null) {
|
||||
if (prop.isManyToMany()) {
|
||||
// expected this
|
||||
readJoinTable(joinTable, prop);
|
||||
|
||||
} else {
|
||||
// OneToMany with @JoinTable
|
||||
prop.setO2mJoinTable();
|
||||
readJoinTable(joinTable, prop);
|
||||
manyToManyDefaultJoins(prop);
|
||||
}
|
||||
} else if (prop.isManyToMany()) {
|
||||
checkSelfManyToMany(prop);
|
||||
}
|
||||
|
||||
if (prop.getMappedBy() != null) {
|
||||
@@ -187,6 +180,12 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkSelfManyToMany(DeployBeanPropertyAssocMany<?> prop) {
|
||||
if (prop.getTargetType().equals(descriptor.getBeanType())) {
|
||||
throw new IllegalStateException("@ManyToMany mapping for " + prop.getFullBeanName() + " requires explicit @JoinTable with joinColumns & inverseJoinColumns. Refer issue #2157");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void readElementCollection(DeployBeanPropertyAssocMany<?> prop, ElementCollection elementCollection) {
|
||||
|
||||
@@ -435,13 +434,7 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
prop.setInverseJoin(inverseDest);
|
||||
}
|
||||
|
||||
|
||||
private String errorMsgMissingBeanTable(Class<?> type, String from) {
|
||||
return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered? See https://ebean.io/docs/trouble-shooting#not-registered";
|
||||
}
|
||||
|
||||
private void readToMany(ManyToMany propAnn, DeployBeanPropertyAssocMany<?> manyProp) {
|
||||
|
||||
manyProp.setMappedBy(propAnn.mappedBy());
|
||||
manyProp.setFetchType(propAnn.fetch());
|
||||
setCascadeTypes(propAnn.cascade(), manyProp.getCascadeInfo());
|
||||
@@ -453,7 +446,6 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
}
|
||||
|
||||
private void readToOne(OneToMany propAnn, DeployBeanPropertyAssocMany<?> manyProp) {
|
||||
|
||||
manyProp.setMappedBy(propAnn.mappedBy());
|
||||
manyProp.setFetchType(propAnn.fetch());
|
||||
setCascadeTypes(propAnn.cascade(), manyProp.getCascadeInfo());
|
||||
@@ -462,20 +454,6 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
manyProp.getTableJoin().setType(SqlJoinType.OUTER);
|
||||
}
|
||||
|
||||
private void setTargetType(Class<?> targetType, DeployBeanPropertyAssocMany<?> prop) {
|
||||
if (!targetType.equals(void.class)) {
|
||||
prop.setTargetType(targetType);
|
||||
}
|
||||
}
|
||||
|
||||
private void setBeanTable(DeployBeanPropertyAssocMany<?> manyProp) {
|
||||
BeanTable assoc = factory.getBeanTable(manyProp.getTargetType());
|
||||
if (assoc == null) {
|
||||
throw new BeanNotRegisteredException(errorMsgMissingBeanTable(manyProp.getTargetType(), manyProp.getFullBeanName()));
|
||||
}
|
||||
manyProp.setBeanTable(assoc);
|
||||
}
|
||||
|
||||
private String getM2MJoinTableName(BeanTable lhsTable, BeanTable rhsTable) {
|
||||
|
||||
TableName lhs = new TableName(lhsTable.getBaseTable());
|
||||
|
||||
+12
-34
@@ -4,13 +4,11 @@ import io.ebean.annotation.DbForeignKey;
|
||||
import io.ebean.annotation.FetchPreference;
|
||||
import io.ebean.annotation.TenantId;
|
||||
import io.ebean.annotation.Where;
|
||||
import io.ebean.config.BeanNotRegisteredException;
|
||||
import io.ebean.config.NamingConvention;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import io.ebeaninternal.server.deploy.BeanTable;
|
||||
import io.ebeaninternal.server.deploy.PropertyForeignKey;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
@@ -28,23 +26,19 @@ import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.PrimaryKeyJoinColumn;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* Read the deployment annotations for Associated One beans.
|
||||
*/
|
||||
public class AnnotationAssocOnes extends AnnotationParser {
|
||||
public class AnnotationAssocOnes extends AnnotationAssoc {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AnnotationAssocOnes.class);
|
||||
|
||||
private final BeanDescriptorManager factory;
|
||||
|
||||
/**
|
||||
* Create with the deploy Info.
|
||||
*/
|
||||
AnnotationAssocOnes(DeployBeanInfo<?> info, ReadAnnotationConfig readConfig, BeanDescriptorManager factory) {
|
||||
super(info, readConfig);
|
||||
this.factory = factory;
|
||||
super(info, readConfig, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,13 +114,10 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
if (nonNull != null) {
|
||||
prop.setNullable(false);
|
||||
}
|
||||
if (validationAnnotations) {
|
||||
NotNull notNull = get(prop, NotNull.class);
|
||||
if (notNull != null && isEbeanValidationGroups(notNull.groups())) {
|
||||
prop.setNullable(false);
|
||||
// overrides optional attribute of ManyToOne etc
|
||||
prop.getTableJoin().setType(SqlJoinType.INNER);
|
||||
}
|
||||
if (readConfig.isValidationNotNull(prop)) {
|
||||
// overrides optional attribute of ManyToOne etc
|
||||
prop.setNullable(false);
|
||||
prop.getTableJoin().setType(SqlJoinType.INNER);
|
||||
}
|
||||
|
||||
// check for manually defined joins
|
||||
@@ -191,25 +182,11 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
}
|
||||
}
|
||||
|
||||
private String errorMsgMissingBeanTable(Class<?> type, String from) {
|
||||
return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered? Does it have the @Entity annotation? See https://ebean.io/docs/trouble-shooting#not-registered";
|
||||
}
|
||||
|
||||
private BeanTable beanTable(DeployBeanPropertyAssoc<?> prop) {
|
||||
BeanTable assoc = factory.getBeanTable(prop.getPropertyType());
|
||||
if (assoc == null) {
|
||||
throw new BeanNotRegisteredException(errorMsgMissingBeanTable(prop.getPropertyType(), prop.getFullBeanName()));
|
||||
}
|
||||
return assoc;
|
||||
}
|
||||
|
||||
private void readManyToOne(ManyToOne propAnn, DeployBeanProperty prop) {
|
||||
|
||||
DeployBeanPropertyAssocOne<?> beanProp = (DeployBeanPropertyAssocOne<?>) prop;
|
||||
private void readManyToOne(ManyToOne propAnn, DeployBeanPropertyAssocOne<?> beanProp) {
|
||||
|
||||
setCascadeTypes(propAnn.cascade(), beanProp.getCascadeInfo());
|
||||
|
||||
beanProp.setBeanTable(beanTable(beanProp));
|
||||
setTargetType(propAnn.targetEntity(), beanProp);
|
||||
setBeanTable(beanProp);
|
||||
beanProp.setDbInsertable(true);
|
||||
beanProp.setDbUpdateable(true);
|
||||
beanProp.setNullable(propAnn.optional());
|
||||
@@ -232,7 +209,8 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
}
|
||||
|
||||
setCascadeTypes(propAnn.cascade(), prop.getCascadeInfo());
|
||||
prop.setBeanTable(beanTable(prop));
|
||||
setTargetType(propAnn.targetEntity(), prop);
|
||||
setBeanTable(prop);
|
||||
}
|
||||
|
||||
private boolean readOrphanRemoval(OneToOne property) {
|
||||
@@ -261,7 +239,7 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
BeanTable baseBeanTable = factory.getBeanTable(info.getDescriptor().getBeanType());
|
||||
|
||||
String localPrimaryKey = baseBeanTable.getIdColumn();
|
||||
String foreignColumn = beanTable(prop).getIdColumn();
|
||||
String foreignColumn = getBeanTable(prop).getIdColumn();
|
||||
|
||||
prop.getTableJoin().addJoinColumn(new DeployTableJoinColumn(localPrimaryKey, foreignColumn, false, false));
|
||||
}
|
||||
|
||||
+9
-17
@@ -39,6 +39,7 @@ import io.ebean.config.dbplatform.DbEncrypt;
|
||||
import io.ebean.config.dbplatform.DbEncryptFunction;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.config.dbplatform.PlatformIdGenerator;
|
||||
import io.ebean.core.type.ScalarType;
|
||||
import io.ebeaninternal.server.deploy.DbMigrationInfo;
|
||||
import io.ebeaninternal.server.deploy.IndexDefinition;
|
||||
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory;
|
||||
@@ -46,7 +47,6 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import io.ebeaninternal.server.type.DataEncryptSupport;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.ScalarTypeBytesBase;
|
||||
import io.ebeaninternal.server.type.ScalarTypeBytesEncrypted;
|
||||
import io.ebeaninternal.server.type.ScalarTypeEncryptedWrapper;
|
||||
@@ -69,8 +69,6 @@ import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.Transient;
|
||||
import javax.persistence.Version;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.sql.Types;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@@ -258,29 +256,19 @@ public class AnnotationFields extends AnnotationParser {
|
||||
}
|
||||
|
||||
private void initValidation(DeployBeanProperty prop) {
|
||||
NotNull notNull = get(prop, NotNull.class);
|
||||
if (notNull != null && isEbeanValidationGroups(notNull.groups())) {
|
||||
// Not null on all validation groups so enable
|
||||
// DDL generation of Not Null Constraint
|
||||
if (readConfig.isValidationNotNull(prop)) {
|
||||
prop.setNullable(false);
|
||||
}
|
||||
|
||||
if (!prop.isLob()) {
|
||||
// take the max size of all @Size annotations
|
||||
int maxSize = -1;
|
||||
for (Size size : prop.getMetaAnnotationSize()) {
|
||||
if (size.max() < Integer.MAX_VALUE) {
|
||||
maxSize = Math.max(maxSize, size.max());
|
||||
}
|
||||
}
|
||||
if (maxSize != -1) {
|
||||
int maxSize = readConfig.maxValidationSize(prop);
|
||||
if (maxSize > 0) {
|
||||
prop.setDbLength(maxSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initTenantId(DeployBeanProperty prop) {
|
||||
if (validationAnnotations) {
|
||||
if (readConfig.checkValidationAnnotations()) {
|
||||
initValidation(prop);
|
||||
}
|
||||
if (has(prop, TenantId.class)) {
|
||||
@@ -311,19 +299,23 @@ public class AnnotationFields extends AnnotationParser {
|
||||
DbMap dbMap = get(prop, DbMap.class);
|
||||
if (dbMap != null) {
|
||||
util.setDbMap(prop, dbMap);
|
||||
setColumnName(prop, dbMap.name());
|
||||
}
|
||||
DbJson dbJson = get(prop, DbJson.class);
|
||||
if (dbJson != null) {
|
||||
util.setDbJsonType(prop, dbJson);
|
||||
setColumnName(prop, dbJson.name());
|
||||
} else {
|
||||
DbJsonB dbJsonB = get(prop, DbJsonB.class);
|
||||
if (dbJsonB != null) {
|
||||
util.setDbJsonBType(prop, dbJsonB);
|
||||
setColumnName(prop, dbJsonB.name());
|
||||
}
|
||||
}
|
||||
DbArray dbArray = get(prop, DbArray.class);
|
||||
if (dbArray != null) {
|
||||
util.setDbArray(prop, dbArray);
|
||||
setColumnName(prop, dbArray.name());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-17
@@ -9,7 +9,6 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import javax.persistence.AttributeOverride;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.validation.groups.Default;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -26,14 +25,11 @@ public abstract class AnnotationParser extends AnnotationBase {
|
||||
|
||||
final Class<?> beanType;
|
||||
|
||||
final boolean validationAnnotations;
|
||||
|
||||
final ReadAnnotationConfig readConfig;
|
||||
|
||||
AnnotationParser(DeployBeanInfo<?> info, ReadAnnotationConfig readConfig) {
|
||||
super(info.getUtil());
|
||||
this.readConfig = readConfig;
|
||||
this.validationAnnotations = readConfig.isJavaxValidationAnnotations();
|
||||
this.info = info;
|
||||
this.beanType = info.getDescriptor().getBeanType();
|
||||
this.descriptor = info.getDescriptor();
|
||||
@@ -99,11 +95,7 @@ public abstract class AnnotationParser extends AnnotationBase {
|
||||
}
|
||||
|
||||
void readColumn(Column columnAnn, DeployBeanProperty prop) {
|
||||
|
||||
if (!isEmpty(columnAnn.name())) {
|
||||
prop.setDbColumn(databasePlatform.convertQuotedIdentifiers(columnAnn.name()));
|
||||
}
|
||||
|
||||
setColumnName(prop, columnAnn.name());
|
||||
prop.setDbInsertable(columnAnn.insertable());
|
||||
prop.setDbUpdateable(columnAnn.updatable());
|
||||
prop.setNullable(columnAnn.nullable());
|
||||
@@ -125,15 +117,10 @@ public abstract class AnnotationParser extends AnnotationBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the validation groups are {@link Default} (respectively empty)
|
||||
* can be applied to DDL generation.
|
||||
*/
|
||||
boolean isEbeanValidationGroups(Class<?>[] groups) {
|
||||
if (!util.isUseJavaxValidationNotNull()) {
|
||||
return false;
|
||||
protected void setColumnName(DeployBeanProperty prop, String name) {
|
||||
if (!isEmpty(name)) {
|
||||
prop.setDbColumn(databasePlatform.convertQuotedIdentifiers(name));
|
||||
}
|
||||
return groups.length == 0 || groups.length == 1 && Default.class.isAssignableFrom(groups[0]);
|
||||
}
|
||||
|
||||
String[] convertColumnNames(String[] columnNames) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user