Merge remote-tracking branch 'ebean/master' into pr/enh/stored_procedures_mysql_drop_column

This commit is contained in:
Jonas Pöhler
2021-11-26 15:58:50 +01:00
138 changed files with 1760 additions and 1369 deletions
+36
View File
@@ -0,0 +1,36 @@
name: Build
on: [push, pull_request]
jobs:
build:
runs-on: ${{ matrix.os }}
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
java_version: [8]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
- name: Set up Java
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java_version }}
distribution: 'adopt'
- name: Maven cache
uses: actions/cache@v2
env:
cache-name: maven-cache
with:
path:
~/.m2
key: build-${{ env.cache-name }}
- name: Build with Maven
run: mvn package
+1 -1
View File
@@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.org/ebean-orm/ebean.svg?branch=master)](https://travis-ci.org/ebean-orm/ebean)
[![Build](https://github.com/ebean-orm/ebean/actions/workflows/build.yml/badge.svg)](https://github.com/ebean-orm/ebean/actions/workflows/build.yml)
[![Maven Central : ebean](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean)
# Sponsors
+3 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</parent>
<name>ebean api</name>
@@ -36,9 +36,8 @@
-->
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-jsr305</artifactId>
<version>1.1</version>
<scope>provided</scope>
<artifactId>avaje-lang</artifactId>
<version>1.0</version>
</dependency>
<dependency>
@@ -1,5 +1,7 @@
package io.ebean;
import io.avaje.lang.NonNullApi;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
@@ -18,6 +20,7 @@ import java.util.concurrent.TimeUnit;
* This also propagates MDC context from the current thread to the
* background task if defined.
*/
@NonNullApi
public interface BackgroundExecutor {
/**
@@ -1,7 +1,7 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import java.util.List;
import java.util.Optional;
@@ -27,10 +27,10 @@ import java.util.Optional;
* @param <I> The ID type
* @param <T> The Bean type
*/
@NonNullApi
public abstract class BeanFinder<I,T> {
protected final Database server;
protected final Class<T> type;
/**
@@ -81,7 +81,6 @@ public abstract class BeanFinder<I,T> {
* <p>
* Equivalent to {@link Database#reference(Class, Object)}
*/
@Nonnull
public T ref(I id) {
return db().reference(type, id);
}
@@ -97,7 +96,6 @@ public abstract class BeanFinder<I,T> {
/**
* Find an entity by ID returning an Optional.
*/
@Nullable
public Optional<T> findByIdOrEmpty(I id) {
return db().find(type).setId(id).findOneOrEmpty();
}
@@ -112,7 +110,6 @@ public abstract class BeanFinder<I,T> {
/**
* Retrieves all entities of the given type.
*/
@Nonnull
public List<T> findAll() {
return query().findList();
}
@@ -1,5 +1,6 @@
package io.ebean;
import io.avaje.lang.NonNullApi;
import io.ebean.bean.EntityBean;
import java.util.Collection;
@@ -31,6 +32,7 @@ import java.util.Collection;
* @param <I> The ID type
* @param <T> The Bean type
*/
@NonNullApi
public abstract class BeanRepository<I, T> extends BeanFinder<I, T> {
/**
@@ -1,6 +1,5 @@
package io.ebean;
import javax.annotation.Nullable;
import java.util.Map;
import java.util.Set;
@@ -138,7 +137,6 @@ public interface BeanState {
/**
* Returns a map with load errors.
*/
@Nullable
Map<String, Exception> loadErrors();
/**
+4 -81
View File
@@ -1,13 +1,13 @@
package io.ebean;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.annotation.TxIsolation;
import io.ebean.cache.ServerCacheManager;
import io.ebean.plugin.Property;
import io.ebean.text.csv.CsvReader;
import io.ebean.text.json.JsonContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import java.util.Collection;
@@ -60,6 +60,7 @@ import java.util.concurrent.Callable;
*
* }</pre>
*/
@NonNullApi
public final class DB {
private static final DbContext context = DbContext.getInstance();
@@ -523,15 +524,13 @@ public final class DB {
* @param bean The entity bean to check uniqueness on
* @return a set of Properties if constraint validation was detected or empty list.
*/
@Nonnull
public static Set<Property> checkUniqueness(Object bean) {
return getDefault().checkUniqueness(bean);
}
/**
* Same as {@link #checkUniqueness(Object)}. but with given transaction.
* Same as {@link #checkUniqueness(Object)} but with given transaction.
*/
@Nonnull
public static Set<Property> checkUniqueness(Object bean, Transaction transaction) {
return getDefault().checkUniqueness(bean, transaction);
}
@@ -851,7 +850,6 @@ public final class DB {
* }</pre>
*/
public static <T> Update<T> createUpdate(Class<T> beanType, String ormUpdate) {
return getDefault().createUpdate(beanType, ormUpdate);
}
@@ -859,7 +857,6 @@ public final class DB {
* Create a CsvReader for a given beanType.
*/
public static <T> CsvReader<T> createCsvReader(Class<T> beanType) {
return getDefault().createCsvReader(beanType);
}
@@ -897,7 +894,6 @@ public final class DB {
* @return A ORM Query for this beanType
*/
public static <T> Query<T> createQuery(Class<T> beanType) {
return getDefault().createQuery(beanType);
}
@@ -935,7 +931,6 @@ public final class DB {
* @return The query with expressions defined as per the parsed query statement
*/
public static <T> Query<T> createQuery(Class<T> beanType, String eql) {
return getDefault().createQuery(beanType, eql);
}
@@ -951,7 +946,6 @@ public final class DB {
* @return A ORM Query object for this beanType
*/
public static <T> Query<T> find(Class<T> beanType) {
return getDefault().find(beanType);
}
@@ -1030,77 +1024,6 @@ public final class DB {
return getDefault().filter(beanType);
}
// /**
// * Execute a Sql Update Delete or Insert statement. This returns the number of
// * rows that where updated, deleted or inserted. If is executed in batch then
// * this returns -1. You can get the actual rowCount after commit() from
// * updateSql.getRowCount().
// * <p>
// * If you wish to execute a Sql Select natively then you should use the
// * FindByNativeSql object.
// * </p>
// * <p>
// * Note that the table modification information is automatically deduced and
// * you do not need to call the DB.externalModification() method when you
// * use this method.
// * </p>
// * <p>
// * Example:
// * </p>
// * <pre>{@code
// *
// * // example that uses 'named' parameters
// * String s = "UPDATE f_topic set post_count = :count where id = :id"
// *
// * SqlUpdate update = DB.createSqlUpdate(s);
// *
// * update.setParameter("id", 1);
// * update.setParameter("count", 50);
// *
// * int modifiedCount = DB.execute(update);
// *
// * String msg = "There where " + modifiedCount + "rows updated";
// *
// * }</pre>
// *
// * @param sqlUpdate the update sql potentially with bind values
// * @return the number of rows updated or deleted. -1 if executed in batch.
// * @see SqlUpdate
// * @see CallableSql
// * @see DB#execute(CallableSql)
// */
// public static int execute(SqlUpdate sqlUpdate) {
// return defaultDatabase().execute(sqlUpdate);
// }
//
// /**
// * For making calls to stored procedures.
// * <p>
// * Example:
// * </p>
// * <pre>{@code
// *
// * String sql = "{call sp_order_modify(?,?,?)}";
// *
// * CallableSql cs = DB.createCallableSql(sql);
// * cs.setParameter(1, 27);
// * cs.setParameter(2, "SHIPPED");
// * cs.registerOut(3, Types.INTEGER);
// *
// * DB.execute(cs);
// *
// * // read the out parameter
// * Integer returnValue = (Integer) cs.getObject(3);
// *
// * }</pre>
// *
// * @see CallableSql
// * @see Ebean#execute(SqlUpdate)
// */
// public static int execute(CallableSql callableSql) {
// return defaultDatabase().execute(callableSql);
// }
/**
* Execute a TxRunnable in a Transaction with an explicit scope.
* <p>
+10 -7
View File
@@ -1,5 +1,7 @@
package io.ebean;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.annotation.Platform;
import io.ebean.annotation.TxIsolation;
import io.ebean.cache.ServerCacheManager;
@@ -10,8 +12,6 @@ import io.ebean.plugin.SpiServer;
import io.ebean.text.csv.CsvReader;
import io.ebean.text.json.JsonContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
@@ -92,6 +92,7 @@ import java.util.concurrent.Callable;
* @see DatabaseFactory
* @see DatabaseConfig
*/
@NonNullApi
public interface Database {
/**
@@ -575,8 +576,8 @@ public interface Database {
<T> DtoQuery<T> createNamedDtoQuery(Class<T> dtoType, String namedQuery);
/**
* Look to execute a native sql query that does not returns beans but instead
* returns SqlRow or direct access to ResultSet (see {@link SqlQuery#findList(RowMapper)}.
* Look to execute a native sql query that does not return beans but instead
* returns SqlRow or direct access to ResultSet.
*
* <p>
* Refer to {@link DtoQuery} for native sql queries returning DTO beans.
@@ -949,7 +950,6 @@ public interface Database {
* @param beanType the type of entity bean
* @param id the id value
*/
@Nonnull
<T> T reference(Class<T> beanType, Object id);
/**
@@ -1236,6 +1236,7 @@ public interface Database {
* @param id the bean id value
* @param transaction the transaction to use (can be null)
*/
@Nullable
<T> T find(Class<T> beanType, Object id, Transaction transaction);
/**
@@ -1294,13 +1295,11 @@ public interface Database {
* @param bean The entity bean to check uniqueness on
* @return a set of Properties if constraint validation was detected or empty list.
*/
@Nonnull
Set<Property> checkUniqueness(Object bean);
/**
* Same as {@link #checkUniqueness(Object)}. but with given transaction.
*/
@Nonnull
Set<Property> checkUniqueness(Object bean, Transaction transaction);
/**
@@ -1614,6 +1613,7 @@ public interface Database {
* @param id the id of the entity bean
* @param transaction the transaction the publish process should use (can be null)
*/
@Nullable
<T> T publish(Class<T> beanType, Object id, Transaction transaction);
/**
@@ -1627,6 +1627,7 @@ public interface Database {
* @param beanType the type of the entity bean
* @param id the id of the entity bean
*/
@Nullable
<T> T publish(Class<T> beanType, Object id);
/**
@@ -1665,6 +1666,7 @@ public interface Database {
* @param id the id of the entity bean to restore
* @param transaction the transaction the restore process should use (can be null)
*/
@Nullable
<T> T draftRestore(Class<T> beanType, Object id, Transaction transaction);
/**
@@ -1678,6 +1680,7 @@ public interface Database {
* @param beanType the type of the entity bean
* @param id the id of the entity bean to restore
*/
@Nullable
<T> T draftRestore(Class<T> beanType, Object id);
/**
@@ -1,9 +1,10 @@
package io.ebean;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.docstore.DocQueryContext;
import io.ebean.docstore.RawDoc;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@@ -13,6 +14,7 @@ import java.util.function.Predicate;
/**
* Document storage operations.
*/
@NonNullApi
public interface DocumentStore {
/**
+12 -6
View File
@@ -1,7 +1,9 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
@@ -38,12 +40,12 @@ import java.util.stream.Stream;
*
* }</pre>
*/
@NonNullApi
public interface DtoQuery<T> extends CancelableQuery {
/**
* Execute the query returning a list.
*/
@Nonnull
List<T> findList();
/**
@@ -53,7 +55,6 @@ public interface DtoQuery<T> extends CancelableQuery {
* resultSet and potentially connection and MUST be closed. We should use
* QueryIterator in a <em>try with resource block</em>.
*/
@Nonnull
QueryIterator<T> findIterate();
/**
@@ -63,7 +64,6 @@ public interface DtoQuery<T> extends CancelableQuery {
* resultSet and potentially connection and MUST be closed. We should use
* the Stream in a <em>try with resource block</em>.
*/
@Nonnull
Stream<T> findStream();
/**
@@ -105,7 +105,6 @@ public interface DtoQuery<T> extends CancelableQuery {
/**
* Execute the query returning an optional bean.
*/
@Nonnull
Optional<T> findOneOrEmpty();
/**
@@ -130,6 +129,13 @@ public interface DtoQuery<T> extends CancelableQuery {
*/
DtoQuery<T> setParameter(String name, Object value);
/**
* Bind the named multi-value array parameter which we would use with Postgres ANY.
* <p>
* For Postgres this binds an ARRAY rather than expands into multiple bind values.
*/
DtoQuery<T> setArrayParameter(String name, Collection<?> values);
/**
* Bind the parameter by its index position (1 based like JDBC).
*/
+1 -4
View File
@@ -1,13 +1,12 @@
package io.ebean;
import io.avaje.lang.Nullable;
import io.ebean.annotation.TxIsolation;
import io.ebean.cache.ServerCacheManager;
import io.ebean.plugin.Property;
import io.ebean.text.csv.CsvReader;
import io.ebean.text.json.JsonContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import java.util.Collection;
@@ -506,7 +505,6 @@ public final class Ebean {
* @param bean The entity bean to check uniqueness on
* @return a set of Properties if constraint validation was detected or empty list.
*/
@Nonnull
public static Set<Property> checkUniqueness(Object bean) {
return getDefault().checkUniqueness(bean);
}
@@ -514,7 +512,6 @@ public final class Ebean {
/**
* Same as {@link #checkUniqueness(Object)}. but with given transaction.
*/
@Nonnull
public static Set<Property> checkUniqueness(Object bean, Transaction transaction) {
return getDefault().checkUniqueness(bean, transaction);
}
@@ -16,15 +16,22 @@ public class EbeanVersion {
private static final Logger log = LoggerFactory.getLogger("io.ebean");
/**
* Maintain the minimum ebean-agent version manually based on required ebean-agent bug fixes.
*/
private static final int MIN_AGENT_MAJOR_VERSION = 12;
private static final int MIN_AGENT_MINOR_VERSION = 12;
private static String version = "unknown";
static {
readVersion();
checkAgentVersion();
}
private static void readVersion() {
try {
Properties prop = new Properties();
try (InputStream in = DB.class.getResourceAsStream("/META-INF/maven/io.ebean/ebean-api/pom.properties")) {
try (InputStream in = ClassLoader.getSystemResourceAsStream("META-INF/maven/io.ebean/ebean-api/pom.properties")) {
if (in != null) {
prop.load(in);
in.close();
version = prop.getProperty("version");
version = readVersion(in);
}
}
log.info("ebean version: {}", version);
@@ -33,6 +40,49 @@ public class EbeanVersion {
}
}
private static void checkAgentVersion() {
try {
try (InputStream in = ClassLoader.getSystemResourceAsStream("META-INF/maven/io.ebean/ebean-agent/pom.properties")) {
// often we only have ebean-agent during development (with build time enhancement), null is expected
if (in != null) {
String agentVersion = readVersion(in);
if (agentVersion != null) {
if (checkMinAgentVersion(agentVersion)) {
log.error("Expected minimum ebean-agent version {}.{}.0 but we have {}, please update the ebean-agent", MIN_AGENT_MAJOR_VERSION, MIN_AGENT_MINOR_VERSION, agentVersion);
}
}
}
}
} catch (IOException e) {
log.warn("Could not check minimum ebean-agent version {}.{}.0 required due to - {}", MIN_AGENT_MAJOR_VERSION, MIN_AGENT_MINOR_VERSION, e.getMessage());
}
}
/**
* Return true if ebean-agent is NOT at our minimum version.
*/
static boolean checkMinAgentVersion(String agentVersion) {
String[] versionSegments = agentVersion.split("\\.");
if (versionSegments.length != 3) {
return true;
} else {
int major = Integer.parseInt(versionSegments[0]);
int minor = Integer.parseInt(versionSegments[1]);
if (major < MIN_AGENT_MAJOR_VERSION) {
return true;
} else {
return major == MIN_AGENT_MAJOR_VERSION && minor < MIN_AGENT_MINOR_VERSION;
}
}
}
private static String readVersion(InputStream in) throws IOException {
Properties prop = new Properties();
prop.load(in);
in.close();
return prop.getProperty("version");
}
private EbeanVersion() {
// hide
}
@@ -1,6 +1,5 @@
package io.ebean;
import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Future;
@@ -25,13 +24,11 @@ public class EmptyPagedList<T> implements PagedList<T> {
// do nothing
}
@Nonnull
@Override
public Future<Integer> getFutureCount() {
return null;
}
@Nonnull
@Override
public List<T> getList() {
return Collections.emptyList();
@@ -1,21 +1,13 @@
package io.ebean;
import io.ebean.search.Match;
import io.ebean.search.MultiMatch;
import io.ebean.search.TextCommonTerms;
import io.ebean.search.TextQueryString;
import io.ebean.search.TextSimple;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.search.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.NonUniqueResultException;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -39,6 +31,7 @@ import java.util.function.Predicate;
*
* @see Query#where()
*/
@NonNullApi
public interface ExpressionList<T> {
/**
@@ -327,7 +320,6 @@ public interface ExpressionList<T> {
*
* @see Query#findList()
*/
@Nonnull
List<T> findList();
/**
@@ -335,7 +327,6 @@ public interface ExpressionList<T> {
*
* @see Query#findIds()
*/
@Nonnull
<A> List<A> findIds();
/**
@@ -351,7 +342,6 @@ public interface ExpressionList<T> {
*
* @see Query#findSet()
*/
@Nonnull
Set<T> findSet();
/**
@@ -359,7 +349,6 @@ public interface ExpressionList<T> {
*
* @see Query#findMap()
*/
@Nonnull
<K> Map<K, T> findMap();
/**
@@ -392,7 +381,6 @@ public interface ExpressionList<T> {
*
* @return the list of values for the selected property
*/
@Nonnull
<A> List<A> findSingleAttributeList();
/**
@@ -429,7 +417,6 @@ public interface ExpressionList<T> {
/**
* Execute the query returning an optional bean.
*/
@Nonnull
Optional<T> findOneOrEmpty();
/**
@@ -442,7 +429,6 @@ public interface ExpressionList<T> {
*
* @return a Future object for the row count query
*/
@Nonnull
FutureRowCount<T> findFutureCount();
/**
@@ -455,7 +441,6 @@ public interface ExpressionList<T> {
*
* @return a Future object for the list of Id's
*/
@Nonnull
FutureIds<T> findFutureIds();
/**
@@ -468,7 +453,6 @@ public interface ExpressionList<T> {
*
* @return a Future object for the list result of the query
*/
@Nonnull
FutureList<T> findFutureList();
/**
@@ -499,7 +483,6 @@ public interface ExpressionList<T> {
* @return The PagedList
* @see Query#findPagedList()
*/
@Nonnull
PagedList<T> findPagedList();
/**
@@ -509,7 +492,6 @@ public interface ExpressionList<T> {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
List<Version<T>> findVersions();
/**
@@ -519,13 +501,11 @@ public interface ExpressionList<T> {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
/**
* Add some filter predicate expressions to the many property.
*/
@Nonnull
ExpressionList<T> filterMany(String manyProperty);
/**
@@ -1,7 +1,7 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.avaje.lang.Nullable;
import javax.persistence.NonUniqueResultException;
import java.time.Clock;
import java.util.List;
@@ -82,7 +82,6 @@ public interface ExtendedServer {
*
* @see Query#findIds()
*/
@Nonnull
<A, T> List<A> findIds(Query<T> query, Transaction transaction);
/**
@@ -100,7 +99,6 @@ public interface ExtendedServer {
* @see Query#findEach(Consumer)
* @see Query#findEachWhile(Predicate)
*/
@Nonnull
<T> QueryIterator<T> findIterate(Query<T> query, Transaction transaction);
/**
@@ -112,7 +110,6 @@ public interface ExtendedServer {
* Note that the stream needs to be closed so use with try with resources.
* </p>
*/
@Nonnull
<T> Stream<T> findStream(Query<T> query, Transaction transaction);
/**
@@ -125,7 +122,6 @@ public interface ExtendedServer {
* <p>
* Note that the stream needs to be closed so use with try with resources.
*/
@Nonnull
@Deprecated
<T> Stream<T> findLargeStream(Query<T> query, Transaction transaction);
@@ -210,7 +206,6 @@ public interface ExtendedServer {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
<T> List<Version<T>> findVersions(Query<T> query, Transaction transaction);
/**
@@ -235,7 +230,6 @@ public interface ExtendedServer {
* @return the list of fetched beans.
* @see Query#findList()
*/
@Nonnull
<T> List<T> findList(Query<T> query, Transaction transaction);
/**
@@ -251,7 +245,6 @@ public interface ExtendedServer {
* @return a Future object for the row count query
* @see Query#findFutureCount()
*/
@Nonnull
<T> FutureRowCount<T> findFutureCount(Query<T> query, Transaction transaction);
/**
@@ -267,7 +260,6 @@ public interface ExtendedServer {
* @return a Future object for the list of Id's
* @see Query#findFutureIds()
*/
@Nonnull
<T> FutureIds<T> findFutureIds(Query<T> query, Transaction transaction);
/**
@@ -284,7 +276,6 @@ public interface ExtendedServer {
* @return a Future object for the list result of the query
* @see Query#findFutureList()
*/
@Nonnull
<T> FutureList<T> findFutureList(Query<T> query, Transaction transaction);
/**
@@ -316,7 +307,6 @@ public interface ExtendedServer {
* @return The PagedList
* @see Query#findPagedList()
*/
@Nonnull
<T> PagedList<T> findPagedList(Query<T> query, Transaction transaction);
/**
@@ -341,7 +331,6 @@ public interface ExtendedServer {
* @return the set of fetched beans.
* @see Query#findSet()
*/
@Nonnull
<T> Set<T> findSet(Query<T> query, Transaction transaction);
/**
@@ -358,7 +347,6 @@ public interface ExtendedServer {
* @return the map of fetched beans.
* @see Query#findMap()
*/
@Nonnull
<K, T> Map<K, T> findMap(Query<T> query, Transaction transaction);
/**
@@ -391,7 +379,6 @@ public interface ExtendedServer {
* @return the list of values for the selected property
* @see Query#findSingleAttributeList()
*/
@Nonnull
<A, T> List<A> findSingleAttributeList(Query<T> query, Transaction transaction);
/**
@@ -419,7 +406,6 @@ public interface ExtendedServer {
/**
* Similar to findOne() but returns an Optional (rather than nullable).
*/
@Nonnull
<T> Optional<T> findOneOrEmpty(Query<T> query, Transaction transaction);
/**
@@ -463,7 +449,6 @@ public interface ExtendedServer {
* @return the list of fetched MapBean.
* @see SqlQuery#findList()
*/
@Nonnull
List<SqlRow> findList(SqlQuery query, Transaction transaction);
/**
@@ -1,9 +1,8 @@
package io.ebean;
import io.avaje.lang.NonNullApi;
import io.ebean.service.SpiFetchGroupQuery;
import javax.annotation.Nonnull;
/**
* Defines what part of the object graph to load (select and fetch clauses).
* <p>
@@ -62,6 +61,7 @@ import javax.annotation.Nonnull;
*
* @param <T> The bean type the Fetch group can be applied to
*/
@NonNullApi
public interface FetchGroup<T> {
/**
@@ -83,7 +83,6 @@ public interface FetchGroup<T> {
*
* @return The FetchGroup with the given select clause
*/
@Nonnull
static <T> FetchGroup<T> of(Class<T> cls, String select) {
return XServiceProvider.fetchGroupOf(cls, select);
}
@@ -108,7 +107,6 @@ public interface FetchGroup<T> {
*
* @return The FetchGroupBuilder with the given select clause which we will add fetch clauses to
*/
@Nonnull
static <T> FetchGroupBuilder<T> of(Class<T> cls) {
return XServiceProvider.fetchGroupOf(cls);
}
@@ -1,6 +1,6 @@
package io.ebean;
import javax.annotation.Nonnull;
import io.avaje.lang.NonNullApi;
/**
* Builds a FetchGroup by adding fetch clauses.
@@ -23,85 +23,73 @@ import javax.annotation.Nonnull;
*
* }</pre>
*/
@NonNullApi
public interface FetchGroupBuilder<T> {
/**
* Specify specific properties to select (top level properties).
*/
@Nonnull
FetchGroupBuilder<T> select(String select);
/**
* Fetch all the properties at the given path.
*/
@Nonnull
FetchGroupBuilder<T> fetch(String path);
/**
* Fetch the path with the nested fetch group.
*/
@Nonnull
FetchGroupBuilder<T> fetch(String path, FetchGroup<?> nestedGroup);
/**
* Fetch the path using a query join with the nested fetch group.
*/
@Nonnull
FetchGroupBuilder<T> fetchQuery(String path, FetchGroup<?> nestedGroup);
/**
* Fetch the path lazily with the nested fetch group.
*/
@Nonnull
FetchGroupBuilder<T> fetchLazy(String path, FetchGroup<?> nestedGroup);
/**
* Fetch the path including specified properties.
*/
@Nonnull
FetchGroupBuilder<T> fetch(String path, String properties);
/**
* Fetch the path including all its properties using a query join.
*/
@Nonnull
FetchGroupBuilder<T> fetchQuery(String path);
/**
* Fetch the path including all its properties using L2 cache.
* Cache misses fallback to fetchQuery().
*/
@Nonnull
FetchGroupBuilder<T> fetchCache(String path);
/**
* Fetch the path including specified properties using a query join.
*/
@Nonnull
FetchGroupBuilder<T> fetchQuery(String path, String properties);
/**
* Fetch the path including specified properties using L2 cache.
* Cache misses fallback to fetchQuery().
*/
@Nonnull
FetchGroupBuilder<T> fetchCache(String path, String properties);
/**
* Fetch the path including all its properties lazily.
*/
@Nonnull
FetchGroupBuilder<T> fetchLazy(String path);
/**
* Fetch the path including specified properties lazily.
*/
@Nonnull
FetchGroupBuilder<T> fetchLazy(String path, String properties);
/**
* Build and return the FetchGroup.
*/
@Nonnull
FetchGroup<T> build();
}
@@ -1,5 +1,7 @@
package io.ebean;
import io.avaje.lang.NonNullApi;
import java.util.List;
import java.util.Set;
@@ -77,6 +79,7 @@ import java.util.Set;
*
* @param <T> the entity bean type
*/
@NonNullApi
public interface Filter<T> {
/**
+3 -4
View File
@@ -1,7 +1,7 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import java.util.List;
/**
@@ -55,6 +55,7 @@ import java.util.List;
* }</pre>
*
*/
@NonNullApi
public class Finder<I, T> {
/**
@@ -139,7 +140,6 @@ public class Finder<I, T> {
* <p>
* Equivalent to {@link Database#reference(Class, Object)}
*/
@Nonnull
public T ref(I id) {
return db().reference(type, id);
}
@@ -166,7 +166,6 @@ public class Finder<I, T> {
/**
* Retrieves all entities of the given type.
*/
@Nonnull
public List<T> all() {
return query().findList();
}
@@ -113,9 +113,9 @@ public interface Junction<T> extends Expression, ExpressionList<T> {
*/
SHOULD("should", "", true);
private String prefix;
private String literal;
private boolean text;
private final String prefix;
private final String literal;
private final boolean text;
Type(String literal, String prefix, boolean text) {
this.literal = literal;
@@ -1,6 +1,5 @@
package io.ebean;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.Future;
@@ -116,13 +115,11 @@ public interface PagedList<T> {
*
* }</pre>
*/
@Nonnull
Future<Integer> getFutureCount();
/**
* Return the list of entities for this page.
*/
@Nonnull
List<T> getList();
/**
+3 -17
View File
@@ -1,7 +1,7 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import javax.persistence.NonUniqueResultException;
import java.sql.Connection;
import java.sql.Timestamp;
@@ -177,6 +177,7 @@ import java.util.stream.Stream;
*
* @param <T> the type of Entity bean this query will fetch.
*/
@NonNullApi
public interface Query<T> extends CancelableQuery {
/**
@@ -689,7 +690,6 @@ public interface Query<T> extends CancelableQuery {
* This query will execute against the Database that was used to create it.
* </p>
*/
@Nonnull
<A> List<A> findIds();
/**
@@ -727,7 +727,6 @@ public interface Query<T> extends CancelableQuery {
*
* }</pre>
*/
@Nonnull
QueryIterator<T> findIterate();
/**
@@ -749,7 +748,6 @@ public interface Query<T> extends CancelableQuery {
*
* }</pre>
*/
@Nonnull
Stream<T> findStream();
/**
@@ -772,7 +770,6 @@ public interface Query<T> extends CancelableQuery {
*
* }</pre>
*/
@Nonnull
@Deprecated
Stream<T> findLargeStream();
@@ -882,7 +879,6 @@ public interface Query<T> extends CancelableQuery {
*
* }</pre>
*/
@Nonnull
List<T> findList();
/**
@@ -898,7 +894,6 @@ public interface Query<T> extends CancelableQuery {
*
* }</pre>
*/
@Nonnull
Set<T> findSet();
/**
@@ -918,7 +913,6 @@ public interface Query<T> extends CancelableQuery {
*
* }</pre>
*/
@Nonnull
<K> Map<K, T> findMap();
/**
@@ -951,7 +945,6 @@ public interface Query<T> extends CancelableQuery {
*
* @return the list of values for the selected property
*/
@Nonnull
<A> List<A> findSingleAttributeList();
/**
@@ -1049,7 +1042,6 @@ public interface Query<T> extends CancelableQuery {
/**
* Execute the query returning an optional bean.
*/
@Nonnull
Optional<T> findOneOrEmpty();
/**
@@ -1064,7 +1056,6 @@ public interface Query<T> extends CancelableQuery {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
List<Version<T>> findVersions();
/**
@@ -1074,7 +1065,6 @@ public interface Query<T> extends CancelableQuery {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end);
/**
@@ -1132,7 +1122,6 @@ public interface Query<T> extends CancelableQuery {
*
* @return a Future object for the row count query
*/
@Nonnull
FutureRowCount<T> findFutureCount();
/**
@@ -1145,7 +1134,6 @@ public interface Query<T> extends CancelableQuery {
*
* @return a Future object for the list of Id's
*/
@Nonnull
FutureIds<T> findFutureIds();
/**
@@ -1157,7 +1145,6 @@ public interface Query<T> extends CancelableQuery {
*
* @return a Future object for the list result of the query
*/
@Nonnull
FutureList<T> findFutureList();
/**
@@ -1187,7 +1174,6 @@ public interface Query<T> extends CancelableQuery {
*
* @return The PagedList
*/
@Nonnull
PagedList<T> findPagedList();
/**
@@ -1,7 +1,7 @@
package io.ebean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
@@ -37,12 +37,12 @@ import java.util.function.Predicate;
*
* }</pre>
*/
@NonNullApi
public interface SqlQuery extends Serializable, CancelableQuery {
/**
* Execute the query returning a list.
*/
@Nonnull
List<SqlRow> findList();
/**
@@ -119,7 +119,6 @@ public interface SqlQuery extends Serializable, CancelableQuery {
/**
* Execute the query returning an optional row.
*/
@Nonnull
Optional<SqlRow> findOneOrEmpty();
/**
@@ -354,6 +353,7 @@ public interface SqlQuery extends Serializable, CancelableQuery {
/**
* Return the single value.
*/
@Nullable
T findOne();
/**
@@ -1,5 +1,7 @@
package io.ebean;
import java.util.Collection;
/**
* A SqlUpdate for executing insert update or delete statements.
* <p>
@@ -324,6 +326,13 @@ public interface SqlUpdate {
*/
SqlUpdate setParameter(String name, Object param);
/**
* Bind the named multi-value array parameter which we would use with Postgres ANY.
* <p>
* For Postgres this binds an ARRAY rather than expands into multiple bind values.
*/
SqlUpdate setArrayParameter(String name, Collection<?> values);
/**
* Set a named parameter that has a null value. Exactly the same as
* {@link #setNullParameter(String, int)}.
@@ -9,11 +9,7 @@ import javax.persistence.PersistenceException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.net.URL;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -1164,7 +1160,7 @@ public final class EntityBeanIntercept implements Serializable {
*/
public Map<String, Exception> getLoadErrors() {
if (loadErrors == null) {
return null;
return Collections.emptyMap();
}
Map<String, Exception> ret = null;
int len = getPropertyLength();
@@ -60,21 +60,15 @@ public interface PersistenceContext {
int size(Class<?> rootType);
/**
* Return a copy of the Persistence context to use for large query iteration.
* Signalizes the PersistenceContext, the begin for large query iteration.
*/
PersistenceContext forIterate();
void beginIterate();
/**
* Return a new Persistence context during iteration of large query result.
* Signalizes the PersistenceContext, the end for large query iteration.
*/
PersistenceContext forIterateReset();
/**
* Return true if the persistence context has grown and hit the 'reset limit'
* during large query iteration.
*/
boolean resetLimit();
void endIterate();
/**
* Wrapper on a bean to also indicate if a bean has been deleted.
* <p>
@@ -1547,6 +1547,9 @@ public class DatabaseConfig {
/**
* Set to true if all DB column and table names should use quoted identifiers.
* <p>
* For Postgres pgjdbc version 42.3.0 should be used with datasource property
* <em>quoteReturningIdentifiers</em> set to <em>false</em> (refer #2303).
*/
public void setAllQuotedIdentifiers(boolean allQuotedIdentifiers) {
platformConfig.setAllQuotedIdentifiers(allQuotedIdentifiers);
@@ -120,6 +120,9 @@ public class PlatformConfig {
/**
* Set to true if all DB column and table names should use quoted identifiers.
* <p>
* For Postgres pgjdbc version 42.3.0 should be used with datasource property
* <em>quoteReturningIdentifiers</em> set to <em>false</em> (refer #2303).
*/
public void setAllQuotedIdentifiers(boolean allQuotedIdentifiers) {
this.allQuotedIdentifiers = allQuotedIdentifiers;
@@ -8,7 +8,6 @@ import io.ebean.event.BeanPersistController;
import io.ebean.event.BeanPersistListener;
import io.ebean.event.BeanQueryAdapter;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
@@ -21,7 +20,6 @@ public interface BeanType<T> {
/**
* Return the short name of the bean type.
*/
@Nonnull
String name();
/**
@@ -35,7 +33,6 @@ public interface BeanType<T> {
/**
* Return the full name of the bean type.
*/
@Nonnull
String fullName();
/**
@@ -49,7 +46,6 @@ public interface BeanType<T> {
/**
* Return the class type this BeanDescriptor describes.
*/
@Nonnull
Class<T> type();
/**
@@ -76,7 +72,6 @@ public interface BeanType<T> {
/**
* Return all the properties for this bean type.
*/
@Nonnull
Collection<? extends Property> allProperties();
/**
@@ -1,7 +1,5 @@
package io.ebean.plugin;
import javax.annotation.Nonnull;
/**
* Property of a entity bean that can be read.
*/
@@ -10,7 +8,6 @@ public interface Property {
/**
* Return the name of the property.
*/
@Nonnull
String name();
/**
@@ -24,7 +21,6 @@ public interface Property {
/**
* Return the type of the property.
*/
@Nonnull
Class<?> type();
/**
@@ -20,7 +20,7 @@ public interface JsonBeanReader<T> {
/**
* Create a new reader taking the context from the existing one but using a new JsonParser.
*/
JsonBeanReader<T> forJson(JsonParser moreJson, boolean resetContext);
JsonBeanReader<T> forJson(JsonParser moreJson);
/**
* Add a bean explicitly to the persistence context.
@@ -2,6 +2,7 @@ package io.ebean.util;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -57,10 +58,8 @@ public class AnnotationUtil {
private static <A extends Annotation> void typeGetAllCollect(Class<?> clazz, Class<A> annotationType, Set<A> result) {
while (clazz != null && clazz != Object.class) {
final A val = clazz.getAnnotation(annotationType);
if (val != null) {
result.add(val);
}
final A[] annotations = clazz.getAnnotationsByType(annotationType);
Collections.addAll(result, annotations);
clazz = clazz.getSuperclass();
}
}
@@ -0,0 +1,31 @@
package io.ebean;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class EbeanVersionTest {
@Test
void checkMinAgentVersion_ok() {
assertFalse(EbeanVersion.checkMinAgentVersion("12.12.0"));
assertFalse(EbeanVersion.checkMinAgentVersion("12.12.99"));
assertFalse(EbeanVersion.checkMinAgentVersion("13.1.0"));
}
@Test
void checkMinAgentVersion_agentTooOld() {
assertTrue(EbeanVersion.checkMinAgentVersion("11.13.0"));
assertTrue(EbeanVersion.checkMinAgentVersion("12.11.0"));
assertTrue(EbeanVersion.checkMinAgentVersion("12.11.99"));
}
@Test
void checkMinAgentVersion_unexpectedAgentVersion() {
assertTrue(EbeanVersion.checkMinAgentVersion("13.13"));
assertTrue(EbeanVersion.checkMinAgentVersion("13"));
assertTrue(EbeanVersion.checkMinAgentVersion(""));
}
}
@@ -0,0 +1,28 @@
package io.ebean.util;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.File;
import java.util.Set;
import org.junit.jupiter.api.Test;
import io.ebean.annotation.Formula;
public class TestAnnotationUtil {
@Formula(select = "x")
@Formula(select = "y")
private static class TestObject {
}
@Test
public void testRepeatableAnnotation() {
Set<Formula> list = AnnotationUtil.typeGetAll(TestObject.class, Formula.class);
assertThat(list).hasSize(2);
}
}
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -26,7 +26,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
+15 -15
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</parent>
<name>ebean bom</name>
@@ -71,88 +71,88 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
</dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</parent>
<artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
+5 -5
View File
@@ -3,7 +3,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</parent>
<artifactId>ebean-core</artifactId>
@@ -41,19 +41,19 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -136,7 +136,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.20</version>
<version>42.2.24</version>
<optional>true</optional>
</dependency>
@@ -223,6 +223,15 @@ public final class BindParams implements Serializable {
return p;
}
/**
* Set a named In parameter that is multi-valued.
*/
public Param setArrayParameter(String name, Collection<?> value) {
Param p = getParam(name);
p.setInValue(new MultiValueWrapper(value));
return p;
}
/**
* Set an encryption key as a bind value.
* <p>
@@ -285,12 +294,17 @@ public final class BindParams implements Serializable {
*/
public boolean isSameBindHash() {
if (bindHash == null) {
bindHash = calcQueryPlanHash();
return false;
}
String oldPlan = bindHash;
String newHash = calcQueryPlanHash();
return bindHash.equals(newHash);
}
/**
* Updates the hash.
*/
public void updateHash() {
bindHash = calcQueryPlanHash();
return bindHash.equals(oldPlan);
}
/**
@@ -36,14 +36,6 @@ public interface LoadContext {
*/
PersistenceContext getPersistenceContext();
/**
* Set the persistence context used by this query and future lazy loading.
* <p>
* Used by query iterator when processing large result sets.
* </p>
*/
void resetPersistenceContext(PersistenceContext persistenceContext);
/**
* Register a Bean for lazy loading.
*/
@@ -16,6 +16,7 @@ import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.query.CQuery;
import io.ebeaninternal.server.transaction.RemoteTransactionEvent;
import javax.annotation.Nullable;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -141,7 +142,7 @@ public interface SpiEbeanServer extends SpiServer, ExtendedServer, EbeanServer,
/**
* Compile a query.
*/
<T> CQuery<T> compileQuery(Type type, Query<T> query, Transaction t);
<T> CQuery<T> compileQuery(Type type, Query<T> query, Transaction transaction);
/**
* Execute the findId's query but without copying the query.
@@ -150,12 +151,12 @@ public interface SpiEbeanServer extends SpiServer, ExtendedServer, EbeanServer,
* the query has finished (if executing in a background thread).
* </p>
*/
<A, T> List<A> findIdsWithCopy(Query<T> query, Transaction t);
<A, T> List<A> findIdsWithCopy(Query<T> query, Transaction transaction);
/**
* Execute the findCount query but without copying the query.
*/
<T> int findCountWithCopy(Query<T> query, Transaction t);
<T> int findCountWithCopy(Query<T> query, Transaction transaction);
/**
* Load a batch of Associated One Beans.
@@ -257,6 +258,7 @@ public interface SpiEbeanServer extends SpiServer, ExtendedServer, EbeanServer,
/**
* DTO findOne query.
*/
@Nullable
<T> T findDtoOne(SpiDtoQuery<T> query);
/**
@@ -24,6 +24,7 @@ import io.ebeaninternal.server.querydefn.OrmUpdateProperties;
import io.ebeaninternal.server.rawsql.SpiRawSql;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -399,6 +400,11 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
List<String> getSoftDeletePredicates();
/**
* Bind the named multi-value array parameter which we would use with Postgres ANY.
*/
void setArrayParameter(String name, Collection<?> values);
/**
* Return a copy of the query.
*/
@@ -14,7 +14,7 @@ public interface SpiJsonReader {
PersistenceContext getPersistenceContext();
SpiJsonReader forJson(JsonParser moreJson, boolean resetContext);
SpiJsonReader forJson(JsonParser moreJson);
<T> void persistenceContextPut(Object beanId, T currentBean);
File diff suppressed because it is too large Load Diff
@@ -331,6 +331,12 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
return this;
}
@Override
public SqlUpdate setArrayParameter(String name, Collection<?> values) {
bindParams.setArrayParameter(name, values);
return this;
}
@Override
public SqlUpdate setNull(String name, int jdbcType) {
bindParams.setNullParameter(name, jdbcType);
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.core;
import io.ebean.*;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.bean.PersistenceContext;
import io.ebean.cache.QueryCacheEntry;
import io.ebean.common.BeanList;
@@ -37,7 +36,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
private final Boolean readOnly;
private LoadContext loadContext;
private PersistenceContext persistenceContext;
private JsonReadOptions jsonRead;
private HashQuery cacheKey;
private CQueryPlanKey queryPlanKey;
private SpiQuerySecondary secondaryQueries;
@@ -201,14 +199,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
return persistenceContext;
}
/**
* Add the bean to the persistence context.
*/
public void persistenceContextAdd(EntityBean bean) {
Object id = beanDescriptor.getId(bean);
beanDescriptor.contextPut(persistenceContext, id, bean);
}
/**
* This will create a local (readOnly) transaction if no current transaction
* exists.
@@ -233,6 +223,9 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
createdTransaction = true;
}
persistenceContext = persistenceContext(query, transaction);
if (Type.ITERATE == query.getType()) {
persistenceContext.beginIterate();
}
loadContext = new DLoadContext(this, secondaryQueries);
}
@@ -241,6 +234,9 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
*/
@Override
public void rollbackTransIfRequired() {
if (Type.ITERATE == query.getType()) {
persistenceContext.endIterate();
}
if (createdTransaction) {
try {
transaction.end();
@@ -262,7 +258,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
if (query.getPersistenceContext() == null) {
query.setPersistenceContext(persistenceContext);
}
jsonRead = new JsonReadOptions();
JsonReadOptions jsonRead = new JsonReadOptions();
jsonRead.setPersistenceContext(persistenceContext);
if (!query.isDisableLazyLoading()) {
loadContext = new DLoadContext(this, secondaryQueries);
@@ -271,20 +267,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
return jsonRead;
}
/**
* For iterate queries reset the persistenceContext and loadContext.
*/
public void flushPersistenceContextOnIterate() {
if (persistenceContext.resetLimit()) {
persistenceContext = persistenceContext.forIterateReset();
loadContext.resetPersistenceContext(persistenceContext);
if (jsonRead != null) {
jsonRead.setPersistenceContext(persistenceContext);
jsonRead.setLoadContext(loadContext);
}
}
}
/**
* Get the TransactionContext either explicitly set on the query or
* transaction scoped.
@@ -300,11 +282,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
if (scope == PersistenceContextScope.QUERY || t == null) {
return new DefaultPersistenceContext();
}
if (Type.ITERATE == query.getType()) {
return t.getPersistenceContext().forIterate();
} else {
return t.getPersistenceContext();
}
return t.getPersistenceContext();
}
/**
@@ -314,6 +292,9 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
*/
@Override
public void endTransIfRequired() {
if (Type.ITERATE == query.getType()) {
persistenceContext.endIterate();
}
if (createdTransaction && transaction.isActive()) {
transaction.commit();
if (query.getType().isUpdate()) {
@@ -552,7 +533,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
@SuppressWarnings({"rawtypes"})
private void mergeCacheHitsToMap(BeanCollection<T> result) {
BeanMap map = (BeanMap)result;
BeanMap map = (BeanMap) result;
ElPropertyValue property = mapProperty();
for (T bean : cacheBeans) {
map.internalPut(property.pathGet(bean), bean);
@@ -580,17 +561,18 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
@SuppressWarnings("unchecked")
private <K> Map<K, T> cacheBeansToMap() {
ElPropertyValue property = mapProperty();
Map<K,T> map = new LinkedHashMap<>();
Map<K, T> map = new LinkedHashMap<>();
for (T bean : cacheBeans) {
map.put((K)property.pathGet(bean), bean);
map.put((K) property.pathGet(bean), bean);
}
return map;
}
private ElPropertyValue mapProperty() {
ElPropertyValue property = beanDescriptor.elGetValue(query.getMapKey());
final String key = query.getMapKey();
final ElPropertyValue property = key == null ? beanDescriptor.idProperty() : beanDescriptor.elGetValue(key);
if (property == null) {
throw new IllegalStateException("Unknown map key property "+query.getMapKey());
throw new IllegalStateException("Unknown map key property " + key);
}
return property;
}
@@ -652,7 +634,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
if (cached != null && isAuditReads() && readAuditQueryType()) {
if (cached instanceof BeanCollection) {
// raw sql can't use L2 cache so normal queries only in here
Collection<T> actualDetails = ((BeanCollection<T>)cached).getActualDetails();
Collection<T> actualDetails = ((BeanCollection<T>) cached).getActualDetails();
List<Object> ids = new ArrayList<>(actualDetails.size());
for (T bean : actualDetails) {
ids.add(beanDescriptor.idForJson(bean));
@@ -663,13 +645,13 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
if (Boolean.FALSE.equals(query.isReadOnly())) {
// return shallow copies if readonly is explicitly set to false
if (cached instanceof BeanCollection) {
cached = ((BeanCollection<?>)cached).getShallowCopy();
cached = ((BeanCollection<?>) cached).getShallowCopy();
} else if (cached instanceof List) {
cached = new CopyOnFirstWriteList<>((List<?>)cached);
cached = new CopyOnFirstWriteList<>((List<?>) cached);
} else if (cached instanceof Set) {
cached = new LinkedHashSet<>((Set<?>)cached);
cached = new LinkedHashSet<>((Set<?>) cached);
} else if (cached instanceof Map) {
cached = new LinkedHashMap<>((Map<?,?>)cached);
cached = new LinkedHashMap<>((Map<?, ?>) cached);
}
}
return cached;
@@ -31,7 +31,12 @@ final class AssocOneHelpRefInherit extends AssocOneHelp {
Object read(DbReadContext ctx) throws SQLException {
// read discriminator to determine the type
InheritInfo rowInheritInfo = inherit.readType(ctx);
if (rowInheritInfo == null) {
BeanDescriptor<?> desc;
if (rowInheritInfo != null) {
desc = rowInheritInfo.desc();
} else if (!inherit.hasChildren()) {
desc = inherit.desc();
} else {
// ignore the id property
property.targetIdBinder.loadIgnore(ctx);
return null;
@@ -42,7 +47,6 @@ final class AssocOneHelpRefInherit extends AssocOneHelp {
}
// check transaction context to see if it already exists
PersistenceContext pc = ctx.getPersistenceContext();
BeanDescriptor<?> desc = rowInheritInfo.desc();
Object existing = desc.contextGet(pc, id);
if (existing != null) {
return existing;
@@ -56,7 +56,6 @@ import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
import io.ebeanservice.docstore.api.mapping.DocumentMapping;
import org.slf4j.Logger;
import javax.annotation.Nonnull;
import javax.persistence.PersistenceException;
import java.io.IOException;
import java.io.StringWriter;
@@ -209,6 +208,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
private final EntityBean prototypeEntityBean;
private final IdBinder idBinder;
private final String idSelect;
private String idBinderInLHSSql;
private String idBinderIdSql;
private String deleteByIdSql;
@@ -350,6 +350,23 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
propertiesIndex[i] = propMap.get(ebi.getProperty(i));
}
}
idSelect = initIdSelect();
}
String initIdSelect() {
if (idProperty != null && !idProperty.name().equals("_idClass")) {
return idProperty.name();
} else if (entityType == EntityType.EMBEDDED) {
return null;
} else {
StringJoiner sj = new StringJoiner(",");
for (BeanProperty prop : propertiesNonMany) {
if (prop.isImportedPrimaryKey()) {
sj.add(prop.name());
}
}
return sj.toString().intern();
}
}
public boolean isJacksonCorePresent() {
@@ -1961,7 +1978,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
* Return the class type this BeanDescriptor describes.
*/
@Override
@Nonnull
public Class<T> type() {
return beanType;
}
@@ -1973,7 +1989,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
* instead.
*/
@Override
@Nonnull
public String fullName() {
return fullName;
}
@@ -1982,7 +1997,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
* Return the short name of the entity bean.
*/
@Override
@Nonnull
public String name() {
return name;
}
@@ -2936,7 +2950,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
}
@Override
@Nonnull
public Collection<? extends Property> allProperties() {
return propertiesAll();
}
@@ -3016,6 +3029,10 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
return idProperty;
}
public String idSelect() {
return idSelect;
}
/**
* Return true if this bean should be inserted rather than updated.
*
@@ -3060,6 +3077,12 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
return versionPropertyIndex > -1 && ebi.isLoadedProperty(versionPropertyIndex);
}
void setReferenceIfIdOnly(EntityBeanIntercept ebi) {
if (referenceIdPropertyOnly(ebi)) {
ebi.setReference(idPropertyIndex);
}
}
/**
* Set the version value returning it in primitive long form.
*/
@@ -23,6 +23,11 @@ abstract class BeanDescriptorElement<T> extends BeanDescriptor<T> {
this.elementHelp = elementHelp;
}
@Override
String initIdSelect() {
return null;
}
private String shortName(String name) {
int pos = name.lastIndexOf('.');
if (pos > 1) {
@@ -90,7 +90,7 @@ final class BeanDescriptorJsonHelp<T> {
return null;
}
JsonParser newParser = node.traverse();
SpiJsonReader newReader = jsonRead.forJson(newParser, false);
SpiJsonReader newReader = jsonRead.forJson(newParser);
// check for the discriminator value to determine the correct sub type
String discColumn = inheritInfo.getRoot().getDiscriminatorColumn();
@@ -152,6 +152,9 @@ final class BeanDescriptorJsonHelp<T> {
}
if (contextBean == null) {
readJson.beanVisitor(bean, unmappedProperties);
if (!isNullOrZero(id)) {
desc.setReferenceIfIdOnly(bean._ebean_getIntercept());
}
}
if (path != null) {
readJson.popPath();
@@ -349,10 +349,10 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
builder = RawSqlBuilder.unparsed(sql.getQuery());
}
for (Map.Entry<String,String> columnMapping : sql.getColumnMapping().entrySet()) {
for (Map.Entry<String, String> columnMapping : sql.getColumnMapping().entrySet()) {
builder.columnMapping(columnMapping.getKey(), columnMapping.getValue());
}
for (Map.Entry<String,String> aliasMapping : sql.getAliasMapping().entrySet()) {
for (Map.Entry<String, String> aliasMapping : sql.getAliasMapping().entrySet()) {
builder.tableAliasMapping(aliasMapping.getKey(), aliasMapping.getValue());
}
info.addRawSql(sql.getName(), builder.create());
@@ -410,7 +410,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
@Override
public boolean isTableManaged(String tableName) {
return tableToDescMap.get(tableName.toLowerCase()) != null
|| tableToViewDescMap.get(tableName.toLowerCase()) != null;
|| tableToViewDescMap.get(tableName.toLowerCase()) != null;
}
/**
@@ -618,7 +618,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
DeployBeanInfo<?> info = createDeployBeanInfo(entityClass);
deployInfoMap.put(entityClass, info);
Class<?> embeddedIdType = info.getEmbeddedIdType();
if (embeddedIdType != null){
if (embeddedIdType != null) {
embeddedIdTypes.add(embeddedIdType);
}
}
@@ -788,8 +788,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
Class<?> targetType = prop.getTargetType();
DeployBeanInfo<?> info = deployInfoMap.get(targetType);
if (info == null) {
String msg = "Can not find descriptor [" + targetType + "] for " + prop.getFullBeanName();
throw new PersistenceException(msg);
throw new PersistenceException("Can not find descriptor [" + targetType + "] for " + prop.getFullBeanName());
}
return info.getDescriptor();
}
@@ -901,21 +900,17 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
Class<?> owningType = oneToMany.getOwningType();
if (!oneToMany.getCascadeInfo().isSave()) {
// The property MUST have persist cascading so that inserts work.
Class<?> targetType = oneToMany.getTargetType();
String msg = "Error on " + oneToMany.getFullBeanName() + ". @OneToMany MUST have ";
msg += "Cascade.PERSIST or Cascade.ALL because this is a unidirectional ";
msg += "relationship. That is, there is no property of type " + owningType + " on " + targetType;
throw new PersistenceException(msg);
}
// mark this property as unidirectional
oneToMany.setUnidirectional();
// specify table and table alias...
BeanTable beanTable = beanTable(owningType);
// define the TableJoin
DeployTableJoin oneToManyJoin = oneToMany.getTableJoin();
if (!oneToManyJoin.hasJoinColumns()) {
@@ -951,27 +946,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
String mappedBy = prop.getMappedBy();
// get the mappedBy property
DeployBeanDescriptor<?> targetDesc = targetDescriptor(prop);
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
if (mappedProp == null) {
String m = "Error on " + prop.getFullBeanName();
m += " Can not find mappedBy property [" + targetDesc + "." + mappedBy + "] ";
throw new PersistenceException(m);
}
if (!(mappedProp instanceof DeployBeanPropertyAssocOne<?>)) {
String m = "Error on " + prop.getFullBeanName();
m += ". mappedBy property [" + targetDesc + "." + mappedBy + "]is not a OneToOne?";
throw new PersistenceException(m);
}
DeployBeanPropertyAssocOne<?> mappedAssocOne = (DeployBeanPropertyAssocOne<?>) mappedProp;
if (!mappedAssocOne.isOneToOne()) {
String m = "Error on " + prop.getFullBeanName();
m += ". mappedBy property [" + targetDesc + "." + mappedBy + "]is not a OneToOne?";
throw new PersistenceException(m);
}
DeployBeanPropertyAssocOne<?> mappedAssocOne = mappedOneToOne(prop, mappedBy, targetDesc);
DeployTableJoin tableJoin = prop.getTableJoin();
if (!tableJoin.hasJoinColumns()) {
// define Join as the inverse of the mappedBy property
@@ -987,6 +962,21 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
}
}
private DeployBeanPropertyAssocOne<?> mappedOneToOne(DeployBeanPropertyAssocOne<?> prop, String mappedBy, DeployBeanDescriptor<?> targetDesc) {
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
if (mappedProp == null) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + " Can not find mappedBy property [" + targetDesc + "." + mappedBy + "]");
}
if (!(mappedProp instanceof DeployBeanPropertyAssocOne<?>)) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + ". mappedBy property [" + targetDesc + "." + mappedBy + "]is not a OneToOne?");
}
DeployBeanPropertyAssocOne<?> mappedAssocOne = (DeployBeanPropertyAssocOne<?>) mappedProp;
if (!mappedAssocOne.isOneToOne()) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + ". mappedBy property [" + targetDesc + "." + mappedBy + "]is not a OneToOne?");
}
return mappedAssocOne;
}
private void checkUniDirectionalPrimaryKeyJoin(DeployBeanPropertyAssocOne<?> prop) {
if (prop.isPrimaryKeyJoin()) {
// uni-directional PrimaryKeyJoin ...
@@ -1008,7 +998,6 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
return;
}
DeployBeanDescriptor<?> targetDesc = targetDescriptor(prop);
if (targetDesc.isDraftableElement()) {
// automatically turning on orphan removal and CascadeType.ALL
prop.setModifyListenMode(BeanCollection.ModifyListenMode.REMOVALS);
@@ -1040,23 +1029,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
String mappedBy = prop.getMappedBy();
// get the mappedBy property
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
if (mappedProp == null) {
String m = "Error on " + prop.getFullBeanName();
m += " Can not find mappedBy property [" + mappedBy + "] ";
m += "in [" + targetDesc + "]";
throw new PersistenceException(m);
}
if (!(mappedProp instanceof DeployBeanPropertyAssocOne<?>)) {
String m = "Error on " + prop.getFullBeanName();
m += ". mappedBy property [" + mappedBy + "]is not a ManyToOne?";
m += "in [" + targetDesc + "]";
throw new PersistenceException(m);
}
DeployBeanPropertyAssocOne<?> mappedAssocOne = (DeployBeanPropertyAssocOne<?>) mappedProp;
DeployBeanPropertyAssocOne<?> mappedAssocOne = mappedManyToOne(prop, targetDesc, mappedBy);
DeployTableJoin tableJoin = prop.getTableJoin();
if (!tableJoin.hasJoinColumns()) {
// define Join as the inverse of the mappedBy property
@@ -1079,6 +1052,17 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
}
}
private DeployBeanPropertyAssocOne<?> mappedManyToOne(DeployBeanPropertyAssocMany<?> prop, DeployBeanDescriptor<?> targetDesc, String mappedBy) {
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
if (mappedProp == null) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + " Can not find mappedBy property [" + mappedBy + "] " + "in [" + targetDesc + "]");
}
if (!(mappedProp instanceof DeployBeanPropertyAssocOne<?>)) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + ". mappedBy property [" + mappedBy + "]is not a ManyToOne?" + "in [" + targetDesc + "]");
}
return (DeployBeanPropertyAssocOne<?>) mappedProp;
}
/**
* For mappedBy copy the joins from the other side.
*/
@@ -1094,33 +1078,10 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
// get the mappedBy property
DeployBeanDescriptor<?> targetDesc = targetDescriptor(prop);
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
if (mappedProp == null) {
String m = "Error on " + prop.getFullBeanName();
m += " Can not find mappedBy property [" + mappedBy + "] ";
m += "in [" + targetDesc + "]";
throw new PersistenceException(m);
}
if (!(mappedProp instanceof DeployBeanPropertyAssocMany<?>)) {
String m = "Error on " + prop.getFullBeanName();
m += ". mappedBy property [" + targetDesc + "." + mappedBy + "] is not a ManyToMany?";
throw new PersistenceException(m);
}
DeployBeanPropertyAssocMany<?> mappedAssocMany = (DeployBeanPropertyAssocMany<?>) mappedProp;
if (!mappedAssocMany.isManyToMany()) {
String m = "Error on " + prop.getFullBeanName();
m += ". mappedBy property [" + targetDesc + "." + mappedBy + "] is not a ManyToMany?";
throw new PersistenceException(m);
}
DeployBeanPropertyAssocMany<?> mappedAssocMany = mappedManyToMany(prop, mappedBy, targetDesc);
// define the relationships/joins on this side as the
// reverse of the other mappedBy side ...
// DeployTableJoin mappedJoin = mappedAssocMany.getTableJoin();
DeployTableJoin mappedIntJoin = mappedAssocMany.getIntersectionJoin();
DeployTableJoin mappendInverseJoin = mappedAssocMany.getInverseJoin();
@@ -1142,6 +1103,22 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy
}
}
private DeployBeanPropertyAssocMany<?> mappedManyToMany(DeployBeanPropertyAssocMany<?> prop, String mappedBy, DeployBeanDescriptor<?> targetDesc) {
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
if (mappedProp == null) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + " Can not find mappedBy property [" + mappedBy + "] " + "in [" + targetDesc + "]");
}
if (!(mappedProp instanceof DeployBeanPropertyAssocMany<?>)) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + ". mappedBy property [" + targetDesc + "." + mappedBy + "] is not a ManyToMany?");
}
DeployBeanPropertyAssocMany<?> mappedAssocMany = (DeployBeanPropertyAssocMany<?>) mappedProp;
if (!mappedAssocMany.isManyToMany()) {
throw new PersistenceException("Error on " + prop.getFullBeanName() + ". mappedBy property [" + targetDesc + "." + mappedBy + "] is not a ManyToMany?");
}
return mappedAssocMany;
}
private <T> void setBeanControllerFinderListener(DeployBeanDescriptor<T> descriptor) {
persistControllerManager.addPersistControllers(descriptor);
postLoadManager.addPostLoad(descriptor);
@@ -40,7 +40,6 @@ import io.ebeanservice.docstore.api.mapping.DocPropertyMapping;
import io.ebeanservice.docstore.api.mapping.DocPropertyOptions;
import io.ebeanservice.docstore.api.support.DocStructure;
import javax.annotation.Nonnull;
import javax.persistence.PersistenceException;
import java.io.DataInput;
import java.io.DataOutput;
@@ -813,7 +812,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
* Return the name of the property.
*/
@Override
@Nonnull
public String name() {
return name;
}
@@ -1299,7 +1297,6 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty {
* Return the property type.
*/
@Override
@Nonnull
public Class<?> type() {
return propertyType;
}
@@ -35,8 +35,7 @@ public final class ImportedIdEmbedded implements ImportedId {
BeanProperty[] embeddedProps = foreignAssocOne.properties();
for (int i = 0; i < imported.length; i++) {
String n = name + "." + foreignAssocOne.name() + "." + embeddedProps[i].name();
BeanFkeyProperty fkey = new BeanFkeyProperty(n, imported[i].localDbColumn, foreignAssocOne.deployOrder());
owner.descriptor().add(fkey);
owner.descriptor().add(new BeanFkeyProperty(n, imported[i].localDbColumn, foreignAssocOne.deployOrder()));
}
}
@@ -88,8 +88,7 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
@Override
public void addFkeys(String name) {
BeanFkeyProperty fkey = new BeanFkeyProperty(name + "." + foreignProperty.name(), localDbColumn, owner.deployOrder());
owner.descriptor().add(fkey);
owner.descriptor().add(new BeanFkeyProperty(name + "." + foreignProperty.name(), localDbColumn, owner.deployOrder()));
}
@Override
@@ -5,7 +5,6 @@ import io.ebean.annotation.*;
import io.ebean.core.type.ScalarType;
import io.ebean.util.AnnotationUtil;
import io.ebeaninternal.api.CoreLog;
import io.ebeaninternal.server.deploy.DetermineManyType;
import io.ebeaninternal.server.deploy.ManyType;
import io.ebeaninternal.server.deploy.meta.*;
import io.ebeaninternal.server.type.TypeManager;
@@ -172,7 +172,7 @@ public final class DeployUtil {
*/
void setDbArray(DeployBeanProperty prop, DbArray dbArray) {
Class<?> type = prop.getPropertyType();
ScalarType<?> scalarType = typeManager.getArrayScalarType(type, dbArray, prop.getGenericType(), prop.isNullable());
ScalarType<?> scalarType = typeManager.getArrayScalarType(type, prop.getGenericType(), prop.isNullable());
if (scalarType == null) {
throw new RuntimeException("No ScalarType for @DbArray type for [" + prop.getFullBeanName() + "]");
}
@@ -1,4 +1,6 @@
package io.ebeaninternal.server.deploy;
package io.ebeaninternal.server.deploy.parse;
import io.ebeaninternal.server.deploy.ManyType;
import java.util.List;
import java.util.Map;
@@ -7,9 +9,9 @@ import java.util.Set;
/**
* Determine the Many Type for a property.
*/
public final class DetermineManyType {
final class DetermineManyType {
public ManyType getManyType(Class<?> type) {
ManyType getManyType(Class<?> type) {
if (type.equals(List.class)) {
return ManyType.LIST;
}
@@ -37,8 +37,7 @@ final class DtoMetaBuilder {
if (includeMethod(method)) {
try {
final String name = propertyName(method.getName());
final Class<?> propertyType = propertyType(method);
properties.add(new DtoMetaProperty(typeManager, dtoType, method, name, propertyType));
properties.add(new DtoMetaProperty(typeManager, dtoType, method, name));
} catch (Exception e) {
CoreLog.log.debug("exclude on " + dtoType + " method " + method, e);
}
@@ -46,10 +45,6 @@ final class DtoMetaBuilder {
}
}
static Class<?> propertyType(Method method) {
return method.getParameterTypes()[0];
}
static String propertyName(String methodName) {
final String name = methodName.substring(3);
return Character.toLowerCase(name.charAt(0)) + name.substring(1);
@@ -8,6 +8,7 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.sql.SQLException;
final class DtoMetaProperty implements DtoReadSet {
@@ -19,18 +20,30 @@ final class DtoMetaProperty implements DtoReadSet {
private final MethodHandle setter;
private final ScalarType<?> scalarType;
DtoMetaProperty(TypeManager typeManager, Class<?> dtoType, Method writeMethod, String name, Class<?> propertyType) throws IllegalAccessException, NoSuchMethodException {
DtoMetaProperty(TypeManager typeManager, Class<?> dtoType, Method writeMethod, String name) throws IllegalAccessException, NoSuchMethodException {
this.dtoType = dtoType;
this.name = name;
if (writeMethod != null) {
this.setter = LOOKUP.findVirtual(dtoType, writeMethod.getName(), MethodType.methodType(void.class, propertyType));
this.scalarType = typeManager.getScalarType(propertyType);
this.setter = lookupMethodHandle(dtoType, writeMethod);
this.scalarType = typeManager.getScalarType(propertyType(writeMethod), propertyClass(writeMethod));
} else {
this.scalarType = null;
this.setter = null;
}
}
private static MethodHandle lookupMethodHandle(Class<?> dtoType, Method method) throws NoSuchMethodException, IllegalAccessException {
return LOOKUP.findVirtual(dtoType, method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()));
}
static Type propertyType(Method method) {
return method.getParameters()[0].getParameterizedType();
}
static Class<?> propertyClass(Method method) {
return method.getParameterTypes()[0];
}
String getName() {
return name;
}
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.el;
import io.avaje.lang.NonNullApi;
import io.ebean.Filter;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -11,6 +12,7 @@ import java.util.regex.Pattern;
/**
* Default implementation of the Filter interface.
*/
@NonNullApi
public final class ElFilter<T> implements Filter<T> {
private final BeanDescriptor<T> beanDescriptor;
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.executor;
import io.avaje.lang.NonNullApi;
import io.ebeaninternal.api.SpiBackgroundExecutor;
import org.slf4j.MDC;
@@ -13,6 +14,7 @@ import java.util.concurrent.TimeUnit;
/**
* The default implementation of the BackgroundExecutor.
*/
@NonNullApi
public final class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
private final ScheduledExecutorService executor;
@@ -1,5 +1,7 @@
package io.ebeaninternal.server.expression;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.CacheMode;
import io.ebean.CountDistinctOrder;
import io.ebean.DtoQuery;
@@ -51,6 +53,7 @@ import java.util.function.Predicate;
/**
* Default implementation of ExpressionList.
*/
@NonNullApi
public class DefaultExpressionList<T> implements SpiExpressionList<T> {
private static final String AND = " and ";
@@ -469,6 +472,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return query.exists();
}
@Nullable
@Override
public T findOne() {
return query.findOne();
@@ -1,23 +1,15 @@
package io.ebeaninternal.server.expression;
import io.ebean.ExpressionFactory;
import io.ebean.ExpressionList;
import io.ebean.FutureIds;
import io.ebean.FutureList;
import io.ebean.FutureRowCount;
import io.ebean.Junction;
import io.ebean.OrderBy;
import io.ebean.Query;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.*;
import io.ebeaninternal.api.SpiExpressionList;
import io.ebeaninternal.api.SpiQuery;
import javax.persistence.PersistenceException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
@NonNullApi
public final class FilterExpressionList<T> extends DefaultExpressionList<T> {
private static final String notAllowedMessage = "This method is not allowed on a filter";
@@ -92,6 +84,7 @@ public final class FilterExpressionList<T> extends DefaultExpressionList<T> {
return rootQuery.findSet();
}
@Nullable
@Override
public T findOne() {
return rootQuery.findOne();
@@ -1,5 +1,7 @@
package io.ebeaninternal.server.expression;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.CacheMode;
import io.ebean.CountDistinctOrder;
import io.ebean.DtoQuery;
@@ -48,6 +50,7 @@ import java.util.function.Predicate;
/**
* Junction implementation.
*/
@NonNullApi
final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, ExpressionList<T> {
DefaultExpressionList<T> exprList;
@@ -476,6 +479,7 @@ final class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expr
return exprList.findSet();
}
@Nullable
@Override
public T findOne() {
return exprList.findOne();
@@ -136,7 +136,7 @@ abstract class EqlWhereListener<T> extends EQLBaseListener {
}
}
@SuppressWarnings("unchecked")
@SuppressWarnings({"unchecked", "rawtypes"})
private List<Object> toList(Object value) {
if (value == null) return null;
if (value instanceof List) {
@@ -46,7 +46,7 @@ final class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext
/**
* Reset the buffers after a query iterator reset.
*/
public void clear() {
private void clear() {
if (bufferList != null) {
bufferList.clear();
}
@@ -57,7 +57,7 @@ public final class DLoadContext implements LoadContext {
private final ProfileLocation profileLocation;
private final ProfilingListener profilingListener;
private final Map<String, ObjectGraphNode> nodePathMap = new HashMap<>();
private PersistenceContext persistenceContext;
private final PersistenceContext persistenceContext;
private List<OrmQueryProperties> secQuery;
private Object tenantId;
@@ -251,19 +251,6 @@ public final class DLoadContext implements LoadContext {
return persistenceContext;
}
@Override
public void resetPersistenceContext(PersistenceContext persistenceContext) {
this.persistenceContext = persistenceContext;
// clear the load contexts for beans and beanCollections
for (DLoadBeanContext beanContext : beanMap.values()) {
beanContext.clear();
}
for (DLoadManyContext manyContext : manyMap.values()) {
manyContext.clear();
}
this.rootBeanContext.clear();
}
@Override
public void register(String path, EntityBeanIntercept ebi) {
getBeanContext(path).register(ebi);
@@ -48,7 +48,7 @@ final class DLoadManyContext extends DLoadBaseContext implements LoadManyContext
/**
* Reset the buffers for a query iterator reset.
*/
public void clear() {
private void clear() {
if (bufferList != null) {
bufferList.clear();
}
@@ -118,7 +118,11 @@ public final class Binder {
bindLog.append(value);
}
}
if (value == null) {
if (value instanceof Collection) {
for (Object entry: (Collection<?>) value) {
bindObject(dataBind, entry);
}
} else if (value == null) {
// this doesn't work for query predicates
bindObject(dataBind, null, param.getType());
} else {
@@ -1,11 +1,6 @@
package io.ebeaninternal.server.persist;
import io.ebean.CallableSql;
import io.ebean.MergeOptions;
import io.ebean.Query;
import io.ebean.SqlUpdate;
import io.ebean.Transaction;
import io.ebean.Update;
import io.ebean.*;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.BeanCollection.ModifyListenMode;
import io.ebean.bean.EntityBean;
@@ -13,30 +8,15 @@ import io.ebean.bean.PersistenceContext;
import io.ebean.event.BeanPersistController;
import io.ebean.meta.MetricVisitor;
import io.ebeaninternal.api.*;
import io.ebeaninternal.server.core.PersistRequest;
import io.ebeaninternal.server.core.*;
import io.ebeaninternal.server.core.PersistRequest.Type;
import io.ebeaninternal.server.core.PersistRequestBean;
import io.ebeaninternal.server.core.PersistRequestCallableSql;
import io.ebeaninternal.server.core.PersistRequestOrmUpdate;
import io.ebeaninternal.server.core.PersistRequestUpdateSql;
import io.ebeaninternal.server.core.Persister;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanDescriptorManager;
import io.ebeaninternal.server.deploy.BeanManager;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import io.ebeaninternal.server.deploy.IntersectionRow;
import io.ebeaninternal.server.deploy.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* Persister implementation using DML.
@@ -82,7 +62,6 @@ public final class DefaultPersister implements Persister {
*/
@Override
public int executeCallable(CallableSql callSql, Transaction t) {
return executeOrQueue(new PersistRequestCallableSql(server, callSql, (SpiTransaction) t, persistExecute));
}
@@ -91,16 +70,8 @@ public final class DefaultPersister implements Persister {
*/
@Override
public int executeOrmUpdate(Update<?> update, Transaction t) {
SpiUpdate<?> ormUpdate = (SpiUpdate<?>) update;
BeanManager<?> mgr = beanDescriptorManager.beanManager(ormUpdate.getBeanType());
if (mgr == null) {
String msg = "No BeanManager found for type [" + ormUpdate.getBeanType() + "]. Is it an entity?";
throw new PersistenceException(msg);
}
BeanManager<?> mgr = beanManager(ormUpdate.getBeanType());
return executeOrQueue(new PersistRequestOrmUpdate(server, mgr, ormUpdate, (SpiTransaction) t, persistExecute));
}
@@ -169,10 +140,8 @@ public final class DefaultPersister implements Persister {
*/
@Override
public <T> List<T> draftRestore(Query<T> query, Transaction transaction) {
Class<T> beanType = query.getBeanType();
BeanDescriptor<T> desc = server.descriptor(beanType);
DraftHandler<T> draftHandler = new DraftHandler<>(desc, transaction);
List<T> liveBeans = draftHandler.fetchSourceBeans(query, false);
@@ -182,7 +151,6 @@ public final class DefaultPersister implements Persister {
}
draftHandler.fetchDestinationBeans(liveBeans, true);
BeanManager<T> mgr = beanDescriptorManager.beanManager(beanType);
for (T liveBean : liveBeans) {
@@ -214,10 +182,8 @@ public final class DefaultPersister implements Persister {
*/
@Override
public <T> List<T> publish(Query<T> query, Transaction transaction) {
Class<T> beanType = query.getBeanType();
BeanDescriptor<T> desc = server.descriptor(beanType);
DraftHandler<T> draftHandler = new DraftHandler<>(desc, transaction);
List<T> draftBeans = draftHandler.fetchSourceBeans(query, true);
@@ -227,7 +193,6 @@ public final class DefaultPersister implements Persister {
}
draftHandler.fetchDestinationBeans(draftBeans, false);
BeanManager<T> mgr = beanDescriptorManager.beanManager(beanType);
List<T> livePublish = new ArrayList<>(draftBeans.size());
@@ -251,7 +216,6 @@ public final class DefaultPersister implements Persister {
}
draftHandler.updateDrafts(transaction, mgr);
PUB.debug("publish - complete for [{}]", desc.name());
return livePublish;
}
@@ -330,9 +294,7 @@ public final class DefaultPersister implements Persister {
* Fetch the destination beans that will be published to.
*/
void fetchDestinationBeans(List<T> sourceBeans, boolean asDraft) {
List<Object> ids = getBeanIds(desc, sourceBeans);
Query<T> destQuery = server.find(desc.type()).where().idIn(ids).query();
if (asDraft) {
destQuery.asDraft();
@@ -376,7 +338,6 @@ public final class DefaultPersister implements Persister {
@Override
public int merge(BeanDescriptor<?> desc, EntityBean bean, MergeOptions options, SpiTransaction transaction) {
MergeHandler merge = new MergeHandler(server, desc, bean, options, transaction);
List<EntityBean> deleteBeans = merge.merge();
if (!deleteBeans.isEmpty()) {
@@ -385,13 +346,11 @@ public final class DefaultPersister implements Persister {
delete(deleteBean, transaction, options.isDeletePermanent());
}
}
// cascade save as normal with forceUpdate flags set
PersistRequestBean<?> request = createRequestRecurse(bean, transaction, null, Flags.MERGE);
request.checkBatchEscalationOnCascade();
saveRecurse(request);
request.flushBatchOnCascade();
// lambda expects a return
return 0;
}
@@ -443,7 +402,6 @@ public final class DefaultPersister implements Persister {
*/
@Override
public void insert(EntityBean bean, Transaction t) {
PersistRequestBean<?> req = createRequest(bean, t, PersistRequest.Type.INSERT);
if (req.isSkipReference()) {
// skip insert on reference bean
@@ -465,7 +423,6 @@ public final class DefaultPersister implements Persister {
}
void saveRecurse(EntityBean bean, Transaction t, Object parentBean, int flags) {
// determine insert or update taking into account stateless updates
saveRecurse(createRequestRecurse(bean, t, parentBean, flags));
}
@@ -493,7 +450,6 @@ public final class DefaultPersister implements Persister {
* Insert the bean.
*/
private void insert(PersistRequestBean<?> request) {
if (request.isRegisteredBean()) {
// skip as already inserted/updated in this request (recursive cascading)
return;
@@ -520,7 +476,6 @@ public final class DefaultPersister implements Persister {
* Update the bean.
*/
private void update(PersistRequestBean<?> request) {
if (request.isRegisteredBean()) {
// skip as already inserted/updated in this request (recursive cascading)
return;
@@ -531,21 +486,16 @@ public final class DefaultPersister implements Persister {
// save associated One beans recursively first
saveAssocOne(request);
}
if (request.isDirty()) {
request.executeOrQueue();
} else if (log.isDebugEnabled()) {
log.debug("Update skipped as bean is unchanged: {}", request.bean());
}
if (request.isPersistCascade()) {
// save all the beans in assocMany's after
saveAssocMany(request);
}
request.completeUpdate();
} finally {
request.unRegisterBean();
}
@@ -557,7 +507,6 @@ public final class DefaultPersister implements Persister {
*/
@Override
public int delete(EntityBean bean, Transaction t, boolean permanent) {
Type deleteType = permanent ? Type.DELETE_PERMANENT : Type.DELETE;
PersistRequestBean<EntityBean> originalRequest = createDeleteRequest(bean, t, deleteType);
if (originalRequest.isHardDeleteDraft()) {
@@ -601,7 +550,6 @@ public final class DefaultPersister implements Persister {
}
req.commitTransIfRequired();
req.flushBatchOnCascade();
return rows;
} catch (RuntimeException ex) {
@@ -631,23 +579,19 @@ public final class DefaultPersister implements Persister {
*/
@Override
public int deleteMany(Class<?> beanType, Collection<?> ids, Transaction transaction, boolean permanent) {
if (ids == null || ids.isEmpty()) {
return 0;
}
BeanDescriptor<?> descriptor = beanDescriptorManager.descriptor(beanType);
DeleteMode deleteMode = (permanent || !descriptor.isSoftDelete()) ? DeleteMode.HARD : DeleteMode.SOFT;
if (descriptor.isMultiTenant()) {
return deleteAsBeans(ids, transaction, deleteMode, descriptor);
}
ArrayList<Object> idList = new ArrayList<>(ids.size());
for (Object id : ids) {
// convert to appropriate type if required
idList.add(descriptor.convertId(id));
}
return delete(descriptor, null, idList, transaction, deleteMode);
}
@@ -698,7 +642,6 @@ public final class DefaultPersister implements Persister {
* Delete by Id or a List of Id's.
*/
private int delete(BeanDescriptor<?> descriptor, Object id, List<Object> idList, Transaction transaction, DeleteMode deleteMode) {
SpiTransaction t = (SpiTransaction) transaction;
if (t.isPersistCascade()) {
BeanPropertyAssocOne<?>[] propImportDelete = descriptor.propertiesOneImportedDelete();
@@ -818,7 +761,6 @@ public final class DefaultPersister implements Persister {
}
private void notifyDeleteById(BeanDescriptor<?> descriptor, Object id, List<Object> idList, Transaction transaction) {
BeanPersistController controller = descriptor.persistController();
if (controller != null) {
DeleteIdRequest request = new DeleteIdRequest(server, transaction, descriptor.type(), id);
@@ -838,7 +780,6 @@ public final class DefaultPersister implements Persister {
* the delete cascades to them (foreign keys).
*/
private Query<?> deleteRequiresQuery(BeanDescriptor<?> desc, BeanPropertyAssocOne<?>[] propImportDelete, DeleteMode deleteMode) {
Query<?> q = server.createQuery(desc.type());
StringBuilder sb = new StringBuilder(30);
for (BeanPropertyAssocOne<?> aPropImportDelete : propImportDelete) {
@@ -860,9 +801,7 @@ public final class DefaultPersister implements Persister {
* </p>
*/
private int delete(PersistRequestBean<?> request) {
DeleteUnloadedForeignKeys unloadedForeignKeys = null;
if (request.isPersistCascade()) {
// delete children first ... register the
// bean to handle bi-directional cascading
@@ -879,16 +818,13 @@ public final class DefaultPersister implements Persister {
int count = request.executeOrQueue();
request.removeFromPersistenceContext();
if (request.isPersistCascade()) {
deleteAssocOne(request);
if (unloadedForeignKeys != null) {
unloadedForeignKeys.deleteCascade();
}
}
request.complete();
// return true if using JDBC batch (as we can't tell until the batch is flushed)
return count;
}
@@ -901,11 +837,9 @@ public final class DefaultPersister implements Persister {
* </p>
*/
private void saveAssocMany(PersistRequestBean<?> request) {
EntityBean parentBean = request.entityBean();
BeanDescriptor<?> desc = request.descriptor();
SpiTransaction t = request.transaction();
EntityBean orphanForRemoval = request.importedOrphanForRemoval();
if (orphanForRemoval != null) {
delete(orphanForRemoval, request.transaction(), true);
@@ -972,7 +906,6 @@ public final class DefaultPersister implements Persister {
* </p>
*/
private void deleteAssocMany(PersistRequestBean<?> request) {
SpiTransaction t = request.transaction();
t.depth(-1);
@@ -1014,7 +947,6 @@ public final class DefaultPersister implements Persister {
deleteManyIntersection(parentBean, many, t, request.isPublish(), false);
}
} else {
if (ModifyListenMode.REMOVALS == many.modifyListenMode()) {
// PrivateOwned ...
// if soft delete then check target also supports soft delete
@@ -1023,7 +955,6 @@ public final class DefaultPersister implements Persister {
if (details instanceof BeanCollection<?>) {
Set<?> modifyRemovals = ((BeanCollection<?>) details).getModifyRemovals();
if (modifyRemovals != null && !modifyRemovals.isEmpty()) {
// delete the orphans that have been removed from the collection
for (Object detail : modifyRemovals) {
EntityBean detailBean = (EntityBean) detail;
@@ -1035,11 +966,9 @@ public final class DefaultPersister implements Persister {
}
}
}
deleteManyDetails(t, desc, parentBean, many, null, deleteMode);
}
}
// restore the depth
t.depth(+1);
}
@@ -1054,7 +983,6 @@ public final class DefaultPersister implements Persister {
*/
void deleteManyDetails(SpiTransaction t, BeanDescriptor<?> desc, EntityBean parentBean,
BeanPropertyAssocMany<?> many, List<Object> excludeDetailIds, DeleteMode deleteMode) {
if (many.cascadeInfo().isDelete()) {
// cascade delete the beans in the collection
BeanDescriptor<?> targetDesc = many.targetDescriptor();
@@ -1083,7 +1011,6 @@ public final class DefaultPersister implements Persister {
* Will use delete by object if the child entity has manyToMany relationships.
*/
private void deleteChildrenById(SpiTransaction t, BeanDescriptor<?> targetDesc, List<Object> childIds, DeleteMode deleteMode) {
if (!targetDesc.isDeleteByBulk()) {
// convert into a list of reference objects and perform delete by object
List<Object> refList = new ArrayList<>(childIds.size());
@@ -1091,7 +1018,6 @@ public final class DefaultPersister implements Persister {
refList.add(targetDesc.createReference(id, null));
}
deleteList(refList, t, deleteMode, true);
} else {
// perform delete by statement if possible
delete(targetDesc, null, childIds, t, deleteMode);
@@ -1102,16 +1028,13 @@ public final class DefaultPersister implements Persister {
* Save any associated one beans.
*/
private void saveAssocOne(PersistRequestBean<?> request) {
BeanDescriptor<?> desc = request.descriptor();
// imported ones with save cascade
for (BeanPropertyAssocOne<?> prop : desc.propertiesOneImportedSave()) {
// check for partial objects
if (prop.isOrphanRemoval() && request.isDirtyProperty(prop)) {
request.setImportedOrphanForRemoval(prop);
}
if (request.isLoadedProperty(prop)) {
EntityBean detailBean = prop.getValueAsEntityBean(request.entityBean());
if (detailBean != null
@@ -1125,7 +1048,6 @@ public final class DefaultPersister implements Persister {
}
}
}
for (BeanPropertyAssocOne<?> prop : desc.propertiesOneExportedSave()) {
if (prop.isOrphanRemoval() && request.isDirtyProperty(prop)) {
deleteOrphan(request, prop);
@@ -1145,9 +1067,7 @@ public final class DefaultPersister implements Persister {
* loaded but required for Delete cascade.
*/
private DeleteUnloadedForeignKeys getDeleteUnloadedForeignKeys(PersistRequestBean<?> request) {
DeleteUnloadedForeignKeys fkeys = null;
for (BeanPropertyAssocOne<?> one : request.descriptor().propertiesOneImportedDelete()) {
if (!request.isLoadedProperty(one)) {
// we have cascade Delete on a partially populated bean and
@@ -1158,7 +1078,6 @@ public final class DefaultPersister implements Persister {
fkeys.add(one);
}
}
return fkeys;
}
@@ -1166,9 +1085,7 @@ public final class DefaultPersister implements Persister {
* Delete any associated one beans.
*/
private void deleteAssocOne(PersistRequestBean<?> request) {
DeleteMode deleteMode = request.deleteMode();
for (BeanPropertyAssocOne<?> prop : request.descriptor().propertiesOneImportedDelete()) {
if (deleteMode.isHard() || prop.isTargetSoftDelete()) {
if (request.isLoadedProperty(prop)) {
@@ -1196,7 +1113,7 @@ public final class DefaultPersister implements Persister {
* Create the Persist Request Object additionally specifying the publish status.
*/
private <T> PersistRequestBean<T> createRequestInternal(T bean, Transaction t, PersistRequest.Type type) {
BeanManager<T> mgr = getBeanManager(bean);
BeanManager<T> mgr = beanManager(bean.getClass());
return createRequest(bean, t, null, mgr, type, Flags.ZERO);
}
@@ -1206,7 +1123,7 @@ public final class DefaultPersister implements Persister {
* This call determines the PersistRequest.Type based on bean state and the insert flag (root persist type).
*/
private <T> PersistRequestBean<T> createRequestRecurse(T bean, Transaction t, Object parentBean, int flags) {
BeanManager<T> mgr = getBeanManager(bean);
BeanManager<T> mgr = beanManager(bean.getClass());
BeanDescriptor<T> desc = mgr.getBeanDescriptor();
EntityBean entityBean = (EntityBean) bean;
PersistRequest.Type type;
@@ -1225,7 +1142,7 @@ public final class DefaultPersister implements Persister {
* Create the Persist Request Object that wraps all the objects used to
* perform an insert, update or delete.
*/
@SuppressWarnings({"unchecked"})
@SuppressWarnings({"unchecked", "rawtypes"})
private <T> PersistRequestBean<T> createRequest(T bean, Transaction t, Object parentBean, BeanManager<?> mgr,
PersistRequest.Type type, int flags) {
// no delete requests come here
@@ -1242,7 +1159,7 @@ public final class DefaultPersister implements Persister {
@SuppressWarnings({"unchecked"})
private <T> PersistRequestBean<T> createDeleteRequest(Object bean, Transaction t, PersistRequest.Type type, int flags) {
BeanManager<T> mgr = getBeanManager(bean);
BeanManager<T> mgr = beanManager(bean.getClass());
if (type == Type.DELETE_PERMANENT) {
type = Type.DELETE;
} else if (type == Type.DELETE && mgr.getBeanDescriptor().isSoftDelete()) {
@@ -1256,9 +1173,8 @@ public final class DefaultPersister implements Persister {
}
private String errNotRegistered(Class<?> beanClass) {
String msg = "The type [" + beanClass + "] is not a registered entity?";
msg += " If you don't explicitly list the entity classes to use Ebean will search for them in the classpath.";
return msg;
return "The type [" + beanClass + "] is not a registered entity?"
+ " If you don't explicitly list the entity classes to use Ebean will search for them in the classpath.";
}
/**
@@ -1269,10 +1185,10 @@ public final class DefaultPersister implements Persister {
* </p>
*/
@SuppressWarnings("unchecked")
private <T> BeanManager<T> getBeanManager(Object bean) {
BeanManager<T> mgr = (BeanManager<T>) beanDescriptorManager.beanManager(bean.getClass());
private <T> BeanManager<T> beanManager(Class<?> cls) {
BeanManager<T> mgr = (BeanManager<T>)beanDescriptorManager.beanManager(cls);
if (mgr == null) {
throw new PersistenceException(errNotRegistered(bean.getClass()));
throw new PersistenceException(errNotRegistered(cls));
}
return mgr;
}
@@ -416,7 +416,6 @@ public final class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfi
} else {
// nextBean set to previously read currentBean
nextBean = currentBean;
request.persistenceContextAdd(nextBean);
// check the current row we have just moved to
if (checkForDifferentBean()) {
return true;
@@ -26,7 +26,6 @@ final class CQueryIteratorSimple<T> implements QueryIterator<T> {
public boolean hasNext() {
boolean ret = false;
try {
request.flushPersistenceContextOnIterate();
ret = cquery.hasNext();
return ret;
} catch (SQLException e) {
@@ -35,8 +35,6 @@ final class CQueryIteratorWithBuffer<T> implements QueryIterator<T> {
try {
if (buffer.isEmpty() && moreToLoad) {
// load buffer
request.flushPersistenceContextOnIterate();
int i = -1;
while (moreToLoad && ++i < bufferSize) {
if (cquery.hasNext()) {
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.query;
import io.avaje.lang.NonNullApi;
import io.ebean.FetchConfig;
import io.ebean.FetchGroup;
import io.ebean.FetchGroupBuilder;
@@ -9,14 +10,12 @@ import io.ebeaninternal.server.querydefn.SpiFetchGroup;
/**
* Default implementation of the FetchGroupBuilder.
*/
@NonNullApi
final class DFetchGroupBuilder<T> implements FetchGroupBuilder<T> {
private static final FetchConfig DEFAULT_FETCH = FetchConfig.ofDefault();
private static final FetchConfig FETCH_CACHE = FetchConfig.ofCache();
private static final FetchConfig FETCH_QUERY = FetchConfig.ofQuery();
private static final FetchConfig FETCH_LAZY = FetchConfig.ofLazy();
private final OrmQueryDetail detail;
@@ -38,22 +37,22 @@ final class DFetchGroupBuilder<T> implements FetchGroupBuilder<T> {
}
@Override
public FetchGroupBuilder<T> fetch(String path, FetchGroup nestedGroup) {
public FetchGroupBuilder<T> fetch(String path, FetchGroup<?> nestedGroup) {
return fetchNested(path, nestedGroup, DEFAULT_FETCH);
}
@Override
public FetchGroupBuilder<T> fetchQuery(String path, FetchGroup nestedGroup) {
public FetchGroupBuilder<T> fetchQuery(String path, FetchGroup<?> nestedGroup) {
return fetchNested(path, nestedGroup, FETCH_QUERY);
}
@Override
public FetchGroupBuilder<T> fetchLazy(String path, FetchGroup nestedGroup) {
public FetchGroupBuilder<T> fetchLazy(String path, FetchGroup<?> nestedGroup) {
return fetchNested(path, nestedGroup, FETCH_LAZY);
}
private FetchGroupBuilder<T> fetchNested(String path, FetchGroup nestedGroup, FetchConfig fetchConfig) {
OrmQueryDetail nestedDetail = ((SpiFetchGroup) nestedGroup).underlying();
private FetchGroupBuilder<T> fetchNested(String path, FetchGroup<?> nestedGroup, FetchConfig fetchConfig) {
OrmQueryDetail nestedDetail = ((SpiFetchGroup<?>) nestedGroup).underlying();
detail.addNested(path, nestedDetail, fetchConfig);
return this;
}
@@ -1,5 +1,7 @@
package io.ebeaninternal.server.query;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.CacheMode;
import io.ebean.CountDistinctOrder;
import io.ebean.Database;
@@ -29,8 +31,6 @@ import io.ebeaninternal.api.SpiQueryFetch;
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
import io.ebeaninternal.server.querydefn.SpiFetchGroup;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.List;
@@ -44,6 +44,7 @@ import java.util.stream.Stream;
/**
* Implementation of FetchGroup query for use to create FetchGroup via query beans.
*/
@NonNullApi
final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQueryFetch {
private static final FetchConfig FETCH_CACHE = FetchConfig.ofCache();
@@ -65,6 +66,7 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
return this;
}
@SuppressWarnings("rawtypes")
@Override
public Query<T> select(FetchGroup fetchGroup) {
this.detail = ((SpiFetchGroup) fetchGroup).detail();
@@ -117,7 +119,7 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
}
@Override
public Query<T> fetch(String property, String columns, FetchConfig config) {
public Query<T> fetch(String property, @Nullable String columns, @Nullable FetchConfig config) {
detail.fetch(property, columns, config);
return this;
}
@@ -234,25 +236,21 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public <A> List<A> findIds() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public QueryIterator<T> findIterate() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public Stream<T> findStream() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public Stream<T> findLargeStream() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
@@ -273,25 +271,21 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public List<T> findList() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public Set<T> findSet() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public <K> Map<K, T> findMap() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public <A> List<A> findSingleAttributeList() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
@@ -318,19 +312,16 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public Optional<T> findOneOrEmpty() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public List<Version<T>> findVersions() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end) {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
@@ -361,25 +352,21 @@ final class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T>, SpiQuery
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public FutureRowCount<T> findFutureCount() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public FutureIds<T> findFutureIds() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public FutureList<T> findFutureList() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
}
@Nonnull
@Override
public PagedList<T> findPagedList() {
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
@@ -268,9 +268,16 @@ class SqlTreeNodeBean implements SqlTreeNode {
contextBean = localBean;
} else {
// bean already exists in persistenceContext
if (isLoadContextBeanNeeded(queryMode, contextBean)) {
// refresh it anyway (lazy loading for example)
if (queryMode.isLoadContextBean()) {
// if explicitly set loadContextBean to true, then reload
localBean = contextBean;
} else if (!contextBean._ebean_getIntercept().isFullyLoadedBean()) {
// reload if contextBean is partial object
localBean = contextBean;
// and switch to lazyLoad query mode in order not to overwrite
// existing properties in SqlBeanLoad::load
queryMode = Mode.LAZYLOAD_BEAN;
} else {
// ignore the DB data...
localBean = null;
@@ -683,14 +690,6 @@ class SqlTreeNodeBean implements SqlTreeNode {
return "SqlTreeNodeBean: " + desc;
}
private boolean isLoadContextBeanNeeded(Mode queryMode, EntityBean contextBean) {
// if explicitly set loadContextBean to true, then reload
if (queryMode.isLoadContextBean()) {
return true;
}
// reload if contextBean is partial object
return !contextBean._ebean_getIntercept().isFullyLoadedBean();
}
@Override
public boolean hasMany() {
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.querydefn;
import io.avaje.lang.NonNullApi;
import io.ebean.DtoQuery;
import io.ebean.ProfileLocation;
import io.ebean.QueryIterator;
@@ -12,6 +13,8 @@ import io.ebeaninternal.server.dto.DtoBeanDescriptor;
import io.ebeaninternal.server.dto.DtoMappingRequest;
import io.ebeaninternal.server.dto.DtoQueryPlan;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
@@ -21,6 +24,7 @@ import java.util.stream.Stream;
/**
* Default implementation of DtoQuery.
*/
@NonNullApi
public final class DefaultDtoQuery<T> extends AbstractQuery implements SpiDtoQuery<T> {
private final SpiEbeanServer server;
@@ -114,6 +118,7 @@ public final class DefaultDtoQuery<T> extends AbstractQuery implements SpiDtoQue
return server.findDtoList(this);
}
@Nullable
@Override
public T findOne() {
return server.findDtoOne(this);
@@ -144,6 +149,16 @@ public final class DefaultDtoQuery<T> extends AbstractQuery implements SpiDtoQue
return this;
}
@Override
public DtoQuery<T> setArrayParameter(String paramName, Collection<?> values) {
if (ormQuery != null) {
ormQuery.setArrayParameter(paramName, values);
} else {
bindParams.setArrayParameter(paramName, values);
}
return this;
}
@Override
public DtoQuery<T> setParameters(Object... values) {
if (ormQuery != null) {
@@ -206,6 +221,7 @@ public final class DefaultDtoQuery<T> extends AbstractQuery implements SpiDtoQue
return label;
}
@Nullable
@Override
public String getPlanLabel() {
if (label != null) {
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.querydefn;
import io.avaje.lang.NonNullApi;
import io.ebean.*;
import io.ebean.OrderBy.Property;
import io.ebean.bean.CallOrigin;
@@ -30,6 +31,7 @@ import java.util.stream.Stream;
/**
* Default implementation of an Object Relational query.
*/
@NonNullApi
public final class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
private static final String DEFAULT_QUERY_NAME = "default";
@@ -584,9 +586,9 @@ public final class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<
*/
@Override
public void setSelectId() {
// clear select and fetch joins..
// clear select and fetch joins
detail.clear();
select(beanDescriptor.idBinder().getIdProperty());
select(beanDescriptor.idSelect());
}
@Override
@@ -1584,6 +1586,17 @@ public final class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<
return this;
}
@Override
public void setArrayParameter(String name, Collection<?> values) {
if (namedParams != null) {
throw new IllegalStateException("setArrayParameter() not supported when EQL parsed query");
}
if (bindParams == null) {
bindParams = new BindParams();
}
bindParams.setArrayParameter(name, values);
}
@Override
public boolean checkPagingOrderBy() {
return orderById && !useDocStore;
@@ -1,5 +1,7 @@
package io.ebeaninternal.server.querydefn;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.RowConsumer;
import io.ebean.RowMapper;
import io.ebean.SqlQuery;
@@ -17,6 +19,7 @@ import java.util.function.Predicate;
/**
* Default implementation of SQuery - SQL Query.
*/
@NonNullApi
public final class DefaultRelationalQuery extends AbstractQuery implements SpiSqlQuery {
private static final long serialVersionUID = -1098305779779591068L;
@@ -263,6 +266,7 @@ public final class DefaultRelationalQuery extends AbstractQuery implements SpiSq
this.mapper = mapper;
}
@Nullable
@Override
public T findOne() {
return mapperFindOne(mapper);
@@ -37,7 +37,11 @@ final class OrmQueryPropertiesParser {
if (rawProperties.equals("*")) {
return ALL;
}
return new Response(false, splitRawSelect(rawProperties));
final Set<String> included = splitRawSelect(rawProperties);
if (included.contains("*")) {
return ALL;
}
return new Response(false, included);
}
/**
@@ -45,7 +45,7 @@ public final class DJsonBeanReader<T> implements JsonBeanReader<T> {
}
@Override
public JsonBeanReader<T> forJson(JsonParser moreJson, boolean resetContext) {
return new DJsonBeanReader<>(desc, readJson.forJson(moreJson, resetContext));
public JsonBeanReader<T> forJson(JsonParser moreJson) {
return new DJsonBeanReader<>(desc, readJson.forJson(moreJson));
}
}
@@ -50,22 +50,14 @@ public final class ReadJson implements SpiJsonReader {
/**
* Construct when transferring load context, persistence context, object mapper etc to a new ReadJson instance.
*/
private ReadJson(JsonParser moreJson, ReadJson source, boolean resetContext) {
private ReadJson(JsonParser moreJson, ReadJson source) {
this.parser = moreJson;
this.rootDesc = source.rootDesc;
this.pathStack = source.pathStack;
this.visitorMap = source.visitorMap;
this.objectMapper = source.objectMapper;
if (resetContext) {
this.persistenceContext = new DefaultPersistenceContext();
this.loadContext = source.loadContext;
if (loadContext != null) {
loadContext.resetPersistenceContext(persistenceContext);
}
} else {
this.persistenceContext = source.persistenceContext;
this.loadContext = source.loadContext;
}
this.persistenceContext = source.persistenceContext;
this.loadContext = source.loadContext;
}
private LoadContext initLoadContext(BeanDescriptor<?> desc, JsonReadOptions readOptions) {
@@ -96,8 +88,8 @@ public final class ReadJson implements SpiJsonReader {
* Return a new instance of ReadJson using the existing context but with a new JsonParser.
*/
@Override
public SpiJsonReader forJson(JsonParser moreJson, boolean resetContext) {
return new ReadJson(moreJson, this, resetContext);
public SpiJsonReader forJson(JsonParser moreJson) {
return new ReadJson(moreJson, this);
}
/**
@@ -1,11 +1,13 @@
package io.ebeaninternal.server.transaction;
import io.ebean.bean.EntityBean;
import io.ebean.bean.PersistenceContext;
import io.ebeaninternal.api.SpiBeanType;
import io.ebeaninternal.api.SpiBeanTypeManager;
import io.ebeaninternal.api.SpiPersistenceContext;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
@@ -25,14 +27,16 @@ import java.util.concurrent.locks.ReentrantLock;
*/
public final class DefaultPersistenceContext implements SpiPersistenceContext {
/**
* Map used hold caches. One cache per bean type.
*/
private final HashMap<Class<?>, ClassContext> typeCache = new HashMap<>();
private final ReentrantLock lock = new ReentrantLock();
private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
private int putCount;
/**
* When we are inside an iterate loop, we will add only WeakReferences. This
* allows the JVM GC to collect beans, which are not referenced elsewhere. In
* normal operation, we will use hard references, to avoid performance impact
*/
private int iterateDepth;
/**
* Create a new PersistenceContext.
@@ -40,60 +44,33 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
public DefaultPersistenceContext() {
}
/**
* Create as a shallow copy with initial or types that have not been added to.
*/
private DefaultPersistenceContext(DefaultPersistenceContext parent, boolean initial) {
for (Map.Entry<Class<?>, ClassContext> entry : parent.typeCache.entrySet()) {
typeCache.put(entry.getKey(), entry.getValue().copy(initial));
}
}
/**
* Return the initial shallow copy with each ClassContext noting it's initialSize (to detect additions).
*/
@Override
public PersistenceContext forIterate() {
return new DefaultPersistenceContext(this, true);
}
/**
* Return a shallow copy including each ClassContext that has had no additions (still at initialSize).
*/
@Override
public PersistenceContext forIterateReset() {
return new DefaultPersistenceContext(this, false);
}
@Override
public boolean resetLimit() {
public void beginIterate() {
lock.lock();
try {
if (putCount < 100) {
return false;
}
putCount = 0;
for (ClassContext value : typeCache.values()) {
if (value.resetLimit()) {
return true;
}
}
// checking after another 100 puts
return false;
iterateDepth++;
} finally {
lock.unlock();
}
}
@Override
public void endIterate() {
lock.lock();
try {
iterateDepth--;
expungeStaleEntries(); // when leaving the iterator, cleanup.
} finally {
lock.unlock();
}
}
/**
* Set an object into the PersistenceContext.
*/
@Override
public void put(Class<?> rootType, Object id, Object bean) {
lock.lock();
try {
putCount++;
getClassContext(rootType).put(id, bean);
expungeStaleEntries();
classContext(rootType).useReferences(iterateDepth > 0).put(id, bean);
} finally {
lock.unlock();
}
@@ -103,8 +80,8 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
public Object putIfAbsent(Class<?> rootType, Object id, Object bean) {
lock.lock();
try {
putCount++;
return getClassContext(rootType).putIfAbsent(id, bean);
expungeStaleEntries();
return classContext(rootType).useReferences(iterateDepth > 0).putIfAbsent(id, bean);
} finally {
lock.unlock();
}
@@ -117,7 +94,8 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
public Object get(Class<?> rootType, Object id) {
lock.lock();
try {
return getClassContext(rootType).get(id);
expungeStaleEntries();
return classContext(rootType).get(id);
} finally {
lock.unlock();
}
@@ -127,19 +105,18 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
public WithOption getWithOption(Class<?> rootType, Object id) {
lock.lock();
try {
return getClassContext(rootType).getWithOption(id);
expungeStaleEntries();
return classContext(rootType).getWithOption(id);
} finally {
lock.unlock();
}
}
/**
* Return the number of beans of the given type in the persistence context.
*/
@Override
public int size(Class<?> rootType) {
lock.lock();
try {
expungeStaleEntries();
ClassContext classMap = typeCache.get(rootType);
return classMap == null ? 0 : classMap.size();
} finally {
@@ -147,14 +124,12 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
}
}
/**
* Clear the PersistenceContext.
*/
@Override
public void clear() {
lock.lock();
try {
typeCache.clear();
expungeStaleEntries();
} finally {
lock.unlock();
}
@@ -168,6 +143,7 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
if (classMap != null) {
classMap.clear();
}
expungeStaleEntries();
} finally {
lock.unlock();
}
@@ -181,6 +157,7 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
if (classMap != null && id != null) {
classMap.deleted(id);
}
expungeStaleEntries();
} finally {
lock.unlock();
}
@@ -194,6 +171,7 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
if (classMap != null && id != null) {
classMap.remove(id);
}
expungeStaleEntries();
} finally {
lock.unlock();
}
@@ -203,6 +181,7 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
public List<Object> dirtyBeans(SpiBeanTypeManager manager) {
lock.lock();
try {
expungeStaleEntries();
List<Object> list = new ArrayList<>();
for (ClassContext classContext : typeCache.values()) {
classContext.dirtyBeans(manager, list);
@@ -213,80 +192,68 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
}
}
/**
* When there is a queue, poll it to remove stale entries from the map. Note:
* This is always done AFTER <code>useReferences</code> was called with
* <code>true</code>. Polling an empty queue has no performance impact.
*/
private void expungeStaleEntries() {
Reference<?> ref;
while ((ref = queue.poll()) != null) {
((BeanRef) ref).expunge();
}
}
@Override
public String toString() {
lock.lock();
try {
expungeStaleEntries();
return typeCache.toString();
} finally {
lock.unlock();
}
}
private ClassContext getClassContext(Class<?> rootType) {
return typeCache.computeIfAbsent(rootType, k -> new ClassContext(rootType));
private ClassContext classContext(Class<?> rootType) {
return typeCache.computeIfAbsent(rootType, k -> new ClassContext(k, queue));
}
private static class ClassContext {
private final Map<Object, Object> map = new HashMap<>();
private final Class<?> rootType;
private final ReferenceQueue<Object> queue;
private Set<Object> deleteSet;
private int initialSize;
private ClassContext parent;
private boolean useReferences;
private int weakCount;
private ClassContext(Class<?> rootType) {
private ClassContext(Class<?> rootType, ReferenceQueue<Object> queue) {
this.rootType = rootType;
this.queue = queue;
}
/**
* Create as a shallow copy.
* When called with "true", initialize referenceQueue and store BeanRefs instead
* of real object references.
*/
private ClassContext(ClassContext source, boolean initial) {
this.rootType = source.rootType;
if (initial || source.isTransfer()) {
parent = source.transferParent();
initialSize = parent.size();
if (source.deleteSet != null) {
deleteSet = new HashSet<>(source.deleteSet);
}
}
}
/**
* True if this should be transferred to a new iterator persistence context.
*/
private boolean isTransfer() {
// map not added to and has some original/parent beans
return map.isEmpty() && initialSize > 0;
}
private ClassContext transferParent() {
return (parent != null) ? parent : this;
}
/**
* Return a shallow copy if initial copy or it has not grown (still at initialSize).
*/
private ClassContext copy(boolean initial) {
return new ClassContext(this, initial);
}
/**
* Return true if grown above the reset limit size of 1000.
*/
private boolean resetLimit() {
return map.size() > 1000;
private ClassContext useReferences(boolean useReferences) {
this.useReferences = useReferences;
return this;
}
@Override
public String toString() {
return "size:" + map.size();
return "size:" + map.size() + " (" + weakCount + " weak)";
}
private Object get(Object id) {
Object bean = (parent == null) ? null : parent.get(id);
return bean != null ? bean : map.get(id);
Object ret = map.get(id);
if (ret instanceof BeanRef) {
return ((BeanRef) ret).get();
} else {
return ret;
}
}
private WithOption getWithOption(Object id) {
@@ -304,24 +271,39 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
return existingValue;
}
// put the new value and return null indicating the put was successful
map.put(id, bean);
put(id, bean);
return null;
}
private void put(Object id, Object b) {
map.put(id, b);
private void put(Object id, Object bean) {
Object existing;
if (useReferences) {
weakCount++;
existing = map.put(id, new BeanRef(this, id, bean, queue));
} else {
existing = map.put(id, bean);
}
if (existing instanceof BeanRef) {
// when a BeanRef is replaced, its expunge() must NOT remove an entry
((BeanRef) existing).setReplaced();
weakCount--;
}
}
private int size() {
return map.size() + initialSize;
return map.size();
}
private void clear() {
map.clear();
weakCount = 0;
}
private void remove(Object id) {
map.remove(id);
Object ret = map.remove(id);
if (ret instanceof BeanRef) {
weakCount--;
}
}
private void deleted(Object id) {
@@ -329,7 +311,7 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
deleteSet = new HashSet<>();
}
deleteSet.add(id);
map.remove(id);
remove(id);
}
/**
@@ -338,6 +320,10 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
void dirtyBeans(SpiBeanTypeManager manager, List<Object> list) {
final SpiBeanType beanType = manager.beanType(rootType);
for (Object value : map.values()) {
if (value instanceof BeanRef) {
value = ((BeanRef) value).get();
if (value == null) continue;
}
EntityBean bean = (EntityBean) value;
if (bean._ebean_getIntercept().isDirty() || beanType.isToManyDirty(bean)) {
list.add(value);
@@ -346,4 +332,27 @@ public final class DefaultPersistenceContext implements SpiPersistenceContext {
}
}
private static class BeanRef extends WeakReference<Object> {
private final ClassContext classContext;
private final Object key;
private boolean replaced;
private BeanRef(ClassContext classContext, Object key, Object referent, ReferenceQueue<? super Object> q) {
super(referent, q);
this.classContext = classContext;
this.key = key;
}
private void setReplaced() {
replaced = true;
}
private void expunge() {
if (!replaced) {
classContext.remove(key);
}
}
}
}
@@ -251,6 +251,18 @@ public final class DefaultTypeManager implements TypeManager {
return nativeMap.get(jdbcType);
}
@Override
public ScalarType<?> getScalarType(Type propertyType, Class<?> propertyClass) {
if (propertyType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType)propertyType;
Type rawType = pt.getRawType();
if (List.class == rawType || Set.class == rawType) {
return getArrayScalarType((Class<?>)rawType, propertyType, true);
}
}
return getScalarType(propertyClass);
}
/**
* This can return null if no matching ScalarType is found.
*/
@@ -286,7 +298,7 @@ public final class DefaultTypeManager implements TypeManager {
}
@Override
public ScalarType<?> getArrayScalarType(Class<?> type, DbArray dbArray, Type genericType, boolean nullable) {
public ScalarType<?> getArrayScalarType(Class<?> type, Type genericType, boolean nullable) {
Type valueType = getValueType(genericType);
if (type.equals(List.class)) {
return getArrayScalarTypeList(valueType, nullable);
@@ -591,8 +603,7 @@ public final class DefaultTypeManager implements TypeManager {
*/
private ScalarTypeEnum<?> createEnumScalarTypeDbValue(Class<? extends Enum<?>> enumType, Method method, boolean integerType, int length, boolean withConstraint) {
Map<String, String> nameValueMap = new LinkedHashMap<>();
Enum<?>[] enumConstants = enumType.getEnumConstants();
for (Enum<?> enumConstant : enumConstants) {
for (Enum<?> enumConstant : enumType.getEnumConstants()) {
try {
Object value = method.invoke(enumConstant);
nameValueMap.put(enumConstant.name(), value.toString());
@@ -19,8 +19,13 @@ final class JsonTrim {
for (int i = 0; i < len; i++) {
char c = json.charAt(i);
if (c == '\"') {
if (!escaped) quoted = !quoted;
else escaped = false;
if (!escaped) {
quoted = !quoted;
} else {
escaped = false;
}
} else if (escaped) {
escaped = false;
} else if (quoted && c == '\\') {
escaped = true;
}
@@ -47,6 +47,13 @@ public interface TypeManager {
*/
ScalarType<?> getScalarType(Class<?> type, int jdbcType);
/**
* Find and return the ScalarType taking into account the property type with generics.
* <p>
* For example Array based ScalarType for types like {@code List<String>}.
*/
ScalarType<?> getScalarType(Type propertyType, Class<?> type);
/**
* Create a ScalarType for an Enum using a mapping (rather than JPA Ordinal
* or String which has limitations).
@@ -64,7 +71,7 @@ public interface TypeManager {
/**
* Return the ScalarType used to handle DB ARRAY.
*/
ScalarType<?> getArrayScalarType(Class<?> type, DbArray dbArray, Type genericType, boolean nullable);
ScalarType<?> getArrayScalarType(Class<?> type, Type genericType, boolean nullable);
/**
* Return the ScalarType used to handle HSTORE (Map<String,String>).
@@ -60,7 +60,6 @@ public final class BindParamsParser {
* </p>
*/
private String parseSql() {
if (params.isSameBindHash()) {
String preparedSql = params.getPreparedSql();
if (preparedSql != null && !preparedSql.isEmpty()) {
@@ -68,114 +67,121 @@ public final class BindParamsParser {
return preparedSql;
}
}
String preparedSql = prepareSql();
params.setPreparedSql(preparedSql);
params.updateHash();
return preparedSql;
}
String preparedSql;
if (params.requiresNamedParamsPrepare()) {
private String prepareSql() {
if (!params.requiresNamedParamsPrepare()) {
return sql;
} else {
// convert named parameters into ordered list
OrderedList orderedList = params.createOrderedList();
parseNamedParams(orderedList);
preparedSql = orderedList.getPreparedSql();
} else {
preparedSql = sql;
return orderedList.getPreparedSql();
}
params.setPreparedSql(preparedSql);
return preparedSql;
}
/**
* Named parameters need to be parsed and replaced with ?.
*/
private void parseNamedParams(OrderedList orderedList) {
parseNamedParams(0, orderedList);
}
private void parseNamedParams(int startPos, OrderedList orderedList) {
if (sql == null) {
throw new PersistenceException("query does not contain any named bind parameters?");
}
if (startPos > sql.length()) {
return;
}
// search for quotes and named params... in order...
// search for quotes and named params in order
int beginQuotePos = sql.indexOf(quote, startPos);
int nameParamStart = findNameStart(sql, startPos);
if (beginQuotePos > 0 && beginQuotePos < nameParamStart) {
// the quote precedes the named parameter...
// find and add up to the end quote
int endQuotePos = sql.indexOf(quote, beginQuotePos + 1);
String sub = sql.substring(startPos, endQuotePos + 1);
orderedList.appendSql(sub);
// start again after the end quote
parseNamedParams(endQuotePos + 1, orderedList);
addNamedParam(startPos, orderedList, beginQuotePos);
} else {
if (nameParamStart < 0) {
// no more params, add the rest
String sub = sql.substring(startPos, sql.length());
orderedList.appendSql(sub);
orderedList.appendSql(sql.substring(startPos));
} else {
// find the end of the parameter name
int endOfParam = nameParamStart + 1;
do {
char c = sql.charAt(endOfParam);
if (c != '_' && !Character.isLetterOrDigit(c)) {
break;
}
endOfParam++;
} while (endOfParam < sql.length());
int endOfParam = findEndOfParam(nameParamStart);
// add the named parameter value to bindList
String paramName = sql.substring(nameParamStart + 1, endOfParam);
Param param = extractNamedParam(paramName);
Param param;
if (paramName.startsWith(ENCRYPTKEY_PREFIX)) {
param = addEncryptKeyParam(paramName);
} else {
param = params.getParameter(paramName);
}
if (param == null) {
String msg = "Bind value is not set or null for [" + paramName + "] in [" + sql + "]";
throw new PersistenceException(msg);
}
String sub = sql.substring(startPos, nameParamStart);
orderedList.appendSql(sub);
// check if inValue is a Collection type...
orderedList.appendSql(sql.substring(startPos, nameParamStart));
Object inValue = param.getInValue();
if (inValue instanceof Collection<?>) {
// Chop up Collection parameter into a number
// of individual parameters and add each one individually
Collection<?> collection = (Collection<?>) inValue;
int c = 0;
for (Object elVal : collection) {
if (++c > 1) {
orderedList.appendSql(",");
}
orderedList.appendSql("?");
BindParams.Param elParam = new BindParams.Param();
elParam.setInValue(elVal);
orderedList.add(elParam);
}
addCollectionParams(orderedList, param, (Collection<?>) inValue);
} else {
// its a normal scalar value parameter...
orderedList.add(param);
orderedList.appendSql("?");
addScalarParam(orderedList, param);
}
// continue on after the end of the parameter
parseNamedParams(endOfParam, orderedList);
}
}
}
private void addScalarParam(OrderedList orderedList, Param param) {
orderedList.add(param);
orderedList.appendSql("?");
}
private Param extractNamedParam(String paramName) {
Param param;
if (paramName.startsWith(ENCRYPTKEY_PREFIX)) {
param = addEncryptKeyParam(paramName);
} else {
param = params.getParameter(paramName);
}
if (param == null) {
throw new PersistenceException("Bind value is not set or null for [" + paramName + "] in [" + sql + "]");
}
return param;
}
private int findEndOfParam(int nameParamStart) {
int endOfParam = nameParamStart + 1;
do {
char c = sql.charAt(endOfParam);
if (c != '_' && !Character.isLetterOrDigit(c)) {
break;
}
endOfParam++;
} while (endOfParam < sql.length());
return endOfParam;
}
private void addNamedParam(int startPos, OrderedList orderedList, int beginQuotePos) {
// the quote precedes the named parameter...
// find and add up to the end quote
int endQuotePos = sql.indexOf(quote, beginQuotePos + 1);
String sub = sql.substring(startPos, endQuotePos + 1);
orderedList.appendSql(sub);
// start again after the end quote
parseNamedParams(endQuotePos + 1, orderedList);
}
private void addCollectionParams(OrderedList orderedList, Param param, Collection<?> inValue) {
// Chop up Collection parameter into a number of individual parameters
Collection<?> collection = inValue;
for (int c = 0; c < collection.size(); c++) {
if (c > 0) {
orderedList.appendSql(",");
}
orderedList.appendSql("?");
}
orderedList.add(param);
}
/**
* Find the next named parameter start position (based on colon).
*/
@@ -200,15 +206,11 @@ public final class BindParamsParser {
* Add an encryption key bind parameter.
*/
private Param addEncryptKeyParam(String keyNamedParam) {
int pos = keyNamedParam.indexOf(ENCRYPTKEY_GAP, ENCRYPTKEY_PREFIX_LEN);
String tableName = keyNamedParam.substring(ENCRYPTKEY_PREFIX_LEN, pos);
String columnName = keyNamedParam.substring(pos + ENCRYPTKEY_GAP_LEN);
EncryptKey key = beanDescriptor.encryptKey(tableName, columnName);
String strKey = key.getStringValue();
return params.setEncryptionKey(keyNamedParam, strKey);
}
@@ -1,5 +1,6 @@
package io.ebeanservice.docstore.none;
import io.avaje.lang.NonNullApi;
import io.ebean.DocStoreQueueEntry;
import io.ebean.DocumentStore;
import io.ebean.PagedList;
@@ -16,6 +17,7 @@ import java.util.function.Predicate;
/**
* DocumentStore that barfs it is used.
*/
@NonNullApi
public final class NoneDocStore implements DocumentStore {
public static IllegalStateException implementationNotInClassPath() {
+3 -3
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</parent>
<name>ebean ddl generation</name>
@@ -28,14 +28,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
@@ -243,11 +243,11 @@ public class ModelBuildContext {
*/
public FkeyBuilder addForeignKey(BeanDescriptor<?> desc, TableJoin tableJoin, boolean direction) {
String baseTable = ctx.normaliseTable(desc.getBaseTable());
String baseTable = ctx.normaliseTable(desc.baseTable());
String fkName = ctx.foreignKeyConstraintName(tableName, baseTable, count.incrementAndGet());
String fkIndex = ctx.foreignKeyIndexName(tableName, baseTable, count.get());
MCompoundForeignKey foreignKey = new MCompoundForeignKey(fkName, desc.getBaseTable(), fkIndex);
MCompoundForeignKey foreignKey = new MCompoundForeignKey(fkName, desc.baseTable(), fkIndex);
for (TableJoinColumn column : tableJoin.columns()) {
String localCol = direction ? column.getForeignDbColumn() : column.getLocalDbColumn();
@@ -203,10 +203,10 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
if (columns.length == 1) {
if (p.hasForeignKeyConstraint() && !importedProperty.descriptor().suppressForeignKey()) {
// single references column (put it on the column)
String refTable = importedProperty.descriptor().getBaseTable();
String refTable = importedProperty.descriptor().baseTable();
if (refTable == null) {
// odd case where an EmbeddedId only has 1 property
refTable = p.targetDescriptor().getBaseTable();
refTable = p.targetDescriptor().baseTable();
}
col.setReferences(refTable + "." + refColumn);
col.setForeignKeyName(foreignKeyConstraintName(col.getName()));
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</parent>
<name>ebean external mapping api</name>
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</parent>
<!-- <parent>-->
<!-- <groupId>org.avaje</groupId>-->
@@ -33,7 +33,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -59,14 +59,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>test</scope>
</dependency>
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</parent>
<name>ebean postgis</name>
@@ -23,7 +23,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
@@ -44,7 +44,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.8</version>
<version>42.2.24</version>
<scope>provided</scope>
</dependency>
@@ -74,7 +74,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>test</scope>
</dependency>
+7 -16
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</parent>
<name>ebean querybean</name>
@@ -17,7 +17,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
@@ -27,9 +27,8 @@
-->
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-jsr305</artifactId>
<version>1.1</version>
<scope>provided</scope>
<artifactId>avaje-lang</artifactId>
<version>1.0</version>
</dependency>
<dependency>
@@ -57,21 +56,21 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>test</scope>
</dependency>
@@ -93,14 +92,6 @@
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
--add-opens io.ebean.querybean/org.querytest=io.ebean.core
</argLine>
</configuration>
</plugin>
<!-- Enhancement -->
<plugin>
<groupId>io.repaint.maven</groupId>
@@ -1,24 +1,8 @@
package io.ebean.typequery;
import io.ebean.CacheMode;
import io.ebean.DB;
import io.ebean.Database;
import io.ebean.DtoQuery;
import io.ebean.ExpressionList;
import io.ebean.FetchConfig;
import io.ebean.FetchGroup;
import io.ebean.FutureIds;
import io.ebean.FutureList;
import io.ebean.FutureRowCount;
import io.ebean.PagedList;
import io.ebean.PersistenceContextScope;
import io.ebean.ProfileLocation;
import io.ebean.Query;
import io.ebean.QueryIterator;
import io.ebean.RawSql;
import io.ebean.Transaction;
import io.ebean.UpdateQuery;
import io.ebean.Version;
import io.avaje.lang.NonNullApi;
import io.avaje.lang.Nullable;
import io.ebean.*;
import io.ebean.search.MultiMatch;
import io.ebean.search.TextCommonTerms;
import io.ebean.search.TextQueryString;
@@ -28,16 +12,9 @@ import io.ebean.text.PathProperties;
import io.ebeaninternal.api.SpiQueryFetch;
import io.ebeaninternal.server.util.ArrayStack;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.sql.Connection;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -81,6 +58,7 @@ import java.util.stream.Stream;
* @param <T> the entity bean type (normal entity bean type e.g. Customer)
* @param <R> the specific root query bean type (e.g. QCustomer)
*/
@NonNullApi
public abstract class TQRootBean<T, R> {
/**
@@ -177,7 +155,6 @@ public abstract class TQRootBean<T, R> {
* the find methods available on this 'root query bean' instance like findList().
* </p>
*/
@Nonnull
public Query<T> query() {
return query;
}
@@ -1621,7 +1598,6 @@ public abstract class TQRootBean<T, R> {
/**
* Execute the query returning an optional bean.
*/
@Nonnull
public Optional<T> findOneOrEmpty() {
return query.findOneOrEmpty();
}
@@ -1643,7 +1619,6 @@ public abstract class TQRootBean<T, R> {
*
* @see Query#findList()
*/
@Nonnull
public List<T> findList() {
return query.findList();
}
@@ -1667,7 +1642,6 @@ public abstract class TQRootBean<T, R> {
*
* }</pre>
*/
@Nonnull
public Stream<T> findStream() {
return query.findStream();
}
@@ -1697,7 +1671,6 @@ public abstract class TQRootBean<T, R> {
*
* @see Query#findSet()
*/
@Nonnull
public Set<T> findSet() {
return query.findSet();
}
@@ -1710,7 +1683,6 @@ public abstract class TQRootBean<T, R> {
*
* @see Query#findIds()
*/
@Nonnull
public <A> List<A> findIds() {
return query.findIds();
}
@@ -1736,7 +1708,6 @@ public abstract class TQRootBean<T, R> {
*
* @see Query#findMap()
*/
@Nonnull
public <K> Map<K, T> findMap() {
return query.findMap();
}
@@ -1777,7 +1748,6 @@ public abstract class TQRootBean<T, R> {
*
* }</pre>
*/
@Nonnull
public QueryIterator<T> findIterate() {
return query.findIterate();
}
@@ -1798,7 +1768,6 @@ public abstract class TQRootBean<T, R> {
*
* @return the list of values for the selected property
*/
@Nonnull
public <A> List<A> findSingleAttributeList() {
return query.findSingleAttributeList();
}
@@ -1913,7 +1882,6 @@ public abstract class TQRootBean<T, R> {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
public List<Version<T>> findVersions() {
return query.findVersions();
}
@@ -1925,7 +1893,6 @@ public abstract class TQRootBean<T, R> {
* It will execute the query against the history returning the versions of the bean.
* </p>
*/
@Nonnull
public List<Version<T>> findVersionsBetween(Timestamp start, Timestamp end) {
return query.findVersionsBetween(start, end);
}
@@ -1936,7 +1903,6 @@ public abstract class TQRootBean<T, R> {
* This is the number of 'top level' or 'root level' entities.
* </p>
*/
@Nonnull
public int findCount() {
return query.findCount();
}
@@ -1951,7 +1917,6 @@ public abstract class TQRootBean<T, R> {
*
* @return a Future object for the row count query
*/
@Nonnull
public FutureRowCount<T> findFutureCount() {
return query.findFutureCount();
}
@@ -1966,7 +1931,6 @@ public abstract class TQRootBean<T, R> {
*
* @return a Future object for the list of Id's
*/
@Nonnull
public FutureIds<T> findFutureIds() {
return query.findFutureIds();
}
@@ -1980,7 +1944,6 @@ public abstract class TQRootBean<T, R> {
*
* @return a Future object for the list result of the query
*/
@Nonnull
public FutureList<T> findFutureList() {
return query.findFutureList();
}
@@ -2014,7 +1977,6 @@ public abstract class TQRootBean<T, R> {
*
* @return The PagedList
*/
@Nonnull
public PagedList<T> findPagedList() {
return query.findPagedList();
}
@@ -2047,7 +2009,6 @@ public abstract class TQRootBean<T, R> {
/**
* Return the type of beans being queried.
*/
@Nonnull
public Class<T> getBeanType() {
return query.getBeanType();
}
@@ -2055,7 +2016,6 @@ public abstract class TQRootBean<T, R> {
/**
* Return the expression list that has been built for this query.
*/
@Nonnull
public ExpressionList<T> getExpressionList() {
return query.where();
}
@@ -1,19 +1,9 @@
package org.querytest;
import io.ebean.DB;
import io.ebean.Database;
import io.ebean.PagedList;
import io.ebean.Query;
import io.ebean.QueryIterator;
import io.ebean.Transaction;
import io.ebean.*;
import io.ebean.annotation.Transactional;
import io.ebean.types.Inet;
import org.example.domain.ACat;
import org.example.domain.ADog;
import org.example.domain.Address;
import org.example.domain.Animal;
import org.example.domain.Country;
import org.example.domain.Customer;
import org.example.domain.*;
import org.example.domain.otherpackage.PhoneNumber;
import org.example.domain.otherpackage.ValidEmail;
import org.example.domain.query.QAnimal;
@@ -26,15 +16,7 @@ import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
@@ -155,23 +137,21 @@ public class QCustomerTest {
assertThat(ids).isNotEmpty();
Map<List, Customer> map = new QCustomer()
Map<Long, Customer> map = new QCustomer()
.status.equalTo(Customer.Status.GOOD)
.findMap();
assertThat(map.size()).isEqualTo(ids.size());
QueryIterator<Customer> iterate = new QCustomer()
.status.equalTo(Customer.Status.GOOD)
.findIterate();
try (QueryIterator<Customer> iterate =
new QCustomer()
.status.equalTo(Customer.Status.GOOD)
.findIterate()) {
try {
while (iterate.hasNext()) {
Customer customer = iterate.next();
assertThat(customer.getName()).isNotNull();
}
} finally {
iterate.close();
}
}
+6 -6
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</parent>
<artifactId>ebean-redis</artifactId>
@@ -22,35 +22,35 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>test</scope>
</dependency>
+4 -4
View File
@@ -4,7 +4,7 @@
<parent>
<artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</parent>
<name>ebean test</name>
@@ -29,14 +29,14 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId>
<version>12.12.1-SNAPSHOT</version>
<version>12.13.2-SNAPSHOT</version>
</dependency>
<dependency>
@@ -147,7 +147,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.23</version>
<version>42.2.24</version>
<exclusions>
<exclusion>
<groupId>org.checkerframework</groupId>

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