Compare commits

..
Author SHA1 Message Date
rob bygrave d5d9a897ae [maven-release-plugin] prepare release ebean-11.40.1 2019-06-29 00:44:05 +12:00
rob bygrave ddf200ffdd #1738 - Refactor toArray() plus various 2019-06-29 00:40:16 +12:00
rob bygrave 7fa5e2aa8c #1738 - Refactor add final, Object.equals, Integer.compare 2019-06-29 00:23:12 +12:00
rob bygrave 8bfae9deef #1738 - Refactor simplify switch and various 2019-06-28 23:48:03 +12:00
rob bygrave e6c9f151c1 #1738 - Refactor tidy suppressWarnings and access 2019-06-28 23:20:57 +12:00
rob bygrave 30a0935300 #1738 - Refactor tidy suppressWarnings 2019-06-28 23:04:20 +12:00
rob bygrave b4182d4519 #1738 - Refactor SqlTreeNodeBean tidy 2019-06-28 22:40:14 +12:00
rob bygrave 93cc0399f1 #1738 - Refactor SqlTreeNodeBean load method 2019-06-28 22:35:36 +12:00
rob bygrave 5404dab5a3 Bump to 11.40.1-SNAPSHOT 2019-06-28 21:35:02 +12:00
rob bygrave d70da1d805 #1738 - Refactor tidy internals - refactor move server.lib.Str 2019-06-28 21:32:15 +12:00
rob bygrave 2225d5b7e8 #1738 - Refactor tidy internals - refactor move DtoQueryRequest 2019-06-28 21:30:15 +12:00
rob bygrave 270369bd65 #1738 - Refactor tidy internals - DLoadContext 2019-06-28 21:20:42 +12:00
rob bygrave a932d61a94 #1737 - PersistenceException while using aggregate query on related entity
This part includes support for joins off an aggregation formula
on a ManyToOne.

e.g. We use min(customer) ... to 'query join' to customer
in the query below.

    List<Contact> contacts = Ebean.find(Contact.class)
      .select("lastName, min(customer)")
      .fetchQuery("customer", "name, status")
      .findList();
2019-06-28 21:03:14 +12:00
rob bygrave 24b08663af #1737 - PersistenceException while using aggregate query on related entity
Fix excluding the ability to additionally join (off the min(manyToOne))
2019-06-28 20:16:05 +12:00
rob bygrave bb6c9c84ba #1736 - Bump to ebean-agent 11.40.1 (with synthetic modifier on generated code) 2019-06-28 10:55:14 +12:00
rob bygrave a1e185b0f6 Refactor tidy internals - BatchedPstmtHolder, always true condition (no effective change)
Remove condition check on firstError == null ... as it is always true
2019-06-24 13:41:21 +12:00
Rob BygraveandGitHub e2a467ca5a Create FUNDING.yml 2019-06-19 23:49:00 +12:00
rob bygrave 4b28933298 [maven-release-plugin] prepare for next development iteration 2019-06-14 16:45:16 +12:00
rob bygrave 6077acf134 [maven-release-plugin] prepare release ebean-11.39.3 2019-06-14 16:45:05 +12:00
rob bygrave 8a4ffd21ab #1722 - Fix for - L2 cache throw exception when query with custom ManyToMany relation model 2019-06-14 16:38:58 +12:00
rob bygrave d1314124af #1722 - Failing test for - L2 cache throw exception when query with custom ManyToMany relation model 2019-06-14 16:38:43 +12:00
rob bygrave 36f018b6aa [maven-release-plugin] prepare for next development iteration 2019-06-13 23:38:28 +12:00
rob bygrave 87ccb6e333 [maven-release-plugin] prepare release ebean-11.39.2 2019-06-13 23:38:18 +12:00
rob bygrave 3432c365f6 Bump ebean-migration to 11.16.2 with fix for migration sql that ...
That includes semi-colon and new line in literal content
2019-06-13 00:14:20 +12:00
rob bygrave b7d5aa344f Fix test only - add missing assert on NoopExpressionTest 2019-06-13 00:11:34 +12:00
rob bygrave 7e768623e4 #1730 - Fix for wrong JDBC batch sorting / ordering
This is a bit of a refactor that simplifies the ordering of
batch execution (BatchedBeanHolder ordering). In short we
batch by bean type and depth (rather than just type).

This means that there are some cases we are not optimal
(where we could batch by bean type in different depths)
but that is expected to be rare and problematic for
hierarchies of the same type.
2019-06-12 23:41:48 +12:00
rob bygrave 73ab2ee1fe Merge branch 'FOCONIS-bug/wrong_batch_sorting' 2019-06-12 21:17:15 +12:00
rob bygrave 122fed448c Merge branch 'bug/wrong_batch_sorting' of https://github.com/FOCONIS/ebean into FOCONIS-bug/wrong_batch_sorting 2019-06-12 21:16:50 +12:00
rob bygrave 6e52bee91f #1723 - Fix for TestUpdateCircularSave.testCircularCascade() 2019-06-10 23:31:47 +12:00
rob bygrave cc26afad13 Merge branch 'tobias--circular_saves_bugs' 2019-06-10 21:04:17 +12:00
rob bygrave bf20449fb5 Merge branch 'circular_saves_bugs' of https://github.com/tobias-/ebean into tobias--circular_saves_bugs 2019-06-10 21:03:55 +12:00
Rob BygraveandGitHub 6af5fae8e9 #1727 - Refactor internals to use Instant for json parse on date time types (#1728) 2019-06-10 16:16:04 +12:00
rob bygrave e26a38ecaa #1727 - No effective change, simplify DefaultServer.createEntityBean() 2019-06-10 16:14:12 +12:00
rob bygrave 1cdf68f1c0 #1727 - No effective change, tests with static imports 2019-06-10 16:13:19 +12:00
jonasPoehlerandRob Bygrave 2923dd1d96 Bugfix/create entity bean unload (#1729)
* #1726 Add a testcase to reveal wrong behaviour of createEntityBean

* #1726 FIX: createEntityBean must not unload properties for "new" beans

(cherry picked from commit 270721bdb54373a83ef00b19a3c35da50f2a2bf5)
2019-06-10 16:09:12 +12:00
Jonas Pöhler (JPo) 9067508e1d Add testcase for wrong batch sorting 2019-06-07 13:42:31 +02:00
rob bygrave 385cc76e34 #1724 - Fix, UtilDateTimeParser - date time parsing with nanos precision 2019-06-04 22:20:28 +12:00
SnōwballandRob Bygrave c14cb4b85e Add (failing) java 11 to travis - date time parsing with nanos precision (#1724)
* Add (failing) java 11 to travis

* Extra test-case for date parser
2019-06-04 21:56:25 +12:00
Snōwball 52644647e4 Add another test case for circular dependencies 2019-05-27 11:14:48 +02:00
Snōwball 3bf9dd6743 Testcase for ebean with circular dependences
1. While the javax.persistance api discourages the use of bidirectional
   cascades, it does not prohibit them. They're very useful and natural
   if you think of the database as a graph instead of a tree.
   test case 1 (testCircularCascade) tests this.
2. Second test case fetches the child, but saves the parent. If used like
   that, the child will not have it's changes saved.
2019-05-23 16:38:55 +02:00
rob bygrave aececa2199 [maven-release-plugin] prepare for next development iteration 2019-05-22 22:23:33 +12:00
178 changed files with 1973 additions and 834 deletions
+3
View File
@@ -0,0 +1,3 @@
# These are supported funding model platforms
custom: https://ebean.io/sponsors
+1
View File
@@ -3,6 +3,7 @@ sudo: required
language: java
jdk:
- oraclejdk8
- openjdk11
git:
depth: 3
+5 -5
View File
@@ -9,7 +9,7 @@
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>11.39.1</version>
<version>11.40.1</version>
<packaging>jar</packaging>
<name>ebean</name>
@@ -22,7 +22,7 @@
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-11.39.1</tag>
<tag>ebean-11.40.1</tag>
</scm>
<profiles>
@@ -141,7 +141,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-migration</artifactId>
<version>11.16.1</version>
<version>11.16.2</version>
</dependency>
<dependency>
@@ -250,7 +250,7 @@
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-agent</artifactId>
<version>11.39.1</version>
<version>11.40.1</version>
<scope>test</scope>
</dependency>
@@ -330,7 +330,7 @@
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>11.39.1</version>
<version>11.40.1</version>
<executions>
<execution>
<id>test</id>
+2 -2
View File
@@ -69,8 +69,8 @@ public enum CacheMode {
*/
GET(true, false);
private boolean get;
private boolean put;
private final boolean get;
private final boolean put;
CacheMode(boolean get, boolean put) {
this.get = get;
@@ -1,6 +1,7 @@
package io.ebean.bean;
import java.io.Serializable;
import java.util.Objects;
/**
* Identifies a unique node of an object graph.
@@ -85,8 +86,7 @@ public final class ObjectGraphNode implements Serializable {
}
ObjectGraphNode e = (ObjectGraphNode) obj;
//noinspection StringEquality
return ((e.path == path) || (e.path != null && e.path.equals(path)))
return (Objects.equals(e.path, path))
&& e.originQueryPoint.equals(originQueryPoint);
}
}
+1 -1
View File
@@ -25,7 +25,7 @@ public enum ServerCacheType {
*/
QUERY("_Q");
private String code;
private final String code;
ServerCacheType(String code) {
this.code = code;
@@ -219,7 +219,6 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
/**
* Copies all relevant properties for a clone. See {@link #getShallowCopy()}
* @param other
*/
protected void setFromOriginal(AbstractBeanCollection<E> other) {
this.disableLazyLoad = other.disableLazyLoad;
+1 -1
View File
@@ -237,7 +237,7 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
@SuppressWarnings({"unchecked"})
public Set<Entry<K, E>> entrySet() {
init();
if (isReadOnly()) {
@@ -77,6 +77,9 @@ public class PlatformConfig {
this.geometrySRID = platformConfig.geometrySRID;
this.dbUuid = platformConfig.dbUuid;
this.caseSensitiveCollation = platformConfig.caseSensitiveCollation;
this.allQuotedIdentifiers = platformConfig.allQuotedIdentifiers;
this.databaseInetAddressVarchar = platformConfig.databaseInetAddressVarchar;
this.customDbTypeMappings = platformConfig.customDbTypeMappings;
}
/**
@@ -653,6 +653,7 @@ public class ServerConfig {
* @param cls The type of the service object to obtain
* @return The service object given the class type
*/
@SuppressWarnings("unchecked")
public <P> P getServiceObject(Class<P> cls) {
return (P) serviceObject.get(serviceObjectKey(cls));
}
@@ -35,9 +35,9 @@ public enum TenantMode {
* (that holds configuration e.g.)
*/
DB_WITH_MASTER(true, true);
boolean dynamicDataSource;
boolean ddlEnabled;
final boolean dynamicDataSource;
final boolean ddlEnabled;
TenantMode(boolean dynamicDataSource, boolean ddlEnabled) {
this.dynamicDataSource = dynamicDataSource;
@@ -50,12 +50,12 @@ public enum TenantMode {
public boolean isDynamicDataSource() {
return dynamicDataSource;
}
/**
* Returns true, if DDL is enabled.
*/
public boolean isDdlEnabled() {
return ddlEnabled;
}
}
@@ -27,15 +27,13 @@ public class DbDefaultValue {
* The key for the NOW / current timestamp.
*/
public static final String NOW = "now";
/**
* The 'null' literal.
*/
public static final String NULL = "null";
protected Map<String, String> map = new LinkedHashMap<>();
protected final Map<String, String> map = new LinkedHashMap<>();
/**
* Set the DB now function.
@@ -82,10 +80,9 @@ public class DbDefaultValue {
return val != null ? val : dbDefaultLiteral;
}
/**
* This method checks & convert the {@link DbDefault#value()} to a valid SQL literal.
*
*
* This is mainly to quote string literals and verify integer/dates for correctness.
* <p>
* Note: There are some special cases:
@@ -98,24 +95,24 @@ public class DbDefaultValue {
* If you need really the String "null", you have to specify <code>@DbDefault("'null'")</code>
* which gives you the <code>default 'null'</code> statement.</li>
* <li>Any statement, that begins and ends with single quote will not be checked or get quoted again.</li>
* <li>A statement that begins with "$RAW:", e.g <code>@DbDefault("$RAW:N'SANDNES'")</code> will lead to
* <li>A statement that begins with "$RAW:", e.g <code>@DbDefault("$RAW:N'SANDNES'")</code> will lead to
* a <code>default N'SANDNES'</code> in DDL. Note that this is platform specific!</li>
* </ul>
*/
public static String toSqlLiteral(String defaultValue, Class<?> propertyType, int sqlType) {
if (propertyType == null
|| defaultValue == null
|| defaultValue == null
|| NULL.equals(defaultValue)
|| (defaultValue.startsWith("'") && defaultValue.endsWith("'"))
|| (defaultValue.startsWith("$RAW:"))) {
|| (defaultValue.startsWith("$RAW:"))) {
return defaultValue;
}
if (Boolean.class.isAssignableFrom(propertyType) || Boolean.TYPE.isAssignableFrom(propertyType)) {
return toBooleanLiteral(defaultValue);
}
if (Number.class.isAssignableFrom(propertyType)
if (Number.class.isAssignableFrom(propertyType)
|| Byte.TYPE.equals(propertyType)
|| Short.TYPE.equals(propertyType)
|| Integer.TYPE.equals(propertyType)
@@ -126,7 +123,7 @@ public class DbDefaultValue {
Double.valueOf(defaultValue); // verify if it is a number
return defaultValue;
}
// check if it is a date/time - in all other cases return quoted defaultValue
switch (sqlType) {
// date
@@ -155,7 +152,7 @@ public class DbDefaultValue {
}
throw new IllegalArgumentException("'" + value + "' is not a valid value for boolean");
}
/**
* This adds single qoutes around the <code>value</code> and doubles single quotes.
* "User's home" will return "'User''s home'"
@@ -175,7 +172,7 @@ public class DbDefaultValue {
return sb.toString();
}
private static String toDateLiteral(String value) {
if (NOW.equals(value)) {
return value; // this will get translated later
@@ -191,7 +188,7 @@ public class DbDefaultValue {
DatatypeConverter.parseTime(value); // verify
return toTextLiteral(value);
}
private static String toDateTimeLiteral(String value) {
if (NOW.equals(value)) {
return value; // this will get translated later
@@ -11,12 +11,12 @@ class DbPlatformTypeLookup {
/**
* A map to lookup the type by name.
*/
private Map<String, DbType> nameLookup = new HashMap<>();
private final Map<String, DbType> nameLookup = new HashMap<>();
/**
* A map to lookup the type by JDBC int value.
*/
private Map<Integer, DbType> idLookup = new HashMap<>();
private final Map<Integer, DbType> idLookup = new HashMap<>();
DbPlatformTypeLookup() {
addAll();
@@ -23,7 +23,7 @@ public class DbPlatformTypeMapping {
}
}
private static DbPlatformTypeLookup lookup = new DbPlatformTypeLookup();
private static final DbPlatformTypeLookup lookup = new DbPlatformTypeLookup();
private static final DbPlatformType BOOLEAN_LOGICAL = new BooleanLogicalType();
@@ -8,7 +8,7 @@ import java.util.Map;
*/
public class SqlErrorCodes {
private Map<String,DataErrorType> map = new HashMap<>();
private final Map<String,DataErrorType> map = new HashMap<>();
/**
* Map the codes to AcquireLockException.
@@ -10,7 +10,7 @@ import java.util.Set;
*/
public class QueryPlanRequest {
private List<MetaQueryPlan> plans = new ArrayList<>();
private final List<MetaQueryPlan> plans = new ArrayList<>();
private Connection connection;
@@ -10,7 +10,7 @@ import java.util.ServiceLoader;
*/
class MetricServiceProvider {
private static MetricFactory metricFactory = init();
private static final MetricFactory metricFactory = init();
private static MetricFactory init() {
@@ -223,7 +223,6 @@ public interface BeanType<T> {
/**
* Visit all children recursively
* @param visitor
*/
void visitAllInheritanceChildren(Consumer<BeanType<?>> visitor);
@@ -77,7 +77,7 @@ public interface ExpressionPath {
/**
* Return the underlying bean property.
*/
public Property getProperty();
Property getProperty();
/**
* The ElPrefix plus name.
@@ -49,13 +49,12 @@ class PathPropertiesParser {
private String getPath() {
do {
char c1 = chars[pos++];
switch (c1) {
case '(':
return currentWord();
default:
if (pos == 1) {
return "";
}
if (c1 == '(') {
return currentWord();
} else {
if (pos == 1) {
return "";
}
}
} while (pos < eof);
throw new RuntimeException("Hit EOF while reading sectionTitle from " + startPos);
@@ -8,7 +8,7 @@ import java.util.List;
*/
public class BeanCacheResult<T> {
private List<Entry<T>> list = new ArrayList<>();
private final List<Entry<T>> list = new ArrayList<>();
/**
* Add an entry.
@@ -115,10 +115,10 @@ public class BindParams implements Serializable {
* Return a Natural Key bind param if supported.
*/
public NaturalKeyBindParam getNaturalKeyBindParam() {
if (positionedParameters != null) {
if (!positionedParameters.isEmpty()) {
return null;
}
if (namedParameters != null && namedParameters.size() == 1) {
if (namedParameters.size() == 1) {
Entry<String, Param> e = namedParameters.entrySet().iterator().next();
return new NaturalKeyBindParam(e.getKey(), e.getValue().getInValue());
}
@@ -12,8 +12,8 @@ import java.util.Map;
*/
public class NaturalKeyEntry {
private Map<String,Object> map = new HashMap<>();
private Object key;
private final Map<String,Object> map = new HashMap<>();
private final Object key;
private Object inValue;
/**
@@ -17,7 +17,7 @@ public class ScopedTransaction extends SpiTransactionProxy {
/**
* Stack of 'nested' transactions.
*/
private ArrayStack<ScopeTrans> stack = new ArrayStack<>();
private final ArrayStack<ScopeTrans> stack = new ArrayStack<>();
private ScopeTrans current;
@@ -106,9 +106,9 @@ public interface SpiQuery<T> extends Query<T>, TxnProfileEventCodes {
*/
UPDATE(FIND_UPDATE, "update", true);
private boolean update;
private String profileEventId;
private String label;
private final boolean update;
private final String profileEventId;
private final String label;
Type(String profileEventId, String label) {
this(profileEventId, label, false);
@@ -75,7 +75,7 @@ public class TransactionEvent implements Serializable {
* Return the list of PersistRequestBean's for this transaction.
*/
public List<PersistRequestBean<?>> getListenerNotify() {
return (listenerNotify == null) ? null : listenerNotify;
return listenerNotify;
}
public TransactionEventTable getEventTables() {
@@ -60,10 +60,7 @@ class LastMigration {
}
private static boolean includeSqlFile(String lowerFileName) {
if (lowerFileName.startsWith("r") || lowerFileName.startsWith("i") || !lowerFileName.endsWith(SQL)) {
return false;
}
return true;
return !lowerFileName.startsWith("r") && !lowerFileName.startsWith("i") && lowerFileName.endsWith(SQL);
}
private static boolean includeModelFile(String lowerFileName) {
@@ -62,14 +62,14 @@ public class BaseTableDdl implements TableDdl {
* Used to check that indexes on foreign keys should be skipped as a unique index on the columns
* already exists.
*/
protected IndexSet indexSet = new IndexSet();
protected final IndexSet indexSet = new IndexSet();
/**
* Used when unique constraints specifically for OneToOne can't be created normally (MsSqlServer).
*/
protected List<Column> externalUnique = new ArrayList<>();
protected final List<Column> externalUnique = new ArrayList<>();
protected List<UniqueConstraint> externalCompoundUnique = new ArrayList<>();
protected final List<UniqueConstraint> externalCompoundUnique = new ArrayList<>();
// counters used when constraint names are truncated due to maximum length
// and these counters are used to keep the constraint name unique
@@ -82,9 +82,9 @@ public class BaseTableDdl implements TableDdl {
* Base tables that have associated history tables that need their triggers/functions regenerated as
* columns have been added, removed, included or excluded.
*/
protected Map<String, HistoryTableUpdate> regenerateHistoryTriggers = new LinkedHashMap<>();
protected final Map<String, HistoryTableUpdate> regenerateHistoryTriggers = new LinkedHashMap<>();
private boolean strictMode;
private final boolean strictMode;
private final HistorySupport historySupport;
@@ -134,7 +134,7 @@ public class BaseTableDdl implements TableDdl {
if (defaultValue == null) {
handleStrictError(tableName, columnName);
}
before = Arrays.asList(platformDdl.getUpdateNullWithDefault());
before = Collections.singletonList(platformDdl.getUpdateNullWithDefault());
} else {
before = getScriptsForPlatform(alter.getBefore(), platformDdl.getPlatform().getName());
}
@@ -150,7 +150,7 @@ public class CurrentModel {
List<DdlScript> ddlScript = extraDdl.getDdlScript();
for (DdlScript script : ddlScript) {
if (script.isInit() && ExtraDdlXmlReader.matchPlatform(server.getDatabasePlatform().getName(), script.getPlatforms())) {
ddl.append(prefix + script.getName()).append('\n');
ddl.append(prefix).append(script.getName()).append('\n');
ddl.append(script.getValue());
}
}
@@ -8,6 +8,7 @@ import io.ebeaninternal.dbmigration.migration.DdlScript;
import io.ebeaninternal.server.deploy.DbMigrationInfo;
import java.util.List;
import java.util.Objects;
/**
* A column in the logical model.
@@ -309,7 +310,7 @@ public class MColumn {
}
protected static boolean different(String val1, String val2) {
return (val1 == null) ? val2 != null : !val1.equals(val2);
return !Objects.equals(val1, val2);
}
private boolean hasValue(String val) {
@@ -769,7 +769,7 @@ public class MTable {
nullableColumns.add(columnName);
}
}
uniq.setNullableColumns(nullableColumns.toArray(new String[nullableColumns.size()]));
uniq.setNullableColumns(nullableColumns.toArray(new String[0]));
}
}
@@ -181,7 +181,7 @@ public class DJsonService implements SpiJsonService {
if (modifyAware) {
return ((ModifyAwareList<T>) list).asSet();
} else {
return new LinkedHashSet<T>(list);
return new LinkedHashSet<>(list);
}
}
@@ -11,7 +11,7 @@ import java.util.List;
*/
public class AutoTuneCollection {
List<Entry> entries = new ArrayList<>();
final List<Entry> entries = new ArrayList<>();
public Entry add(ObjectGraphOrigin origin, OrmQueryDetail detail, String sourceQuery) {
Entry entry = new Entry(origin, detail, sourceQuery);
@@ -8,7 +8,7 @@ import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiSqlBinding;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.server.lib.util.Str;
import io.ebeaninternal.server.lib.Str;
import io.ebeaninternal.server.persist.Binder;
import io.ebeaninternal.server.persist.TrimLogSql;
import io.ebeaninternal.server.util.BindParamsParser;
@@ -91,17 +91,13 @@ public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
if (map == null) {
return schedulePool.schedule(c, delay, unit);
} else {
return schedulePool.schedule(new Callable<V>() {
@Override
public V call() throws Exception {
MDC.setContextMap(map);
try {
return c.call();
} finally {
MDC.clear();
}
return schedulePool.schedule(() -> {
MDC.setContextMap(map);
try {
return c.call();
} finally {
MDC.clear();
}
}, delay, unit);
}
}
@@ -55,10 +55,7 @@ public class DefaultCallStackFactory implements CallStackFactory {
if (element.getClassName().startsWith(IO_EBEAN)) {
return true;
}
if (element.getMethodName().startsWith("_ebean_")) {
return true;
}
return false;
return element.getMethodName().startsWith("_ebean_");
}
private CallStack createCallStack(StackTraceElement[] finalTrace) {
@@ -102,7 +102,7 @@ import io.ebeaninternal.server.query.LimitOffsetPagedList;
import io.ebeaninternal.server.query.QueryFutureIds;
import io.ebeaninternal.server.query.QueryFutureList;
import io.ebeaninternal.server.query.QueryFutureRowCount;
import io.ebeaninternal.server.query.dto.DtoQueryEngine;
import io.ebeaninternal.server.query.DtoQueryEngine;
import io.ebeaninternal.server.querydefn.DefaultDtoQuery;
import io.ebeaninternal.server.querydefn.DefaultOrmQuery;
import io.ebeaninternal.server.querydefn.DefaultOrmUpdate;
@@ -160,7 +160,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
/**
* Clock to use for WhenModified and WhenCreated.
*/
private ClockService clockService;
private final ClockService clockService;
private final CallStackFactory callStackFactory;
@@ -658,10 +658,8 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
* </p>
*/
@Override
@SuppressWarnings("unchecked")
public <T> T createEntityBean(Class<T> type) {
BeanDescriptor<T> desc = getBeanDescriptor(type);
return (T) desc.createEntityBean(true);
return getBeanDescriptor(type).createBean();
}
/**
@@ -7,7 +7,7 @@ import io.ebeaninternal.server.dto.DtoColumn;
import io.ebeaninternal.server.dto.DtoMappingRequest;
import io.ebeaninternal.server.dto.DtoQueryPlan;
import io.ebeaninternal.server.persist.Binder;
import io.ebeaninternal.server.query.dto.DtoQueryEngine;
import io.ebeaninternal.server.query.DtoQueryEngine;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.RsetDataReader;
@@ -65,7 +65,7 @@ import io.ebeaninternal.server.persist.platform.PostgresMultiValueBind;
import io.ebeaninternal.server.query.CQueryEngine;
import io.ebeaninternal.server.query.DefaultOrmQueryEngine;
import io.ebeaninternal.server.query.DefaultRelationalQueryEngine;
import io.ebeaninternal.server.query.dto.DtoQueryEngine;
import io.ebeaninternal.server.query.DtoQueryEngine;
import io.ebeaninternal.server.readaudit.DefaultReadAuditLogger;
import io.ebeaninternal.server.readaudit.DefaultReadAuditPrepare;
import io.ebeaninternal.server.text.json.DJsonContext;
@@ -328,12 +328,10 @@ public class InternalConfiguration {
private MultiValueBind createMultiValueBind(Platform platform) {
// only Postgres at this stage
switch (platform) {
case POSTGRES:
return new PostgresMultiValueBind();
default:
return new MultiValueBind();
if (platform == Platform.POSTGRES) {
return new PostgresMultiValueBind();
}
return new MultiValueBind();
}
public SpiJsonContext createJsonContext(SpiEbeanServer server) {
@@ -24,7 +24,7 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe
DELETE_PERMANENT(EVT_DELETE_PERMANENT),
UPDATESQL(EVT_UPDATESQL),
CALLABLESQL(EVT_CALLABLESQL);
String profileEventId;
final String profileEventId;
Type(String profileEventId) {
this.profileEventId = profileEventId;
@@ -85,7 +85,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
private DocStoreMode docStoreMode;
private ConcurrencyMode concurrencyMode;
private final ConcurrencyMode concurrencyMode;
/**
* The unique id used for logging summary.
@@ -223,6 +223,12 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
beanDescriptor.setDraftDirty(entityBean, true);
}
this.dirty = intercept.isDirty();
}
/**
* Init generated properties for soft delete (as it's an update).
*/
public void initForSoftDelete() {
initGeneratedProperties();
}
@@ -1320,10 +1326,8 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
*/
public void docStorePersist() {
idValue = beanDescriptor.getId(entityBean);
switch (type) {
case UPDATE:
dirtyProperties = intercept.getDirtyProperties();
break;
if (type == Type.UPDATE) {
dirtyProperties = intercept.getDirtyProperties();
}
// processing now so set IGNORE (unlike DB + DocStore processing with post-commit)
docStoreMode = DocStoreMode.IGNORE;
@@ -1370,6 +1374,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
* Set the request flags indicating this is an insert.
*/
public void flagInsert() {
initGeneratedProperties();
if (intercept.isNew()) {
flags = Flags.setInsertNormal(flags);
} else {
@@ -1381,6 +1386,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
* Unset the request insert flag indicating this is an update.
*/
public void flagUpdate() {
initGeneratedProperties();
if (intercept.isLoaded()) {
flags = Flags.setUpdateNormal(flags);
} else {
@@ -3,7 +3,7 @@ package io.ebeaninternal.server.core;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiSqlUpdate;
import io.ebeaninternal.api.SpiTransaction;
import io.ebeaninternal.server.lib.util.Str;
import io.ebeaninternal.server.lib.Str;
import io.ebeaninternal.server.persist.BatchControl;
import io.ebeaninternal.server.persist.PersistExecute;
import io.ebeaninternal.server.persist.TrimLogSql;
@@ -29,7 +29,7 @@ public final class PersistRequestUpdateSql extends PersistRequest {
private boolean addBatch;
private boolean forceNoBatch;
private final boolean forceNoBatch;
private boolean batchThisRequest;
@@ -100,7 +100,7 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
for (int i = 1; i < columnsPlusOne; i++) {
propNames.add(metaData.getColumnLabel(i));
}
return propNames.toArray(new String[propNames.size()]);
return propNames.toArray(new String[0]);
}
/**
@@ -235,7 +235,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
/**
* Map of BeanProperty Linked so as to preserve order.
*/
protected final LinkedHashMap<String, BeanProperty> propMap;
private final LinkedHashMap<String, BeanProperty> propMap;
/**
* Map of DB column to property path (for nativeSql mapping).
@@ -252,7 +252,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
*/
final Class<T> beanType;
protected final Class<?> rootBeanType;
final Class<?> rootBeanType;
/**
* This is not sent to a remote client.
@@ -287,11 +287,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
*/
private final ChangeLogFilter changeLogFilter;
/**
* The table joins for this bean.
*/
private final TableJoin[] derivedTableJoins;
/**
* Inheritance information. Server side only.
*/
@@ -374,7 +369,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* All non transient properties excluding the id properties.
*/
private final BeanProperty[] propertiesNonTransient;
protected final BeanProperty[] propertiesIndex;
final BeanProperty[] propertiesIndex;
private final BeanProperty[] propertiesGenInsert;
private final BeanProperty[] propertiesGenUpdate;
private final List<BeanProperty[]> propertiesUnique = new ArrayList<>();
@@ -423,7 +418,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
private final BeanDescriptorDraftHelp<T> draftHelp;
private final BeanDescriptorCacheHelp<T> cacheHelp;
final BeanDescriptorJsonHelp<T> jsonHelp;
private final BeanDescriptorJsonHelp<T> jsonHelp;
private DocStoreBeanAdapter<T> docStoreAdapter;
private DocumentMapping docMapping;
private boolean docStoreEmbeddedInvalidation;
@@ -529,8 +524,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
this.propertiesGenInsert = listHelper.getGeneratedInsert();
this.propertiesGenUpdate = listHelper.getGeneratedUpdate();
this.derivedTableJoins = listHelper.getTableJoin();
boolean noRelationships = propertiesOne.length + propertiesMany.length == 0;
this.cacheSharableBeans = noRelationships && deploy.getCacheOptions().isReadOnly();
@@ -655,7 +648,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
/**
* Return true if this is an abstract type.
*/
public boolean isAbstractType() {
boolean isAbstractType() {
return abstractType;
}
@@ -689,7 +682,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* as they are used to get the imported and exported properties.
* </p>
*/
public void initialiseId(BeanDescriptorInitContext initContext) {
void initialiseId(BeanDescriptorInitContext initContext) {
if (logger.isTraceEnabled()) {
logger.trace("BeanDescriptor initialise " + fullName);
@@ -783,7 +776,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
/**
* Perform last initialisation for the descriptor.
*/
public void initLast() {
void initLast() {
for (BeanProperty prop : propertiesNonTransient) {
if (prop.isUnique()) {
@@ -825,7 +818,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
* Initialise the document mapping.
*/
@SuppressWarnings("unchecked")
public void initialiseDocMapping() {
void initialiseDocMapping() {
for (BeanPropertyAssocMany<?> many : propertiesMany) {
many.initialisePostTarget();
}
@@ -840,7 +833,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
cacheHelp.deriveNotifyFlags();
}
public void initInheritInfo() {
void initInheritInfo() {
if (inheritInfo != null) {
// need to check every BeanDescriptor in the inheritance hierarchy
if (saveRecurseSkippable) {
@@ -894,7 +887,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
/**
* Return the ReadAuditPrepare for preparing read audit events prior to logging.
*/
public ReadAuditPrepare getReadAuditPrepare() {
private ReadAuditPrepare getReadAuditPrepare() {
return ebeanServer.getReadAuditPrepare();
}
@@ -980,7 +973,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
/**
* Populate the diff for inserts with flattened non-null property values.
*/
protected void jsonWriteForInsert(SpiJsonWriter jsonWriter, EntityBean newBean) throws IOException {
void jsonWriteForInsert(SpiJsonWriter jsonWriter, EntityBean newBean) throws IOException {
jsonWriter.writeStartObject();
for (BeanProperty prop : propertiesBaseScalar) {
prop.jsonWriteForInsert(jsonWriter, newBean);
@@ -1057,7 +1050,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
elDeployCache.put(fkey.getName(), fkey);
}
public void initialiseFkeys() {
void initialiseFkeys() {
for (BeanPropertyAssocOne<?> aPropertiesOneImported : propertiesOneImported) {
if (!aPropertiesOneImported.isFormula()) {
aPropertiesOneImported.addFkey();
@@ -1915,18 +1908,19 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
beanPostConstructListener.autowire(bean); // calls all registered listeners
beanPostConstructListener.postConstruct(bean); // calls first the @PostConstruct method and then the listeners
}
if (unloadProperties.length > 0) {
if (isNew) {
if (beanPostConstructListener != null) {
beanPostConstructListener.postCreate(bean);
// if bean is not new, postLoad will be executed later in the bean's lifecycle
}
// do not unload properties for new beans!
} else if (unloadProperties.length > 0) {
// 'unload' any properties initialised in the default constructor
EntityBeanIntercept ebi = bean._ebean_getIntercept();
for (int unloadProperty : unloadProperties) {
ebi.setPropertyUnloaded(unloadProperty);
}
}
if (beanPostConstructListener != null && isNew) {
beanPostConstructListener.postCreate(bean);
// if bean is not new, postLoad will be executed later in the bean's lifecycle
}
return bean;
} catch (Exception ex) {
@@ -2575,7 +2569,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
*/
private STreeProperty findSqlTreeFormula(String formula, String path) {
String key = formula + "-" + path;
return dynamicProperty.computeIfAbsent(key, (fullKey) -> new FormulaPropertyPath(this, formula, path).build());
return dynamicProperty.computeIfAbsent(key, (fullKey) -> FormulaPropertyPath.create(this, formula, path));
}
/**
@@ -39,7 +39,7 @@ public final class BeanDescriptorDraftHelp<T> {
}
}
return list.toArray(new BeanProperty[list.size()]);
return list.toArray(new BeanProperty[0]);
}
/**
@@ -815,7 +815,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
return new BeanTable(beanTable, this);
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void readEntityRelationships() {
// We only perform 'circular' checks etc after we have
@@ -1650,7 +1649,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
return changeLogListener;
}
public void addPrimaryKeyJoin(DeployBeanPropertyAssocOne<?> prop) {
private void addPrimaryKeyJoin(DeployBeanPropertyAssocOne<?> prop) {
String baseTable = prop.getDesc().getBaseTable();
DeployTableJoin inverse = prop.getTableJoin().createInverse(baseTable);
@@ -142,7 +142,7 @@ class BeanLifecycleAdapterFactory {
* Utility method to covert List of Method into array (because we care about performance here).
*/
static Method[] toArray(List<Method> methodList) {
return methodList.toArray(new Method[methodList.size()]);
return methodList.toArray(new Method[0]);
}
static RuntimeException unwrapException(ReflectiveOperationException e) {
@@ -107,6 +107,7 @@ public abstract class BeanPropertyAssoc<T> extends BeanProperty implements STree
/**
* Copy constructor for ManyToOne inside Embeddable.
*/
@SuppressWarnings("unchecked")
public BeanPropertyAssoc(BeanPropertyAssoc source, BeanPropertyOverride override) {
super(source, override);
foreignKey = source.foreignKey;
@@ -79,7 +79,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
/**
* Descriptor for the 'target' when the property maps to an element collection.
*/
BeanDescriptor<T> elementDescriptor;
final BeanDescriptor<T> elementDescriptor;
/**
* Order by used when fetch joining the associated many.
@@ -683,7 +683,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
}
}
return list.toArray(new ExportedProperty[list.size()]);
return list.toArray(new ExportedProperty[0]);
}
/**
@@ -23,6 +23,7 @@ import io.ebeaninternal.server.query.SqlBeanLoad;
import io.ebeaninternal.server.query.SqlJoinType;
import io.ebeaninternal.server.type.DataReader;
import io.ebeaninternal.server.type.ScalarDataReader;
import io.ebeaninternal.server.type.ScalarType;
import javax.persistence.PersistenceException;
import java.io.IOException;
@@ -465,6 +466,10 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
return targetDescriptor.getIdProperty();
}
public ScalarType getIdScalarType() {
return targetDescriptor.getIdProperty().scalarType;
}
/**
* Return the Id values from the given bean.
*/
@@ -577,7 +582,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
}
}
return list.toArray(new ExportedProperty[list.size()]);
return list.toArray(new ExportedProperty[0]);
}
/**
@@ -764,10 +769,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> implements STr
writeJson.writeNullField(name);
} else {
if (writeJson.isParentBean(value)) {
// bi-directional and already rendered parent
} else {
if (!writeJson.isParentBean(value)) {
// Hmmm, not writing complex non-entity bean
if (value instanceof EntityBean) {
writeJson.beginAssocOne(name, bean);
@@ -8,6 +8,7 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
*/
public class BeanPropertyIdClass extends BeanPropertyAssocOne {
@SuppressWarnings("unchecked")
public BeanPropertyIdClass(BeanDescriptorMap owner, BeanDescriptor descriptor, DeployBeanPropertyAssocOne deploy) {
super(owner, descriptor, deploy);
}
@@ -44,7 +44,7 @@ public class ChainedBeanPersistController implements BeanPersistController {
*/
public ChainedBeanPersistController(List<BeanPersistController> list) {
this.list = list;
BeanPersistController[] c = list.toArray(new BeanPersistController[list.size()]);
BeanPersistController[] c = list.toArray(new BeanPersistController[0]);
Arrays.sort(c, SORTER);
this.chain = c;
}
@@ -185,7 +185,7 @@ public class ChainedBeanPersistController implements BeanPersistController {
int i1 = o1.getExecutionOrder();
int i2 = o2.getExecutionOrder();
return (i1 < i2 ? -1 : (i1 == i2 ? 0 : 1));
return Integer.compare(i1, i2);
}
}
@@ -50,7 +50,7 @@ public class ChainedBeanPersistListener implements BeanPersistListener {
*/
public ChainedBeanPersistListener(List<BeanPersistListener> list) {
this.list = list;
this.chain = list.toArray(new BeanPersistListener[list.size()]);
this.chain = list.toArray(new BeanPersistListener[0]);
}
/**
@@ -19,7 +19,7 @@ public class ChainedBeanPostConstructListener implements BeanPostConstructListen
*/
public ChainedBeanPostConstructListener(List<BeanPostConstructListener> list) {
this.list = list;
this.chain = list.toArray(new BeanPostConstructListener[list.size()]);
this.chain = list.toArray(new BeanPostConstructListener[0]);
}
/**
@@ -19,7 +19,7 @@ public class ChainedBeanPostLoad implements BeanPostLoad {
*/
public ChainedBeanPostLoad(List<BeanPostLoad> list) {
this.list = list;
this.chain = list.toArray(new BeanPostLoad[list.size()]);
this.chain = list.toArray(new BeanPostLoad[0]);
}
/**
@@ -24,7 +24,7 @@ public class ChainedBeanQueryAdapter implements BeanQueryAdapter {
*/
public ChainedBeanQueryAdapter(List<BeanQueryAdapter> list) {
this.list = list;
BeanQueryAdapter[] c = list.toArray(new BeanQueryAdapter[list.size()]);
BeanQueryAdapter[] c = list.toArray(new BeanQueryAdapter[0]);
Arrays.sort(c, SORTER);
this.chain = c;
}
@@ -89,10 +89,7 @@ public class ChainedBeanQueryAdapter implements BeanQueryAdapter {
@Override
public int compare(BeanQueryAdapter o1, BeanQueryAdapter o2) {
int i1 = o1.getExecutionOrder();
int i2 = o2.getExecutionOrder();
return (i1 < i2 ? -1 : (i1 == i2 ? 0 : 1));
return Integer.compare(o1.getExecutionOrder(), o2.getExecutionOrder());
}
}
@@ -4,7 +4,7 @@ import io.ebeaninternal.api.SpiCacheRegion;
class DCacheRegionNone implements SpiCacheRegion {
static SpiCacheRegion INSTANCE = new DCacheRegionNone();
static final SpiCacheRegion INSTANCE = new DCacheRegionNone();
@Override
public String getName() {
@@ -31,13 +31,7 @@ public class DeployPropertyParserMap extends DeployParser {
@Override
public String getDeployWord(String expression) {
String deployExpr = map.get(expression);
if (deployExpr == null) {
return null;
} else {
return deployExpr;
}
return map.get(expression);
}
}
@@ -27,17 +27,19 @@ public final class DeployUpdateParser extends DeployParser {
public String convertWord() {
String dbWord = getDeployWord(word);
if (dbWord != null) {
return dbWord;
}
// maybe tableAlias.propertyName
return convertSubword(0, word, null);
return convertSubword(word);
}
private String convertSubword(int start, String currentWord, StringBuilder localBuffer) {
while (true) {
private String convertSubword(String currentWord) {
int start = 0;
StringBuilder localBuffer = null;
while (true) {
int dotPos = currentWord.indexOf('.', start);
if (start == 0 && dotPos == -1) {
return currentWord;
@@ -63,15 +65,11 @@ public final class DeployUpdateParser extends DeployParser {
start = dotPos + 1;
String remainder = currentWord.substring(start, currentWord.length());
//String dbWord = deployMap.get(remainder.toLowerCase());
String dbWord = getDeployWord(remainder);
if (dbWord != null) {
// we have found a match for the remainder
localBuffer.append(dbWord);
return localBuffer.toString();
} else {
//
}
}
}
@@ -84,11 +82,7 @@ public final class DeployUpdateParser extends DeployParser {
}
ElPropertyDeploy elProp = beanDescriptor.getElPropertyDeploy(expression);
if (elProp != null) {
return elProp.getDbColumn();
} else {
return null;
}
return elProp != null ? elProp.getDbColumn() : null;
}
}
@@ -16,7 +16,7 @@ class DetermineAggPath {
// a top level aggregation (so here we need to exclude Id property)
return null;
}
return path.getManyPath(0, desc);
return path.getManyPath(desc);
}
static Path paths(String aggregation) {
@@ -82,9 +82,9 @@ class DetermineAggPath {
}
}
String getManyPath(int pos, DeployBeanDescriptor<?> desc) {
String getManyPath(DeployBeanDescriptor<?> desc) {
int pos = 0;
while (true) {
String path = paths[pos];
DeployBeanProperty details = desc.getBeanProperty(path);
if (details instanceof DeployBeanPropertyAssocMany<?>) {
@@ -92,8 +92,7 @@ class DetermineAggPath {
} else if (details instanceof DeployBeanPropertyAssocOne<?>) {
DeployBeanPropertyAssocOne<?> one = (DeployBeanPropertyAssocOne<?>) details;
DeployBeanDescriptor<?> targetDesc = one.getTargetDeploy();
desc = targetDesc;
desc = one.getTargetDeploy();
pos = pos + 1;
continue;
}
@@ -16,7 +16,7 @@ class DynamicPropertyAggregationFormula extends DynamicPropertyBase {
private final boolean aggregate;
private final BeanProperty asTarget;
final BeanProperty asTarget;
private final String alias;
@@ -0,0 +1,33 @@
package io.ebeaninternal.server.deploy;
import io.ebeaninternal.server.query.SqlBeanLoad;
public class DynamicPropertyAggregationFormulaMTO extends DynamicPropertyAggregationFormula {
private final BeanPropertyAssocOne prop;
DynamicPropertyAggregationFormulaMTO(BeanPropertyAssocOne prop, String name, String parsedFormula, boolean aggregate, BeanProperty asTarget, String alias) {
super(name, prop.getIdScalarType(), parsedFormula, aggregate, asTarget, alias);
this.prop = prop;
}
@Override
public boolean isAggregationManyToOne() {
return true;
}
@Override
public void load(SqlBeanLoad sqlBeanLoad) {
Object value;
try {
value = prop.read(sqlBeanLoad.ctx());
} catch (Exception e) {
sqlBeanLoad.ctx().handleLoadError(fullName, e);
return;
}
if (asTarget != null) {
sqlBeanLoad.load(asTarget, value);
}
}
}
@@ -11,7 +11,7 @@ class ElementEntityBean implements EntityBean {
private Object[] data;
private EntityBeanIntercept intercept;
private final EntityBeanIntercept intercept;
ElementEntityBean(String[] properties) {
this.properties = properties;
@@ -15,7 +15,7 @@ class ElementHelpList implements ElementHelp {
private static class Collector implements ElementCollector {
private List<Object> list = new ArrayList<>();
private final List<Object> list = new ArrayList<>();
@Override
public void addElement(Object element) {
@@ -15,7 +15,7 @@ class ElementHelpMap implements ElementHelp {
private static class Collector implements ElementCollector {
private Map<Object, Object> map = new LinkedHashMap<>();
private final Map<Object, Object> map = new LinkedHashMap<>();
@Override
public void addElement(Object element) {
@@ -15,7 +15,7 @@ class ElementHelpSet implements ElementHelp {
private static class Collector implements ElementCollector {
private Set<Object> set = new LinkedHashSet<>();
private final Set<Object> set = new LinkedHashSet<>();
@Override
public void addElement(Object element) {
@@ -6,7 +6,7 @@ import io.ebeaninternal.server.type.ScalarType;
import java.sql.Types;
class FormulaPropertyPath {
final class FormulaPropertyPath {
private static final String[] AGG_FUNCTIONS = {"count", "max", "min", "avg", "sum"};
@@ -20,17 +20,22 @@ class FormulaPropertyPath {
private final String internalExpression;
private final String path;
private final ElPropertyDeploy firstProp;
private final String parsedAggregation;
private boolean countDistinct;
private String cast;
private String alias;
static STreeProperty create(BeanDescriptor<?> descriptor, String formula, String path) {
return new FormulaPropertyPath(descriptor, formula, path).build();
}
FormulaPropertyPath(BeanDescriptor<?> descriptor, String formula, String path) {
this.descriptor = descriptor;
this.formula = formula;
this.path = path;
int openBracket = formula.indexOf('(');
int closeBracket = formula.lastIndexOf(')');
@@ -38,13 +43,21 @@ class FormulaPropertyPath {
throw new IllegalStateException("Unable to parse formula [" + formula + "]");
}
outerFunction = formula.substring(0, openBracket).trim();
internalExpression = trimDistinct(formula.substring(openBracket+1, closeBracket));
internalExpression = trimDistinct(formula.substring(openBracket + 1, closeBracket));
if (closeBracket < formula.length() -1) {
if (closeBracket < formula.length() - 1) {
// ::CastType as foo
String suffix = formula.substring(closeBracket+1).trim();
parseSuffix(suffix);
parseSuffix(formula.substring(closeBracket + 1).trim());
}
DeployPropertyParser parser = descriptor.parser().setCatchFirst(true);
String parsed = parser.parse(internalExpression);
if (path != null) {
// fetch("machineStats", "sum(hours), sum(totalKms)")
parsed = parsed.replace("${}", "${" + path + "}");
}
this.parsedAggregation = buildFormula(parsed);
this.firstProp = parser.getFirstProp();
}
private void parseSuffix(String suffix) {
@@ -93,42 +106,50 @@ class FormulaPropertyPath {
STreeProperty build() {
DeployPropertyParser parser = descriptor.parser().setCatchFirst(true);
String parsed = parser.parse(internalExpression);
if (path != null) {
// fetch("machineStats", "sum(hours), sum(totalKms)")
parsed = parsed.replace("${}", "${" + path + "}");
}
ElPropertyDeploy firstProp = parser.getFirstProp();
ScalarType<?> scalarType;
if (cast != null) {
scalarType = descriptor.getScalarType(cast);
ScalarType<?> scalarType = descriptor.getScalarType(cast);
if (scalarType == null) {
throw new IllegalStateException("Unable to find scalarType for cast of ["+cast+"] on formula [" + formula + "] for type " + descriptor);
}
} else if (isCount()) {
scalarType = descriptor.getScalarType(Types.BIGINT);
} else if (isConcat()) {
scalarType = descriptor.getScalarType(Types.VARCHAR);
} else {
// determine scalarType based on first property found by parser
if (firstProp != null) {
scalarType = firstProp.getBeanProperty().getScalarType();
} else {
throw new IllegalStateException("unable to determine scalarType of formula [" + formula + "] for type " + descriptor + " - maybe use a cast like ::String ?");
throw new IllegalStateException("Unable to find scalarType for cast of [" + cast + "] on formula [" + formula + "] for type " + descriptor);
}
return create(scalarType);
}
if (isCount()) {
return create(descriptor.getScalarType(Types.BIGINT));
}
if (isConcat()) {
return create(descriptor.getScalarType(Types.VARCHAR));
}
if (firstProp == null) {
throw new IllegalStateException("unable to determine scalarType of formula [" + formula + "] for type " + descriptor + " - maybe use a cast like ::String ?");
}
String logicalName = (alias == null) ? internalExpression : alias;
BeanProperty targetProperty = descriptor._findBeanProperty(logicalName);
String parsedAggregation = buildFormula(parsed);
return new DynamicPropertyAggregationFormula(logicalName, scalarType, parsedAggregation, isAggregate(), targetProperty, alias);
// determine scalarType based on first property found by parser
final BeanProperty property = firstProp.getBeanProperty();
if (!property.isAssocId()) {
return create(property.getScalarType());
} else {
return createManyToOne(property);
}
}
private DynamicPropertyAggregationFormula create(ScalarType<?> scalarType) {
String logicalName = logicalName();
return new DynamicPropertyAggregationFormula(logicalName, scalarType, parsedAggregation, isAggregate(), target(logicalName), alias);
}
private DynamicPropertyAggregationFormula createManyToOne(BeanProperty property) {
String logicalName = logicalName();
return new DynamicPropertyAggregationFormulaMTO((BeanPropertyAssocOne) property, logicalName, parsedAggregation, isAggregate(), target(logicalName), alias);
}
private BeanProperty target(String logicalName) {
return descriptor._findBeanProperty(logicalName);
}
private String logicalName() {
return (alias == null) ? internalExpression : alias;
}
private boolean isAggregate() {
@@ -346,19 +346,20 @@ public final class IdBinderEmbedded implements IdBinder {
public Object read(DbReadContext ctx) throws SQLException {
EntityBean embId = idDesc.createEntityBean();
boolean notNull = true;
boolean nullValue = true;
for (BeanProperty prop : props) {
Object value = prop.readSet(ctx, embId);
if (value == null) {
notNull = false;
Object value = prop.read(ctx);
if (value != null) {
prop.setValue(embId, value);
nullValue = false;
}
}
if (notNull) {
return embId;
} else {
if (nullValue) {
return null;
} else {
return embId;
}
}
@@ -78,7 +78,7 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
*/
public static ImportedIdSimple[] sort(List<ImportedIdSimple> list) {
ImportedIdSimple[] importedIds = list.toArray(new ImportedIdSimple[list.size()]);
ImportedIdSimple[] importedIds = list.toArray(new ImportedIdSimple[0]);
// sort into the same order as the BeanProperties
Arrays.sort(importedIds, COMPARATOR);
@@ -100,7 +100,7 @@ public final class ImportedIdSimple implements ImportedId, Comparable<ImportedId
@Override
public int compareTo(ImportedIdSimple other) {
return (position < other.position ? -1 : (position == other.position ? 0 : 1));
return Integer.compare(position, other.position);
}
@Override
@@ -561,7 +561,7 @@ public class DeployBeanDescriptor<T> {
if (indexDefinitions == null) {
return null;
} else {
return indexDefinitions.toArray(new IndexDefinition[indexDefinitions.size()]);
return indexDefinitions.toArray(new IndexDefinition[0]);
}
}
@@ -1267,6 +1267,7 @@ public class DeployBeanDescriptor<T> {
/**
* Returns the jackson annotated class, if jackson is present.
*/
@SuppressWarnings("unchecked")
public Object /*AnnotatedClass*/ getJacksonAnnotatedClass() {
if (jacksonAnnotatedClass == null) {
jacksonAnnotatedClass = new DeployBeanObtainJackson(serverConfig, beanType).obtain();
@@ -249,7 +249,7 @@ public class DeployBeanProperty {
/**
* Wrap the ScalarType using a ScalarTypeConverter.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
@SuppressWarnings({"unchecked"})
private ScalarType<?> wrapScalarType(Class<?> propertyType, ScalarType<?> scalarType, ScalarTypeConverter<?, ?> typeConverter) {
if (typeConverter == null) {
return scalarType;
@@ -71,7 +71,7 @@ public class DeployBeanPropertyLists {
private final BeanPropertyAssocOne<?> unidirectional;
private final BeanProperty orderColumn;
@SuppressWarnings({"unchecked", "rawtypes"})
@SuppressWarnings({"unchecked"})
public DeployBeanPropertyLists(BeanDescriptorMap owner, BeanDescriptor<?> desc, DeployBeanDescriptor<?> deploy) {
this.desc = desc;
@@ -284,7 +284,7 @@ public class DeployBeanPropertyLists {
* properties).
*/
public BeanProperty[] getBaseScalar() {
return baseScalar.toArray(new BeanProperty[baseScalar.size()]);
return baseScalar.toArray(new BeanProperty[0]);
}
public BeanProperty getId() {
@@ -292,11 +292,11 @@ public class DeployBeanPropertyLists {
}
public BeanProperty[] getNonTransients() {
return nonTransients.toArray(new BeanProperty[nonTransients.size()]);
return nonTransients.toArray(new BeanProperty[0]);
}
public BeanProperty[] getTransients() {
return transients.toArray(new BeanProperty[transients.size()]);
return transients.toArray(new BeanProperty[0]);
}
public BeanProperty getVersionProperty() {
@@ -304,23 +304,23 @@ public class DeployBeanPropertyLists {
}
public BeanProperty[] getLocal() {
return local.toArray(new BeanProperty[local.size()]);
return local.toArray(new BeanProperty[0]);
}
public BeanProperty[] getMutable() {
return mutable.toArray(new BeanProperty[mutable.size()]);
return mutable.toArray(new BeanProperty[0]);
}
public BeanPropertyAssocOne<?>[] getEmbedded() {
return embedded.toArray(new BeanPropertyAssocOne[embedded.size()]);
return embedded.toArray(new BeanPropertyAssocOne[0]);
}
public BeanPropertyAssocOne<?>[] getOneImported() {
return onesImported.toArray(new BeanPropertyAssocOne[onesImported.size()]);
return onesImported.toArray(new BeanPropertyAssocOne[0]);
}
public BeanPropertyAssocOne<?>[] getOnes() {
return ones.toArray(new BeanPropertyAssocOne[ones.size()]);
return ones.toArray(new BeanPropertyAssocOne[0]);
}
public BeanPropertyAssocOne<?>[] getOneExportedSave() {
@@ -340,11 +340,11 @@ public class DeployBeanPropertyLists {
}
public BeanProperty[] getNonMany() {
return nonManys.toArray(new BeanProperty[nonManys.size()]);
return nonManys.toArray(new BeanProperty[0]);
}
public BeanPropertyAssocMany<?>[] getMany() {
return manys.toArray(new BeanPropertyAssocMany[manys.size()]);
return manys.toArray(new BeanPropertyAssocMany[0]);
}
public BeanPropertyAssocMany<?>[] getManySave() {
@@ -397,7 +397,7 @@ public class DeployBeanPropertyLists {
list.add(prop);
}
}
return list.toArray(new BeanProperty[list.size()]);
return list.toArray(new BeanProperty[0]);
}
/**
@@ -412,7 +412,7 @@ public class DeployBeanPropertyLists {
list.add(prop);
}
}
return list.toArray(new BeanProperty[list.size()]);
return list.toArray(new BeanProperty[0]);
}
/**
@@ -443,7 +443,7 @@ public class DeployBeanPropertyLists {
}
}
return (BeanPropertyAssocOne[]) list.toArray(new BeanPropertyAssocOne[list.size()]);
return (BeanPropertyAssocOne[]) list.toArray(new BeanPropertyAssocOne[0]);
}
private BeanPropertyAssocMany<?>[] getMany2Many() {
@@ -454,7 +454,7 @@ public class DeployBeanPropertyLists {
}
}
return (BeanPropertyAssocMany[]) list.toArray(new BeanPropertyAssocMany[list.size()]);
return (BeanPropertyAssocMany[]) list.toArray(new BeanPropertyAssocMany[0]);
}
private BeanPropertyAssocMany<?>[] getMany(Mode mode) {
@@ -476,7 +476,7 @@ public class DeployBeanPropertyLists {
}
}
return (BeanPropertyAssocMany[]) list.toArray(new BeanPropertyAssocMany[list.size()]);
return (BeanPropertyAssocMany[]) list.toArray(new BeanPropertyAssocMany[0]);
}
@SuppressWarnings({"unchecked", "rawtypes"})
@@ -54,7 +54,7 @@ public class DeployBeanTable {
return idProperty == null ? null : createProperty(owner, idProperty);
}
@SuppressWarnings({"unchecked", "rawtypes"})
@SuppressWarnings({"unchecked"})
private BeanProperty createProperty(BeanDescriptorMap owner, DeployBeanProperty prop) {
if (prop instanceof DeployBeanPropertyAssocOne<?>) {
@@ -106,7 +106,7 @@ public class DeployTableJoin {
* Return the join columns.
*/
public DeployTableJoinColumn[] columns() {
return columns.toArray(new DeployTableJoinColumn[columns.size()]);
return columns.toArray(new DeployTableJoinColumn[0]);
}
/**
@@ -183,6 +183,7 @@ class AnnotationAssocManys extends AnnotationParser {
}
}
@SuppressWarnings("unchecked")
private void readElementCollection(DeployBeanPropertyAssocMany<?> prop, ElementCollection elementCollection) {
prop.setElementCollection();
@@ -189,7 +189,7 @@ public class AnnotationAssocOnes extends AnnotationParser {
private void checkForNoConstraint(DeployBeanPropertyAssocOne<?> prop, JoinColumn joinColumn) {
ForeignKey foreignKey = joinColumn.foreignKey();
if (foreignKey != null && foreignKey.value() == ConstraintMode.NO_CONSTRAINT) {
if (foreignKey.value() == ConstraintMode.NO_CONSTRAINT) {
prop.setForeignKey(new PropertyForeignKey());
}
}
@@ -496,7 +496,7 @@ public class AnnotationFields extends AnnotationParser {
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
@SuppressWarnings({"unchecked"})
private ScalarTypeEncryptedWrapper<?> createScalarType(DeployBeanProperty prop, ScalarType<?> st) {
// Use Java Encryptor wrapping the logical scalar type
@@ -199,7 +199,7 @@ public class DeployCreateProperties {
return null;
}
@SuppressWarnings({"unchecked", "rawtypes"})
@SuppressWarnings({"unchecked"})
private DeployBeanProperty createManyType(DeployBeanDescriptor<?> desc, Class<?> targetType, ManyType manyType) {
try {
@@ -213,7 +213,7 @@ public class DeployCreateProperties {
return new DeployBeanPropertyAssocMany(desc, targetType, manyType);
}
@SuppressWarnings({"unchecked", "rawtypes"})
@SuppressWarnings({"unchecked"})
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field) {
Class<?> propertyType = field.getType();
@@ -175,7 +175,7 @@ class ElMatchBuilder {
final Set<?> set;
final ElPropertyValue elGetValue;
@SuppressWarnings({"unchecked", "rawtypes"})
@SuppressWarnings({"unchecked"})
public InSet(Set<?> set, ElPropertyValue elGetValue) {
this.set = new HashSet(set);
this.elGetValue = elGetValue;
@@ -58,13 +58,12 @@ public class ElPropertyChainBuilder {
* Build the immutable ElGetChain from the build information.
*/
public ElPropertyChain build() {
return new ElPropertyChain(containsMany, embedded, expression, chain.toArray(new ElPropertyValue[chain.size()]));
return new ElPropertyChain(containsMany, embedded, expression, chain.toArray(new ElPropertyValue[0]));
}
/**
* Permits to set whole chain as embedded when the leaf is embedded
* @param embedded
*/
*/
public void setEmbedded(boolean embedded) {
this.embedded = embedded;
}
@@ -8,7 +8,7 @@ import java.io.IOException;
class CaseInsensitiveEqualExpression extends AbstractValueExpression {
private boolean not;
private final boolean not;
CaseInsensitiveEqualExpression(String propertyName, Object value, boolean not) {
super(propertyName, value);
@@ -303,9 +303,7 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
*/
private boolean isZero(Object value) {
if (value instanceof Number) {
Number num = (Number) value;
double doubleValue = num.doubleValue();
if (doubleValue == 0) {
if (((Number) value).doubleValue() == 0) {
return true;
}
}
@@ -60,7 +60,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
private final ExpressionList<T> parentExprList;
protected ExpressionFactory expr;
protected final ExpressionFactory expr;
String allDocNestedPath;
@@ -495,7 +495,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
}
@Override
public Query<T> select(FetchGroup fetchGroup) {
public Query<T> select(FetchGroup<T> fetchGroup) {
return query.select(fetchGroup);
}
@@ -4,6 +4,7 @@ import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import java.io.IOException;
import java.util.Objects;
/**
* Generally speaking tests the value at a given path in the JSON document.
@@ -91,8 +92,8 @@ class JsonPathExpression extends AbstractExpression {
@Override
public boolean isSameByBind(SpiExpression other) {
JsonPathExpression that = (JsonPathExpression) other;
if (value != null ? !value.equals(that.value) : that.value != null) return false;
return upperValue != null ? upperValue.equals(that.upperValue) : that.upperValue == null;
if (!Objects.equals(value, that.value)) return false;
return Objects.equals(upperValue, that.upperValue);
}
@Override
@@ -2,6 +2,7 @@ package io.ebeaninternal.server.expression;
import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;
/**
* Utility to help isSame methods.
@@ -12,14 +13,14 @@ public class Same {
* Return true if both values are null or both an not null.
*/
public static boolean sameByNull(Object v1, Object v2) {
return v1 == null ? v2 == null : v2 != null;
return (v1 == null) == (v2 == null);
}
/**
* Null safe equals check.
*/
public static boolean sameByValue(Object v1, Object v2) {
return v1 == null ? v2 == null : v1.equals(v2);
return Objects.equals(v1, v2);
}
/**
@@ -261,10 +261,7 @@ class EqlAdapter<T> extends EQLBaseListener {
}
private boolean isValue(String text) {
if (text.length() == 1 && (text.equals("(") || text.equals(")") || text.equals(","))) {
return false;
}
return true;
return text.length() != 1 || (!text.equals("(") && !text.equals(")") && !text.equals(","));
}
@Override
@@ -5,7 +5,7 @@ import java.util.Map;
class OperatorMapping {
Map<String, EqlOperator> map = new HashMap<>();
final Map<String, EqlOperator> map = new HashMap<>();
public OperatorMapping() {
map.put("eq", EqlOperator.EQ);
@@ -1,4 +1,4 @@
package io.ebeaninternal.server.lib.util;
package io.ebeaninternal.server.lib;
/**
* String utility for adding strings together.
@@ -1,12 +0,0 @@
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
<TITLE>AvajeLib</TITLE>
</HEAD>
<Body BGCOLOR="#ffffff">
General utility objects.
<P>Provides general utility objects.
</P>
</Body>
</HTML>
@@ -49,7 +49,7 @@ public class DLoadContext implements LoadContext {
private final boolean disableLazyLoading;
private final boolean disableReadAudit;
private final boolean includeSoftDeletes;
protected final boolean useDocStore;
final boolean useDocStore;
/**
* The path relative to the root of the object graph.
@@ -137,7 +137,7 @@ public class DLoadContext implements LoadContext {
/**
* Return the query plan label of the origin query.
*/
public String getPlanLabel() {
String getPlanLabel() {
return planLabel;
}
@@ -180,7 +180,7 @@ public class DLoadContext implements LoadContext {
registerSecondaryNode(many, props);
}
protected boolean isBeanCacheGet() {
boolean isBeanCacheGet() {
return useBeanCache.isGet();
}
@@ -247,7 +247,7 @@ public class DLoadContext implements LoadContext {
return new ObjectGraphNode(origin, path);
}
protected String getFullPath(String path) {
String getFullPath(String path) {
if (relativePath == null) {
return path;
} else {
@@ -295,12 +295,11 @@ public class DLoadContext implements LoadContext {
getManyContext(path).register(bc);
}
protected DLoadBeanContext getBeanContext(String path) {
DLoadBeanContext getBeanContext(String path) {
if (path == null) {
return rootBeanContext;
}
DLoadBeanContext beanContext = beanMap.computeIfAbsent(path, p -> createBeanContext(p, defaultBatchSize, null));
return beanContext;
return beanMap.computeIfAbsent(path, p -> createBeanContext(p, defaultBatchSize, null));
}
private void registerSecondaryNode(boolean many, OrmQueryProperties props) {
@@ -321,27 +320,23 @@ public class DLoadContext implements LoadContext {
}
}
protected DLoadManyContext getManyContext(String path) {
DLoadManyContext getManyContext(String path) {
if (path == null) {
throw new RuntimeException("path is null?");
}
DLoadManyContext ctx = manyMap.computeIfAbsent(path, p -> createManyContext(p, defaultBatchSize, null));
return ctx;
return manyMap.computeIfAbsent(path, p -> createManyContext(p, defaultBatchSize, null));
}
private DLoadManyContext createManyContext(String path, int batchSize, OrmQueryProperties queryProps) {
BeanPropertyAssocMany<?> p = (BeanPropertyAssocMany<?>) getBeanProperty(rootDescriptor, path);
return new DLoadManyContext(this, p, path, batchSize, queryProps);
}
private DLoadBeanContext createBeanContext(String path, int batchSize, OrmQueryProperties queryProps) {
BeanPropertyAssoc<?> p = (BeanPropertyAssoc<?>) getBeanProperty(rootDescriptor, path);
BeanDescriptor<?> targetDescriptor = p.getTargetDescriptor();
return new DLoadBeanContext(this, targetDescriptor, path, batchSize, queryProps);
return new DLoadBeanContext(this, p.getTargetDescriptor(), path, batchSize, queryProps);
}
private BeanProperty getBeanProperty(BeanDescriptor<?> desc, String path) {
@@ -351,7 +346,7 @@ public class DLoadContext implements LoadContext {
/**
* Propagate the original query settings (draft, asOf etc) to the secondary queries.
*/
public void propagateQueryState(SpiQuery<?> query, boolean docStoreMapped) {
void propagateQueryState(SpiQuery<?> query, boolean docStoreMapped) {
if (useDocStore && docStoreMapped) {
query.setUseDocStore(true);
}
@@ -5,12 +5,12 @@ import io.ebeaninternal.server.core.PersistRequest;
import io.ebeaninternal.server.core.PersistRequestBean;
import io.ebeaninternal.server.core.PersistRequestUpdateSql;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
/**
@@ -29,6 +29,8 @@ import java.util.List;
*/
public final class BatchControl {
private static final Object DUMMY = new Object();
/**
* Used to sort queue entries by depth.
*/
@@ -46,6 +48,17 @@ public final class BatchControl {
*/
private final HashMap<String, BatchedBeanHolder> beanHoldMap = new HashMap<>();
/**
* Set of beans in this batch. This is used to ensure that a single bean instance is not included
* in the batch twice (two separate insert requests etc).
*/
private final IdentityHashMap<Object, Object> persistedBeans = new IdentityHashMap<>();
/**
* Helper to determine statement ordering based on depth (and type).
*/
private final BatchDepthOrder depthOrder = new BatchDepthOrder();
private final SpiTransaction transaction;
/**
@@ -63,13 +76,10 @@ public final class BatchControl {
private boolean batchFlushOnMixed = true;
private int maxDepth;
/**
* Size of the largest buffer.
*/
private int bufferMax;
private int topCounter;
private Queue earlyQueue;
private Queue lateQueue;
@@ -183,6 +193,14 @@ public final class BatchControl {
*/
private boolean addToBatch(PersistRequestBean<?> request) throws BatchedSqlException {
Object alreadyInBatch = persistedBeans.put(request.getEntityBean(), DUMMY);
if (alreadyInBatch != null) {
// special case where the same bean instance has already been
// added to the batch (doesn't really occur with non-batching
// as the bean gets changed from dirty to loaded earlier)
return false;
}
BatchedBeanHolder beanHolder = getBeanHolder(request);
int bufferSize = beanHolder.append(request);
@@ -227,14 +245,14 @@ public final class BatchControl {
}
/**
* Flush without resetting the topOrder (maintains the depth info).
* Flush without resetting the depth info.
*/
public void flush() throws BatchedSqlException {
flushBuffer(false);
}
/**
* Flush with a reset the topOrder (fully empty the batch).
* Flush with a reset of the depth info.
*/
public void flushReset() throws BatchedSqlException {
flushBuffer(true);
@@ -246,8 +264,8 @@ public final class BatchControl {
public void clear() {
pstmtHolder.clear();
beanHoldMap.clear();
maxDepth = 0;
topCounter = 0;
depthOrder.clear();
persistedBeans.clear();
}
private void flushBuffer(boolean resetTop) throws BatchedSqlException {
@@ -289,10 +307,10 @@ public final class BatchControl {
for (BatchedBeanHolder beanHolder : bsArray) {
beanHolder.executeNow();
}
persistedBeans.clear();
if (resetTop) {
beanHoldMap.clear();
maxDepth = 0;
depthOrder.clear();
}
} catch (BatchedSqlException e) {
// clear the batch on error in case we want to
@@ -306,76 +324,35 @@ public final class BatchControl {
* Return an entry for the given type description. The type description is
* typically the bean class name (or table name for MapBeans).
*/
private BatchedBeanHolder getBeanHolder(PersistRequestBean<?> request) throws BatchedSqlException {
private BatchedBeanHolder getBeanHolder(PersistRequestBean<?> request) {
BeanDescriptor<?> beanDescriptor = request.getBeanDescriptor();
BatchedBeanHolder batchBeanHolder = beanHoldMap.get(beanDescriptor.rootName());
int depth = transaction.depth();
BeanDescriptor<?> desc = request.getBeanDescriptor();
// batching by bean type AND depth
String key = desc.rootName() + ":" + depth;
BatchedBeanHolder batchBeanHolder = beanHoldMap.get(key);
if (batchBeanHolder == null) {
int relativeDepth = transaction.depth();
int beanDepth = 100 + relativeDepth;
if (relativeDepth == 0 && !beanHoldMap.isEmpty()) {
// could be non-cascading or uni-directional relationship
// so see look for a 'parent' in the beanHoldMap
int maybe = relativeToParentDepth(beanDescriptor);
if (maybe != -1) {
beanDepth = maybe;
} else {
// additional "top level" bean type ordered by save() order
beanDepth += ++topCounter;
}
}
maxDepth = Math.max(maxDepth, beanDepth);
batchBeanHolder = new BatchedBeanHolder(this, beanDescriptor, beanDepth);
beanHoldMap.put(beanDescriptor.rootName(), batchBeanHolder);
int ordering = depthOrder.orderingFor(depth);
batchBeanHolder = new BatchedBeanHolder(this, desc, ordering);
beanHoldMap.put(key, batchBeanHolder);
}
return batchBeanHolder;
}
/**
* Find a depth based on imported relationships (to a parent that is already in the buffer).
*/
private int relativeToParentDepth(BeanDescriptor<?> beanDescriptor) {
BeanPropertyAssocOne<?>[] imported = beanDescriptor.propertiesOneImported();
if (imported.length == 0) {
// a top level type so just maintain the order relative to the current depth
return maxDepth + 1;
}
int parentMaxDepth = -1;
for (BeanPropertyAssocOne<?> parent : imported) {
BatchedBeanHolder parentBatch = beanHoldMap.get(parent.getTargetDescriptor().rootName());
if (parentBatch != null) {
// deeper that the parent
parentMaxDepth = Math.max(parentMaxDepth, parentBatch.getOrder() + 1);
}
}
return parentMaxDepth;
}
/**
* Return true if this holds no persist requests.
*/
private boolean isBeansEmpty() {
if (beanHoldMap.isEmpty()) {
return true;
}
for (BatchedBeanHolder beanHolder : beanHoldMap.values()) {
if (!beanHolder.isEmpty()) {
return false;
}
}
return true;
return persistedBeans.isEmpty();
}
/**
* Return the BatchedBeanHolder's ready for sorting and executing.
*/
private BatchedBeanHolder[] getBeanHolderArray() {
return beanHoldMap.values().toArray(new BatchedBeanHolder[beanHoldMap.size()]);
return beanHoldMap.values().toArray(new BatchedBeanHolder[0]);
}
/**
@@ -19,13 +19,7 @@ public class BatchDepthComparator implements Comparator<BatchedBeanHolder>, Seri
@Override
public int compare(BatchedBeanHolder b1, BatchedBeanHolder b2) {
if (b1.getOrder() < b2.getOrder()) {
return -1;
}
if (b1.getOrder() == b2.getOrder()) {
return 0;
}
return 1;
return Integer.compare(b1.getOrder(), b2.getOrder());
}
}
@@ -0,0 +1,33 @@
package io.ebeaninternal.server.persist;
import java.util.HashMap;
import java.util.Map;
/**
* Helper to determine batch execution order for BatchedBeanHolders.
*/
class BatchDepthOrder {
private final Map<Integer, Counter> map = new HashMap<>();
/**
* Return the batch order for the given depth.
*/
int orderingFor(int depth) {
final Counter slot = map.computeIfAbsent(depth, integer -> new Counter());
return (depth * 100) + slot.increment();
}
void clear() {
map.clear();
}
private static class Counter {
int count;
public int increment() {
return count++;
}
}
}
@@ -5,7 +5,6 @@ import io.ebeaninternal.server.core.PersistRequestBean;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import java.util.ArrayList;
import java.util.IdentityHashMap;
/**
* Holds lists of persist requests for beans of a given type.
@@ -21,8 +20,6 @@ import java.util.IdentityHashMap;
*/
public class BatchedBeanHolder {
private static final Object DUMMY = new Object();
/**
* The owning queue.
*/
@@ -50,12 +47,6 @@ public class BatchedBeanHolder {
*/
private ArrayList<PersistRequest> deletes;
/**
* Set of beans in this batch. This is used to ensure that a single bean instance is not included
* in the batch twice (two separate insert requests etc).
*/
private final IdentityHashMap<Object, Object> persistedBeans = new IdentityHashMap<>();
/**
* Create a new entry with a given type and depth.
*/
@@ -99,7 +90,6 @@ public class BatchedBeanHolder {
updates = new ArrayList<>();
control.executeNow(bufferedUpdates);
}
persistedBeans.clear();
}
@Override
@@ -123,14 +113,6 @@ public class BatchedBeanHolder {
*/
public int append(PersistRequestBean<?> request) {
Object alreadyInBatch = persistedBeans.put(request.getEntityBean(), DUMMY);
if (alreadyInBatch != null) {
// special case where the same bean instance has already been
// added to the batch (doesn't really occur with non-batching
// as the bean gets changed from dirty to loaded earlier)
return 0;
}
request.setBatched();
switch (request.getType()) {
@@ -161,10 +143,4 @@ public class BatchedBeanHolder {
}
}
/**
* Return true if this is empty containing no batched beans.
*/
public boolean isEmpty() {
return persistedBeans.isEmpty();
}
}
@@ -114,10 +114,9 @@ public class BatchedPstmtHolder {
// the flush may get called recursively in executeBatch/postExecute.
// which leads that we process stmtMap.values() twice in the loop.
// So we copy the values, that we want to flush and clear it immediately.
BatchedPstmt[] values = stmtMap.values().toArray(new BatchedPstmt[stmtMap.values().size()]);
BatchedPstmt[] values = stmtMap.values().toArray(new BatchedPstmt[0]);
clear();
// this loop
for (BatchedPstmt bs : values) {
try {
if (!isError) {
@@ -130,12 +129,8 @@ public class BatchedPstmtHolder {
next = next.getNextException();
}
if (firstError == null) {
firstError = ex;
errorSql = bs.getSql();
} else {
logger.error("Error executing batched PreparedStatement", ex);
}
firstError = ex;
errorSql = bs.getSql();
isError = true;
} finally {
@@ -147,7 +142,6 @@ public class BatchedPstmtHolder {
}
}
if (firstError != null) {
String msg = "Error when batch flush on sql: " + errorSql;
throw new BatchedSqlException(msg, firstError);
@@ -108,7 +108,7 @@ public class Binder {
if (isLob(dt)) {
bindBuf.append("[LOB]");
} else {
bindBuf.append(String.valueOf(val));
bindBuf.append(val);
}
}
}
@@ -377,7 +377,7 @@ public final class DefaultPersister implements Persister {
* Recursively delete the bean. This calls back to the EbeanServer.
*/
private int deleteRecurse(EntityBean detailBean, Transaction t, DeleteMode deleteMode) {
return deleteRequest(createRequest(detailBean, t, deleteMode.persistType()));
return deleteRequest(createDeleteRequest(detailBean, t, deleteMode.persistType()));
}
@Override
@@ -578,12 +578,11 @@ public final class DefaultPersister implements Persister {
public int delete(EntityBean bean, Transaction t, boolean permanent) {
Type deleteType = permanent ? Type.DELETE_PERMANENT : Type.DELETE;
PersistRequestBean<EntityBean> originalRequest = createRequest(bean, t, deleteType);
PersistRequestBean<EntityBean> originalRequest = createDeleteRequest(bean, t, deleteType);
if (originalRequest.isHardDeleteDraft()) {
// a hard delete of a draftable bean so first we need to delete the associated 'live' bean
// due to FK constraint and then after that execute the original delete of the draft bean
return deleteRequest(createPublishRequest(originalRequest.createReference(), t, Type.DELETE_PERMANENT, Flags.PUBLISH), originalRequest);
return deleteRequest(createDeleteRequest(originalRequest.createReference(), t, Type.DELETE_PERMANENT, Flags.PUBLISH), originalRequest);
} else {
// normal delete or soft delete
@@ -639,8 +638,8 @@ public final class DefaultPersister implements Persister {
t.depth(-1);
t.checkBatchEscalationOnCollection();
}
for (Object aBeanList : beanList) {
deleteRecurse((EntityBean) aBeanList, t, deleteMode);
for (Object bean : beanList) {
deleteRecurse((EntityBean) bean, t, deleteMode);
}
if (children) {
t.flushBatchOnCollection();
@@ -1245,25 +1244,15 @@ public final class DefaultPersister implements Persister {
* perform an insert, update or delete.
*/
private <T> PersistRequestBean<T> createRequest(T bean, Transaction t, PersistRequest.Type type) {
return createRequestInternal(bean, t, type, Flags.ZERO);
return createRequestInternal(bean, t, type);
}
/**
* Create the Persist Request Object additionally specifying the publish status.
*/
<T> PersistRequestBean<T> createPublishRequest(T bean, Transaction t, PersistRequest.Type type, int flags) {
return createRequestInternal(bean, t, type, Flags.unsetRecuse(flags));
}
/**
* Create the Persist Request Object additionally specifying the publish status.
*/
private <T> PersistRequestBean<T> createRequestInternal(T bean, Transaction t, PersistRequest.Type type, int flags) {
private <T> PersistRequestBean<T> createRequestInternal(T bean, Transaction t, PersistRequest.Type type) {
BeanManager<T> mgr = getBeanManager(bean);
if (mgr == null) {
throw new PersistenceException(errNotRegistered(bean.getClass()));
}
return createRequest(bean, t, null, mgr, type, flags);
return createRequest(bean, t, null, mgr, type, Flags.ZERO);
}
/**
@@ -1273,9 +1262,6 @@ public final class DefaultPersister implements Persister {
*/
private <T> PersistRequestBean<T> createRequestRecurse(T bean, Transaction t, Object parentBean, int flags) {
BeanManager<T> mgr = getBeanManager(bean);
if (mgr == null) {
throw new PersistenceException(errNotRegistered(bean.getClass()));
}
BeanDescriptor<T> desc = mgr.getBeanDescriptor();
EntityBean entityBean = (EntityBean) bean;
PersistRequest.Type type;
@@ -1294,10 +1280,26 @@ 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", "rawtypes"})
@SuppressWarnings({"unchecked"})
private <T> PersistRequestBean<T> createRequest(T bean, Transaction t, Object parentBean, BeanManager<?> mgr,
PersistRequest.Type type, int flags) {
// no delete requests come here
return new PersistRequestBean(server, bean, parentBean, mgr, (SpiTransaction) t, persistExecute, type, flags);
}
<T> PersistRequestBean<T> createDeleteRemoved(T bean, Transaction t, PersistRequest.Type type, int flags) {
return createDeleteRequest(bean, t, type, Flags.unsetRecurse(flags));
}
private <T> PersistRequestBean<T> createDeleteRequest(EntityBean bean, Transaction t, Type type) {
return createDeleteRequest(bean, t, type, Flags.ZERO);
}
@SuppressWarnings({"unchecked"})
private <T> PersistRequestBean<T> createDeleteRequest(Object bean, Transaction t, PersistRequest.Type type, int flags) {
BeanManager<T> mgr = getBeanManager(bean);
if (type == Type.DELETE_PERMANENT) {
type = Type.DELETE;
} else if (type == Type.DELETE && mgr.getBeanDescriptor().isSoftDelete()) {
@@ -1305,7 +1307,9 @@ public final class DefaultPersister implements Persister {
type = Type.DELETE_SOFT;
}
return new PersistRequestBean(server, bean, parentBean, mgr, (SpiTransaction) t, persistExecute, type, flags);
PersistRequestBean<T> request = new PersistRequestBean<>(server, (T)bean, null, mgr, (SpiTransaction) t, persistExecute, type, flags);
request.initForSoftDelete();
return request;
}
private String errNotRegistered(Class<?> beanClass) {
@@ -1323,8 +1327,12 @@ public final class DefaultPersister implements Persister {
* </p>
*/
@SuppressWarnings("unchecked")
private <T> BeanManager<T> getBeanManager(T bean) {
private <T> BeanManager<T> getBeanManager(Object bean) {
return (BeanManager<T>) beanDescriptorManager.getBeanManager(bean.getClass());
BeanManager<T> mgr = (BeanManager<T>) beanDescriptorManager.getBeanManager(bean.getClass());
if (mgr == null) {
throw new PersistenceException(errNotRegistered(bean.getClass()));
}
return mgr;
}
}
@@ -18,9 +18,9 @@ public enum DeleteMode {
*/
HARD(PersistRequest.Type.DELETE_PERMANENT, true);
private boolean hard;
private final boolean hard;
private PersistRequest.Type persistType;
private final PersistRequest.Type persistType;
DeleteMode(PersistRequest.Type persistType, boolean hard) {
this.persistType = persistType;
@@ -122,7 +122,7 @@ public final class Flags {
return set(state, RECURSE);
}
public static int unsetRecuse(int state) {
public static int unsetRecurse(int state) {
return unset(state, RECURSE);
}
@@ -8,7 +8,7 @@ import java.util.Collection;
*/
public class MultiValueWrapper {
private final Collection<?> values;
private Class<?> type;
private final Class<?> type;
public MultiValueWrapper(Collection<?> values, Class<?> type) {
this.values = values;

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