Compare commits

...
Author SHA1 Message Date
Robin Bygrave a1f10b8704 [maven-release-plugin] prepare release avaje-ebeanorm-7.16.1 2016-06-23 21:38:42 +12:00
Robin Bygrave 3c21950b91 Bump pom to 7.16.1-SNAPSHOT 2016-06-23 21:36:57 +12:00
Robin Bygrave 3b45308ac7 Merge branch 'DevFactory-release/collection-isempty-1' 2016-06-23 13:40:23 +12:00
Robin Bygrave 00e69e1b5d No effective change - remove extra whitespace 2016-06-23 13:39:34 +12:00
Robin Bygrave 11b3f7a813 Merge branch 'release/collection-isempty-1' of https://github.com/DevFactory/avaje-ebeanorm into DevFactory-release/collection-isempty-1
Conflicts:
	src/main/java/com/avaje/ebeaninternal/server/query/DefaultDbSqlContext.java
2016-06-23 13:24:58 +12:00
Robin Bygrave 2185c8a886 #752 - Refactor: SQL generation for @History support with Postgres, MySql (views/triggers based) such that it more closely aligns with SQL 2011 based SQL 2016-06-23 11:33:01 +12:00
Robin Bygrave f8bda05b37 #751 - @History with @ManyToMany ... intersection table not getting associated history support 2016-06-23 11:05:16 +12:00
Artyom Melnikov 0a3b819991 Fixing squid:S1155 - Collection.isEmpty() should be used to test for emptiness 2016-06-22 13:43:15 +03:00
Rob BygraveandGitHub 5c8b1eb3bb Merge pull request #748 from yuqiyi/master
fix DeployBeanDescriptor.java of the method setView
2016-06-22 22:21:52 +12:00
yuqiyi 824f6dcc7e fix DeployBeanDescriptor.java of the method setView 2016-06-22 18:11:37 +08:00
Robin Bygrave 06e23b85ad #747 - @History findVersionsBetween query with Oracle has incorrect ordering 2016-06-22 20:16:35 +12:00
Robin Bygrave 09219c759b [maven-release-plugin] prepare for next development iteration 2016-06-20 22:57:36 +12:00
Robin Bygrave b861038568 [maven-release-plugin] prepare release avaje-ebeanorm-7.15.1 2016-06-20 22:57:16 +12:00
Robin Bygrave bfd8445bcd Bump pom to 7.15.1-SNAPSHOT 2016-06-20 22:56:04 +12:00
Robin Bygrave c30e3bf78c #746 - SqlQuery with named parameter and limit/offset gives SQL exception 2016-06-20 22:54:08 +12:00
Robin Bygrave c793d6652f #745 - ElasticSearch - internally translate where().id.eq(42) ... to where().setId(42) 2016-06-20 22:29:38 +12:00
Robin Bygrave d12e55c20b #744 - ElasticSearch - isEmpty() expression needs to have outer not:{} negation to work as per .. 2016-06-20 21:32:05 +12:00
Robin Bygrave 3477f590dd #743 - Fix issue with ElasticSearch nested path query with multiple nested path expressions 2016-06-20 20:57:45 +12:00
Robin Bygrave 6bbf93aba8 No effective change - extract private constant in DefaultExpressionList 2016-06-20 13:14:28 +12:00
Robin Bygrave 42d02cc521 [maven-release-plugin] prepare for next development iteration 2016-06-17 22:27:25 +12:00
Robin Bygrave 9ea58572de [maven-release-plugin] prepare release avaje-ebeanorm-7.14.1 2016-06-17 22:27:04 +12:00
Robin Bygrave 35d82c9104 Bump pom to 7.14.1-SNAPSHOT 2016-06-17 22:26:06 +12:00
Robin Bygrave 31aae38616 #742 - ENH: DocStoreConfig ... read System properties for isGenerateMapping(), isDropCreate() and isCreate() 2016-06-17 22:25:11 +12:00
Robin Bygrave f144b53651 #741 - ENH: Add DocumentStore indexSettings() method ... for setting ElasticSearch refresh_interval 2016-06-17 22:21:22 +12:00
Robin Bygrave f47cd7e7c2 Add extra-dll.xml example for .... ENH: For @Index add support for index types (like Postgres GIN) #707 ... 2016-06-17 15:04:12 +12:00
Robin Bygrave 8765cb8356 No effective change - reformat code 2016-06-17 13:24:49 +12:00
Robin Bygrave 30abe75a96 Travis - enable caching .m2 2016-06-17 13:19:01 +12:00
Robin Bygrave 164e6c71c1 Travis - stop caching .m2 2016-06-17 13:15:42 +12:00
Robin Bygrave dfa6353850 #740 - ClassCastException: java.util.ArrayList cannot be cast to com.avaje.ebean.bean.BeanCollection at com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany.resetMany(BeanPropertyAssocMany.java:273) 2016-06-17 12:30:57 +12:00
Robin Bygrave d88ff2a3b2 #739 - UpdateQuery with idEq() expression gives wrong update statement (still has table alias) 2016-06-17 11:34:47 +12:00
Robin Bygrave 713ae75464 No effective change - reformat 2016-06-17 11:03:47 +12:00
Rob BygraveandGitHub 710fb0e947 Merge pull request #738 from DevFactory/staging/using-isempty-fix-1
Refactor: Use Collection.isEmpty() instead of size() comparison to 0 etc
2016-06-15 20:55:02 +12:00
Rob BygraveandGitHub cb0cf97f3f Merge pull request #736 from DevFactory/staging/make-public-static-fields-constant-fix-1
Updating "public static" fields to add final modifier
2016-06-15 20:46:37 +12:00
Artyom Melnikov 07edb2c81f Using Collection.isEmpty() to test for emptiness 2016-06-14 15:21:23 +03:00
Artyom Melnikov 066effa5bf "public static" fields should be constant 2016-06-14 14:18:18 +03:00
Robin Bygrave bb5ca6c56e Bump agent in pom to 4.11.1 2016-06-14 22:24:50 +12:00
Robin Bygrave a64a020e36 #734 - Add ServerConfig.skipCacheAfterWrite & transaction.setSkipCache(boolean) ... to control L2 Bean cache use during transaction 2016-06-10 17:59:37 +12:00
Robin Bygrave c24ee53462 [maven-release-plugin] prepare for next development iteration 2016-06-08 14:40:18 +12:00
145 changed files with 2547 additions and 973 deletions
+5 -5
View File
@@ -9,7 +9,7 @@
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>7.13.1</version>
<version>7.16.1</version>
<packaging>jar</packaging>
<name>avaje-ebeanorm</name>
@@ -37,7 +37,7 @@
<scm>
<developerConnection>scm:git:https://github.com/ebean-orm/avaje-ebeanorm.git</developerConnection>
<tag>avaje-ebeanorm-7.13.1</tag>
<tag>avaje-ebeanorm-7.16.1</tag>
</scm>
<dependencies>
@@ -168,7 +168,7 @@
<dependency>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm-agent</artifactId>
<version>4.10.1</version>
<version>4.11.1</version>
<scope>test</scope>
</dependency>
@@ -243,14 +243,14 @@
<plugin>
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
<version>4.10.1</version>
<version>4.11.1</version>
<executions>
<execution>
<id>test</id>
<phase>process-test-classes</phase>
<configuration>
<classSource>target/test-classes</classSource>
<packages>com.avaje.tests.**</packages>
<!--<packages>com.avaje.tests.**</packages>-->
<transformArgs>debug=1</transformArgs>
</configuration>
<goals>
@@ -49,7 +49,7 @@ final class DRawSqlColumnsParser {
if (split.length > 1) {
ArrayList<String> tmp = new ArrayList<String>(split.length);
for (int i = 0; i < split.length; i++) {
if (split[i].trim().length() > 0) {
if (!split[i].trim().isEmpty()) {
tmp.add(split[i].trim());
}
}
@@ -5,6 +5,7 @@ import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* Document storage operations.
@@ -205,6 +206,39 @@ public interface DocumentStore {
*/
void createIndex(String indexName, String alias);
/**
* Modify the settings on an index.
* <p>
* For example, this can be used be used to set elasticSearch refresh_interval
* on an index before a bulk update.
* </p>
* <pre>{@code
*
* // refresh_interval -1 ... disable refresh while bulk loading
*
* Map<String,Object> settings = new LinkedHashMap<>();
* settings.put("refresh_interval", "-1");
*
* documentStore.indexSettings("product", settings);
*
* }</pre>
*
* <pre>{@code
*
* // refresh_interval 1s ... restore after bulk loading
*
* Map<String,Object> settings = new LinkedHashMap<>();
* settings.put("refresh_interval", "1s");
*
* documentStore.indexSettings("product", settings);
*
* }</pre>
*
* @param indexName the name of the index to update settings on
* @param settings the settings to set on the index
*/
void indexSettings(String indexName, Map<String, Object> settings);
/**
* Copy the index to a new index.
* <p>
+2 -2
View File
@@ -161,7 +161,7 @@ public final class Ebean {
// look to see if there is a default server defined
String defaultName = PrimaryServer.getDefaultServerName();
logger.debug("defaultName:" + defaultName);
if (defaultName != null && defaultName.trim().length() > 0) {
if (defaultName != null && !defaultName.trim().isEmpty()) {
defaultServer = getWithCreate(defaultName.trim());
}
}
@@ -182,7 +182,7 @@ public final class Ebean {
}
private EbeanServer get(String name) {
if (name == null || name.length() == 0) {
if (name == null || name.isEmpty()) {
return defaultServer;
}
// non-synchronized read
+1 -1
View File
@@ -400,6 +400,6 @@ public final class OrderBy<T> implements Serializable {
}
private boolean isEmptyString(String s) {
return s == null || s.length() == 0;
return s == null || s.isEmpty();
}
}
@@ -78,6 +78,6 @@ class PrimaryServer {
* Return true if the string is null or empty.
*/
private static boolean isEmpty(String value) {
return value == null || value.trim().length() == 0;
return value == null || value.trim().isEmpty();
}
}
+69 -3
View File
@@ -3,6 +3,7 @@ package com.avaje.ebean;
import com.avaje.ebean.annotation.DocStoreMode;
import com.avaje.ebean.config.DocStoreConfig;
import com.avaje.ebean.config.PersistBatch;
import com.avaje.ebean.config.ServerConfig;
import javax.persistence.PersistenceException;
import javax.persistence.RollbackException;
@@ -125,13 +126,78 @@ public interface Transaction extends Closeable {
* Set to true when you want all loaded properties to be included in the update
* (rather than just the changed properties).
* <p>
* You might set this when using JDBC batch in order to get multiple updates
* with slightly different sets of changed properties into the same statement
* and hence better JDBC batch performance.
* You might set this when using JDBC batch in order to get multiple updates
* with slightly different sets of changed properties into the same statement
* and hence better JDBC batch performance.
* </p>
*/
void setUpdateAllLoadedProperties(boolean updateAllLoadedProperties);
/**
* Set if the L2 cache should be skipped for "find by id" and "find by natural key" queries.
* <p>
* By default {@link ServerConfig#isSkipCacheAfterWrite()} is true and that means that for
* "find by id" and "find by natural key" queries which normally hit L2 bean cache automatically
* - will not do so after a persist/write on the transaction.
* </p>
* <p>
* This method provides explicit control over whether "find by id" and "find by natural key"
* will skip the L2 bean cache or not (regardless of whether the transaction is considered "read only").
* </p>
* <p>
* Refer to {@link ServerConfig#setSkipCacheAfterWrite(boolean)} for configuring the default behavior
* for using the L2 bean cache in transactions spanning multiple query/persist requests.
* </p>
*
* <pre>{@code
*
* // assume Customer has L2 bean caching enabled ...
*
* Transaction transaction = Ebean.beginTransaction();
* try {
*
* // this uses L2 bean cache as the transaction
* // ... is considered "query only" at this point
* Customer.find.byId(42);
*
* // transaction no longer "query only" once
* // ... a bean has been saved etc
* Ebean.save(someBean);
*
* // will NOT use L2 bean cache as the transaction
* // ... is no longer considered "query only"
* Customer.find.byId(55);
*
*
*
* // explicit control - please use L2 bean cache
*
* transaction.setSkipCache(false);
* Customer.find.byId(77); // hit the l2 bean cache
*
*
* // explicit control - please don't use L2 bean cache
*
* transaction.setSkipCache(true);
* Customer.find.byId(99); // skips l2 bean cache
*
*
* } finally {
* transaction.end();
* }
*
* }</pre>
*
* @see ServerConfig#isSkipCacheAfterWrite()
*/
void setSkipCache(boolean skipCache);
/**
* Return true if the L2 cache should be skipped. More accurately if true then find by id
* and find by natural key queries should NOT automatically use the L2 bean cache.
*/
boolean isSkipCache();
/**
* Turn on or off statement batching. Statement batching can be transparent
* for drivers and databases that support getGeneratedKeys. Otherwise you may
@@ -274,7 +274,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
* Checks string is null or empty .
*/
protected boolean isEmpty(String s) {
return s == null || s.trim().length() == 0;
return s == null || s.trim().isEmpty();
}
/**
@@ -83,7 +83,6 @@ public class DocStoreConfig {
if (systemValue != null) {
return systemValue;
}
return url;
}
@@ -100,6 +99,10 @@ public class DocStoreConfig {
* Return true if Ebean should generate mapping files on server startup.
*/
public boolean isGenerateMapping() {
String systemValue = System.getProperty("ebean.docstore.generateMapping");
if (systemValue != null) {
return Boolean.parseBoolean(systemValue);
}
return generateMapping;
}
@@ -114,6 +117,10 @@ public class DocStoreConfig {
* Return true if the document store should recreate mapped indexes.
*/
public boolean isDropCreate() {
String systemValue = System.getProperty("ebean.docstore.dropCreate");
if (systemValue != null) {
return Boolean.parseBoolean(systemValue);
}
return dropCreate;
}
@@ -129,6 +136,10 @@ public class DocStoreConfig {
* This is only used if dropCreate is false.
*/
public boolean isCreate() {
String systemValue = System.getProperty("ebean.docstore.create");
if (systemValue != null) {
return Boolean.parseBoolean(systemValue);
}
return create;
}
@@ -220,6 +220,11 @@ public class ServerConfig {
private String ddlSeedSql;
/**
* When true L2 bean cache use is skipped after a write has occurred on a transaction.
*/
private boolean skipCacheAfterWrite = true;
private boolean useJtaTransactionManager;
/**
@@ -1795,6 +1800,66 @@ public class ServerConfig {
return classes;
}
/**
* Return true if L2 bean cache should be skipped once writes have occurred on a transaction.
* <p>
* This defaults to true and means that for "find by id" and "find by natural key"
* queries that normally hit L2 bean cache automatically will not do so after a write/persist
* on the transaction.
* </p>
*
* <pre>{@code
*
* // assume Customer has L2 bean caching enabled ...
*
* Transaction transaction = Ebean.beginTransaction();
* try {
*
* // this uses L2 bean cache as the transaction
* // ... is considered "query only" at this point
* Customer.find.byId(42);
*
* // transaction no longer "query only" once
* // ... a bean has been saved etc
* Ebean.save(someBean);
*
* // will NOT use L2 bean cache as the transaction
* // ... is no longer considered "query only"
* Customer.find.byId(55);
*
*
*
* // explicit control - please use L2 bean cache
*
* transaction.setSkipCache(false);
* Customer.find.byId(77); // hit the l2 bean cache
*
*
* // explicit control - please don't use L2 bean cache
*
* transaction.setSkipCache(true);
* Customer.find.byId(99); // skips l2 bean cache
*
*
* } finally {
* transaction.end();
* }
*
* }</pre>
*
* @see com.avaje.ebean.Transaction#setSkipCache(boolean)
*/
public boolean isSkipCacheAfterWrite() {
return skipCacheAfterWrite;
}
/**
* Set to false when we still want to hit the cache after a write has occurred on a transaction.
*/
public void setSkipCacheAfterWrite(boolean skipCacheAfterWrite) {
this.skipCacheAfterWrite = skipCacheAfterWrite;
}
/**
* Return true to only update changed properties.
*/
@@ -2312,6 +2377,7 @@ public class ServerConfig {
collectQueryStatsByNode = p.getBoolean("collectQueryStatsByNode", collectQueryStatsByNode);
collectQueryOrigins = p.getBoolean("collectQueryOrigins", collectQueryOrigins);
skipCacheAfterWrite = p.getBoolean("skipCacheAfterWrite", skipCacheAfterWrite);
updateAllPropertiesInBatch = p.getBoolean("updateAllPropertiesInBatch", updateAllPropertiesInBatch);
updateChangesOnly = p.getBoolean("updateChangesOnly", updateChangesOnly);
@@ -2394,7 +2460,7 @@ public class ServerConfig {
String[] split = classNames.split("[ ,;]");
for (int i = 0; i < split.length; i++) {
String cn = split[i].trim();
if (cn.length() > 0 && !"class".equalsIgnoreCase(cn)) {
if (!cn.isEmpty() && !"class".equalsIgnoreCase(cn)) {
try {
classes.add(Class.forName(cn));
} catch (ClassNotFoundException e) {
@@ -146,6 +146,6 @@ public final class TableName {
* @return true, if is valid
*/
public boolean isValid() {
return name != null && name.length() > 0;
return name != null && !name.isEmpty();
}
}
@@ -492,7 +492,7 @@ public class DatabasePlatform {
*/
public String convertQuotedIdentifiers(String dbName) {
// Ignore null values e.g. schema name or catalog
if (dbName != null && dbName.length() > 0) {
if (dbName != null && !dbName.isEmpty()) {
if (dbName.charAt(0) == BACK_TICK) {
if (dbName.charAt(dbName.length() - 1) == BACK_TICK) {
@@ -6,11 +6,13 @@ package com.avaje.ebean.config.dbplatform;
public interface DbHistorySupport {
/**
* Return true if the 'As of' predicate is part of the from clause
* (more standard sql2011). So true for Oracle total recall and false
* for Postgres and MySql (where we use views and history tables).
* Return true if the implementation is SQL2011 standards based.
* <p>
* Non standards based means we need to add additional predicates into the
* JOIN ON clause and add an additional predicate for the base table.
* </p>
*/
boolean isBindWithFromClause();
boolean isStandardsBased();
/**
* Return the number of columns bound in a 'As Of' predicate.
@@ -5,11 +5,8 @@ package com.avaje.ebean.config.dbplatform;
*/
public abstract class DbStandardHistorySupport implements DbHistorySupport {
/**
* Return true as with sql2011 the 'as of timestamp' clause included in from or join clause.
*/
@Override
public boolean isBindWithFromClause() {
public boolean isStandardsBased() {
return true;
}
@@ -9,11 +9,8 @@ package com.avaje.ebean.config.dbplatform;
*/
public abstract class DbViewHistorySupport implements DbHistorySupport {
/**
* Return false for view based implementations where we append extra 'as of' predicates to the end.
*/
@Override
public boolean isBindWithFromClause() {
public boolean isStandardsBased() {
return false;
}
@@ -114,7 +114,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
public Object nextId(Transaction t) {
synchronized (monitor) {
if (idList.size() == 0) {
if (idList.isEmpty()) {
loadMoreIds(batchSize, t);
}
Long nextId = idList.remove(0);
@@ -193,7 +193,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
while (rset.next()) {
newIds.add(rset.getLong(1));
}
if (newIds.size() == 0) {
if (newIds.isEmpty()) {
throw new PersistenceException("Always expecting more than 1 row from " + sql);
}
@@ -85,6 +85,11 @@ public class ModelBuildIntersectionTable {
String tableName = intersectionTableJoin.getTable();
MTable table = new MTable(tableName);
if (!manyProp.isExcludedFromHistory()) {
if (localDesc.isHistorySupport()) {
table.setWithHistory(true);
}
}
table.setPkName(ctx.primaryKeyName(tableName));
TableJoinColumn[] columns = intersectionTableJoin.columns();
@@ -109,7 +109,7 @@ public class PathProperties implements FetchPath {
String path = entry.getKey();
String props = entry.getValue().getPropertiesAsString();
if (path == null || path.length() == 0) {
if (path == null || path.isEmpty()) {
query.select(props);
} else {
query.fetch(path, props);
@@ -108,7 +108,7 @@ class PathPropertiesParser {
private void addCurrentProperty() {
String w = currentWord();
if (w.length() > 0) {
if (!w.isEmpty()) {
currentPathProps.addProperty(w);
}
}
@@ -23,7 +23,7 @@ public final class TimeStringParser implements StringParser {
*/
@SuppressWarnings("deprecation")
public Object parse(String value) {
if (value == null || value.trim().length() == 0) {
if (value == null || value.trim().isEmpty()) {
return null;
}
@@ -123,7 +123,7 @@ public class StringHelper {
String listDelimiter, String nameValueSeparator) {
HashMap<String, String> params = new HashMap<String, String>();
if ((allNameValuePairs == null) || (allNameValuePairs.length() == 0)) {
if ((allNameValuePairs == null) || (allNameValuePairs.isEmpty())) {
return params;
}
// trim off any leading listDelimiter...
@@ -155,7 +155,7 @@ public class StringHelper {
* Return true if the value is null or an empty string.
*/
public static boolean isNull(String value) {
return value == null || value.trim().length() == 0;
return value == null || value.trim().isEmpty();
}
/**
@@ -189,7 +189,7 @@ public class StringHelper {
// there is a key without a value?
String key = allNameValuePairs.substring(pos, delimPos);
key = key.trim();
if (key.length() > 0) {
if (!key.isEmpty()) {
map.put(key, null);
}
return getKeyValue(map, delimPos + 1, allNameValuePairs, listDelimiter,
@@ -251,7 +251,7 @@ public class StringHelper {
if (endPos == -1) {
if (startPos <= str.length()) {
String lastValue = str.substring(startPos, str.length());
if (keepEmpties || lastValue.length() != 0) {
if (keepEmpties || !lastValue.isEmpty()) {
list.add(lastValue);
}
}
@@ -260,7 +260,7 @@ public class StringHelper {
} else {
// get the delimited value... add it..
String value = str.substring(startPos, endPos);
if (keepEmpties || value.length() != 0) {
if (keepEmpties || !value.isEmpty()) {
list.add(value);
}
// recursively search as we are not at the end yet...
@@ -105,6 +105,16 @@ public class ScopedTransaction implements SpiTransaction {
transaction.logSummary(msg);
}
@Override
public void setSkipCache(boolean skipCache) {
transaction.setSkipCache(skipCache);
}
@Override
public boolean isSkipCache() {
return transaction.isSkipCache();
}
@Override
public void addBeanChange(BeanChange beanChange) {
transaction.addBeanChange(beanChange);
@@ -18,8 +18,13 @@ public interface SpiExpression extends Expression {
*/
void writeDocQuery(DocQueryContext context) throws IOException;
/**
* Process "Many" properties populating ManyWhereJoins.
/**
* Return the nested path for this expression.
*/
String nestedPath(BeanDescriptor<?> desc);
/**
* Process "Many" properties populating ManyWhereJoins.
* <p>
* Predicates on Many properties require an extra independent join clause.
* </p>
@@ -89,4 +94,8 @@ public interface SpiExpression extends Expression {
*/
SpiExpression copyForPlanKey();
/**
* Return the bind Id value if this is a "equal to" expression for the id property.
*/
Object getIdEqualTo(String idName);
}
@@ -133,6 +133,11 @@ public interface SpiQuery<T> extends Query<T> {
}
}
/**
* Check for a single "equal to" expression for the Id.
*/
void checkIdEqualTo();
/**
* Return true if AutoTune should be attempted on this query.
*/
@@ -218,14 +223,14 @@ public interface SpiQuery<T> extends Query<T> {
Timestamp getAsOf();
/**
* Add a table alias for a @History entity involved in a 'As Of' query.
* Increment the counter of tables used in 'As Of' query.
*/
void addAsOfTableAlias(String tableAlias);
void incrementAsOfTableCount();
/**
* Return the list of table alias involved in a 'As Of' query that have @History support.
* Return the table alias used for the base table.
*/
List<String> getAsOfTableAlias();
int getAsOfTableCount();
void addSoftDeletePredicate(String softDeletePredicate);
@@ -301,6 +306,11 @@ public interface SpiQuery<T> extends Query<T> {
*/
NaturalKeyBindParam getNaturalKeyBindParam();
/**
* Prepare the query for docstore execution with nested paths.
*/
void prepareDocNested();
/**
* Set the query to be a delete query.
*/
@@ -40,7 +40,7 @@ public class ExtraDdlXmlReader {
* @param platforms The platforms (comma delimited) this script should run for
*/
public static boolean matchPlatform(String platformName, String platforms) {
if (platforms == null || platforms.trim().length() == 0) {
if (platforms == null || platforms.trim().isEmpty()) {
return true;
}
String[] names = platforms.split("[,;]");
@@ -10,7 +10,7 @@ public class CacheOptions {
/**
* Instance when no caching is used.
*/
public static CacheOptions NO_CACHING = new CacheOptions();
public static final CacheOptions NO_CACHING = new CacheOptions();
private final boolean enableBeanCache;
private final boolean enableQueryCache;
@@ -281,7 +281,7 @@ public class DefaultBeanLoader {
}
}
SpiQuery<?> query = (SpiQuery<?>) server.createQuery(desc.getBeanType());
SpiQuery<?> query = server.createQuery(desc.getBeanType());
query.setLazyLoadProperty(ebi.getLazyLoadProperty());
if (draft) {
query.asDraft();
@@ -218,7 +218,7 @@ public class DefaultContainer implements SpiContainer {
private BootupClasses getBootupClasses1(ServerConfig serverConfig) {
List<Class<?>> entityClasses = serverConfig.getClasses();
if (serverConfig.isDisableClasspathSearch() || (entityClasses != null && entityClasses.size() > 0)) {
if (serverConfig.isDisableClasspathSearch() || (entityClasses != null && !entityClasses.isEmpty())) {
// use classes we explicitly added via configuration
return new BootupClasses(entityClasses);
}
@@ -836,7 +836,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
if (sortByClause == null) {
throw new NullPointerException("sortByClause is null");
}
if (list.size() == 0) {
if (list.isEmpty()) {
// don't need to sort an empty list
return;
}
@@ -991,7 +991,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
}
if (!query.isUseBeanCache()) {
if (!query.isUseBeanCache() || (t != null && t.isSkipCache())) {
return null;
}
@@ -1041,26 +1041,31 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
}
public <T> T findUnique(Query<T> query, Transaction t) {
Object id = query.getId();
if (id != null) {
// actually a find by Id query
return findId(query, t);
}
public <T> T findUnique(Query<T> query, Transaction transaction) {
SpiQuery<T> spiQuery = (SpiQuery<T>) query;
BeanDescriptor<T> desc = spiQuery.getBeanDescriptor();
id = desc.cacheNaturalKeyIdLookup(spiQuery);
spiQuery.checkIdEqualTo();
Object id = spiQuery.getId();
if (id != null) {
T bean = findIdCheckPersistenceContextAndCache(t, spiQuery, id);
if (bean != null) {
return bean;
// actually a find by Id query
return findId(query, transaction);
}
SpiTransaction t = (SpiTransaction) transaction;
if (t == null) {
t = getCurrentServerTransaction();
}
if (t == null || !t.isSkipCache()) {
id = spiQuery.getBeanDescriptor().cacheNaturalKeyIdLookup(spiQuery);
if (id != null) {
T bean = findIdCheckPersistenceContextAndCache(t, spiQuery, id);
if (bean != null) {
return bean;
}
}
}
// a query that is expected to return either 0 or 1 rows
// a query that is expected to return either 0 or 1 beans
List<T> list = findList(query, t);
return extractUnique(list);
}
@@ -235,7 +235,7 @@ public class InternalConfiguration {
if (historySupport == null) {
return new Binder(typeManager, 0, false, jsonHandler, dataTimeZone);
}
return new Binder(typeManager, historySupport.getBindCount(), historySupport.isBindWithFromClause(), jsonHandler, dataTimeZone);
return new Binder(typeManager, historySupport.getBindCount(), historySupport.isStandardsBased(), jsonHandler, dataTimeZone);
}
/**
@@ -513,4 +513,11 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
public boolean isAuditReads() {
return !query.isDisableReadAudit() && beanDescriptor.isReadAuditing();
}
/**
* Return the base table alias for this query.
*/
public String getBaseTableAlias() {
return query.getAlias() == null ? beanDescriptor.getBaseTableAlias() : query.getAlias();
}
}
@@ -219,7 +219,7 @@ public final class RelationalQueryRequest {
int maxRows = query.getMaxRows();
if (firstRow > 0 || maxRows > 0) {
return ebeanServer.getDatabasePlatform().getBasicSqlLimiter()
.limit(query.getQuery(), firstRow, maxRows);
.limit(sql, firstRow, maxRows);
}
return sql;
}
@@ -49,7 +49,7 @@ public class BootupClassPathSearch {
long st = System.currentTimeMillis();
for (ClassPathScanner finder : this.scanners) {
if (packages != null && packages.size() > 0) {
if (packages != null && !packages.isEmpty()) {
for (String packageName : packages) {
finder.scanForClasses(packageName, bc);
}
@@ -21,6 +21,7 @@ abstract class AssocOneHelp {
this.property = property;
this.target = property.targetDescriptor;
}
/**
* Effectively skip reading (the jdbc resultSet as already in the persistence context etc).
*/
@@ -10,56 +10,69 @@ import javax.persistence.CascadeType;
*/
public class BeanCascadeInfo {
/**
* should delete cascade.
*/
boolean delete;
/**
* Should save cascade.
*/
boolean save;
private boolean delete;
public void setTypes(CascadeType[] types) {
for (int i = 0; i < types.length; i++) {
setType(types[i]);
}
private boolean save;
private boolean refresh;
public void setTypes(CascadeType[] types) {
for (int i = 0; i < types.length; i++) {
setType(types[i]);
}
private void setType(CascadeType type) {
if (type.equals(CascadeType.ALL)){
save = true;
delete = true;
}
if (type.equals(CascadeType.REMOVE)){
delete = true;
}
if (type.equals(CascadeType.PERSIST)){
save = true;
}
if (type.equals(CascadeType.MERGE)){
save = true;
}
}
/**
* Return true if delete should cascade.
*/
public boolean isDelete() {
return delete;
}
/**
* Set to true if delete should cascade.
*/
public void setDelete(boolean delete) {
this.delete = delete;
}
/**
* Return true if save should cascade.
*/
public boolean isSave() {
return save;
}
private void setType(CascadeType type) {
switch (type) {
case ALL:
save = true;
delete = true;
refresh = true;
break;
case REMOVE:
delete = true;
break;
case REFRESH:
refresh = true;
break;
case PERSIST:
save = true;
break;
case MERGE:
save = true;
break;
default:
throw new IllegalStateException("Unexpected CascadeType " + type);
}
}
/**
* Return true if refresh should cascade.
*/
public boolean isRefresh() {
return refresh;
}
/**
* Return true if delete should cascade.
*/
public boolean isDelete() {
return delete;
}
/**
* Set to true if delete should cascade.
*/
public void setDelete(boolean delete) {
this.delete = delete;
}
/**
* Return true if save should cascade.
*/
public boolean isSave() {
return save;
}
/**
* Set cascade save and delete settings.
@@ -16,48 +16,48 @@ import java.io.IOException;
*/
public interface BeanCollectionHelp<T> {
/**
* Set the EbeanServer that owns the configuration.
*/
void setLoader(BeanCollectionLoader loader);
/**
* Return the mechanism to add beans to the underlying collection.
* <p>
* For Map's this needs to take the mapKey.
* </p>
*/
BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey);
/**
* Set the EbeanServer that owns the configuration.
*/
void setLoader(BeanCollectionLoader loader);
/**
* Return the mechanism to add beans to the underlying collection.
* <p>
* For Map's this needs to take the mapKey.
* </p>
*/
BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey);
/**
* Create an empty collection of the correct type without a parent bean.
*/
BeanCollection<T> createEmptyNoParent();
/**
* Create an empty collection of the correct type.
*/
BeanCollection<T> createEmpty(EntityBean bean);
/**
* Create an empty collection of the correct type.
*/
BeanCollection<T> createEmpty(EntityBean bean);
/**
* Add a bean to the List Set or Map.
*/
void add(BeanCollection<?> collection, EntityBean bean, boolean withCheck);
/**
* Add a bean to the List Set or Map.
*/
void add(BeanCollection<?> collection, EntityBean bean, boolean withCheck);
/**
* Create a lazy loading proxy for a List Set or Map.
*/
BeanCollection<T> createReference(EntityBean parentBean);
/**
* Create a lazy loading proxy for a List Set or Map.
*/
BeanCollection<T> createReference(EntityBean parentBean);
/**
* Refresh the List Set or Map.
*/
void refresh(EbeanServer server, Query<?> query, Transaction t, EntityBean parentBean);
/**
* Apply the new refreshed BeanCollection to the appropriate property of the parent bean.
*/
void refresh(BeanCollection<?> bc, EntityBean parentBean);
/**
* Refresh the List Set or Map.
*/
void refresh(EbeanServer server, Query<?> query, Transaction t, EntityBean parentBean);
/**
* Apply the new refreshed BeanCollection to the appropriate property of the parent bean.
*/
void refresh(BeanCollection<?> bc, EntityBean parentBean);
/**
* Write the collection out as json.
@@ -13,42 +13,42 @@ public class BeanCollectionHelpFactory {
static final BeanSetHelp SET_HELP = new BeanSetHelp();
/**
* Create the helper based on the many property.
*/
public static <T> BeanCollectionHelp<T> create(BeanPropertyAssocMany<T> manyProperty) {
/**
* Create the helper based on the many property.
*/
public static <T> BeanCollectionHelp<T> create(BeanPropertyAssocMany<T> manyProperty) {
ManyType manyType = manyProperty.getManyType();
switch (manyType) {
case LIST:
return new BeanListHelp<T>(manyProperty);
case SET:
return new BeanSetHelp<T>(manyProperty);
case MAP:
return new BeanMapHelp<T>(manyProperty);
default:
throw new RuntimeException("Invalid type "+manyType);
}
}
ManyType manyType = manyProperty.getManyType();
switch (manyType) {
case LIST:
return new BeanListHelp<T>(manyProperty);
case SET:
return new BeanSetHelp<T>(manyProperty);
case MAP:
return new BeanMapHelp<T>(manyProperty);
default:
throw new RuntimeException("Invalid type " + manyType);
}
}
@SuppressWarnings("unchecked")
public static <T> BeanCollectionHelp<T> create(OrmQueryRequest<T> request) {
public static <T> BeanCollectionHelp<T> create(OrmQueryRequest<T> request) {
SpiQuery.Type manyType = request.getQuery().getType();
if (manyType.equals(SpiQuery.Type.LIST)) {
return LIST_HELP;
} else if (manyType.equals(SpiQuery.Type.SET)) {
return SET_HELP;
} else {
BeanDescriptor<T> target = request.getBeanDescriptor();
String mapKey = request.getQuery().getMapKey();
return new BeanMapHelp<T>(target, mapKey);
}
}
SpiQuery.Type manyType = request.getQuery().getType();
if (manyType.equals(SpiQuery.Type.LIST)){
return LIST_HELP;
} else if (manyType.equals(SpiQuery.Type.SET)) {
return SET_HELP;
} else {
BeanDescriptor<T> target = request.getBeanDescriptor();
String mapKey = request.getQuery().getMapKey();
return new BeanMapHelp<T>(target, mapKey);
}
}
}
@@ -119,7 +119,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
for (int i = 0; i < propertyLength; i++) {
if (fromEbi.isLoadedProperty(i) ) {
if (fromEbi.isLoadedProperty(i)) {
BeanProperty property = getBeanProperty(names[i]);
if (!toEbi.isLoadedProperty(i)) {
Object val = property.getValue(bean);
@@ -228,9 +228,9 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
*/
private final BeanDescriptorMap owner;
private final String[] properties;
/**
* Intercept pre post on insert,update, and delete .
*/
@@ -276,7 +276,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
* Derived list of properties that are used for version concurrency checking.
*/
private final BeanProperty versionProperty;
private final int versionPropertyIndex;
private final BeanProperty whenModifiedProperty;
@@ -287,7 +287,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
* Properties that are initialised in the constructor need to be 'unloaded' to support partial object queries.
*/
private final int[] unloadProperties;
/**
* Properties local to this type (not from a super type).
*/
@@ -298,7 +298,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
*/
private final BeanProperty[] propertiesMutable;
private final BeanPropertyAssocOne<?> unidirectional;
/**
@@ -358,7 +358,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
private boolean deleteRecurseSkippable;
private final EntityBean prototypeEntityBean;
private final IdBinder idBinder;
private String idBinderInLHSSql;
@@ -499,7 +499,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
// Check if there are no cascade delete associated beans (also subject to
// change in initialiseOther()).
deleteRecurseSkippable = (0 == (propertiesOneExportedDelete.length + propertiesOneImportedDelete.length + propertiesManyDelete.length));
// object used to handle Id values
this.idBinder = owner.createIdBinder(idProperty);
this.whenModifiedProperty = findWhenModifiedProperty();
@@ -511,7 +511,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
this.versionPropertyIndex = -1;
this.unloadProperties = new int[0];
this.propertiesIndex = new BeanProperty[0];
} else {
EntityBeanIntercept ebi = prototypeEntityBean._ebean_getIntercept();
this.idPropertyIndex = (idProperty == null) ? -1 : ebi.findProperty(idProperty.getName());
@@ -529,40 +529,40 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
* These properties need to be unloaded when populating beans for queries.
*/
private int[] derivePropertiesToUnload(EntityBean prototypeEntityBean) {
boolean[] loaded = prototypeEntityBean._ebean_getIntercept().getLoaded();
int[] props = new int[loaded.length];
int pos = 0;
// collect the positions of the properties initialised in the default constructor.
for (int i = 0; i < loaded.length; i++) {
if (loaded[i]) {
props[pos++] = i;
}
}
if (pos == 0) {
// nothing set in the constructor
return new int[0];
}
// populate a smaller/minimal array
int[] unload = new int[pos];
System.arraycopy(props, 0, unload, 0, pos);
return unload;
}
/**
* Create an entity bean that is used as a prototype/factory to create new instances.
* Create an entity bean that is used as a prototype/factory to create new instances.
*/
private EntityBean createPrototypeEntityBean(Class<T> beanType) {
if (Modifier.isAbstract(beanType.getModifiers())) {
return null;
}
return null;
}
try {
return (EntityBean) beanType.newInstance();
} catch (Exception e) {
throw new IllegalStateException("Error trying to create the prototypeEntityBean for "+beanType, e);
throw new IllegalStateException("Error trying to create the prototypeEntityBean for " + beanType, e);
}
}
@@ -608,9 +608,10 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
* These properties need to be initialised prior to the association properties
* as they are used to get the imported and exported properties.
* </p>
*
* @param withHistoryTables map populated if @History is supported on this entity bean
*/
public void initialiseId(Map<String, String> withHistoryTables, Map<String,String> draftTables) {
public void initialiseId(Map<String, String> withHistoryTables, Map<String, String> draftTables) {
if (logger.isTraceEnabled()) {
logger.trace("BeanDescriptor initialise " + fullName);
@@ -644,9 +645,9 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
/**
* Initialise the exported and imported parts for associated properties.
*
* @param asOfTableMap the map of base tables to associated 'with history' tables
* @param asOfTableMap the map of base tables to associated 'with history' tables
* @param asOfViewSuffix the suffix added to the table name to derive the 'with history' view name
* @param draftTableMap the map of base tables to associated 'draft' tables.
* @param draftTableMap the map of base tables to associated 'draft' tables.
*/
public void initialiseOther(Map<String, String> asOfTableMap, String asOfViewSuffix, Map<String, String> draftTableMap) {
@@ -709,7 +710,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
propertiesMany[i].initialisePostTarget();
}
if (inheritInfo != null && !inheritInfo.isRoot()) {
docStoreAdapter = (DocStoreBeanAdapter<T>)inheritInfo.getRoot().desc().docStoreAdapter();
docStoreAdapter = (DocStoreBeanAdapter<T>) inheritInfo.getRoot().desc().docStoreAdapter();
}
docMapping = docStoreAdapter.createDocMapping();
docStoreAdapter.registerPaths();
@@ -753,12 +754,12 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
PersistRequest.Type type = request.getType();
switch (type) {
case INSERT:
return changeLogFilter.includeInsert(request) ? insertBeanChange(request): null;
return changeLogFilter.includeInsert(request) ? insertBeanChange(request) : null;
case UPDATE:
case SOFT_DELETE:
return changeLogFilter.includeUpdate(request) ? updateBeanChange(request): null;
return changeLogFilter.includeUpdate(request) ? updateBeanChange(request) : null;
case DELETE:
return changeLogFilter.includeDelete(request) ? deleteBeanChange(request) :null;
return changeLogFilter.includeDelete(request) ? deleteBeanChange(request) : null;
default:
throw new IllegalStateException("Unhandled request type " + type);
}
@@ -959,7 +960,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
mapping.add(new DocPropertyMapping(discCol, DocPropertyType.INTEGER));
}
}
for (BeanProperty prop: propertiesNonTransient) {
for (BeanProperty prop : propertiesNonTransient) {
prop.docStoreMapping(mapping, prefix);
}
if (inheritInfo != null) {
@@ -1121,7 +1122,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
public CachedBeanData cacheEmbeddedBeanExtract(EntityBean bean) {
return cacheHelp.beanExtractData(this, bean);
}
/**
* Load the embedded bean (taking into account inheritance).
*/
@@ -1177,7 +1178,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
public void cacheHandleDeleteById(Object id) {
cacheHelp.beanCacheRemove(id);
}
/**
* Returns true if it managed to populate/load the bean from the cache.
*/
@@ -1330,15 +1331,15 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
public List<MetaQueryPlanStatistic> collectQueryPlanStatistics(boolean reset) {
return collectQueryPlanStatisticsInternal(reset, false);
}
@Override
public List<MetaQueryPlanStatistic> collectAllQueryPlanStatistics(boolean reset) {
return collectQueryPlanStatisticsInternal(reset, false);
}
public List<MetaQueryPlanStatistic> collectQueryPlanStatisticsInternal(boolean reset, boolean collectAll) {
List<MetaQueryPlanStatistic> list = new ArrayList<MetaQueryPlanStatistic>(queryPlanCache.size());
for (CQueryPlan queryPlan : queryPlanCache.values()) {
for (CQueryPlan queryPlan : queryPlanCache.values()) {
Snapshot snapshot = queryPlan.getSnapshot(reset);
if (collectAll || snapshot.getExecutionCount() > 0) {
list.add(snapshot);
@@ -1413,7 +1414,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
/**
* Return true if delete can use a single SQL statement.
*
* <p>
* This implies cascade delete does not continue depth wise and that this is no
* associated L2 bean caching.
*/
@@ -1529,7 +1530,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
@Override
@SuppressWarnings("unchecked")
public T createBean() {
return (T)createEntityBean();
return (T) createEntityBean();
}
/**
@@ -1538,8 +1539,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
@SuppressWarnings("unchecked")
public EntityBean createEntityBean() {
try {
EntityBean bean = (EntityBean)prototypeEntityBean._ebean_newInstance();
EntityBean bean = (EntityBean) prototypeEntityBean._ebean_newInstance();
if (unloadProperties.length > 0) {
// 'unload' any properties initialised in the default constructor
EntityBeanIntercept ebi = bean._ebean_getIntercept();
@@ -1548,7 +1549,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
}
}
return bean;
} catch (Exception ex) {
throw new PersistenceException(ex);
}
@@ -1767,6 +1768,13 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
pc.deleted(rootBeanType, idValue);
}
/**
* Return the Id property name or null if no Id property exists.
*/
public String getIdName() {
return (idProperty == null) ? null : idProperty.getName();
}
/**
* Helper method to return the unique property. If only one property makes up
* the unique id then it's value is returned. If there is a concatenated
@@ -1806,7 +1814,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
public Object convertIdFromJson(Object idValue) {
return idBinder.convertIdFromJson(idValue);
}
/**
* Return the default order by that may need to be added if a many property is
* included in the query.
@@ -1871,7 +1879,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
/**
* Register all the assoc many properties on this bean that are not populated with the load context.
* <p>
* This provides further lazy loading via the load context.
* This provides further lazy loading via the load context.
* </p>
*/
public void lazyLoadRegister(String prefix, EntityBeanIntercept ebi, EntityBean bean, LoadContext loadContext) {
@@ -1930,9 +1938,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
/**
* Return a Comparator for local sorting of lists.
*
* @param sortByClause
* list of property names with optional ASC or DESC suffix.
*
* @param sortByClause list of property names with optional ASC or DESC suffix.
*/
@SuppressWarnings("unchecked")
private ElComparator<T> createComparator(String sortByClause) {
@@ -2025,7 +2032,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
ElPropertyDeploy fk = elDeployCache.get(propName);
if (fk != null && fk instanceof BeanFkeyProperty) {
// propertyDeploy chain for foreign key column
return ((BeanFkeyProperty)fk).create(chain.getExpression(), chain.isContainsMany());
return ((BeanFkeyProperty) fk).create(chain.getExpression(), chain.isContainsMany());
}
}
@@ -2087,9 +2094,11 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
*/
public void resetManyProperties(Object dbBean) {
EntityBean bean = (EntityBean)dbBean;
EntityBean bean = (EntityBean) dbBean;
for (int i = 0; i < propertiesMany.length; i++) {
propertiesMany[i].resetMany(bean);
if (propertiesMany[i].isCascadeRefresh()) {
propertiesMany[i].resetMany(bean);
}
}
}
@@ -2334,10 +2343,14 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
*/
public String getBaseTable(SpiQuery.TemporalMode mode) {
switch (mode) {
case DRAFT: return draftTable;
case VERSIONS: return baseTableVersionsBetween;
case AS_OF: return baseTableAsOf;
default: return baseTable;
case DRAFT:
return draftTable;
case VERSIONS:
return baseTableVersionsBetween;
case AS_OF:
return baseTableAsOf;
default:
return baseTable;
}
}
@@ -2552,19 +2565,17 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
/**
* Return true if this bean should be inserted rather than updated.
*
* @param ebi
* The entity bean intercept
* @param insertMode
* true if the 'root request' was an insert rather than an update
*
* @param ebi The entity bean intercept
* @param insertMode true if the 'root request' was an insert rather than an update
*/
public boolean isInsertMode(EntityBeanIntercept ebi, boolean insertMode) {
if (ebi.isLoaded()) {
// must be an update as the bean is loaded
return false;
}
if (idProperty.isEmbedded()) {
// not using Id generator so just base on isLoaded()
return !ebi.isLoaded();
@@ -2576,11 +2587,11 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
// same as the 'root request'
return insertMode;
}
public boolean isReference(EntityBeanIntercept ebi) {
return ebi.isReference() || hasIdPropertyOnly(ebi);
}
public boolean hasIdPropertyOnly(EntityBeanIntercept ebi) {
return ebi.hasIdOnly(idPropertyIndex);
}
@@ -2629,13 +2640,13 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
}
}
}
public ConcurrencyMode getConcurrencyMode(EntityBeanIntercept ebi) {
if (!hasVersionProperty(ebi)) {
return ConcurrencyMode.NONE;
} else {
return concurrencyMode;
return concurrencyMode;
}
}
@@ -2721,7 +2732,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
query.order(rawSql.getSql().getOrderBy());
}
query.order().asc(idProperty.getName());
} else if (!orderBy.containsProperty(idProperty.getName())){
} else if (!orderBy.containsProperty(idProperty.getName())) {
query.order().asc(idProperty.getName());
}
}
@@ -2853,8 +2864,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
public void jsonWrite(WriteJson writeJson, EntityBean bean) throws IOException {
jsonHelp.jsonWrite(writeJson, bean, null);
}
}
public void jsonWrite(WriteJson writeJson, EntityBean bean, String key) throws IOException {
jsonHelp.jsonWrite(writeJson, bean, key);
}
@@ -2862,11 +2873,11 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
protected void jsonWriteProperties(WriteJson writeJson, EntityBean bean) throws IOException {
jsonHelp.jsonWriteProperties(writeJson, bean);
}
public T jsonRead(ReadJson jsonRead, String path) throws IOException {
return jsonHelp.jsonRead(jsonRead, path);
}
protected T jsonReadObject(ReadJson jsonRead, String path) throws IOException {
return jsonHelp.jsonReadObject(jsonRead, path);
}
@@ -29,7 +29,7 @@ import java.util.Map;
/**
* Helper for BeanDescriptor that manages the bean, query and collection caches.
*
*
* @param <T> The entity bean type
*/
final class BeanDescriptorCacheHelp<T> {
@@ -55,7 +55,7 @@ final class BeanDescriptorCacheHelp<T> {
private final Class<?> beanType;
private final String cacheName;
private final BeanPropertyAssocOne<?>[] propertiesOneImported;
private final String naturalKeyProperty;
@@ -74,7 +74,7 @@ final class BeanDescriptorCacheHelp<T> {
private boolean cacheNotifyOnDelete;
BeanDescriptorCacheHelp(BeanDescriptor<T> desc, ServerCacheManager cacheManager, CacheOptions cacheOptions,
boolean cacheSharableBeans, BeanPropertyAssocOne<?>[] propertiesOneImported) {
boolean cacheSharableBeans, BeanPropertyAssocOne<?>[] propertiesOneImported) {
this.desc = desc;
this.beanType = desc.rootBeanType;
@@ -88,7 +88,7 @@ final class BeanDescriptorCacheHelp<T> {
if (!cacheOptions.isEnableQueryCache()) {
this.queryCache = null;
} else {
this.queryCache = cacheManager.getQueryCache(beanType);
this.queryCache = cacheManager.getQueryCache(beanType);
}
if (cacheOptions.isEnableBeanCache()) {
@@ -240,7 +240,7 @@ final class BeanDescriptorCacheHelp<T> {
manyLog.trace(" GET {}({}).{} - cache miss", cacheName, parentId, propertyName);
}
} else if (manyLog.isDebugEnabled()) {
manyLog.debug(" GET {}({}).{} - hit", cacheName, parentId, propertyName);
manyLog.debug(" GET {}({}).{} - hit", cacheName, parentId, propertyName);
}
return entry;
}
@@ -255,7 +255,7 @@ final class BeanDescriptorCacheHelp<T> {
// not in cache so return unsuccessful
return false;
}
Object ownerBean = bc.getOwnerBean();
EntityBeanIntercept ebi = ((EntityBean) ownerBean)._ebean_getIntercept();
PersistenceContext persistenceContext = ebi.getPersistenceContext();
@@ -326,7 +326,7 @@ final class BeanDescriptorCacheHelp<T> {
// try to lookup the id using the natural key
Object id = naturalKeyCache.get(keyBindParam.getValue());
if (natLog.isTraceEnabled() && id != null) {
if (natLog.isTraceEnabled()) {
natLog.trace(" LOOKUP {}({}) - id:{}", cacheName, keyBindParam.getValue(), id);
}
return id;
@@ -350,13 +350,13 @@ final class BeanDescriptorCacheHelp<T> {
// Not using a loadContext for beans coming out of L2 cache
// so that means no batch lazy loading for these beans
EntityBean entityBean = (EntityBean)bean;
EntityBean entityBean = (EntityBean) bean;
EntityBeanIntercept ebi = entityBean._ebean_getIntercept();
ebi.setPersistenceContext(context);
Object id = desc.getId(entityBean);
desc.contextPut(context, id, bean);
}
/**
* Return the beanCache creating it if necessary.
*/
@@ -366,7 +366,7 @@ final class BeanDescriptorCacheHelp<T> {
}
return beanCache;
}
/**
* Clear the bean cache.
*/
@@ -422,7 +422,7 @@ final class BeanDescriptorCacheHelp<T> {
CachedBeanData beanCacheGetData(Object id) {
return (CachedBeanData) getBeanCache().get(id);
}
T beanCacheGet(Object id, Boolean readOnly, PersistenceContext context) {
T bean = beanCacheGetInternal(id, readOnly, context);
if (bean != null) {
@@ -430,7 +430,7 @@ final class BeanDescriptorCacheHelp<T> {
}
return bean;
}
/**
* Return a bean from the bean cache.
*/
@@ -457,7 +457,7 @@ final class BeanDescriptorCacheHelp<T> {
}
}
return (T)loadBean(id, readOnly, data, context);
return (T) loadBean(id, readOnly, data, context);
}
/**
@@ -636,7 +636,7 @@ final class BeanDescriptorCacheHelp<T> {
}
}
}
// check if the bean itself was updated
if (!updateRequest.isUpdatedManysOnly()) {
@@ -8,7 +8,7 @@ import java.util.List;
/**
* Helper for BeanDescriptor that manages draft entity beans.
*
*
* @param <T> The entity bean type
*/
public final class BeanDescriptorDraftHelp<T> {
@@ -47,7 +47,7 @@ public final class BeanDescriptorDraftHelp<T> {
*/
public boolean draftReset(T draftBean) {
EntityBean draftEntityBean = (EntityBean)draftBean;
EntityBean draftEntityBean = (EntityBean) draftBean;
if (draftDirty != null) {
// set @DraftDirty property to false
@@ -72,11 +72,11 @@ public final class BeanDescriptorDraftHelp<T> {
public T publish(T draftBean, T liveBean) {
if (liveBean == null) {
liveBean = (T)desc.createEntityBean();
liveBean = (T) desc.createEntityBean();
}
EntityBean draft = (EntityBean)draftBean;
EntityBean live = (EntityBean)liveBean;
EntityBean draft = (EntityBean) draftBean;
EntityBean live = (EntityBean) liveBean;
BeanProperty idProperty = desc.getIdProperty();
if (idProperty != null) {
@@ -794,7 +794,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
}
if (matchSet.size() == 0) {
if (matchSet.isEmpty()) {
// this is a unidirectional relationship
// ... that is no matching property on the 'detail' bean
return false;
@@ -1141,7 +1141,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
// already assigned (So custom or UUID)
return;
}
if (desc.propertiesId().size() == 0) {
if (desc.propertiesId().isEmpty()) {
// bean doesn't have an Id property
if (desc.isBaseTableType() && desc.getBeanFinder() == null) {
// expecting an id property
@@ -2,18 +2,18 @@ package com.avaje.ebeaninternal.server.deploy;
public class BeanEmbeddedMeta {
final BeanProperty[] properties;
public BeanEmbeddedMeta(BeanProperty[] properties) {
this.properties = properties;
}
/**
* Return the properties with over ridden mapping information.
*/
public BeanProperty[] getProperties() {
return properties;
}
final BeanProperty[] properties;
public BeanEmbeddedMeta(BeanProperty[] properties) {
this.properties = properties;
}
/**
* Return the properties with over ridden mapping information.
*/
public BeanProperty[] getProperties() {
return properties;
}
}
@@ -12,41 +12,41 @@ import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
*/
public class BeanEmbeddedMetaFactory {
/**
* Create BeanProperties for embedded beans using the deployment specific DB column name and table alias.
*/
public static BeanEmbeddedMeta create(BeanDescriptorMap owner, DeployBeanPropertyAssocOne<?> prop) {
/**
* Create BeanProperties for embedded beans using the deployment specific DB column name and table alias.
*/
public static BeanEmbeddedMeta create(BeanDescriptorMap owner, DeployBeanPropertyAssocOne<?> prop) {
// we can get a BeanDescriptor for an Embedded bean
// and know that it is NOT recursive, as Embedded beans are
// only allow to hold simple scalar types...
BeanDescriptor<?> targetDesc = owner.getBeanDescriptor(prop.getTargetType());
if (targetDesc == null){
String msg = "Could not find BeanDescriptor for "+prop.getTargetType()
+". Perhaps the EmbeddedId class is not registered?";
throw new PersistenceException(msg);
}
// we can get a BeanDescriptor for an Embedded bean
// and know that it is NOT recursive, as Embedded beans are
// only allow to hold simple scalar types...
BeanDescriptor<?> targetDesc = owner.getBeanDescriptor(prop.getTargetType());
if (targetDesc == null) {
String msg = "Could not find BeanDescriptor for " + prop.getTargetType()
+ ". Perhaps the EmbeddedId class is not registered?";
throw new PersistenceException(msg);
}
// deployment override information (column names)
Map<String, String> propColMap = prop.getDeployEmbedded().getPropertyColumnMap();
// deployment override information (column names)
Map<String, String> propColMap = prop.getDeployEmbedded().getPropertyColumnMap();
BeanProperty[] sourceProperties = targetDesc.propertiesBaseScalar();
BeanProperty[] sourceProperties = targetDesc.propertiesBaseScalar();
BeanProperty[] embeddedProperties = new BeanProperty[sourceProperties.length];
BeanProperty[] embeddedProperties = new BeanProperty[sourceProperties.length];
for (int i = 0; i < sourceProperties.length; i++) {
for (int i = 0; i < sourceProperties.length; i++) {
String propertyName = sourceProperties[i].getName();
String dbColumn = propColMap.get(propertyName);
if (dbColumn == null) {
// dbColumn not overridden so take original
dbColumn = sourceProperties[i].getDbColumn();
}
String propertyName = sourceProperties[i].getName();
String dbColumn = propColMap.get(propertyName);
if (dbColumn == null) {
// dbColumn not overridden so take original
dbColumn = sourceProperties[i].getDbColumn();
}
BeanPropertyOverride overrides = new BeanPropertyOverride(dbColumn);
embeddedProperties[i] = new BeanProperty(sourceProperties[i], overrides);
}
BeanPropertyOverride overrides = new BeanPropertyOverride(dbColumn);
embeddedProperties[i] = new BeanProperty(sourceProperties[i], overrides);
}
return new BeanEmbeddedMeta(embeddedProperties);
}
return new BeanEmbeddedMeta(embeddedProperties);
}
}
@@ -21,7 +21,7 @@ public final class BeanFkeyProperty implements ElPropertyValue {
public BeanFkeyProperty(String name, String dbColumn, int deployOrder) {
this(null, name, dbColumn, deployOrder, false);
}
private BeanFkeyProperty(String prefix, String name, String dbColumn, int deployOrder, boolean containsMany) {
this.prefix = prefix;
this.name = name;
@@ -32,7 +32,7 @@ public final class BeanFkeyProperty implements ElPropertyValue {
}
public String toString() {
return "prefix:"+prefix+" name:"+name+" dbColumn:"+dbColumn+" ph:"+placeHolder;
return "prefix:" + prefix + " name:" + name + " dbColumn:" + dbColumn + " ph:" + placeHolder;
}
public int getDeployOrder() {
@@ -7,27 +7,27 @@ import com.avaje.ebeaninternal.server.persist.BeanPersister;
*/
public class BeanManager<T> {
private final BeanPersister persister;
private final BeanPersister persister;
private final BeanDescriptor<T> descriptor;
private final BeanDescriptor<T> descriptor;
public BeanManager(BeanDescriptor<T> descriptor, BeanPersister persister) {
this.descriptor = descriptor;
this.persister = persister;
}
public BeanManager(BeanDescriptor<T> descriptor, BeanPersister persister) {
this.descriptor = descriptor;
this.persister = persister;
}
/**
* Return the associated BeanPersister.
*/
public BeanPersister getBeanPersister() {
return persister;
}
/**
* Return the associated BeanPersister.
*/
public BeanPersister getBeanPersister() {
return persister;
}
/**
* Return the BeanDescriptor.
*/
public BeanDescriptor<T> getBeanDescriptor() {
return descriptor;
}
/**
* Return the BeanDescriptor.
*/
public BeanDescriptor<T> getBeanDescriptor() {
return descriptor;
}
}
@@ -38,7 +38,8 @@ public final class BeanMapHelp<T> implements BeanCollectionHelp<T> {
/**
* When help is attached to a specific many property.
*/ public BeanMapHelp(BeanPropertyAssocMany<T> many) {
*/
public BeanMapHelp(BeanPropertyAssocMany<T> many) {
this.many = many;
this.targetDescriptor = many.getTargetDescriptor();
this.propertyName = many.getName();
@@ -332,9 +332,9 @@ public class BeanProperty implements ElPropertyValue, Property {
this.softDelete = deploy.isSoftDelete();
if (softDelete) {
ScalarTypeBoolean.BooleanBase boolType = (ScalarTypeBoolean.BooleanBase)scalarType;
this.softDeleteDbSet = dbColumn+"="+boolType.getDbTrueLiteral();
this.softDeleteDbPredicate = "."+dbColumn+","+boolType.getDbFalseLiteral()+")="+boolType.getDbFalseLiteral();
ScalarTypeBoolean.BooleanBase boolType = (ScalarTypeBoolean.BooleanBase) scalarType;
this.softDeleteDbSet = dbColumn + "=" + boolType.getDbTrueLiteral();
this.softDeleteDbPredicate = "." + dbColumn + "," + boolType.getDbFalseLiteral() + ")=" + boolType.getDbFalseLiteral();
} else {
this.softDeleteDbSet = null;
this.softDeleteDbPredicate = null;
@@ -763,7 +763,7 @@ public class BeanProperty implements ElPropertyValue, Property {
public void setCacheDataValue(EntityBean bean, Object cacheData, PersistenceContext context) {
if (cacheData instanceof String) {
// parse back from string to support optimisation of java object serialisation
cacheData = scalarType.parse((String)cacheData);
cacheData = scalarType.parse((String) cacheData);
}
setValue(bean, cacheData);
}
@@ -776,7 +776,7 @@ public class BeanProperty implements ElPropertyValue, Property {
}
public Object getVal(Object bean) {
return getValue((EntityBean)bean);
return getValue((EntityBean) bean);
}
/**
@@ -814,7 +814,7 @@ public class BeanProperty implements ElPropertyValue, Property {
if (bean != null) {
Object logicalVal = convertToLogicalType(value);
setValue((EntityBean)bean, logicalVal);
setValue((EntityBean) bean, logicalVal);
}
}
@@ -823,7 +823,7 @@ public class BeanProperty implements ElPropertyValue, Property {
if (bean == null) {
return null;
}
return getValueIntercept((EntityBean)bean);
return getValueIntercept((EntityBean) bean);
}
@Override
@@ -1322,7 +1322,7 @@ public class BeanProperty implements ElPropertyValue, Property {
// change in behavior for #318
objValue = null;
String msg = "Error trying to use Jackson ObjectMapper to read transient property "
+ getFullBeanName() +" - consider marking this property with @JsonIgnore";
+ getFullBeanName() + " - consider marking this property with @JsonIgnore";
logger.error(msg, e);
}
}
@@ -1371,7 +1371,7 @@ public class BeanProperty implements ElPropertyValue, Property {
DocPropertyType type = scalarType.getDocType();
DocPropertyOptions options = docOptions.copy();
if (DocPropertyType.UUID == type || DocPropertyType.ENUM == type ||isStringId(type)) {
if (DocPropertyType.UUID == type || DocPropertyType.ENUM == type || isStringId(type)) {
options.setCode(true);
}
@@ -1,19 +1,7 @@
package com.avaje.ebeaninternal.server.deploy;
import java.util.ArrayList;
import javax.persistence.PersistenceException;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebeaninternal.server.query.SplitName;
import com.avaje.ebeanservice.docstore.api.mapping.DocMappingBuilder;
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyMapping;
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
import com.avaje.ebeanservice.docstore.api.support.DocStructure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.text.PathProperties;
import com.avaje.ebeaninternal.server.core.InternString;
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
@@ -22,206 +10,223 @@ import com.avaje.ebeaninternal.server.deploy.id.ImportedIdSimple;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
import com.avaje.ebeaninternal.server.el.ElPropertyChainBuilder;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
import com.avaje.ebeaninternal.server.query.SplitName;
import com.avaje.ebeaninternal.server.query.SqlJoinType;
import com.avaje.ebeanservice.docstore.api.mapping.DocMappingBuilder;
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyMapping;
import com.avaje.ebeanservice.docstore.api.mapping.DocPropertyType;
import com.avaje.ebeanservice.docstore.api.support.DocStructure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import java.util.ArrayList;
/**
* Abstract base for properties mapped to an associated bean, list, set or map.
*/
public abstract class BeanPropertyAssoc<T> extends BeanProperty {
private static final Logger logger = LoggerFactory.getLogger(BeanPropertyAssoc.class);
private static final Logger logger = LoggerFactory.getLogger(BeanPropertyAssoc.class);
/**
* The descriptor of the target. This MUST be initialised after construction
* so as to avoid a dependency loop between BeanDescriptors.
*/
BeanDescriptor<T> targetDescriptor;
/**
* The descriptor of the target. This MUST be initialised after construction
* so as to avoid a dependency loop between BeanDescriptors.
*/
BeanDescriptor<T> targetDescriptor;
IdBinder targetIdBinder;
IdBinder targetIdBinder;
InheritInfo targetInheritInfo;
InheritInfo targetInheritInfo;
String targetIdProperty;
String targetIdProperty;
/**
* Persist settings.
*/
final BeanCascadeInfo cascadeInfo;
/**
* Persist settings.
*/
final BeanCascadeInfo cascadeInfo;
/**
* Join between the beans.
*/
final TableJoin tableJoin;
/**
* Join between the beans.
*/
final TableJoin tableJoin;
/**
* The type of the joined bean.
*/
final Class<T> targetType;
/**
* The type of the joined bean.
*/
final Class<T> targetType;
/**
* The join table information.
*/
final BeanTable beanTable;
final String mappedBy;
/**
* The join table information.
*/
final BeanTable beanTable;
final String mappedBy;
final String docStoreDoc;
final String extraWhere;
boolean saveRecurseSkippable;
final String extraWhere;
/**
* Construct the property.
*/
public BeanPropertyAssoc(BeanDescriptor<?> descriptor, DeployBeanPropertyAssoc<T> deploy) {
super(descriptor, deploy);
this.extraWhere = InternString.intern(deploy.getExtraWhere());
this.beanTable = deploy.getBeanTable();
this.mappedBy = InternString.intern(deploy.getMappedBy());
boolean saveRecurseSkippable;
/**
* Construct the property.
*/
public BeanPropertyAssoc(BeanDescriptor<?> descriptor, DeployBeanPropertyAssoc<T> deploy) {
super(descriptor, deploy);
this.extraWhere = InternString.intern(deploy.getExtraWhere());
this.beanTable = deploy.getBeanTable();
this.mappedBy = InternString.intern(deploy.getMappedBy());
this.docStoreDoc = deploy.getDocStoreDoc();
this.tableJoin = new TableJoin(deploy.getTableJoin());
this.tableJoin = new TableJoin(deploy.getTableJoin());
this.targetType = deploy.getTargetType();
this.cascadeInfo = deploy.getCascadeInfo();
}
/**
* Initialise post construction.
*/
@Override
public void initialise() {
// this *MUST* execute after the BeanDescriptor is
// put into the map to stop infinite recursion
this.targetType = deploy.getTargetType();
this.cascadeInfo = deploy.getCascadeInfo();
}
/**
* Initialise post construction.
*/
@Override
public void initialise() {
// this *MUST* execute after the BeanDescriptor is
// put into the map to stop infinite recursion
targetDescriptor = descriptor.getBeanDescriptor(targetType);
if (!isTransient){
targetIdBinder = targetDescriptor.getIdBinder();
targetInheritInfo = targetDescriptor.getInheritInfo();
saveRecurseSkippable = targetDescriptor.isSaveRecurseSkippable();
if (!isTransient) {
targetIdBinder = targetDescriptor.getIdBinder();
targetInheritInfo = targetDescriptor.getInheritInfo();
saveRecurseSkippable = targetDescriptor.isSaveRecurseSkippable();
if (!targetIdBinder.isComplexId()){
targetIdProperty = targetIdBinder.getIdProperty();
}
}
}
/**
* Create a ElPropertyValue for a *ToOne or *ToMany.
*/
protected ElPropertyValue createElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) {
// associated or embedded bean
BeanDescriptor<?> embDesc = getTargetDescriptor();
if (chain == null) {
chain = new ElPropertyChainBuilder(isEmbedded(), propName);
}
chain.add(this);
if (containsMany()) {
chain.setContainsMany();
}
return embDesc.buildElGetValue(remainder, chain, propertyDeploy);
if (!targetIdBinder.isComplexId()) {
targetIdProperty = targetIdBinder.getIdProperty();
}
}
/**
* Add table join with table alias based on prefix.
*/
public SqlJoinType addJoin(SqlJoinType joinType, String prefix, DbSqlContext ctx) {
return tableJoin.addJoin(joinType, prefix, ctx);
}
/**
* Add table join with explicit table alias.
*/
public SqlJoinType addJoin(SqlJoinType joinType, String a1, String a2, DbSqlContext ctx) {
return tableJoin.addJoin(joinType, a1, a2, ctx);
}
/**
* Return false.
*/
public boolean isScalar() {
return false;
}
/**
* Return the mappedBy property.
* This will be null on the owning side.
*/
public String getMappedBy() {
return mappedBy;
}
}
/**
* Return the Id property of the target entity type.
* <p>
* This will return null for multiple Id properties.
* </p>
*/
public String getTargetIdProperty() {
return targetIdProperty;
}
/**
* Create a ElPropertyValue for a *ToOne or *ToMany.
*/
protected ElPropertyValue createElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) {
/**
* Return the BeanDescriptor of the target.
*/
public BeanDescriptor<T> getTargetDescriptor() {
return targetDescriptor;
}
public boolean isSaveRecurseSkippable(Object bean) {
// associated or embedded bean
BeanDescriptor<?> embDesc = getTargetDescriptor();
if (chain == null) {
chain = new ElPropertyChainBuilder(isEmbedded(), propName);
}
chain.add(this);
if (containsMany()) {
chain.setContainsMany();
}
return embDesc.buildElGetValue(remainder, chain, propertyDeploy);
}
/**
* Add table join with table alias based on prefix.
*/
public SqlJoinType addJoin(SqlJoinType joinType, String prefix, DbSqlContext ctx) {
return tableJoin.addJoin(joinType, prefix, ctx);
}
/**
* Add table join with explicit table alias.
*/
public SqlJoinType addJoin(SqlJoinType joinType, String a1, String a2, DbSqlContext ctx) {
return tableJoin.addJoin(joinType, a1, a2, ctx);
}
/**
* Return false.
*/
public boolean isScalar() {
return false;
}
/**
* Return the mappedBy property.
* This will be null on the owning side.
*/
public String getMappedBy() {
return mappedBy;
}
/**
* Return the Id property of the target entity type.
* <p>
* This will return null for multiple Id properties.
* </p>
*/
public String getTargetIdProperty() {
return targetIdProperty;
}
/**
* Return the BeanDescriptor of the target.
*/
public BeanDescriptor<T> getTargetDescriptor() {
return targetDescriptor;
}
/**
* Return true if REFRESH should cascade.
*/
public boolean isCascadeRefresh() {
return cascadeInfo.isRefresh();
}
public boolean isSaveRecurseSkippable(Object bean) {
return saveRecurseSkippable && bean instanceof EntityBean && !((EntityBean) bean)._ebean_getIntercept().isNewOrDirty();
}
/**
* Return true if save can be skipped for unmodified bean(s) of this
* property.
* <p>
* That is, if a bean of this property is unmodified we don't need to
* saveRecurse because none of its associated beans have cascade save set to
* true.
* </p>
*/
public boolean isSaveRecurseSkippable() {
return saveRecurseSkippable;
}
/**
* Return true if save can be skipped for unmodified bean(s) of this
* property.
* <p>
* That is, if a bean of this property is unmodified we don't need to
* saveRecurse because none of its associated beans have cascade save set to
* true.
* </p>
*/
public boolean isSaveRecurseSkippable() {
return saveRecurseSkippable;
}
/**
* Return true if the unique id properties are all not null for this bean.
*/
public boolean hasId(EntityBean bean) {
/**
* Return true if the unique id properties are all not null for this bean.
*/
public boolean hasId(EntityBean bean) {
BeanDescriptor<?> targetDesc = getTargetDescriptor();
BeanProperty idProp = targetDesc.getIdProperty();
if (idProp != null) {
Object value = idProp.getValue(bean);
if (value == null) {
return false;
}
}
// all the unique properties are non-null
return true;
}
BeanDescriptor<?> targetDesc = getTargetDescriptor();
BeanProperty idProp = targetDesc.getIdProperty();
if (idProp != null) {
Object value = idProp.getValue(bean);
if (value == null) {
return false;
}
}
// all the unique properties are non-null
return true;
}
/**
* Return the type of the target.
* <p>
* This is the class of the associated bean, or beans contained in a list,
* set or map.
* </p>
*/
public Class<?> getTargetType() {
return targetType;
}
/**
* Return the type of the target.
* <p>
* This is the class of the associated bean, or beans contained in a list,
* set or map.
* </p>
*/
public Class<?> getTargetType() {
return targetType;
}
/**
* Return an extra clause to add to the query for loading or joining
* to this bean type.
*/
public String getExtraWhere() {
return extraWhere;
}
/**
* Return an extra clause to add to the query for loading or joining
* to this bean type.
*/
public String getExtraWhere() {
return extraWhere;
}
/**
* Return the elastic search doc for this embedded property.
@@ -280,104 +285,104 @@ public abstract class BeanPropertyAssoc<T> extends BeanProperty {
}
}
/**
* Return true if this association is updateable.
*/
public boolean isUpdateable() {
/**
* Return true if this association is updateable.
*/
public boolean isUpdateable() {
return tableJoin.columns().length <= 0 || tableJoin.columns()[0].isUpdateable();
}
/**
* Return true if this association is insertable.
*/
public boolean isInsertable() {
/**
* Return true if this association is insertable.
*/
public boolean isInsertable() {
return tableJoin.columns().length <= 0 || tableJoin.columns()[0].isInsertable();
}
/**
* return the join to use for the bean.
*/
public TableJoin getTableJoin() {
return tableJoin;
}
/**
* return the join to use for the bean.
*/
public TableJoin getTableJoin() {
return tableJoin;
}
/**
* Get the persist info.
*/
public BeanCascadeInfo getCascadeInfo() {
return cascadeInfo;
}
/**
* Get the persist info.
*/
public BeanCascadeInfo getCascadeInfo() {
return cascadeInfo;
}
/**
* Build the list of imported property. Matches BeanProperty from the target
* descriptor back to local database columns in the TableJoin.
*/
protected ImportedId createImportedId(BeanPropertyAssoc<?> owner, BeanDescriptor<?> target, TableJoin join) {
/**
* Build the list of imported property. Matches BeanProperty from the target
* descriptor back to local database columns in the TableJoin.
*/
protected ImportedId createImportedId(BeanPropertyAssoc<?> owner, BeanDescriptor<?> target, TableJoin join) {
BeanProperty idProp = target.getIdProperty();
BeanProperty[] others = target.propertiesBaseScalar();
BeanProperty idProp = target.getIdProperty();
BeanProperty[] others = target.propertiesBaseScalar();
if (descriptor.isSqlSelectBased()){
String dbColumn = owner.getDbColumn();
return new ImportedIdSimple(owner, dbColumn, idProp, 0);
}
if (descriptor.isSqlSelectBased()) {
String dbColumn = owner.getDbColumn();
return new ImportedIdSimple(owner, dbColumn, idProp, 0);
}
TableJoinColumn[] cols = join.columns();
TableJoinColumn[] cols = join.columns();
if (idProp == null) {
return null;
}
if (!idProp.isEmbedded()) {
// simple single scalar id
if (cols.length != 1){
String msg = "No Imported Id column for ["+idProp+"] in table ["+join.getTable()+"]";
logger.error(msg);
return null;
} else {
BeanProperty[] idProps = {idProp};
return createImportedScalar(owner, cols[0], idProps, others);
}
} else {
// embedded id
BeanPropertyAssocOne<?> embProp = (BeanPropertyAssocOne<?>)idProp;
BeanProperty[] embBaseProps = embProp.getTargetDescriptor().propertiesBaseScalar();
ImportedIdSimple[] scalars = createImportedList(owner, cols, embBaseProps, others);
if (idProp == null) {
return null;
}
if (!idProp.isEmbedded()) {
// simple single scalar id
if (cols.length != 1) {
String msg = "No Imported Id column for [" + idProp + "] in table [" + join.getTable() + "]";
logger.error(msg);
return null;
} else {
BeanProperty[] idProps = {idProp};
return createImportedScalar(owner, cols[0], idProps, others);
}
} else {
// embedded id
BeanPropertyAssocOne<?> embProp = (BeanPropertyAssocOne<?>) idProp;
BeanProperty[] embBaseProps = embProp.getTargetDescriptor().propertiesBaseScalar();
ImportedIdSimple[] scalars = createImportedList(owner, cols, embBaseProps, others);
return new ImportedIdEmbedded(owner, embProp, scalars);
}
}
return new ImportedIdEmbedded(owner, embProp, scalars);
}
}
private ImportedIdSimple[] createImportedList(BeanPropertyAssoc<?> owner, TableJoinColumn[] cols, BeanProperty[] props, BeanProperty[] others) {
private ImportedIdSimple[] createImportedList(BeanPropertyAssoc<?> owner, TableJoinColumn[] cols, BeanProperty[] props, BeanProperty[] others) {
ArrayList<ImportedIdSimple> list = new ArrayList<ImportedIdSimple>();
ArrayList<ImportedIdSimple> list = new ArrayList<ImportedIdSimple>();
for (int i = 0; i < cols.length; i++) {
list.add(createImportedScalar(owner, cols[i], props, others));
}
return ImportedIdSimple.sort(list);
}
for (int i = 0; i < cols.length; i++) {
list.add(createImportedScalar(owner, cols[i], props, others));
}
private ImportedIdSimple createImportedScalar(BeanPropertyAssoc<?> owner, TableJoinColumn col, BeanProperty[] props, BeanProperty[] others) {
return ImportedIdSimple.sort(list);
}
String matchColumn = col.getForeignDbColumn();
String localColumn = col.getLocalDbColumn();
for (int j = 0; j < props.length; j++) {
if (props[j].getDbColumn().equalsIgnoreCase(matchColumn)) {
return new ImportedIdSimple(owner, localColumn, props[j], j);
}
}
private ImportedIdSimple createImportedScalar(BeanPropertyAssoc<?> owner, TableJoinColumn col, BeanProperty[] props, BeanProperty[] others) {
for (int j = 0; j < others.length; j++) {
if (others[j].getDbColumn().equalsIgnoreCase(matchColumn)) {
return new ImportedIdSimple(owner, localColumn, others[j], j+props.length);
}
}
String msg = "Error with the Join on ["+getFullBeanName()
+"]. Could not find the local match for ["+matchColumn+"] "//in table["+searchTable+"]?"
+" Perhaps an error in a @JoinColumn";
throw new PersistenceException(msg);
}
String matchColumn = col.getForeignDbColumn();
String localColumn = col.getLocalDbColumn();
for (int j = 0; j < props.length; j++) {
if (props[j].getDbColumn().equalsIgnoreCase(matchColumn)) {
return new ImportedIdSimple(owner, localColumn, props[j], j);
}
}
for (int j = 0; j < others.length; j++) {
if (others[j].getDbColumn().equalsIgnoreCase(matchColumn)) {
return new ImportedIdSimple(owner, localColumn, others[j], j + props.length);
}
}
String msg = "Error with the Join on [" + getFullBeanName()
+ "]. Could not find the local match for [" + matchColumn + "] "//in table["+searchTable+"]?"
+ " Perhaps an error in a @JoinColumn";
throw new PersistenceException(msg);
}
}
@@ -265,12 +265,11 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
*/
public void resetMany(EntityBean bean) {
Object value = getValue(bean);
if (value == null) {
// not expecting this - set an empty reference
createReference(bean);
} else {
if (value instanceof BeanCollection) {
// reset the collection back to empty
((BeanCollection)value).reset(bean, name);
} else {
createReference(bean);
}
}
@@ -283,7 +283,7 @@ public class DeployBeanDescriptor<T> {
docStoreUpdate = docStore.update();
docStoreDelete = docStore.delete();
String doc = docStore.doc();
if (doc.length() > 0) {
if (!doc.isEmpty()) {
docStorePathProperties = PathProperties.parse(doc);
}
}
@@ -388,7 +388,7 @@ public class DeployBeanDescriptor<T> {
public void setCache(Cache cache) {
String naturalKey = null;
if (cache.naturalKey().length() > 0) {
if (!cache.naturalKey().isEmpty()) {
// find the property and mark as natural key property
String propName = cache.naturalKey().trim();
DeployBeanProperty beanProperty = getBeanProperty(propName);
@@ -477,7 +477,7 @@ public class DeployBeanDescriptor<T> {
* Return the BeanPersistController (could be a chain of them, 1 or null).
*/
public BeanPersistController getPersistController() {
if (persistControllers.size() == 0) {
if (persistControllers.isEmpty()) {
return null;
} else if (persistControllers.size() == 1) {
return persistControllers.get(0);
@@ -490,7 +490,7 @@ public class DeployBeanDescriptor<T> {
* Return the BeanPersistListener (could be a chain of them, 1 or null).
*/
public BeanPersistListener getPersistListener() {
if (persistListeners.size() == 0) {
if (persistListeners.isEmpty()) {
return null;
} else if (persistListeners.size() == 1) {
return persistListeners.get(0);
@@ -500,7 +500,7 @@ public class DeployBeanDescriptor<T> {
}
public BeanQueryAdapter getQueryAdapter() {
if (queryAdapters.size() == 0) {
if (queryAdapters.isEmpty()) {
return null;
} else if (queryAdapters.size() == 1) {
return queryAdapters.get(0);
@@ -513,7 +513,7 @@ public class DeployBeanDescriptor<T> {
* Return the BeanPostLoad (could be a chain of them, 1 or null).
*/
public BeanPostLoad getPostLoad() {
if (postLoaders.size() == 0) {
if (postLoaders.isEmpty()) {
return null;
} else if (postLoaders.size() == 1) {
return postLoaders.get(0);
@@ -583,7 +583,7 @@ public class DeployBeanDescriptor<T> {
*/
public void setView(String viewName, String[] dependentTables) {
this.entityType = EntityType.VIEW;
this.dependentTables = this.dependentTables;
this.dependentTables = dependentTables;
setBaseTable(new TableName(viewName), "", "");
}
@@ -835,7 +835,7 @@ public class DeployBeanDescriptor<T> {
return null;
}
String selectClause = sb.toString();
if (selectClause.length() == 0) {
if (selectClause.isEmpty()) {
throw new IllegalStateException("Bean " + getFullName() + " has no properties?");
}
return selectClause.substring(0, selectClause.length() - 1);
@@ -386,7 +386,7 @@ public class DeployBeanProperty {
* Set a specific DB column definition.
*/
public void setDbColumnDefn(String dbColumnDefn) {
if (dbColumnDefn == null || dbColumnDefn.trim().length() == 0) {
if (dbColumnDefn == null || dbColumnDefn.trim().isEmpty()) {
this.dbColumnDefn = null;
} else {
this.dbColumnDefn = InternString.intern(dbColumnDefn);
@@ -178,7 +178,7 @@ public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
* Set the default mapKey to use when returning a Map.
*/
public void setMapKey(String mapKey) {
if (mapKey != null && mapKey.length() > 0) {
if (mapKey != null && !mapKey.isEmpty()) {
this.mapKey = mapKey;
}
}
@@ -188,7 +188,7 @@ public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
* list, set or map.
*/
public void setFetchOrderBy(String orderBy) {
if (orderBy != null && orderBy.length() > 0) {
if (orderBy != null && !orderBy.isEmpty()) {
fetchOrderBy = orderBy;
}
}
@@ -46,7 +46,7 @@ public class DeployTableJoin {
* Return true if the JoinOnPair have been set.
*/
public boolean hasJoinColumns() {
return columns.size() > 0;
return !columns.isEmpty();
}
/**
@@ -32,7 +32,7 @@ public abstract class AnnotationBase {
* Checks string is null or empty .
*/
protected boolean isEmpty(String s) {
return s == null || s.trim().length() == 0;
return s == null || s.trim().isEmpty();
}
@@ -188,7 +188,7 @@ public class DeployInheritInfo {
public void setDiscriminatorValue(String value) {
if (value != null) {
value = value.trim();
if (value.length() != 0) {
if (!value.isEmpty()) {
discriminatorStringValue = value;
// convert the value if desired
if (discriminatorType == Types.INTEGER) {
@@ -70,7 +70,7 @@ public class SqlReservedWords {
public static synchronized void addKeyword(String keyword){
if (keyword != null){
keyword = keyword.trim().toUpperCase();
if (keyword.length() > 0){
if (!keyword.isEmpty()){
keywords.add(keyword);
}
}
@@ -8,6 +8,7 @@ import com.avaje.ebeaninternal.api.SpiExpressionValidation;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.el.ElPropertyDeploy;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
import com.avaje.ebeaninternal.server.query.SplitName;
/**
* Base class for simple expressions.
@@ -20,11 +21,32 @@ public abstract class AbstractExpression implements SpiExpression {
this.propName = propName;
}
@Override
public Object getIdEqualTo(String idName) {
// override on SimpleExpression
return null;
}
@Override
public SpiExpression copyForPlanKey() {
return this;
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
return propertyNestedPath(propName, desc);
}
protected String propertyNestedPath(String propertyName, BeanDescriptor<?> desc) {
if (propertyName != null) {
ElPropertyDeploy elProp = desc.getElPropertyDeploy(propertyName);
if (elProp != null && elProp.containsMany()) {
return SplitName.begin(propName);
}
}
return null;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
@@ -16,6 +16,12 @@ public abstract class AbstractTextExpression extends AbstractExpression {
super(propName);
}
@Override
public Object getIdEqualTo(String idName) {
// always null for this expression
return null;
}
@Override
public void addSql(SpiExpressionRequest request) {
// do nothing, only execute against document store
@@ -30,6 +30,11 @@ class AllEqualsExpression extends NonPrepareExpression {
context.writeAllEquals(propMap);
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
return null;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
if (propMap != null) {
@@ -7,6 +7,7 @@ import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.el.ElPropertyDeploy;
import com.avaje.ebeaninternal.server.query.SplitName;
import java.io.IOException;
@@ -39,6 +40,16 @@ class BetweenPropertyExpression extends NonPrepareExpression {
context.endBool();
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
ElPropertyDeploy elProp = desc.getElPropertyDeploy(name(lowProperty));
if (elProp != null && elProp.containsMany()) {
// assumes highProperty is also nested property which seems reasonable
return SplitName.begin(lowProperty);
}
return null;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
@@ -1,8 +1,5 @@
package com.avaje.ebeaninternal.server.expression;
import java.io.IOException;
import java.util.ArrayList;
import com.avaje.ebean.ExampleExpression;
import com.avaje.ebean.LikeType;
import com.avaje.ebean.bean.EntityBean;
@@ -12,33 +9,34 @@ import com.avaje.ebeaninternal.api.ManyWhereJoins;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.query.SplitName;
import java.io.IOException;
import java.util.ArrayList;
/**
* A "Query By Example" type of expression.
* <p>
* Pass in an example entity and for each non-null scalar properties an
* expression is added.
* </p>
*
* <pre class="code">
* <p>
* <pre>{@code
* // create an example bean and set the properties
* // with the query parameters you want
* Customer example = new Customer();
* example.setName(&quot;Rob%&quot;);
* example.setNotes(&quot;%something%&quot;);
*
* List&lt;Customer&gt; list = Ebean.find(Customer.class).where()
* // pass the bean into the where() clause
* .exampleLike(example)
* // you can add other expressions to the same query
* .gt(&quot;id&quot;, 2).findList();
*
* </pre>
* example.setName("Rob%");
* example.setNotes("%something%");
*
* List<Customer> list = Ebean.find(Customer.class)
* .where()
* .exampleLike(example)
* .findList();
*
* }</pre>
*/
public class DefaultExampleExpression implements SpiExpression, ExampleExpression {
@@ -71,13 +69,10 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
/**
* Construct the query by example expression.
*
* @param entity
* the example entity with non null property values
* @param caseInsensitive
* if true use case insensitive expressions
* @param likeType
* the type of Like wild card used
*
* @param entity the example entity with non null property values
* @param caseInsensitive if true use case insensitive expressions
* @param likeType the type of Like wild card used
*/
public DefaultExampleExpression(EntityBean entity, boolean caseInsensitive, LikeType likeType) {
this.entity = entity;
@@ -104,11 +99,22 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
}
}
@Override
public Object getIdEqualTo(String idName) {
// always return null for this expression
return null;
}
@Override
public SpiExpression copyForPlanKey() {
return new DefaultExampleExpression(list);
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
return null;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins whereManyJoins) {
list = buildExpressions(desc);
@@ -290,9 +296,9 @@ public class DefaultExampleExpression implements SpiExpression, ExampleExpressio
}
} else if ((beanProperty instanceof BeanPropertyAssocOne) && (value instanceof EntityBean)) {
BeanPropertyAssocOne assocOne = (BeanPropertyAssocOne)beanProperty;
BeanPropertyAssocOne assocOne = (BeanPropertyAssocOne) beanProperty;
BeanDescriptor targetDescriptor = assocOne.getTargetDescriptor();
addExpressions(list, targetDescriptor, (EntityBean)value, propName);
addExpressions(list, targetDescriptor, (EntityBean) value, propName);
}
}
}
@@ -29,7 +29,9 @@ import java.util.Set;
*/
public class DefaultExpressionList<T> implements SpiExpressionList<T> {
protected final List<SpiExpression> list;
private static final String AND = " and ";
protected List<SpiExpression> list;
protected final Query<T> query;
@@ -37,9 +39,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
protected transient ExpressionFactory expr;
private final String listAndStart;
private final String listAndEnd;
private final String listAndJoin;
protected String allDocNestedPath;
/**
* Set to true for the "Text" root expression list.
@@ -71,16 +71,32 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
this.query = query;
this.expr = expr;
this.parentExprList = parentExprList;
this.listAndStart = "";
this.listAndEnd = "";
this.listAndJoin = " and ";
}
private DefaultExpressionList() {
this(null, null, null, new ArrayList<SpiExpression>());
}
/**
* Wrap the expression list as a Junction or top level DefaultExpressionList.
*
* @param list The list of expressions grouped by nested path
* @param nestedPath The doc store nested path
* @param type The junction type (or null for top level expression list).
* @return A single SpiExpression that has the nestedPath set
*/
SpiExpression wrap(List<SpiExpression> list, String nestedPath, Junction.Type type) {
DefaultExpressionList<T> wrapper = new DefaultExpressionList<T>(query, expr, null, list, false);
wrapper.setAllDocNested(nestedPath);
if (type != null) {
return new JunctionExpression<T>(type, wrapper);
} else {
return wrapper;
}
}
/**
* Write being aware if it is the Top level "text" expressions.
* <p>
@@ -100,6 +116,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
// this is a Top level "text" expressions so we may need to wrap in Bool SHOULD etc.
if (list.isEmpty()) throw new IllegalStateException("empty expression list?");
if (allDocNestedPath!=null) context.startNested(allDocNestedPath);
int size = list.size();
SpiExpression first = list.get(0);
@@ -130,11 +147,13 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
if (implicitBool || explicitBool) {
context.endBoolGroup();
}
if (allDocNestedPath!=null) context.endNested();
}
}
public void writeDocQuery(DocQueryContext context, SpiExpression idEquals) throws IOException {
if (allDocNestedPath!=null) context.startNested(allDocNestedPath);
int size = list.size();
if (size == 1 && idEquals == null) {
// only 1 expression - skip bool
@@ -153,6 +172,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
}
context.endBool();
}
if (allDocNestedPath!=null) context.endNested();
}
@Override
@@ -184,6 +204,12 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return copy;
}
@Override
public Object getIdEqualTo(String idName) {
// always return null for this expression
return null;
}
/**
* Return true if one of the expressions is related to a Many property.
*/
@@ -433,15 +459,13 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
@Override
public void addSql(SpiExpressionRequest request) {
request.append(listAndStart);
for (int i = 0, size = list.size(); i < size; i++) {
SpiExpression expression = list.get(i);
if (i > 0) {
request.append(listAndJoin);
request.append(AND);
}
expression.addSql(request);
}
request.append(listAndEnd);
}
@Override
@@ -983,4 +1007,37 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
return junction(Junction.Type.MUST_NOT);
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
// effectively handled by JunctionExpression
return null;
}
/**
* Set the nested path that all contained expressions share.
*/
public void setAllDocNested(String allDocNestedPath) {
this.allDocNestedPath = allDocNestedPath;
}
/**
* Replace the underlying expression list with one organised by nested path.
*/
public void setUnderlying(List<SpiExpression> groupedByNesting) {
this.list = groupedByNesting;
}
/**
* Prepare expressions for document store nested path handling.
*/
public void prepareDocNested(BeanDescriptor<T> beanDescriptor) {
PrepareDocNested.prepare(this, beanDescriptor);
}
public Object idEqualTo(String idName) {
if (list.size() == 1) {
return list.get(0).getIdEqualTo(idName);
}
return null;
}
}
@@ -147,4 +147,24 @@ public interface DocQueryContext {
* Return the expression path for the given property path.
*/
ExpressionPath getExpressionPath(String propName);
/**
* Start nested path expressions.
*/
void startNested(String nestedPath) throws IOException;
/**
* End nested path expressions.
*/
void endNested() throws IOException;
/**
* Start a not wrapping an expression.
*/
void startNot() throws IOException;
/**
* End a not wrapper.
*/
void endNot() throws IOException;
}
@@ -41,6 +41,12 @@ class ExistsQueryExpression implements SpiExpression, UnsupportedDocStoreExpress
throw new IllegalStateException("Not supported");
}
@Override
public Object getIdEqualTo(String idName) {
// always return null for this expression
return null;
}
@Override
public void prepareExpression(BeanQueryRequest<?> request) {
@@ -118,6 +124,11 @@ class ExistsQueryExpression implements SpiExpression, UnsupportedDocStoreExpress
return true;
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
return null;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins whereManyJoins) {
// Nothing to do for exists expression
@@ -25,6 +25,11 @@ class IdExpression extends NonPrepareExpression implements SpiExpression {
context.writeId(value);
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
return null;
}
/**
* Always returns false.
*/
@@ -22,6 +22,11 @@ public class IdInExpression extends NonPrepareExpression {
this.idList = idList;
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
return null;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
}
@@ -16,15 +16,38 @@ class IsEmptyExpression extends AbstractExpression {
private final String propertyPath;
private String nestedPath;
IsEmptyExpression(String propertyName, boolean empty) {
super(propertyName);
this.empty = empty;
this.propertyPath = SplitName.split(propertyName)[0];
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
if (empty) {
// capture the nestedPath as we want to put wrap
// a NOT around the outer of the nested path exists
this.nestedPath = propertyNestedPath(propName, desc);
return null;
} else {
return super.nestedPath(desc);
}
}
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
context.writeExists(!empty, propName);
if (nestedPath == null) {
context.writeExists(!empty, propName);
} else {
// wrap NOT around the outside of nested path exists expression
context.startNot();
context.startNested(nestedPath);
context.writeExists(empty, propName);
context.endNested();
context.endNot();
}
}
public final String getPropName() {
@@ -39,7 +39,7 @@ import java.util.Set;
*/
class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, ExpressionList<T> {
private final DefaultExpressionList<T> exprList;
protected final DefaultExpressionList<T> exprList;
protected final Junction.Type type;
@@ -80,6 +80,12 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
context.endBoolGroupList();
}
@Override
public Object getIdEqualTo(String idName) {
// always null for this expression
return null;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
@@ -790,4 +796,17 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
public ExpressionList<T> endNot() {
return endJunction();
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
PrepareDocNested.prepare(exprList, desc, type);
String nestedPath = exprList.allDocNestedPath;
if (nestedPath != null) {
// push the nestedPath up to parent
exprList.setAllDocNested(null);
return nestedPath;
}
return null;
}
}
@@ -45,9 +45,9 @@ abstract class LogicExpression implements SpiExpression {
}
}
protected final SpiExpression expOne;
protected SpiExpression expOne;
protected final SpiExpression expTwo;
protected SpiExpression expTwo;
private final String joinType;
@@ -67,6 +67,33 @@ abstract class LogicExpression implements SpiExpression {
context.endBool();
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
String pathOne = expOne.nestedPath(desc);
String pathTwo = expTwo.nestedPath(desc);
if (pathOne == null && pathTwo == null) {
return null;
}
if (pathOne != null && pathOne.equals(pathTwo)) {
return pathOne;
}
if (pathOne != null) {
expOne = new NestedPathWrapperExpression(pathOne, expOne);
}
if (pathTwo != null) {
expTwo = new NestedPathWrapperExpression(pathTwo, expTwo);
}
return null;
}
@Override
public Object getIdEqualTo(String idName) {
// always return null for this expression
return null;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
expOne.containsMany(desc, manyWhereJoin);
@@ -0,0 +1,99 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.event.BeanQueryRequest;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.ManyWhereJoins;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
import com.avaje.ebeaninternal.api.SpiExpressionValidation;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import java.io.IOException;
/**
* Wraps a single expression with nestedPath for document queries.
*/
class NestedPathWrapperExpression implements SpiExpression {
protected final String nestedPath;
protected final SpiExpression delegate;
NestedPathWrapperExpression(String nestedPath, SpiExpression delegate) {
this.nestedPath = nestedPath;
this.delegate = delegate;
}
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
context.startNested(nestedPath);
delegate.writeDocQuery(context);
context.endNested();
}
@Override
public Object getIdEqualTo(String idName) {
// always return null for this expression
return null;
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
return nestedPath;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins whereManyJoins) {
delegate.containsMany(desc, whereManyJoins);
}
@Override
public void prepareExpression(BeanQueryRequest<?> request) {
delegate.prepareExpression(request);
}
@Override
public void queryPlanHash(HashQueryPlanBuilder builder) {
delegate.queryPlanHash(builder);
}
@Override
public int queryBindHash() {
return delegate.queryBindHash();
}
@Override
public boolean isSameByPlan(SpiExpression other) {
if (other instanceof NestedPathWrapperExpression) {
NestedPathWrapperExpression that = (NestedPathWrapperExpression)other;
return nestedPath.equals(that.nestedPath)
&& delegate.isSameByPlan(that.delegate);
}
return false;
}
@Override
public boolean isSameByBind(SpiExpression other) {
return delegate.isSameByBind(other);
}
@Override
public void addSql(SpiExpressionRequest request) {
delegate.addSql(request);
}
@Override
public void addBindValues(SpiExpressionRequest request) {
delegate.addBindValues(request);
}
@Override
public void validate(SpiExpressionValidation validation) {
delegate.validate(validation);
}
@Override
public SpiExpression copyForPlanKey() {
return new NestedPathWrapperExpression(nestedPath, delegate.copyForPlanKey());
}
}
@@ -13,6 +13,12 @@ abstract class NonPrepareExpression implements SpiExpression {
// do nothing
}
@Override
public Object getIdEqualTo(String idName) {
// always null in this expression
return null;
}
@Override
public SpiExpression copyForPlanKey() {
return this;
@@ -26,6 +26,17 @@ class NoopExpression implements SpiExpression {
public void writeDocQuery(DocQueryContext context) throws IOException {
}
@Override
public Object getIdEqualTo(String idName) {
// always return null for this expression
return null;
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
return null;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins whereManyJoins) {
// nothing to do
@@ -29,11 +29,22 @@ final class NotExpression implements SpiExpression {
context.endBool();
}
@Override
public Object getIdEqualTo(String idName) {
// always return null for this expression
return null;
}
@Override
public SpiExpression copyForPlanKey() {
return new NotExpression(exp.copyForPlanKey());
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
return exp.nestedPath(desc);
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
exp.containsMany(desc, manyWhereJoin);
@@ -0,0 +1,163 @@
package com.avaje.ebeaninternal.server.expression;
import com.avaje.ebean.Junction;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Prepare nested path expressions for
*/
class PrepareDocNested {
/**
* Prepare the top level expressions for nested path handling.
*/
static void prepare(DefaultExpressionList<?> expressions, BeanDescriptor<?> beanDescriptor) {
new PrepareDocNested(expressions, beanDescriptor, null).process();
}
/**
* Prepare the Junction expressions for nested path handling.
*/
static void prepare(DefaultExpressionList<?> expressions, BeanDescriptor<?> beanDescriptor, Junction.Type type) {
new PrepareDocNested(expressions, beanDescriptor, type).process();
}
enum Mode {
NONE,
SINGLE,
MIXED
}
private final Junction.Type type;
private final DefaultExpressionList<?> original;
private final BeanDescriptor<?> beanDescriptor;
private final List<SpiExpression> origUnderlying;
private final int origSize;
private boolean hasNesting;
private boolean hasMixedNesting;
private String firstNestedPath;
PrepareDocNested(DefaultExpressionList<?> original, BeanDescriptor<?> beanDescriptor, Junction.Type type) {
this.type = type;
this.beanDescriptor = beanDescriptor;
this.original = original;
this.origUnderlying = original.getUnderlyingList();
this.origSize = origUnderlying.size();
}
void process() {
PrepareDocNested.Mode mode = determineMode();
if (mode == PrepareDocNested.Mode.SINGLE) {
original.setAllDocNested(firstNestedPath);
} else if (mode == PrepareDocNested.Mode.MIXED) {
original.setUnderlying(group());
}
}
/**
* Reorganise the flat list of expressions into a tree grouping expressions by nested path.
*
* Returns the new top level list of expressions.
*/
private List<SpiExpression> group() {
Map<String,Group> groups = new LinkedHashMap<String,Group>();
// organise expressions by nestedPath
for (int i = 0; i < origSize; i++) {
SpiExpression expr = origUnderlying.get(i);
String nestedPath = expr.nestedPath(beanDescriptor);
Group group = groups.get(nestedPath);
if (group == null) {
group = new Group(nestedPath);
groups.put(nestedPath, group);
}
group.list.add(expr);
}
List<SpiExpression> newList = new ArrayList<SpiExpression>();
Collection<Group> values = groups.values();
for (Group group : values) {
group.addTo(newList);
}
return newList;
}
/**
* Determined the nested path mode.
*/
private Mode determineMode() {
if (!hasNesting()) {
// no nested paths at all
return Mode.NONE;
}
if (!hasMixedNesting) {
// single nested path for all expressions
return Mode.SINGLE;
}
// mixed nested paths to underlying expression list needs re-organising by nested path
return Mode.MIXED;
}
/**
* Return true if the expressions have nested paths.
*/
private boolean hasNesting() {
for (int i = 0; i < origSize; i++) {
SpiExpression expr = origUnderlying.get(i);
String nestedPath = expr.nestedPath(beanDescriptor);
if (nestedPath == null) {
hasMixedNesting = true;
} if (nestedPath != null) {
hasNesting = true;
if (firstNestedPath == null) {
firstNestedPath = nestedPath;
} else if (hasMixedNesting || !firstNestedPath.equals(nestedPath)) {
hasMixedNesting = true;
return true;
}
}
}
return hasNesting;
}
/**
* List of SpiExpression grouped by nested path.
*/
class Group {
final String nestedPath;
final List<SpiExpression> list = new ArrayList<SpiExpression>();
Group(String nestedPath) {
this.nestedPath = nestedPath;
}
void addTo(List<SpiExpression> newList) {
if (nestedPath == null) {
newList.addAll(list);
} else {
newList.add(original.wrap(list, nestedPath, type));
}
}
}
}
@@ -25,6 +25,11 @@ class RawExpression extends NonPrepareExpression {
context.writeRaw(sql, values);
}
@Override
public String nestedPath(BeanDescriptor<?> desc) {
return null;
}
@Override
public void containsMany(BeanDescriptor<?> desc, ManyWhereJoins manyWhereJoin) {
@@ -21,6 +21,14 @@ public class SimpleExpression extends AbstractExpression {
this.value = value;
}
@Override
public Object getIdEqualTo(String idName) {
if (type == Op.EQ && idName.equals(propName)) {
return value;
}
return null;
}
@Override
public void writeDocQuery(DocQueryContext context) throws IOException {
if (type == Op.BETWEEN) {
@@ -10,7 +10,7 @@ import java.util.UUID;
*/
public class UuidIdGenerator implements PlatformIdGenerator {
public static UuidIdGenerator INSTANCE = new UuidIdGenerator();
public static final UuidIdGenerator INSTANCE = new UuidIdGenerator();
/**
* Return UUID from UUID.randomUUID();
@@ -24,7 +24,7 @@ public class StringHelper {
String listDelimiter, String nameValueSeparator) {
HashMap<String, String> params = new HashMap<String, String>();
if ((allNameValuePairs == null) || (allNameValuePairs.length() == 0)) {
if ((allNameValuePairs == null) || (allNameValuePairs.isEmpty())) {
return params;
}
// trim off any leading listDelimiter...
@@ -56,7 +56,7 @@ public class StringHelper {
* Return true if the value is null or an empty string.
*/
public static boolean isNull(String value) {
return value == null || value.trim().length() == 0;
return value == null || value.trim().isEmpty();
}
/**
@@ -90,7 +90,7 @@ public class StringHelper {
// there is a key without a value?
String key = allNameValuePairs.substring(pos, delimPos);
key = key.trim();
if (key.length() > 0) {
if (!key.isEmpty()) {
map.put(key, null);
}
return getKeyValue(map, delimPos + 1, allNameValuePairs, listDelimiter,
@@ -33,7 +33,7 @@ public class Binder {
private final int asOfBindCount;
private final boolean bindAsOfWithFromClause;
private final boolean asOfStandardsBased;
private final DbExpressionHandler dbExpressionHandler;
@@ -42,12 +42,12 @@ public class Binder {
/**
* Set the PreparedStatement with which to bind variables to.
*/
public Binder(TypeManager typeManager, int asOfBindCount, boolean bindAsOfWithFromClause,
public Binder(TypeManager typeManager, int asOfBindCount, boolean asOfStandardsBased,
DbExpressionHandler dbExpressionHandler, DataTimeZone dataTimeZone) {
this.typeManager = typeManager;
this.asOfBindCount = asOfBindCount;
this.bindAsOfWithFromClause = bindAsOfWithFromClause;
this.asOfStandardsBased = asOfStandardsBased;
this.dbExpressionHandler = dbExpressionHandler;
this.dataTimeZone = dataTimeZone;
}
@@ -60,12 +60,10 @@ public class Binder {
}
/**
* Return true if the 'as of' predicates are in the from/join clause in which case the timestamp is
* bound early (before all the other predicates ala Oracle). Return false if the 'as of' predicates are
* appended to the end of the predicates and the timestamp is bound last (Postgres, MySql).
* Return true if the 'as of' history support is SQL2011 standards based.
*/
public boolean isBindAsOfWithFromClause() {
return bindAsOfWithFromClause;
public boolean isAsOfStandardsBased() {
return asOfStandardsBased;
}
/**
@@ -567,7 +567,7 @@ public final class DefaultPersister implements Persister {
*/
public int deleteMany(Class<?> beanType, Collection<?> ids, Transaction transaction, boolean permanent) {
if (ids == null || ids.size() == 0) {
if (ids == null || ids.isEmpty()) {
return 0;
}
@@ -139,10 +139,10 @@ public class CQueryBuilder {
if (!sqlTree.isIncludeJoins()) {
// simple - update table set ... where ...
return aliasStrip(buildSql(updateClause, request, predicates, sqlTree).getSql());
return aliasStrip(buildSqlUpdate(updateClause, request, predicates, sqlTree).getSql());
}
// wrap as - update table set ... where id in (select id ...)
String sql = buildSql(null, request, predicates, sqlTree).getSql();
String sql = buildSqlUpdate(null, request, predicates, sqlTree).getSql();
sql = updateClause + " " + request.getBeanDescriptor().getWhereIdInSql() + "in (" + sql + ")";
String alias = (rootTableAlias == null) ? "t0" : rootTableAlias;
sql = aliasReplace(sql, alias);
@@ -406,7 +406,21 @@ public class CQueryBuilder {
return new SqlTreeBuilder(request, predicates, detail, rawNoId).build();
}
/**
* Return the SQL response with row limiting (when not an update statement).
*/
private SqlLimitResponse buildSql(String selectClause, OrmQueryRequest<?> request, CQueryPredicates predicates, SqlTree select) {
return buildSql(selectClause, request, predicates, select, false);
}
/**
* Return the SQL response for update statement (stripping table alias for find by id expression).
*/
private SqlLimitResponse buildSqlUpdate(String selectClause, OrmQueryRequest<?> request, CQueryPredicates predicates, SqlTree select) {
return buildSql(selectClause, request, predicates, select, true);
}
private SqlLimitResponse buildSql(String selectClause, OrmQueryRequest<?> request, CQueryPredicates predicates, SqlTree select, boolean stripAlias) {
SpiQuery<?> query = request.getQuery();
@@ -452,18 +466,20 @@ public class CQueryBuilder {
String inheritanceWhere = select.getInheritanceWhereSql();
boolean hasWhere = false;
if (inheritanceWhere.length() > 0) {
if (!inheritanceWhere.isEmpty()) {
sb.append(" where");
sb.append(inheritanceWhere);
hasWhere = true;
}
int asOfCount = query.getAsOfTableCount();
if (asOfCount > 0 && !historySupport.isStandardsBased()) {
hasWhere = appendWhere(hasWhere, sb);
sb.append(historySupport.getAsOfPredicate(request.getBaseTableAlias()));
}
if (request.isFindById() || query.getId() != null) {
if (hasWhere) {
sb.append(" and ");
} else {
sb.append(" where ");
}
appendWhere(hasWhere, sb);
BeanDescriptor<?> desc = request.getBeanDescriptor();
String idSql = desc.getIdBinderIdSql();
@@ -471,6 +487,10 @@ public class CQueryBuilder {
throw new IllegalStateException("Executing FindById query on entity bean " + desc.getName()
+ " that doesn't have an @Id property??");
}
if (stripAlias) {
// strip the table alias for use in update statement
idSql = StringHelper.replaceString(idSql, "t0.","");
}
sb.append(idSql).append(" ");
hasWhere = true;
}
@@ -497,24 +517,6 @@ public class CQueryBuilder {
sb.append(dbFilterMany);
}
List<String> asOfTableAlias = query.getAsOfTableAlias();
if (asOfTableAlias != null && !historySupport.isBindAtFromClause()) {
// append the effective date predicates for each table alias
// that maps to a @History entity involved in this query
// Do this when history using separate tables/views (PG, MySql etc)
if (!hasWhere) {
sb.append(" where ");
} else {
sb.append("and ");
}
for (int i = 0; i < asOfTableAlias.size(); i++) {
if (i > 0) {
sb.append(" and ");
}
sb.append(historySupport.getAsOfPredicate(asOfTableAlias.get(i)));
}
}
if (!query.isIncludeSoftDeletes()) {
List<String> softDeletePredicates = query.getSoftDeletePredicates();
if (softDeletePredicates != null) {
@@ -547,6 +549,18 @@ public class CQueryBuilder {
}
/**
* Append where or and based on the hasWhere flag.
*/
private boolean appendWhere(boolean hasWhere, StringBuilder sb) {
if (hasWhere) {
sb.append(" and ");
} else {
sb.append(" where ");
}
return true;
}
/**
* Convert the dbOrderBy clause to be safe for adding to select. This is done when 'distinct' is
* used.
@@ -557,7 +571,7 @@ public class CQueryBuilder {
}
private boolean isEmpty(String s) {
return s == null || s.length() == 0;
return s == null || s.isEmpty();
}
}
@@ -134,7 +134,7 @@ public class CQueryBuilderRawSql {
}
private boolean isEmpty(String s) {
return s == null || s.length() == 0;
return s == null || s.isEmpty();
}
private String getOrderBy(CQueryPredicates predicates, RawSql.Sql sql) {
@@ -19,6 +19,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -204,15 +205,16 @@ public class CQueryEngine {
SpiQuery<T> query = request.getQuery();
if (query.isVersionsBetween() && !historySupport.isBindAtFromClause()) {
String sysPeriodLower = getSysPeriodLower(query);
if (query.isVersionsBetween() && !historySupport.isStandardsBased()) {
// just add as normal predicates using the lower bound
query.where().gt(getSysPeriodLower(query), query.getVersionStart());
query.where().lt(getSysPeriodLower(query), query.getVersionEnd());
query.where().gt(sysPeriodLower, query.getVersionStart());
query.where().lt(sysPeriodLower, query.getVersionEnd());
}
// order by id asc, lower sys period desc
query.orderBy().asc(request.getBeanDescriptor().getIdProperty().getName());
query.orderBy().desc(getSysPeriodLower(query));
query.orderBy().desc(sysPeriodLower);
CQuery<T> cquery = queryBuilder.buildQuery(request);
try {
@@ -222,6 +224,9 @@ public class CQueryEngine {
}
List<Version<T>> versions = cquery.readVersions();
// just order in memory rather than use NULLS LAST as that
// is not universally supported, not expect huge list here
Collections.sort(versions, OrderVersionDesc.INSTANCE);
deriveVersionDiffs(versions, request);
if (request.isLogSummary()) {
@@ -31,11 +31,10 @@ public class CQueryHistorySupport {
}
/**
* Return true if the bind of 'as of' timestamp occurs with the from clause
* rather than at the end.
* Return true if the underlying history support is standards based.
*/
public boolean isBindAtFromClause() {
return dbHistorySupport.isBindWithFromClause();
public boolean isStandardsBased() {
return dbHistorySupport.isStandardsBased();
}
/**
@@ -126,7 +126,7 @@ public class CQueryPredicates {
updateProperties.bind(binder, dataBind);
}
if (query.isVersionsBetween() && binder.isBindAsOfWithFromClause()) {
if (query.isVersionsBetween() && binder.isAsOfStandardsBased()) {
// sql2011 based versions between timestamp syntax
Timestamp start = query.getVersionStart();
Timestamp end = query.getVersionEnd();
@@ -136,13 +136,13 @@ public class CQueryPredicates {
dataBind.append(", ");
}
List<String> historyTableAlias = query.getAsOfTableAlias();
if (historyTableAlias != null && binder.isBindAsOfWithFromClause()) {
int asOfTableCount = query.getAsOfTableCount();
if (asOfTableCount > 0) {
// bind the asOf value for each table alias as part of the from/join clauses
// there is one effective date predicate per table alias
Timestamp asOf = query.getAsOf();
dataBind.append("asOf ").append(asOf);
for (int i = 0; i < historyTableAlias.size() * binder.getAsOfBindCount(); i++) {
for (int i = 0; i < asOfTableCount * binder.getAsOfBindCount(); i++) {
binder.bindObject(dataBind, asOf);
}
dataBind.append(", ");
@@ -167,16 +167,6 @@ public class CQueryPredicates {
filterMany.bind(dataBind);
}
if (historyTableAlias != null && !binder.isBindAsOfWithFromClause()) {
// bind the asOf value for each table alias after all the normal predicates
// there is one effective date predicate per table alias
Timestamp asOf = query.getAsOf();
dataBind.append(" asOf ").append(asOf);
for (int i = 0; i < historyTableAlias.size() * binder.getAsOfBindCount(); i++) {
binder.bindObject(dataBind, asOf);
}
}
if (having != null) {
having.bind(dataBind);
}
@@ -305,7 +295,7 @@ public class CQueryPredicates {
}
private boolean isEmpty(String s) {
return s == null || s.length() == 0;
return s == null || s.isEmpty();
}
private String parse(String expr, DeployParser deployParser) {
@@ -106,8 +106,8 @@ public class DefaultDbSqlContext implements DbSqlContext {
tableJoins.add(joinKey);
sb.append(" ");
sb.append(type);
sb.append(" ").append(type);
boolean addAsOfOnClause = false;
if (draftSupport != null) {
appendTable(table, draftSupport.getDraftTable(table));
@@ -117,32 +117,32 @@ public class DefaultDbSqlContext implements DbSqlContext {
} else {
// check if there is an associated history table and if so
// use the unionAll view - we expect an additional predicate to match
appendTable(table, historySupport.getAsOfView(table));
String asOfView = historySupport.getAsOfView(table);
appendTable(table, asOfView);
if (asOfView != null) {
addAsOfOnClause = !historySupport.isStandardsBased();
}
}
sb.append(a2);
sb.append(" on ");
for (int i = 0; i < cols.length; i++) {
TableJoinColumn pair = cols[i];
if (i > 0) {
sb.append(" and ");
}
sb.append(a2);
sb.append(".").append(pair.getForeignDbColumn());
sb.append(a2).append(".").append(pair.getForeignDbColumn());
sb.append(" = ");
sb.append(a1);
sb.append(".").append(pair.getLocalDbColumn());
sb.append(a1).append(".").append(pair.getLocalDbColumn());
}
// add on any inheritance where clause
if (inheritance != null && inheritance.length() > 0) {
sb.append(" and ");
sb.append(a2);
sb.append(".");
sb.append(inheritance);
if (inheritance != null && !inheritance.isEmpty()) {
sb.append(" and ").append(a2).append(".").append(inheritance);
}
if (addAsOfOnClause) {
sb.append(" and ").append(historySupport.getAsOfPredicate(a2));
}
sb.append(" ");
@@ -0,0 +1,29 @@
package com.avaje.ebeaninternal.server.query;
import com.avaje.ebean.Version;
import java.sql.Timestamp;
import java.util.Comparator;
/**
* Compare Version beans in descending order with nulls last.
*/
class OrderVersionDesc implements Comparator<Version<?>> {
static final OrderVersionDesc INSTANCE = new OrderVersionDesc();
@Override
public int compare(Version<?> o1, Version<?> o2) {
Timestamp v1 = o1.getStart();
if (v1 == null) {
return 1;
}
Timestamp v2 = o2.getStart();
if (v2 == null) {
return -1;
}
return v1.compareTo(v2) * -1;
}
}
@@ -1,9 +1,15 @@
package com.avaje.ebeaninternal.server.query;
/**
* Helper for dot notation property paths.
*/
public class SplitName {
private static final char PERIOD = '.';
/**
* Add the two name sections together in dot notation.
*/
public static String add(String prefix, String name) {
if (prefix != null) {
return prefix + "." + name;
@@ -38,10 +44,20 @@ public class SplitName {
}
}
/**
* Return the name split by last.
*/
public static String[] split(String name) {
return split(name, true);
}
/**
* Return the first part of the name.
*/
public static String begin(String name) {
return splitBegin(name)[0];
}
public static String[] splitBegin(String name) {
return split(name, false);
}
@@ -111,7 +111,7 @@ public class SqlTreeBuilder {
this.queryDetail = query.getDetail();
this.predicates = predicates;
this.alias = new SqlTreeAlias(request.getQuery().getAlias() == null ? request.getBeanDescriptor().getBaseTableAlias() : request.getQuery().getAlias());
this.alias = new SqlTreeAlias(request.getBaseTableAlias());
this.ctx = new DefaultDbSqlContext(alias, tableAliasPlaceHolder, columnAliasPrefix, !subQuery, historySupport, draftSupport);
}
@@ -417,7 +417,7 @@ public class SqlTreeBuilder {
// This makes sense for transient properties used to
// hold sum() count() type values (with SqlSelect)
for (String propName : queryProps.getSelectProperties()) {
if (propName.length() > 0) {
if (!propName.isEmpty()) {
addProperty(selectProps, desc, queryProps, propName);
}
}
@@ -81,7 +81,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
* Table alias set if this bean node includes a join to a intersection
* table and that table has history support.
*/
protected String intersectionAsOfTableAlias;
private boolean intersectionAsOfTableAlias;
/**
* Construct for Raw SQL.
@@ -501,11 +501,10 @@ public class SqlTreeNodeBean implements SqlTreeNode {
// if history on this bean type add it's alias
// for each alias we add an effect date predicate
if (desc.isHistorySupport()) {
query.addAsOfTableAlias(baseTableAlias);
query.incrementAsOfTableCount();
}
if (intersectionAsOfTableAlias != null) {
// adds the 'as of' predicate for this intersection table
query.addAsOfTableAlias(intersectionAsOfTableAlias);
if (intersectionAsOfTableAlias) {
query.incrementAsOfTableCount();
}
for (int i = 0; i < children.length; i++) {
children[i].addAsOfTableAlias(query);
@@ -531,7 +530,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
TableJoin manyToManyJoin = manyProp.getIntersectionTableJoin();
manyToManyJoin.addJoin(joinType, parentAlias, alias2, ctx);
if (!manyProp.isExcludedFromHistory()) {
intersectionAsOfTableAlias = alias2;
intersectionAsOfTableAlias = true;
}
return nodeBeanProp.addJoin(joinType, alias2, alias, ctx);
@@ -144,10 +144,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
private DefaultExpressionList<T> havingExpressions;
/**
* The list of table alias associated with @History entity beans.
*/
private List<String> asOfTableAlias;
private int asOfTableCount;
/**
* Set for flashback style 'as of' query.
@@ -236,6 +233,16 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return beanDescriptor;
}
@Override
public void checkIdEqualTo() {
if (id == null && whereExpressions != null) {
id = whereExpressions.idEqualTo(beanDescriptor.getIdName());
if (id != null) {
whereExpressions = null;
}
}
}
@Override
public boolean isAutoTunable() {
return beanDescriptor.isAutoTunable();
@@ -271,21 +278,14 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
return softDeletePredicates;
}
/**
* This table alias is for a @History entity involved in the query and as
* such we need to add a 'as of predicate' to the query using this alias.
*/
@Override
public void addAsOfTableAlias(String tableAlias) {
if (asOfTableAlias == null) {
asOfTableAlias = new ArrayList<String>();
}
asOfTableAlias.add(tableAlias);
public void incrementAsOfTableCount() {
asOfTableCount++;
}
@Override
public List<String> getAsOfTableAlias() {
return asOfTableAlias;
public int getAsOfTableCount() {
return asOfTableCount;
}
@Override
@@ -484,6 +484,16 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
}
}
@Override
public void prepareDocNested() {
if (textExpressions != null) {
textExpressions.prepareDocNested(beanDescriptor);
}
if (whereExpressions != null) {
whereExpressions.prepareDocNested(beanDescriptor);
}
}
/**
* Setup to be a delete query.
*/
@@ -522,7 +532,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
List<SpiExpression> exprList = whereExpressions.internalList();
if (exprList.size() > 1) {
return null;
} else if (exprList.size() == 0) {
} else if (exprList.isEmpty()) {
return namedBind;
} else {
if (namedBind != null) {
@@ -1151,7 +1161,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
@Override
public DefaultOrmQuery<T> order(String orderByClause) {
if (orderByClause == null || orderByClause.trim().length() == 0) {
if (orderByClause == null || orderByClause.trim().isEmpty()) {
this.orderBy = null;
} else {
this.orderBy = new OrderBy<T>(this, orderByClause);
@@ -198,7 +198,7 @@ public class OrmQueryDetail implements Serializable {
}
}
if (matchingPaths.size() == 0) {
if (matchingPaths.isEmpty()) {
return null;
}
@@ -134,7 +134,7 @@ public class OrmQueryDetailParser {
}
}
String whereClause = sb.toString().trim();
if (whereClause.length() > 0) {
if (!whereClause.isEmpty()) {
rawWhereClause = whereClause;
}
@@ -236,7 +236,7 @@ public class OrmQueryProperties implements Serializable {
@SuppressWarnings("unchecked")
public void configureBeanQuery(SpiQuery<?> query) {
if (trimmedProperties != null && trimmedProperties.length() > 0) {
if (trimmedProperties != null && !trimmedProperties.isEmpty()) {
query.select(trimmedProperties);
}
@@ -122,7 +122,7 @@ public class OrmQueryPropertiesParser {
String temp;
for (int i = 0; i < res.length; i++) {
temp = res[i].trim();
if (temp.length() > 0) {
if (!temp.isEmpty()) {
if (count > 0) {
sb.append(",");
}
@@ -268,7 +268,7 @@ public class TCsvReader<T> implements CsvReader<T> {
strValue = strValue.trim();
if (strValue.length() == 0) {
if (strValue.isEmpty()) {
return;
}
@@ -4,6 +4,7 @@ import com.avaje.ebean.TransactionCallback;
import com.avaje.ebean.annotation.DocStoreMode;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebean.config.PersistBatch;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.DatabasePlatform.OnQueryOnly;
import com.avaje.ebean.event.changelog.BeanChange;
import com.avaje.ebean.event.changelog.ChangeSet;
@@ -151,6 +152,16 @@ public class JdbcTransaction implements SpiTransaction {
protected int docStoreBatchSize;
/**
* Explicit control over skipCache.
*/
protected Boolean skipCache;
/**
* Default skip cache behavior from {@link ServerConfig#isSkipCacheAfterWrite()}.
*/
protected final boolean skipCacheAfterWrite;
/**
* Create a new JdbcTransaction.
*/
@@ -162,11 +173,20 @@ public class JdbcTransaction implements SpiTransaction {
this.explicit = explicit;
this.manager = manager;
this.connection = connection;
this.batchMode = manager == null ? PersistBatch.NONE : manager.getPersistBatch();
this.batchOnCascadeMode = manager == null ? PersistBatch.NONE : manager.getPersistBatchOnCascade();
this.onQueryOnly = manager == null ? OnQueryOnly.ROLLBACK : manager.getOnQueryOnly();
this.persistenceContext = new DefaultPersistenceContext();
if (manager == null) {
this.skipCacheAfterWrite = true;
this.batchMode = PersistBatch.NONE;
this.batchOnCascadeMode = PersistBatch.NONE;
this.onQueryOnly = OnQueryOnly.ROLLBACK;
} else {
this.skipCacheAfterWrite = manager.isSkipCacheAfterWrite();
this.batchMode = manager.getPersistBatch();
this.batchOnCascadeMode = manager.getPersistBatchOnCascade();
this.onQueryOnly = manager.getOnQueryOnly();
}
checkAutoCommit(connection);
} catch (Exception e) {
@@ -197,6 +217,17 @@ public class JdbcTransaction implements SpiTransaction {
return sb.toString();
}
@Override
public boolean isSkipCache() {
if (skipCache != null) return skipCache;
return skipCacheAfterWrite && !queryOnly;
}
@Override
public void setSkipCache(boolean skipCache) {
this.skipCache = skipCache;
}
@Override
public String getLogPrefix() {
return logPrefix;
@@ -109,12 +109,15 @@ public class TransactionManager {
protected final boolean viewInvalidation;
private final boolean skipCacheAfterWrite;
/**
* Create the TransactionManager
*/
public TransactionManager(boolean localL2Caching, ServerConfig config, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor,
DocStoreUpdateProcessor docStoreUpdateProcessor, BeanDescriptorManager descMgr, BootupClasses bootupClasses) {
this.skipCacheAfterWrite = config.isSkipCacheAfterWrite();
this.localL2Caching = localL2Caching;
this.persistBatch = config.getPersistBatch();
this.persistBatchOnCascade = config.appliedPersistBatchOnCascade();
@@ -149,6 +152,10 @@ public class TransactionManager {
return docStoreActive;
}
public boolean isSkipCacheAfterWrite() {
return skipCacheAfterWrite;
}
public BeanDescriptorManager getBeanDescriptorManager() {
return beanDescriptorManager;
}
@@ -35,7 +35,7 @@ public class ScalarTypeChar extends ScalarTypeBaseVarchar<Character> {
public Character read(DataReader dataReader) throws SQLException {
String string = dataReader.getString();
if (string == null || string.length() == 0) {
if (string == null || string.isEmpty()) {
return null;
} else {
return string.charAt(0);
@@ -86,7 +86,7 @@ public class BindParamsParser {
if (params.isSameBindHash()) {
String preparedSql = params.getPreparedSql();
if (preparedSql != null && preparedSql.length() > 0) {
if (preparedSql != null && !preparedSql.isEmpty()) {
// the sql has already been parsed and positionedParameters are set in order
return preparedSql;
}

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