mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65ba231fc0 | ||
|
|
1da2382e45 | ||
|
|
a86af94a8c | ||
|
|
8301cb634e | ||
|
|
721654d033 | ||
|
|
fe1817ef02 | ||
|
|
fc996659f2 | ||
|
|
368d22baa6 | ||
|
|
daf3d97266 | ||
|
|
f2179fca2d | ||
|
|
2c436c3af5 | ||
|
|
8d334ff2e8 | ||
|
|
f3e4696498 | ||
|
|
221260fa44 | ||
|
|
f8e7a79e9a | ||
|
|
b66f18bfd6 | ||
|
|
ac6708e0d0 | ||
|
|
a5f46c095d |
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>10.4.6</version>
|
||||
<version>11.1.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-10.4.6</tag>
|
||||
<tag>ebean-11.1.1</tag>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
@@ -87,7 +87,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>2.4</version>
|
||||
<version>3.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -117,7 +117,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>10.2.1</version>
|
||||
<version>10.3.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -210,7 +210,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-agent</artifactId>
|
||||
<version>10.4.1</version>
|
||||
<version>11.1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -283,7 +283,7 @@
|
||||
<plugin>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>10.4.1</version>
|
||||
<version>11.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.annotation.TxIsolation;
|
||||
import io.ebean.cache.ServerCacheManager;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.text.csv.CsvReader;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.annotation.TxIsolation;
|
||||
import io.ebean.cache.ServerCacheManager;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.meta.MetaInfoManager;
|
||||
@@ -561,8 +562,8 @@ public interface EbeanServer {
|
||||
* Start a transaction typically specifying REQUIRES_NEW or REQUIRED semantics.
|
||||
* <p>
|
||||
* <p>
|
||||
* Note that this provides an try finally alternative to using {@link #execute(TxScope, TxCallable)} or
|
||||
* {@link #execute(TxScope, TxRunnable)}.
|
||||
* Note that this provides an try finally alternative to using {@link #executeCall(TxScope, Callable)} or
|
||||
* {@link #execute(TxScope, Runnable)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* <h3>REQUIRES_NEW example:</h3>
|
||||
@@ -1668,10 +1669,12 @@ public interface EbeanServer {
|
||||
* Deprecated - please migrate to executeCall().
|
||||
*/
|
||||
@Deprecated
|
||||
<T> T execute(TxScope scope, TxCallable<T> callable);
|
||||
default <T> T execute(TxScope scope, TxCallable<T> callable) {
|
||||
return executeCall(scope, callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a Callable in a Transaction with the default scope.
|
||||
* Execute a TxCallable in a Transaction with the default scope.
|
||||
* <p>
|
||||
* The default scope runs with REQUIRED and by default will rollback on any
|
||||
* exception (checked or runtime).
|
||||
@@ -1702,7 +1705,9 @@ public interface EbeanServer {
|
||||
* Deprecated - please migrate to executeCall().
|
||||
*/
|
||||
@Deprecated
|
||||
<T> T execute(TxCallable<T> callable);
|
||||
default <T> T execute(TxCallable<T> callable) {
|
||||
return executeCall(null, callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the manager of the server cache ("L2" cache).
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.config.DocStoreConfig;
|
||||
import io.ebean.config.ServerConfig;
|
||||
|
||||
|
||||
@@ -46,5 +46,6 @@ public interface TxCallable<T> extends Callable<T> {
|
||||
* instead.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
T call();
|
||||
}
|
||||
|
||||
@@ -37,5 +37,6 @@ public interface TxRunnable extends Runnable {
|
||||
/**
|
||||
* Run the method in a transaction sope.
|
||||
*/
|
||||
@Override
|
||||
void run();
|
||||
}
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.TxIsolation;
|
||||
import io.ebean.annotation.TxType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* Holds the definition of how a transactional method should run.
|
||||
* <p>
|
||||
* This information matches the features of the Transactional annotation. You
|
||||
* can use it directly with TxRunnable or TxCallable via
|
||||
* {@link Ebean#execute(TxScope, TxCallable)} or
|
||||
* {@link Ebean#execute(TxScope, TxRunnable)}.
|
||||
* can use it directly with Runnable or Callable via
|
||||
* {@link Ebean#execute(TxScope, Runnable)} or
|
||||
* {@link Ebean#executeCall(TxScope, Callable)}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This object is used internally with the enhancement of a method with
|
||||
* Transactional annotation.
|
||||
* </p>
|
||||
*
|
||||
* @see TxCallable
|
||||
* @see TxRunnable
|
||||
* @see Ebean#execute(TxScope, TxCallable)
|
||||
* @see Ebean#execute(TxScope, TxRunnable)
|
||||
* @see Ebean#execute(TxScope, Runnable)
|
||||
* @see Ebean#executeCall(TxScope, Callable)
|
||||
*/
|
||||
public final class TxScope {
|
||||
|
||||
@@ -38,6 +41,11 @@ public final class TxScope {
|
||||
|
||||
boolean readOnly;
|
||||
|
||||
/**
|
||||
* Set this to false if the JDBC batch should not be automatically be flushed when a query is executed.
|
||||
*/
|
||||
boolean flushOnQuery = true;
|
||||
|
||||
ArrayList<Class<? extends Throwable>> rollbackFor;
|
||||
|
||||
ArrayList<Class<? extends Throwable>> noRollbackFor;
|
||||
@@ -235,6 +243,21 @@ public final class TxScope {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return false if the JDBC batch buffer should not be flushed automatically when a query is executed.
|
||||
*/
|
||||
public boolean isFlushOnQuery() {
|
||||
return flushOnQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set flushOnQuery to be false to stop automatically flushing the JDBC batch buffer when a query is executed.
|
||||
*/
|
||||
public TxScope setFlushOnQuery(boolean flushOnQuery) {
|
||||
this.flushOnQuery = flushOnQuery;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Isolation level this transaction should run with.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
/**
|
||||
* Visitor for collecting new/old values for a bean update.
|
||||
*/
|
||||
public interface BeanDiffVisitor {
|
||||
|
||||
/**
|
||||
* Collect a new/old value pair.
|
||||
*/
|
||||
void visit(int position, Object newVal, Object oldVal);
|
||||
|
||||
/**
|
||||
* Start processing an associated bean.
|
||||
*/
|
||||
void visitPush(int position);
|
||||
|
||||
/**
|
||||
* Stop processing an associated bean.
|
||||
*/
|
||||
void visitPop();
|
||||
}
|
||||
@@ -507,6 +507,15 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
loadedProps[propertyIndex] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all properties to be loaded (post insert).
|
||||
*/
|
||||
public void setLoadedPropertyAll() {
|
||||
for (int i = 0; i < loadedProps.length; i++) {
|
||||
loadedProps[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the property is loaded.
|
||||
*/
|
||||
@@ -694,6 +703,28 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively add dirty properties.
|
||||
*/
|
||||
public void addDirtyPropertyValues(BeanDiffVisitor visitor) {
|
||||
int len = getPropertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (changedProps != null && changedProps[i]) {
|
||||
// the property has been changed on this bean
|
||||
Object newVal = owner._ebean_getField(i);
|
||||
Object oldVal = getOrigValue(i);
|
||||
visitor.visit(i, newVal, oldVal);
|
||||
|
||||
} else if (embeddedDirty != null && embeddedDirty[i]) {
|
||||
// an embedded property has been changed - recurse
|
||||
EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i);
|
||||
visitor.visitPush(i);
|
||||
embeddedBean._ebean_getIntercept().addDirtyPropertyValues(visitor);
|
||||
visitor.visitPop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a dirty property hash taking into account embedded beans.
|
||||
*/
|
||||
@@ -1124,4 +1155,11 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
return (pcs == null) ? null : new PropertyChangeEvent(owner, getProperty(propertyIndex), oldValue, newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly set an old value.
|
||||
*/
|
||||
public void setOldValue(int propertyIndex,Object oldValue) {
|
||||
setChangedPropertyValue(propertyIndex, true, oldValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
|
||||
/**
|
||||
* Custom mappings for DB types that override the default.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.migration.MigrationConfig;
|
||||
import io.ebean.migration.MigrationRunner;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@@ -2,7 +2,7 @@ package io.ebean.config;
|
||||
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -2,9 +2,9 @@ package io.ebean.config;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import io.ebean.EbeanServerFactory;
|
||||
import io.ebean.PersistBatch;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.PersistenceContextScope;
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.annotation.Encrypted;
|
||||
@@ -439,6 +439,16 @@ public class ServerConfig {
|
||||
*/
|
||||
private boolean disableL2Cache;
|
||||
|
||||
/**
|
||||
* The time in millis used to determine when a query is alerted for being slow.
|
||||
*/
|
||||
private long slowQueryMillis;
|
||||
|
||||
/**
|
||||
* The listener for processing slow query events.
|
||||
*/
|
||||
private SlowQueryListener slowQueryListener;
|
||||
|
||||
/**
|
||||
* Construct a Server Configuration for programmatically creating an EbeanServer.
|
||||
*/
|
||||
@@ -446,6 +456,34 @@ public class ServerConfig {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the slow query time in millis.
|
||||
*/
|
||||
public long getSlowQueryMillis() {
|
||||
return slowQueryMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the slow query time in millis.
|
||||
*/
|
||||
public void setSlowQueryMillis(long slowQueryMillis) {
|
||||
this.slowQueryMillis = slowQueryMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the slow query event listener.
|
||||
*/
|
||||
public SlowQueryListener getSlowQueryListener() {
|
||||
return slowQueryListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the slow query event listener.
|
||||
*/
|
||||
public void setSlowQueryListener(SlowQueryListener slowQueryListener) {
|
||||
this.slowQueryListener = slowQueryListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a service object into configuration such that it can be passed to a plugin.
|
||||
* <p>
|
||||
@@ -2534,6 +2572,7 @@ public class ServerConfig {
|
||||
dbTypeConfig.setGeometrySRID(srid);
|
||||
}
|
||||
|
||||
slowQueryMillis = p.getLong("slowQueryMillis", slowQueryMillis);
|
||||
docStoreOnly = p.getBoolean("docStoreOnly", docStoreOnly);
|
||||
disableL2Cache = p.getBoolean("disableL2Cache", disableL2Cache);
|
||||
explicitTransactionBeginMode = p.getBoolean("explicitTransactionBeginMode", explicitTransactionBeginMode);
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
|
||||
/**
|
||||
* Slow query event.
|
||||
*/
|
||||
public class SlowQueryEvent {
|
||||
|
||||
private final String sql;
|
||||
|
||||
private final long timeMillis;
|
||||
|
||||
private final int rowCount;
|
||||
|
||||
private final ObjectGraphNode originNode;
|
||||
|
||||
/**
|
||||
* Construct with the SQL and execution time in millis.
|
||||
*/
|
||||
public SlowQueryEvent(String sql, long timeMillis, int rowCount, ObjectGraphNode originNode) {
|
||||
this.sql = sql;
|
||||
this.timeMillis = timeMillis;
|
||||
this.rowCount = rowCount;
|
||||
this.originNode = originNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL for the slow query.
|
||||
*/
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the execution time in millis.
|
||||
*/
|
||||
public long getTimeMillis() {
|
||||
return timeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total row count associated with the query.
|
||||
*/
|
||||
public int getRowCount() {
|
||||
return rowCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the origin point for the root query.
|
||||
* <p>
|
||||
* Typically the <code>originNode.getOriginQueryPoint().getFirstStackElement()</code> provides the stack line that
|
||||
* shows the code that invoked the query.
|
||||
* </p>
|
||||
*/
|
||||
public ObjectGraphNode getOriginNode() {
|
||||
return originNode;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package io.ebean.config;
|
||||
|
||||
/**
|
||||
* Listener for slow query events.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SlowQueryListener {
|
||||
|
||||
/**
|
||||
* Process a slow query event.
|
||||
*/
|
||||
void process(SlowQueryEvent event);
|
||||
}
|
||||
@@ -4,8 +4,8 @@ import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.config.CustomDbTypeMapping;
|
||||
import io.ebean.config.DbTypeConfig;
|
||||
import io.ebean.PersistBatch;
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.dbmigration.ddlgeneration.DdlHandler;
|
||||
import io.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.ebean.config.dbplatform.db2;
|
||||
|
||||
import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.PersistBatch;
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
@@ -44,7 +44,7 @@ public class DB2Platform extends DatabasePlatform {
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("bigint", false));
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("real"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("decimal", 15));
|
||||
|
||||
|
||||
persistBatchOnCascade = PersistBatch.NONE;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.config.dbplatform.h2;
|
||||
|
||||
import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.config.dbplatform.hsqldb;
|
||||
|
||||
import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.config.dbplatform.mysql;
|
||||
|
||||
import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.config.dbplatform.oracle;
|
||||
|
||||
import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.config.dbplatform.BasicSqlAnsiLimiter;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.config.dbplatform.postgres;
|
||||
|
||||
import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.Query;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebean.config.dbplatform.sqlanywhere;
|
||||
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebean.config.dbplatform.sqlite;
|
||||
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebean.config.dbplatform.sqlserver;
|
||||
|
||||
import io.ebean.PersistBatch;
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbPlatformType;
|
||||
import io.ebean.config.dbplatform.DbType;
|
||||
|
||||
@@ -4,7 +4,7 @@ import io.ebean.Ebean;
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.config.DbConstraintNaming;
|
||||
import io.ebean.config.DbMigrationConfig;
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.db2.DB2Platform;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
@@ -539,7 +539,7 @@ public class DbMigration {
|
||||
return new SQLitePlatform();
|
||||
case GENERIC:
|
||||
return new DatabasePlatform();
|
||||
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Platform missing? " + platform);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebean.dbmigration;
|
||||
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import io.ebean.config.DbConstraintNaming;
|
||||
import io.ebean.config.NamingConvention;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.DbHistorySupport;
|
||||
import io.ebean.config.dbplatform.DbIdentity;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebean.dbmigration.ddlgeneration.DdlWrite;
|
||||
|
||||
@@ -17,6 +17,7 @@ public class DB2Ddl extends PlatformDdl {
|
||||
this.inlineUniqueWhenNullable = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterTableAddUniqueConstraint(String tableName, String uqName, String[] columns, boolean notNull) {
|
||||
if (notNull) {
|
||||
return super.alterTableAddUniqueConstraint(tableName, uqName, columns, true);
|
||||
|
||||
@@ -82,6 +82,7 @@ public class SqlServerDdl extends PlatformDdl {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String alterTableDropConstraint(String tableName, String constraintName) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("IF (OBJECT_ID('").append(constraintName).append("', 'C') IS NOT NULL) ");
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import io.ebean.config.DbConstraintNaming;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.dbmigration.ddlgeneration.DdlBuffer;
|
||||
import io.ebean.dbmigration.ddlgeneration.DdlWrite;
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
package io.ebean.event.changelog;
|
||||
|
||||
import io.ebean.ValuePair;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A bean insert, update or delete change sent as part of a ChangeSet.
|
||||
*/
|
||||
@@ -12,68 +8,68 @@ public class BeanChange {
|
||||
/**
|
||||
* The underling base table name.
|
||||
*/
|
||||
String table;
|
||||
private final String type;
|
||||
|
||||
/**
|
||||
* The tenantId value.
|
||||
*/
|
||||
Object tenantId;
|
||||
|
||||
private final Object tenantId;
|
||||
|
||||
/**
|
||||
* The id value.
|
||||
*/
|
||||
Object id;
|
||||
private final Object id;
|
||||
|
||||
/**
|
||||
* The INSERT, UPDATE or DELETE change type.
|
||||
*/
|
||||
ChangeType type;
|
||||
private final ChangeType event;
|
||||
|
||||
/**
|
||||
* The time the bean change was created.
|
||||
*/
|
||||
long eventTime;
|
||||
private final long eventTime;
|
||||
|
||||
/**
|
||||
* The values for insert or update. Note that null values are not included for insert.
|
||||
* The change in JSON form.
|
||||
*/
|
||||
Map<String, ValuePair> values;
|
||||
private final String data;
|
||||
|
||||
/**
|
||||
* Construct with all the details.
|
||||
* The change in JSON form.
|
||||
*/
|
||||
public BeanChange(String table, Object tenantId, Object id, ChangeType type, Map<String, ValuePair> values) {
|
||||
this.table = table;
|
||||
private final String oldData;
|
||||
|
||||
/**
|
||||
* Construct with change as JSON.
|
||||
*/
|
||||
public BeanChange(String type, Object tenantId, Object id, ChangeType event, String data, String oldData) {
|
||||
this.type = type;
|
||||
this.tenantId = tenantId;
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.event = event;
|
||||
this.eventTime = System.currentTimeMillis();
|
||||
this.values = values;
|
||||
this.data = data;
|
||||
this.oldData = oldData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor for JSON tools.
|
||||
* Construct with change as JSON.
|
||||
*/
|
||||
public BeanChange() {
|
||||
public BeanChange(String table, Object tenantId, Object id, ChangeType event, String data) {
|
||||
this(table, tenantId , id , event , data , null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "table:" + table + " tenantId: " + tenantId + " id:" + id + " values:" + values;
|
||||
return "type:" + type + " tenantId: " + tenantId + " id:" + id + " data:" + data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the object type (typically table name).
|
||||
*/
|
||||
public String getTable() {
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object type (for JSON tools).
|
||||
*/
|
||||
public void setTable(String table) {
|
||||
this.table = table;
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,13 +79,6 @@ public class BeanChange {
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean id (for JSON tools).
|
||||
*/
|
||||
public void setTenantId(Object tenantId) {
|
||||
this.tenantId = tenantId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the object id.
|
||||
*/
|
||||
@@ -97,25 +86,11 @@ public class BeanChange {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bean id (for JSON tools).
|
||||
*/
|
||||
public void setId(Object id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the change type (INSERT, UPDATE or DELETE).
|
||||
*/
|
||||
public ChangeType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type (for JSON tools).
|
||||
*/
|
||||
public void setType(ChangeType type) {
|
||||
this.type = type;
|
||||
public ChangeType getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,23 +101,16 @@ public class BeanChange {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the event time in epoch millis.
|
||||
* Return the change data in JSON form.
|
||||
*/
|
||||
public void setEventTime(long eventTime) {
|
||||
this.eventTime = eventTime;
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value pairs. For inserts the ValuePair oldValue is always null.
|
||||
* Return the old data in JSON form.
|
||||
*/
|
||||
public Map<String, ValuePair> getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value pairs (for JSON tools).
|
||||
*/
|
||||
public void setValues(Map<String, ValuePair> values) {
|
||||
this.values = values;
|
||||
public String getOldData() {
|
||||
return oldData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ public class EJson {
|
||||
/**
|
||||
* Parse the json and return as a modify aware List.
|
||||
*/
|
||||
public static List<Object> parseList(String json, boolean modifyAware) throws IOException {
|
||||
public static <T> List<T> parseList(String json, boolean modifyAware) throws IOException {
|
||||
return EJsonReader.parseList(json, modifyAware);
|
||||
}
|
||||
|
||||
@@ -125,8 +125,8 @@ public class EJson {
|
||||
* Parse the json returning as a List taking into account the current token.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<Object> parseList(JsonParser parser, JsonToken currentToken) throws IOException {
|
||||
return (List<Object>) EJsonReader.parse(parser, currentToken, false);
|
||||
public static <T> List<T> parseList(JsonParser parser, JsonToken currentToken) throws IOException {
|
||||
return (List<T>) EJsonReader.parse(parser, currentToken, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,23 +153,23 @@ public class EJson {
|
||||
/**
|
||||
* Parse the json returning a Set that might be modify aware.
|
||||
*/
|
||||
public static Set parseSet(String json, boolean modifyAware) throws IOException {
|
||||
List<Object> list = parseList(json, modifyAware);
|
||||
public static <T> Set<T> parseSet(String json, boolean modifyAware) throws IOException {
|
||||
List<T> list = parseList(json, modifyAware);
|
||||
if (list == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (modifyAware) {
|
||||
return ((ModifyAwareList) list).asSet();
|
||||
return ((ModifyAwareList<T>) list).asSet();
|
||||
} else {
|
||||
return new LinkedHashSet<>(list);
|
||||
return new LinkedHashSet<T>(list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the json returning as a Set taking into account the current token.
|
||||
*/
|
||||
public static Set<Object> parseSet(JsonParser parser, JsonToken currentToken) throws IOException {
|
||||
return new LinkedHashSet<>(parseList(parser, currentToken));
|
||||
public static <T> Set<T> parseSet(JsonParser parser, JsonToken currentToken) throws IOException {
|
||||
return new LinkedHashSet<T>(parseList(parser, currentToken));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,8 +52,8 @@ class EJsonReader {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static List<Object> parseList(String json, boolean modifyAware) throws IOException {
|
||||
return (List<Object>) parse(json, modifyAware);
|
||||
static <T> List<T> parseList(String json, boolean modifyAware) throws IOException {
|
||||
return (List<T>) parse(json, modifyAware);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.TxScope;
|
||||
import io.ebean.PersistBatch;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -53,6 +53,8 @@ public class ScopeTrans implements Thread.UncaughtExceptionHandler {
|
||||
|
||||
private Boolean restoreBatchGeneratedKeys;
|
||||
|
||||
private boolean restoreBatchFlushOnQuery;
|
||||
|
||||
/**
|
||||
* Flag set when a rollback has occurred.
|
||||
*/
|
||||
@@ -77,10 +79,14 @@ public class ScopeTrans implements Thread.UncaughtExceptionHandler {
|
||||
restoreBatchOnCascade = transaction.getBatchOnCascade();
|
||||
restoreBatchSize = transaction.getBatchSize();
|
||||
restoreBatchGeneratedKeys = transaction.getBatchGetGeneratedKeys();
|
||||
restoreBatchFlushOnQuery = transaction.isBatchFlushOnQuery();
|
||||
}
|
||||
if (txScope.isBatchSet()) {
|
||||
transaction.setBatch(txScope.getBatch());
|
||||
}
|
||||
if (!txScope.isFlushOnQuery()) {
|
||||
transaction.setBatchFlushOnQuery(false);
|
||||
}
|
||||
if (txScope.isBatchOnCascadeSet()) {
|
||||
transaction.setBatchOnCascade(txScope.getBatchOnCascade());
|
||||
}
|
||||
@@ -158,6 +164,7 @@ public class ScopeTrans implements Thread.UncaughtExceptionHandler {
|
||||
if (created) {
|
||||
transaction.commit();
|
||||
} else {
|
||||
transaction.setBatchFlushOnQuery(restoreBatchFlushOnQuery);
|
||||
if (restoreBatch != null) {
|
||||
transaction.setBatch(restoreBatch);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import io.ebean.PersistBatch;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.TransactionCallback;
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
|
||||
@@ -25,6 +25,11 @@ import java.util.List;
|
||||
*/
|
||||
public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionLoader {
|
||||
|
||||
/**
|
||||
* Return the server extended Json context.
|
||||
*/
|
||||
SpiJsonContext jsonExtended();
|
||||
|
||||
/**
|
||||
* For internal use, shutdown of the server invoked by JVM Shutdown.
|
||||
*/
|
||||
@@ -200,4 +205,9 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
|
||||
* Return the DataTimeZone to use when reading/writing timestamps via JDBC.
|
||||
*/
|
||||
DataTimeZone getDataTimeZone();
|
||||
|
||||
/**
|
||||
* Check for slow query event.
|
||||
*/
|
||||
void slowQueryCheck(long executionTimeMicros, int rowCount, SpiQuery<?> query);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package io.ebeaninternal.api;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import io.ebean.text.json.JsonContext;
|
||||
import io.ebean.text.json.JsonWriteOptions;
|
||||
import io.ebeaninternal.server.text.json.SpiJsonWriter;
|
||||
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* Extended Json Context for internal server use.
|
||||
*/
|
||||
public interface SpiJsonContext extends JsonContext {
|
||||
|
||||
/**
|
||||
* Create a Json Writer for writing beans as JSON.
|
||||
*/
|
||||
SpiJsonWriter createJsonWriter(JsonGenerator gen, JsonWriteOptions options);
|
||||
|
||||
/**
|
||||
* Create a Json Writer for writing beans as JSON supplying a writer.
|
||||
*/
|
||||
SpiJsonWriter createJsonWriter(Writer writer);
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.ebeaninternal.extraddl.model;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package io.ebeaninternal.server.changelog;
|
||||
|
||||
import io.ebean.ValuePair;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import io.ebean.event.changelog.BeanChange;
|
||||
import io.ebean.event.changelog.ChangeSet;
|
||||
import io.ebean.event.changelog.ChangeType;
|
||||
import io.ebean.text.json.JsonContext;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
@@ -15,25 +14,23 @@ import java.util.Map;
|
||||
/**
|
||||
* Builds JSON document for a bean change.
|
||||
*/
|
||||
public class ChangeJsonBuilder {
|
||||
class ChangeJsonBuilder {
|
||||
|
||||
protected final JsonFactory jsonFactory = new JsonFactory();
|
||||
|
||||
protected final JsonContext json;
|
||||
|
||||
protected ChangeJsonBuilder(JsonContext json) {
|
||||
ChangeJsonBuilder(JsonContext json) {
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the bean change as JSON.
|
||||
*/
|
||||
public void writeBeanJson(Writer writer, BeanChange bean, ChangeSet changeSet, int position) throws IOException {
|
||||
void writeBeanJson(Writer writer, BeanChange bean, ChangeSet changeSet) throws IOException {
|
||||
|
||||
try (JsonGenerator generator = jsonFactory.createGenerator(writer)) {
|
||||
|
||||
writeBeanChange(generator, bean, changeSet, position);
|
||||
|
||||
writeBeanChange(generator, bean, changeSet);
|
||||
generator.flush();
|
||||
}
|
||||
}
|
||||
@@ -41,34 +38,29 @@ public class ChangeJsonBuilder {
|
||||
/**
|
||||
* Write the bean change as JSON document containing the transaction header details.
|
||||
*/
|
||||
protected void writeBeanChange(JsonGenerator gen, BeanChange bean, ChangeSet changeSet, int position) throws IOException {
|
||||
private void writeBeanChange(JsonGenerator gen, BeanChange bean, ChangeSet changeSet) throws IOException {
|
||||
|
||||
gen.writeStartObject();
|
||||
|
||||
writeBeanTransactionDetails(gen, changeSet, position);
|
||||
|
||||
gen.writeStringField("object", bean.getTable());
|
||||
gen.writeNumberField("ts", bean.getEventTime());
|
||||
gen.writeStringField("change", bean.getEvent().getCode());
|
||||
gen.writeStringField("type", bean.getType());
|
||||
gen.writeStringField("id", bean.getId().toString());
|
||||
if (bean.getTenantId() != null) {
|
||||
gen.writeStringField("tenantId", bean.getTenantId().toString());
|
||||
}
|
||||
gen.writeStringField("objectId", bean.getId().toString());
|
||||
gen.writeStringField("change", bean.getType().getCode());
|
||||
gen.writeNumberField("eventTime", bean.getEventTime());
|
||||
|
||||
writeBeanTransactionDetails(gen, changeSet);
|
||||
|
||||
writeBeanValues(gen, bean);
|
||||
|
||||
gen.writeEndObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Denormalise by writing the transaction header details.
|
||||
*/
|
||||
protected void writeBeanTransactionDetails(JsonGenerator gen, ChangeSet changeSet, int position) throws IOException {
|
||||
private void writeBeanTransactionDetails(JsonGenerator gen, ChangeSet changeSet) throws IOException {
|
||||
|
||||
gen.writeStringField("txnId", changeSet.getTxnId());
|
||||
gen.writeStringField("txnState", changeSet.getTxnState().getCode());
|
||||
gen.writeNumberField("txnBatch", changeSet.getTxnBatch());
|
||||
gen.writeNumberField("txnPosition", position);
|
||||
String source = changeSet.getSource();
|
||||
if (source != null) {
|
||||
gen.writeStringField("source", source);
|
||||
@@ -94,39 +86,18 @@ public class ChangeJsonBuilder {
|
||||
/**
|
||||
* For insert and update write the new/old values.
|
||||
*/
|
||||
protected void writeBeanValues(JsonGenerator gen, BeanChange bean) throws IOException {
|
||||
private void writeBeanValues(JsonGenerator gen, BeanChange bean) throws IOException {
|
||||
|
||||
if (bean.getType() != ChangeType.DELETE) {
|
||||
gen.writeFieldName("values");
|
||||
gen.writeStartObject();
|
||||
writeValuePairs(bean, gen);
|
||||
gen.writeEndObject();
|
||||
}
|
||||
}
|
||||
if (bean.getEvent() != ChangeType.DELETE) {
|
||||
gen.writeFieldName("data");
|
||||
gen.writeRaw(":");
|
||||
gen.writeRaw(bean.getData());
|
||||
|
||||
/**
|
||||
* Write all the value pairs suppressing null values.
|
||||
* <p>
|
||||
* We are intentionally keeping the same new/old structure for both inserts and updates.
|
||||
* </p>
|
||||
*/
|
||||
protected void writeValuePairs(BeanChange bean, JsonGenerator gen) throws IOException {
|
||||
|
||||
for (Map.Entry<String, ValuePair> entry : bean.getValues().entrySet()) {
|
||||
gen.writeFieldName(entry.getKey());
|
||||
gen.writeStartObject();
|
||||
ValuePair value = entry.getValue();
|
||||
Object newValue = value.getNewValue();
|
||||
if (newValue != null) {
|
||||
gen.writeFieldName("new");
|
||||
json.writeScalar(gen, newValue);
|
||||
String oldData = bean.getOldData();
|
||||
if (oldData != null) {
|
||||
gen.writeRaw(",\"oldData\":");
|
||||
gen.writeRaw(oldData);
|
||||
}
|
||||
Object oldValue = value.getOldValue();
|
||||
if (oldValue != null) {
|
||||
gen.writeFieldName("old");
|
||||
json.writeScalar(gen, oldValue);
|
||||
}
|
||||
gen.writeEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,15 +10,10 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Logs the change sets in JSON to logger named <code>io.ebean.ChangeLog</code>.
|
||||
* <p>
|
||||
* The logged entries duplicate/denormalise the transaction details so that each bean change
|
||||
* is fully contained with the transaction information.
|
||||
* </p>
|
||||
* Simply logs the change sets in JSON form to logger named <code>io.ebean.ChangeLog</code>.
|
||||
*/
|
||||
public class DefaultChangeLogListener implements ChangeLogListener, Plugin {
|
||||
|
||||
@@ -30,22 +25,17 @@ public class DefaultChangeLogListener implements ChangeLogListener, Plugin {
|
||||
/**
|
||||
* The named logger we send the change set payload to. Can be externally configured as desired.
|
||||
*/
|
||||
protected static final Logger changeLog = LoggerFactory.getLogger("io.ebean.ChangeLog");
|
||||
private static final Logger changeLog = LoggerFactory.getLogger("io.ebean.ChangeLog");
|
||||
|
||||
/**
|
||||
* Used to build the JSON.
|
||||
*/
|
||||
protected ChangeJsonBuilder jsonBuilder;
|
||||
private ChangeJsonBuilder jsonBuilder;
|
||||
|
||||
/**
|
||||
* A bigger default buffer for bean inserts and updates (that have value pairs).
|
||||
*/
|
||||
protected int defaultBufferSize = 400;
|
||||
|
||||
/**
|
||||
* Expected to be a reasonable buffer size for deletes (which do not have value pairs).
|
||||
*/
|
||||
protected int defaultDeleteBufferSize = 250;
|
||||
private int defaultBufferSize = 400;
|
||||
|
||||
public DefaultChangeLogListener() {
|
||||
}
|
||||
@@ -79,13 +69,11 @@ public class DefaultChangeLogListener implements ChangeLogListener, Plugin {
|
||||
@Override
|
||||
public void log(ChangeSet changeSet) {
|
||||
|
||||
List<BeanChange> changes = changeSet.getChanges();
|
||||
for (int i = 0; i < changes.size(); i++) {
|
||||
for (BeanChange beanChange : changeSet.getChanges()) {
|
||||
// log each bean change as a separate log entry
|
||||
BeanChange beanChange = changes.get(i);
|
||||
try {
|
||||
StringWriter writer = new StringWriter(getBufferSize(beanChange));
|
||||
jsonBuilder.writeBeanJson(writer, beanChange, changeSet, i);
|
||||
jsonBuilder.writeBeanJson(writer, beanChange, changeSet);
|
||||
changeLog.info(writer.toString());
|
||||
} catch (Exception e) {
|
||||
logger.error("Exception logging beanChange " + beanChange.toString(), e);
|
||||
@@ -96,9 +84,9 @@ public class DefaultChangeLogListener implements ChangeLogListener, Plugin {
|
||||
/**
|
||||
* Return a decent buffer size based on the bean change.
|
||||
*/
|
||||
protected int getBufferSize(BeanChange beanChange) {
|
||||
private int getBufferSize(BeanChange beanChange) {
|
||||
|
||||
return ChangeType.DELETE == beanChange.getType() ? defaultDeleteBufferSize : defaultBufferSize;
|
||||
return ChangeType.DELETE == beanChange.getEvent() ? 250 : defaultBufferSize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -134,8 +134,6 @@ public class DatabasePlatformFactory {
|
||||
String dbProductName = metaData.getDatabaseProductName();
|
||||
dbProductName = dbProductName.toLowerCase();
|
||||
|
||||
int majorVersion = metaData.getDatabaseMajorVersion();
|
||||
|
||||
if (dbProductName.contains("oracle")) {
|
||||
return new OraclePlatform();
|
||||
} else if (dbProductName.contains("microsoft")) {
|
||||
|
||||
@@ -20,8 +20,6 @@ import io.ebean.SqlRow;
|
||||
import io.ebean.SqlUpdate;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.TransactionCallback;
|
||||
import io.ebean.TxCallable;
|
||||
import io.ebean.TxRunnable;
|
||||
import io.ebean.TxScope;
|
||||
import io.ebean.Update;
|
||||
import io.ebean.UpdateQuery;
|
||||
@@ -43,6 +41,8 @@ import io.ebean.config.TenantMode;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.dbmigration.DdlGenerator;
|
||||
import io.ebean.event.BeanPersistController;
|
||||
import io.ebean.config.SlowQueryEvent;
|
||||
import io.ebean.config.SlowQueryListener;
|
||||
import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.meta.MetaInfoManager;
|
||||
@@ -51,16 +51,8 @@ import io.ebean.plugin.Plugin;
|
||||
import io.ebean.plugin.SpiServer;
|
||||
import io.ebean.text.csv.CsvReader;
|
||||
import io.ebean.text.json.JsonContext;
|
||||
import io.ebeaninternal.api.LoadBeanRequest;
|
||||
import io.ebeaninternal.api.LoadManyRequest;
|
||||
import io.ebeaninternal.api.ScopeTrans;
|
||||
import io.ebeaninternal.api.ScopedTransaction;
|
||||
import io.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.api.*;
|
||||
import io.ebeaninternal.api.SpiQuery.Type;
|
||||
import io.ebeaninternal.api.SpiTransaction;
|
||||
import io.ebeaninternal.api.TransactionEventTable;
|
||||
import io.ebeaninternal.server.autotune.AutoTuneService;
|
||||
import io.ebeaninternal.server.core.timezone.DataTimeZone;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
@@ -91,8 +83,8 @@ import io.ebeaninternal.server.transaction.TransactionScopeManager;
|
||||
import io.ebeaninternal.util.ParamTypeHelper;
|
||||
import io.ebeaninternal.util.ParamTypeHelper.TypeInfo;
|
||||
import io.ebeanservice.docstore.api.DocStoreIntegration;
|
||||
import io.ebean.TxIsolation;
|
||||
import io.ebean.TxType;
|
||||
import io.ebean.annotation.TxIsolation;
|
||||
import io.ebean.annotation.TxType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -179,7 +171,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
private final EncryptKeyManager encryptKeyManager;
|
||||
|
||||
private final JsonContext jsonContext;
|
||||
private final SpiJsonContext jsonContext;
|
||||
|
||||
private final DocumentStore documentStore;
|
||||
|
||||
@@ -213,6 +205,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
private final boolean collectQueryStatsByNode;
|
||||
|
||||
private final long slowQueryMicros;
|
||||
|
||||
private final SlowQueryListener slowQueryListener;
|
||||
|
||||
/**
|
||||
* Cache used to collect statistics based on ObjectGraphNode (used to highlight lazy loading origin points).
|
||||
*/
|
||||
@@ -238,6 +234,8 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
this.encryptKeyManager = serverConfig.getEncryptKeyManager();
|
||||
this.defaultPersistenceContextScope = serverConfig.getPersistenceContextScope();
|
||||
this.currentTenantProvider = serverConfig.getCurrentTenantProvider();
|
||||
this.slowQueryMicros = config.getSlowQueryMicros();
|
||||
this.slowQueryListener = config.getSlowQueryListener();
|
||||
|
||||
this.beanDescriptorManager = config.getBeanDescriptorManager();
|
||||
beanDescriptorManager.setEbeanServer(this);
|
||||
@@ -661,16 +659,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return transactionManager.createTransaction(true, isolation.getLevel());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T execute(TxCallable<T> c) {
|
||||
return execute(null, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T execute(TxScope scope, TxCallable<T> c) {
|
||||
return executeCall(scope, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T executeCall(Callable<T> c) {
|
||||
return executeCall(null, c);
|
||||
@@ -2219,6 +2207,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
return jsonContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiJsonContext jsonExtended() {
|
||||
return jsonContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collectQueryStats(ObjectGraphNode node, long loadedBeanCount, long timeMicros) {
|
||||
|
||||
@@ -2234,4 +2227,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void slowQueryCheck(long timeMicros, int rowCount, SpiQuery<?> query) {
|
||||
if (timeMicros > slowQueryMicros) {
|
||||
if (slowQueryListener != null) {
|
||||
slowQueryListener.process(new SlowQueryEvent(query.getGeneratedSql(), timeMicros / 1000L, rowCount, query.getParentNode()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebean.bean.ObjectGraphNode;
|
||||
import io.ebean.config.SlowQueryEvent;
|
||||
import io.ebean.config.SlowQueryListener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Default slow query listener implementation that logs a warning message.
|
||||
*/
|
||||
class DefaultSlowQueryListener implements SlowQueryListener {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger("io.ebean.SlowQuery");
|
||||
|
||||
@Override
|
||||
public void process(SlowQueryEvent event) {
|
||||
|
||||
String firstStack = "";
|
||||
ObjectGraphNode node = event.getOriginNode();
|
||||
if (node != null) {
|
||||
firstStack = node.getOriginQueryPoint().getFirstStackElement();
|
||||
}
|
||||
log.warn("Slow query warning - millis:{} rows:{} caller[{}] sql[{}]", event.getTimeMillis(), event.getRowCount(), firstStack, event.getSql());
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,7 @@ package io.ebeaninternal.server.core;
|
||||
import io.ebean.ValuePair;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -54,51 +49,4 @@ public class DiffHelp {
|
||||
return desc.diff((EntityBean) newBean, (EntityBean) oldBean);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Flattens an existing diff map converting assoc one beans into the associated id changes.
|
||||
*/
|
||||
public static Map<String, ValuePair> flatten(Map<String, ValuePair> values, BeanDescriptor<?> desc) {
|
||||
|
||||
Map<String, ValuePair> flattened = null;
|
||||
|
||||
Iterator<Map.Entry<String, ValuePair>> iterator = values.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, ValuePair> entry = iterator.next();
|
||||
BeanProperty beanProperty = desc.getBeanProperty(entry.getKey());
|
||||
if (beanProperty instanceof BeanPropertyAssocMany) {
|
||||
// filter out assoc many bean properties
|
||||
iterator.remove();
|
||||
|
||||
} else if (beanProperty instanceof BeanPropertyAssocOne) {
|
||||
BeanPropertyAssocOne<?> assoc = (BeanPropertyAssocOne<?>) beanProperty;
|
||||
if (!assoc.isEmbedded()) {
|
||||
// flatten for assoc one beans
|
||||
if (flattened == null) {
|
||||
flattened = new LinkedHashMap<>();
|
||||
}
|
||||
flattenToId(flattened, entry, beanProperty, assoc);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flattened != null) {
|
||||
values.putAll(flattened);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
private static void flattenToId(Map<String, ValuePair> flattened, Map.Entry<String, ValuePair> entry, BeanProperty beanProperty, BeanPropertyAssocOne<?> assoc) {
|
||||
|
||||
BeanDescriptor<?> oneDesc = assoc.getTargetDescriptor();
|
||||
|
||||
ValuePair value = entry.getValue();
|
||||
Object newId = value.getNewValue() == null ? null : oneDesc.getId((EntityBean) value.getNewValue());
|
||||
Object oldId = value.getOldValue() == null ? null : oneDesc.getId((EntityBean) value.getOldValue());
|
||||
|
||||
String propName = beanProperty.getName() + "." + oneDesc.getIdProperty().getName();
|
||||
flattened.put(propName, new ValuePair(newId, oldId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import io.ebean.ExpressionFactory;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.cache.ServerCacheManager;
|
||||
import io.ebean.config.ExternalTransactionManager;
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DbHistorySupport;
|
||||
import io.ebean.config.SlowQueryListener;
|
||||
import io.ebean.event.changelog.ChangeLogListener;
|
||||
import io.ebean.event.changelog.ChangeLogPrepare;
|
||||
import io.ebean.event.changelog.ChangeLogRegister;
|
||||
@@ -14,9 +16,9 @@ import io.ebean.event.readaudit.ReadAuditLogger;
|
||||
import io.ebean.event.readaudit.ReadAuditPrepare;
|
||||
import io.ebean.plugin.Plugin;
|
||||
import io.ebean.plugin.SpiServer;
|
||||
import io.ebean.text.json.JsonContext;
|
||||
import io.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiJsonContext;
|
||||
import io.ebeaninternal.server.autotune.AutoTuneService;
|
||||
import io.ebeaninternal.server.autotune.service.AutoTuneServiceFactory;
|
||||
import io.ebeaninternal.server.cache.DefaultCacheAdapter;
|
||||
@@ -60,7 +62,6 @@ import io.ebeanservice.docstore.api.DocStoreFactory;
|
||||
import io.ebeanservice.docstore.api.DocStoreIntegration;
|
||||
import io.ebeanservice.docstore.api.DocStoreUpdateProcessor;
|
||||
import io.ebeanservice.docstore.none.NoneDocStoreFactory;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import org.avaje.datasource.DataSourcePool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -261,7 +262,7 @@ public class InternalConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
public JsonContext createJsonContext(SpiEbeanServer server) {
|
||||
public SpiJsonContext createJsonContext(SpiEbeanServer server) {
|
||||
return new DJsonContext(server, jsonFactory, typeManager);
|
||||
}
|
||||
|
||||
@@ -432,4 +433,30 @@ public class InternalConfiguration {
|
||||
public ServerCacheManager cache() {
|
||||
return new DefaultCacheAdapter(cacheManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the slow query warning limit in micros.
|
||||
*/
|
||||
long getSlowQueryMicros() {
|
||||
long millis = serverConfig.getSlowQueryMillis();
|
||||
return (millis < 1) ? Long.MAX_VALUE : millis * 1000L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SlowQueryListener with a default that logs a warning message.
|
||||
*/
|
||||
SlowQueryListener getSlowQueryListener() {
|
||||
long millis = serverConfig.getSlowQueryMillis();
|
||||
if (millis < 1) {
|
||||
return null;
|
||||
}
|
||||
SlowQueryListener listener = serverConfig.getSlowQueryListener();
|
||||
if (listener == null) {
|
||||
listener = serverConfig.service(SlowQueryListener.class);
|
||||
if (listener == null) {
|
||||
listener = new DefaultSlowQueryListener();
|
||||
}
|
||||
}
|
||||
return listener;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,7 +385,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<?> findSet() {
|
||||
public Set<T> findSet() {
|
||||
return (Set<T>) queryEngine.findMany(this);
|
||||
}
|
||||
|
||||
@@ -393,7 +393,8 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
* Execute the query as findMap.
|
||||
*/
|
||||
@Override
|
||||
public Map<?, ?> findMap() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public <K> Map<K, T> findMap() {
|
||||
String mapKey = query.getMapKey();
|
||||
if (mapKey == null) {
|
||||
BeanProperty idProp = beanDescriptor.getIdProperty();
|
||||
@@ -403,7 +404,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
throw new PersistenceException("No mapKey specified for query");
|
||||
}
|
||||
}
|
||||
return (Map<?, ?>) queryEngine.findMany(this);
|
||||
return (Map<K, T>) queryEngine.findMany(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -480,7 +481,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
} else {
|
||||
cacheKey = query.queryHash();
|
||||
}
|
||||
|
||||
|
||||
if (!query.getUseQueryCache().isGet()) {
|
||||
return null;
|
||||
}
|
||||
@@ -504,11 +505,11 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
if (cached instanceof BeanCollection) {
|
||||
cached = ((BeanCollection<?>)cached).getShallowCopy();
|
||||
} else if (cached instanceof List) {
|
||||
cached = new CopyOnFirstWriteList<>((List)cached);
|
||||
cached = new CopyOnFirstWriteList<>((List<?>)cached);
|
||||
} else if (cached instanceof Set) {
|
||||
cached = new LinkedHashSet<>((Set)cached);
|
||||
cached = new LinkedHashSet<>((Set<?>)cached);
|
||||
} else if (cached instanceof Map) {
|
||||
cached = new LinkedHashMap<>((Map)cached);
|
||||
cached = new LinkedHashMap<>((Map<?,?>)cached);
|
||||
}
|
||||
}
|
||||
return cached;
|
||||
@@ -596,4 +597,11 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
public Object getTenantId() {
|
||||
return (transaction == null) ? null : transaction.getTenantId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for slow query event.
|
||||
*/
|
||||
public void slowQueryCheck(long executionTimeMicros, int rowCount) {
|
||||
ebeanServer.slowQueryCheck(executionTimeMicros, rowCount, query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanManager;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
import io.ebeaninternal.server.deploy.id.ImportedId;
|
||||
import io.ebeaninternal.server.persist.BatchControl;
|
||||
import io.ebeaninternal.server.persist.BatchedSqlException;
|
||||
@@ -179,6 +180,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
beanDescriptor.setDraftDirty(entityBean, true);
|
||||
}
|
||||
this.dirty = intercept.isDirty();
|
||||
initGeneratedProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,6 +227,52 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
persistCascade = transaction.isPersistCascade();
|
||||
}
|
||||
|
||||
private void initGeneratedProperties() {
|
||||
switch (type) {
|
||||
case INSERT:
|
||||
onInsertGeneratedProperties();
|
||||
break;
|
||||
case UPDATE:
|
||||
if (!beanDescriptor.isReference(intercept) && (dirty || statelessUpdate)) {
|
||||
onUpdateGeneratedProperties();
|
||||
}
|
||||
break;
|
||||
case SOFT_DELETE:
|
||||
onUpdateGeneratedProperties();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void onUpdateGeneratedProperties() {
|
||||
|
||||
for (BeanProperty prop : beanDescriptor.propertiesGenUpdate()) {
|
||||
|
||||
GeneratedProperty generatedProperty = prop.getGeneratedProperty();
|
||||
if (prop.isVersion()) {
|
||||
if (isLoadedProperty(prop)) {
|
||||
// @Version property must be loaded to be involved
|
||||
Object value = generatedProperty.getUpdateValue(prop, entityBean, now());
|
||||
Object oldVal = prop.getValue(entityBean);
|
||||
setVersionValue(value);
|
||||
intercept.setOldValue(prop.getPropertyIndex(), oldVal);
|
||||
}
|
||||
} else {
|
||||
// @WhenModified set without invoking interception
|
||||
Object oldVal = prop.getValue(entityBean);
|
||||
Object value = generatedProperty.getUpdateValue(prop, entityBean, now());
|
||||
prop.setValueChanged(entityBean, value);
|
||||
intercept.setOldValue(prop.getPropertyIndex(), oldVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onInsertGeneratedProperties() {
|
||||
for (BeanProperty prop : beanDescriptor.propertiesGenInsert()) {
|
||||
Object value = prop.getGeneratedProperty().getInsertValue(prop, entityBean, now());
|
||||
prop.setValueChanged(entityBean, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If using batch on cascade flush if required.
|
||||
*/
|
||||
@@ -525,7 +573,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
* Prepare the update after potential modifications in a BeanPersistController.
|
||||
*/
|
||||
private void postControllerPrepareUpdate() {
|
||||
if (intercept.isNew() && controller != null) {
|
||||
if (statelessUpdate && controller != null) {
|
||||
// 'stateless update' - set dirty properties modified in controller preUpdate
|
||||
intercept.setNewBeanForUpdate();
|
||||
}
|
||||
@@ -780,17 +828,20 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
@Override
|
||||
public void postExecute() {
|
||||
|
||||
changeLog();
|
||||
|
||||
if (controller != null) {
|
||||
controllerPost();
|
||||
}
|
||||
setNotifyCache();
|
||||
|
||||
if (type == Type.UPDATE && (notifyCache || docStoreMode == DocStoreMode.UPDATE)) {
|
||||
boolean isChangeLog = beanDescriptor.isChangeLog();
|
||||
if (type == Type.UPDATE && (isChangeLog || notifyCache || docStoreMode == DocStoreMode.UPDATE)) {
|
||||
// get the dirty properties for update notification to the doc store
|
||||
dirtyProperties = intercept.getDirtyProperties();
|
||||
}
|
||||
if (isChangeLog) {
|
||||
changeLog();
|
||||
}
|
||||
|
||||
// if bean persisted again then should result in an update
|
||||
intercept.setLoaded();
|
||||
if (isInsert()) {
|
||||
@@ -857,27 +908,6 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the concurrency mode depending on fully/partially populated bean.
|
||||
* <p>
|
||||
* Specifically with version concurrency we want to check that the version property was one of the
|
||||
* loaded properties.
|
||||
* </p>
|
||||
*/
|
||||
public ConcurrencyMode determineConcurrencyMode() {
|
||||
|
||||
// 'partial bean' update/delete...
|
||||
if (concurrencyMode.equals(ConcurrencyMode.VERSION)) {
|
||||
// check the version property was loaded
|
||||
BeanProperty prop = beanDescriptor.getVersionProperty();
|
||||
if (prop == null || !intercept.isLoadedProperty(prop.getPropertyIndex())) {
|
||||
concurrencyMode = ConcurrencyMode.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
return concurrencyMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the update DML/SQL must be dynamically generated.
|
||||
* <p>
|
||||
@@ -908,11 +938,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
|
||||
private void postInsert() {
|
||||
// mark all properties as loaded after an insert to support immediate update
|
||||
int len = intercept.getPropertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
intercept.setLoadedProperty(i);
|
||||
}
|
||||
beanDescriptor.setEmbeddedOwner(entityBean);
|
||||
beanDescriptor.setAllLoaded(entityBean);
|
||||
if (!publish) {
|
||||
beanDescriptor.setDraft(entityBean);
|
||||
}
|
||||
@@ -1147,4 +1173,10 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
return now;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is a stateless update request (in which case it doesn't really have 'old values').
|
||||
*/
|
||||
public boolean isStatelessUpdate() {
|
||||
return statelessUpdate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,12 +101,12 @@ public interface SpiOrmQueryRequest<T> extends DocQueryRequest<T> {
|
||||
/**
|
||||
* Execute the query as findSet.
|
||||
*/
|
||||
Set<?> findSet();
|
||||
Set<T> findSet();
|
||||
|
||||
/**
|
||||
* Execute the query as findMap.
|
||||
*/
|
||||
Map<?, ?> findMap();
|
||||
<K> Map<K, T> findMap();
|
||||
|
||||
/**
|
||||
* Execute the findSingleAttributeList query.
|
||||
|
||||
@@ -61,7 +61,7 @@ public class BootupClassPathSearch {
|
||||
}
|
||||
|
||||
long searchTime = System.currentTimeMillis() - st;
|
||||
logger.info("Classpath search entities[{}] searchTime[{}] in packages[{}]", bc.getEntities().size(), searchTime, packages);
|
||||
logger.debug("Classpath search entities[{}] searchTime[{}] in packages[{}]", bc.getEntities().size(), searchTime, packages);
|
||||
return bc;
|
||||
|
||||
} catch (Exception ex) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.ebeaninternal.server.core.bootup;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.PersistenceIOException;
|
||||
import io.ebean.bean.BeanDiffVisitor;
|
||||
import io.ebeaninternal.server.text.json.SpiJsonWriter;
|
||||
import io.ebeaninternal.server.util.ArrayStack;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* Builds the 'new values' and 'old values' in JSON form for ChangeLog.
|
||||
*/
|
||||
class BeanChangeJson implements BeanDiffVisitor {
|
||||
|
||||
private final StringWriter newData;
|
||||
private final StringWriter oldData;
|
||||
|
||||
private final SpiJsonWriter newJson;
|
||||
private final SpiJsonWriter oldJson;
|
||||
|
||||
private final ArrayStack<BeanDescriptor<?>> stack = new ArrayStack<>();
|
||||
|
||||
private BeanDescriptor<?> descriptor;
|
||||
|
||||
BeanChangeJson(BeanDescriptor<?> descriptor, boolean statelessUpdate) {
|
||||
this.descriptor = descriptor;
|
||||
this.newData = new StringWriter(200);
|
||||
this.newJson = descriptor.createJsonWriter(newData);
|
||||
newJson.writeStartObject();
|
||||
|
||||
if (statelessUpdate) {
|
||||
this.oldJson = null;
|
||||
this.oldData = null;
|
||||
} else {
|
||||
this.oldData = new StringWriter(200);
|
||||
this.oldJson = descriptor.createJsonWriter(oldData);
|
||||
oldJson.writeStartObject();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int position, Object newVal, Object oldVal) {
|
||||
|
||||
try {
|
||||
BeanProperty prop = descriptor.propertiesIndex[position];
|
||||
if (prop.isDbUpdatable()) {
|
||||
prop.jsonWriteValue(newJson, newVal);
|
||||
if (oldJson != null) {
|
||||
prop.jsonWriteValue(oldJson, oldVal);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPush(int position) {
|
||||
stack.push(descriptor);
|
||||
|
||||
BeanPropertyAssocOne<?> embedded = (BeanPropertyAssocOne<?>)descriptor.propertiesIndex[position];
|
||||
descriptor = embedded.getTargetDescriptor();
|
||||
newJson.writeStartObject(embedded.getName());
|
||||
if (oldJson != null) {
|
||||
oldJson.writeStartObject(embedded.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPop() {
|
||||
newJson.writeEndObject();
|
||||
if (oldJson != null) {
|
||||
oldJson.writeEndObject();
|
||||
}
|
||||
descriptor = stack.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the buffers.
|
||||
*/
|
||||
void flush() {
|
||||
try {
|
||||
newJson.writeEndObject();
|
||||
newJson.gen().flush();
|
||||
if (oldJson != null) {
|
||||
oldJson.writeEndObject();
|
||||
oldJson.gen().flush();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the new values JSON.
|
||||
*/
|
||||
String newJson() {
|
||||
return newData.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the old values JSON.
|
||||
*/
|
||||
String oldJson() {
|
||||
return oldData == null ? null : oldData.toString();
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.BeanCollectionAdd;
|
||||
import io.ebean.bean.BeanCollectionLoader;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.server.text.json.WriteJson;
|
||||
import io.ebeaninternal.server.text.json.SpiJsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -62,6 +62,6 @@ public interface BeanCollectionHelp<T> {
|
||||
/**
|
||||
* Write the collection out as json.
|
||||
*/
|
||||
void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException;
|
||||
void jsonWrite(SpiJsonWriter ctx, String name, Object collection, boolean explicitInclude) throws IOException;
|
||||
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@ import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
*/
|
||||
public class BeanCollectionHelpFactory {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
static final BeanListHelp LIST_HELP = new BeanListHelp();
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
static final BeanSetHelp SET_HELP = new BeanSetHelp();
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,7 +47,6 @@ import io.ebeaninternal.server.cache.CachedBeanData;
|
||||
import io.ebeaninternal.server.cache.CachedManyIds;
|
||||
import io.ebeaninternal.server.core.CacheOptions;
|
||||
import io.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import io.ebeaninternal.server.core.DiffHelp;
|
||||
import io.ebeaninternal.server.core.InternString;
|
||||
import io.ebeaninternal.server.core.PersistRequest;
|
||||
import io.ebeaninternal.server.core.PersistRequestBean;
|
||||
@@ -67,7 +66,7 @@ import io.ebeaninternal.server.query.CQueryPlanStats.Snapshot;
|
||||
import io.ebeaninternal.server.query.SplitName;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import io.ebeaninternal.server.text.json.ReadJson;
|
||||
import io.ebeaninternal.server.text.json.WriteJson;
|
||||
import io.ebeaninternal.server.text.json.SpiJsonWriter;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
import io.ebeaninternal.util.SortByClause;
|
||||
import io.ebeaninternal.util.SortByClauseParser;
|
||||
@@ -83,12 +82,12 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -340,6 +339,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
*/
|
||||
private final BeanProperty[] propertiesNonTransient;
|
||||
protected final BeanProperty[] propertiesIndex;
|
||||
private final BeanProperty[] propertiesGenInsert;
|
||||
private final BeanProperty[] propertiesGenUpdate;
|
||||
|
||||
/**
|
||||
* The bean class name or the table name for MapBeans.
|
||||
@@ -478,6 +479,8 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
this.propertiesManySave = listHelper.getManySave();
|
||||
this.propertiesManyDelete = listHelper.getManyDelete();
|
||||
this.propertiesManyToMany = listHelper.getManyToMany();
|
||||
this.propertiesGenInsert = listHelper.getGeneratedInsert();
|
||||
this.propertiesGenUpdate = listHelper.getGeneratedUpdate();
|
||||
|
||||
this.derivedTableJoins = listHelper.getTableJoin();
|
||||
|
||||
@@ -797,16 +800,15 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
return ebeanServer.getReadAuditPrepare();
|
||||
}
|
||||
|
||||
public boolean isChangeLog() {
|
||||
return changeLogFilter != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this request should be included in the change log.
|
||||
*/
|
||||
public BeanChange getChangeLogBean(PersistRequestBean<T> request) {
|
||||
|
||||
if (changeLogFilter == null) {
|
||||
return null;
|
||||
}
|
||||
PersistRequest.Type type = request.getType();
|
||||
switch (type) {
|
||||
switch (request.getType()) {
|
||||
case INSERT:
|
||||
return changeLogFilter.includeInsert(request) ? insertBeanChange(request) : null;
|
||||
case UPDATE:
|
||||
@@ -815,34 +817,79 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
case DELETE:
|
||||
return changeLogFilter.includeDelete(request) ? deleteBeanChange(request) : null;
|
||||
default:
|
||||
throw new IllegalStateException("Unhandled request type " + type);
|
||||
throw new IllegalStateException("Unhandled request type " + request.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private BeanChange beanChange(ChangeType type, Object id, String data, String oldData) {
|
||||
Object tenantId = ebeanServer.currentTenantId();
|
||||
return new BeanChange(name, tenantId, id, type, data, oldData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean change for a delete.
|
||||
*/
|
||||
private BeanChange deleteBeanChange(PersistRequestBean<T> request) {
|
||||
return newBeanChange(request.getBeanId(), ChangeType.DELETE, Collections.<String, ValuePair>emptyMap());
|
||||
return beanChange(ChangeType.DELETE, request.getBeanId(), null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean change for an update.
|
||||
* Return the bean change for an update generating 'new values' and 'old values' in JSON form.
|
||||
*/
|
||||
private BeanChange updateBeanChange(PersistRequestBean<T> request) {
|
||||
return newBeanChange(request.getBeanId(), ChangeType.UPDATE, diffFlatten(request.getEntityBeanIntercept().getDirtyValues()));
|
||||
|
||||
try {
|
||||
BeanChangeJson changeJson = new BeanChangeJson(this, request.isStatelessUpdate());
|
||||
request.getEntityBeanIntercept().addDirtyPropertyValues(changeJson);
|
||||
changeJson.flush();
|
||||
|
||||
return beanChange(ChangeType.UPDATE, request.getBeanId(), changeJson.newJson(), changeJson.oldJson());
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
logger.error("Failed to write ChangeLog entry for update", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean change for an insert.
|
||||
*/
|
||||
private BeanChange insertBeanChange(PersistRequestBean<T> request) {
|
||||
return newBeanChange(request.getBeanId(), ChangeType.INSERT, diffForInsert(request.getEntityBean()));
|
||||
|
||||
try {
|
||||
StringWriter writer = new StringWriter(200);
|
||||
SpiJsonWriter jsonWriter = createJsonWriter(writer);
|
||||
|
||||
jsonWriteForInsert(jsonWriter, request.getEntityBean());
|
||||
jsonWriter.gen().flush();
|
||||
|
||||
return beanChange(ChangeType.INSERT, request.getBeanId(), writer.toString(), null);
|
||||
|
||||
} catch (IOException e) {
|
||||
logger.error("Failed to write ChangeLog entry for insert", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private BeanChange newBeanChange(Object id, ChangeType changeType, Map<String, ValuePair> values) {
|
||||
Object tenantId = ebeanServer.currentTenantId();
|
||||
return new BeanChange(getBaseTable(), tenantId, id, changeType, values);
|
||||
SpiJsonWriter createJsonWriter(StringWriter writer) {
|
||||
return ebeanServer.jsonExtended().createJsonWriter(writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the diff for inserts with flattened non-null property values.
|
||||
*/
|
||||
protected void jsonWriteForInsert(SpiJsonWriter jsonWriter, EntityBean newBean) throws IOException {
|
||||
jsonWriter.writeStartObject();
|
||||
for (BeanProperty prop : propertiesBaseScalar) {
|
||||
prop.jsonWriteForInsert(jsonWriter, newBean);
|
||||
}
|
||||
for (BeanPropertyAssocOne<?> prop : propertiesOne) {
|
||||
prop.jsonWriteForInsert(jsonWriter, newBean);
|
||||
}
|
||||
for (BeanPropertyAssocOne<?> prop : propertiesEmbedded) {
|
||||
prop.jsonWriteForInsert(jsonWriter, newBean);
|
||||
}
|
||||
jsonWriter.writeEndObject();
|
||||
}
|
||||
|
||||
public SqlUpdate deleteById(Object id, List<Object> idList, boolean softDelete) {
|
||||
@@ -1747,7 +1794,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
* account inheritance.
|
||||
*/
|
||||
public BeanProperty getBeanPropertyFromPath(String path) {
|
||||
BeanDescriptor other = this;
|
||||
BeanDescriptor<?> other = this;
|
||||
while (true) {
|
||||
|
||||
String[] split = SplitName.splitBegin(path);
|
||||
@@ -1771,7 +1818,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
* Return the BeanDescriptor for a given path of Associated One or Many beans.
|
||||
*/
|
||||
public BeanDescriptor<?> getBeanDescriptor(String path) {
|
||||
BeanDescriptor result = this;
|
||||
BeanDescriptor<?> result = this;
|
||||
while (true) {
|
||||
if (path == null) {
|
||||
return result;
|
||||
@@ -1806,7 +1853,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
* </p>
|
||||
*/
|
||||
public BeanPropertyAssocOne<?> getUnidirectional() {
|
||||
BeanDescriptor other = this;
|
||||
BeanDescriptor<?> other = this;
|
||||
while (true) {
|
||||
if (other.unidirectional != null) {
|
||||
return other.unidirectional;
|
||||
@@ -2029,8 +2076,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
}
|
||||
|
||||
public ElComparator<T> getElComparator(String propNameOrSortBy) {
|
||||
ElComparator<T> c = comparatorCache.computeIfAbsent(propNameOrSortBy, this::createComparator);
|
||||
return c;
|
||||
return comparatorCache.computeIfAbsent(propNameOrSortBy, this::createComparator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2747,11 +2793,12 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the embedded owner on any embedded bean properties.
|
||||
* Set all properties to be loaded (recurse to embedded beans).
|
||||
*/
|
||||
public void setEmbeddedOwner(EntityBean bean) {
|
||||
for (BeanPropertyAssocOne<?> aPropertiesEmbedded : propertiesEmbedded) {
|
||||
aPropertiesEmbedded.setEmbeddedOwner(bean);
|
||||
public void setAllLoaded(EntityBean bean) {
|
||||
bean._ebean_getIntercept().setLoadedPropertyAll();
|
||||
for (BeanPropertyAssocOne<?> embedded : propertiesEmbedded) {
|
||||
embedded.setAllLoadedEmbedded(bean);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2848,45 +2895,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten the diff that comes from the entity bean intercept.
|
||||
*/
|
||||
Map<String, ValuePair> diffFlatten(Map<String, ValuePair> diff) {
|
||||
return DiffHelp.flatten(diff, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a map of the differences between a and b.
|
||||
* <p>
|
||||
* A and B must be of the same type. B can be null, in which case the 'dirty
|
||||
* diff' of a is returned.
|
||||
* </p>
|
||||
* <p>
|
||||
* This intentionally does not include as OneToMany or ManyToMany properties.
|
||||
* </p>
|
||||
*/
|
||||
public Map<String, ValuePair> diffForInsert(EntityBean newBean) {
|
||||
|
||||
Map<String, ValuePair> map = new LinkedHashMap<>();
|
||||
diffForInsert(null, map, newBean);
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the diff for inserts with flattened non-null property values.
|
||||
*/
|
||||
public void diffForInsert(String prefix, Map<String, ValuePair> map, EntityBean newBean) {
|
||||
for (BeanProperty aPropertiesBaseScalar : propertiesBaseScalar) {
|
||||
aPropertiesBaseScalar.diffForInsert(prefix, map, newBean);
|
||||
}
|
||||
for (BeanPropertyAssocOne<?> aPropertiesOne : propertiesOne) {
|
||||
aPropertiesOne.diffForInsert(prefix, map, newBean);
|
||||
}
|
||||
for (BeanPropertyAssocOne<?> aPropertiesEmbedded : propertiesEmbedded) {
|
||||
aPropertiesEmbedded.diffForInsert(prefix, map, newBean);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the diff comparing the bean values.
|
||||
*/
|
||||
@@ -3049,23 +3057,37 @@ public class BeanDescriptor<T> implements MetaBeanInfo, BeanType<T> {
|
||||
return propertiesLocal;
|
||||
}
|
||||
|
||||
public void jsonWriteDirty(WriteJson writeJson, EntityBean bean, boolean[] dirtyProps) throws IOException {
|
||||
/**
|
||||
* Return the properties set as generated values on insert.
|
||||
*/
|
||||
public BeanProperty[] propertiesGenInsert() {
|
||||
return propertiesGenInsert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties set as generated values on update.
|
||||
*/
|
||||
public BeanProperty[] propertiesGenUpdate() {
|
||||
return propertiesGenUpdate;
|
||||
}
|
||||
|
||||
public void jsonWriteDirty(SpiJsonWriter writeJson, EntityBean bean, boolean[] dirtyProps) throws IOException {
|
||||
jsonHelp.jsonWriteDirty(writeJson, bean, dirtyProps);
|
||||
}
|
||||
|
||||
protected void jsonWriteDirtyProperties(WriteJson writeJson, EntityBean bean, boolean[] dirtyProps) throws IOException {
|
||||
protected void jsonWriteDirtyProperties(SpiJsonWriter writeJson, EntityBean bean, boolean[] dirtyProps) throws IOException {
|
||||
jsonHelp.jsonWriteDirtyProperties(writeJson, bean, dirtyProps);
|
||||
}
|
||||
|
||||
public void jsonWrite(WriteJson writeJson, EntityBean bean) throws IOException {
|
||||
public void jsonWrite(SpiJsonWriter writeJson, EntityBean bean) throws IOException {
|
||||
jsonHelp.jsonWrite(writeJson, bean, null);
|
||||
}
|
||||
|
||||
public void jsonWrite(WriteJson writeJson, EntityBean bean, String key) throws IOException {
|
||||
public void jsonWrite(SpiJsonWriter writeJson, EntityBean bean, String key) throws IOException {
|
||||
jsonHelp.jsonWrite(writeJson, bean, key);
|
||||
}
|
||||
|
||||
protected void jsonWriteProperties(WriteJson writeJson, EntityBean bean) throws IOException {
|
||||
protected void jsonWriteProperties(SpiJsonWriter writeJson, EntityBean bean) throws IOException {
|
||||
jsonHelp.jsonWriteProperties(writeJson, bean);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,7 @@ import com.fasterxml.jackson.core.JsonToken;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.text.json.EJson;
|
||||
import io.ebeaninternal.server.text.json.ReadJson;
|
||||
import io.ebeaninternal.server.text.json.WriteJson;
|
||||
import io.ebeaninternal.server.text.json.WriteJson.WriteBean;
|
||||
import io.ebeaninternal.server.text.json.SpiJsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -24,7 +23,7 @@ public class BeanDescriptorJsonHelp<T> {
|
||||
this.inheritInfo = desc.inheritInfo;
|
||||
}
|
||||
|
||||
public void jsonWrite(WriteJson writeJson, EntityBean bean, String key) throws IOException {
|
||||
public void jsonWrite(SpiJsonWriter writeJson, EntityBean bean, String key) throws IOException {
|
||||
|
||||
writeJson.writeStartObject(key);
|
||||
|
||||
@@ -43,13 +42,12 @@ public class BeanDescriptorJsonHelp<T> {
|
||||
writeJson.writeEndObject();
|
||||
}
|
||||
|
||||
protected void jsonWriteProperties(WriteJson writeJson, EntityBean bean) throws IOException {
|
||||
protected void jsonWriteProperties(SpiJsonWriter writeJson, EntityBean bean) throws IOException {
|
||||
|
||||
WriteBean writeBean = writeJson.createWriteBean(desc, bean);
|
||||
writeBean.write(writeJson);
|
||||
writeJson.writeBean(desc, bean);
|
||||
}
|
||||
|
||||
public void jsonWriteDirty(WriteJson writeJson, EntityBean bean, boolean[] dirtyProps) throws IOException {
|
||||
public void jsonWriteDirty(SpiJsonWriter writeJson, EntityBean bean, boolean[] dirtyProps) throws IOException {
|
||||
|
||||
if (inheritInfo == null) {
|
||||
jsonWriteDirtyProperties(writeJson, bean, dirtyProps);
|
||||
@@ -58,7 +56,7 @@ public class BeanDescriptorJsonHelp<T> {
|
||||
}
|
||||
}
|
||||
|
||||
protected void jsonWriteDirtyProperties(WriteJson writeJson, EntityBean bean, boolean[] dirtyProps) throws IOException {
|
||||
protected void jsonWriteDirtyProperties(SpiJsonWriter writeJson, EntityBean bean, boolean[] dirtyProps) throws IOException {
|
||||
|
||||
writeJson.writeStartObject(null);
|
||||
// render the dirty properties
|
||||
@@ -85,7 +83,7 @@ public class BeanDescriptorJsonHelp<T> {
|
||||
return null;
|
||||
}
|
||||
if (JsonToken.START_OBJECT != token) {
|
||||
throw new JsonParseException("Unexpected token " + token + " - expecting start_object", parser.getCurrentLocation());
|
||||
throw new JsonParseException(parser, "Unexpected token " + token + " - expecting start_object", parser.getCurrentLocation());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +96,7 @@ public class BeanDescriptorJsonHelp<T> {
|
||||
|
||||
if (parser.nextToken() != JsonToken.FIELD_NAME) {
|
||||
String msg = "Error reading inheritance discriminator - expected [" + discColumn + "] but no json key?";
|
||||
throw new JsonParseException(msg, parser.getCurrentLocation());
|
||||
throw new JsonParseException(parser, msg, parser.getCurrentLocation());
|
||||
}
|
||||
|
||||
String propName = parser.getCurrentName();
|
||||
@@ -111,7 +109,7 @@ public class BeanDescriptorJsonHelp<T> {
|
||||
return jsonReadProperties(jsonRead, bean, path);
|
||||
}
|
||||
String msg = "Error reading inheritance discriminator, expected property [" + discColumn + "] but got [" + propName + "] ?";
|
||||
throw new JsonParseException(msg, parser.getCurrentLocation());
|
||||
throw new JsonParseException(parser, msg, parser.getCurrentLocation());
|
||||
}
|
||||
|
||||
String discValue = parser.nextTextValue();
|
||||
|
||||
@@ -8,7 +8,7 @@ import io.ebean.bean.BeanCollectionAdd;
|
||||
import io.ebean.bean.BeanCollectionLoader;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.common.BeanList;
|
||||
import io.ebeaninternal.server.text.json.WriteJson;
|
||||
import io.ebeaninternal.server.text.json.SpiJsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@@ -125,7 +125,7 @@ public final class BeanListHelp<T> implements BeanCollectionHelp<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException {
|
||||
public void jsonWrite(SpiJsonWriter ctx, String name, Object collection, boolean explicitInclude) throws IOException {
|
||||
|
||||
List<?> list;
|
||||
if (collection instanceof BeanCollection<?>) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import io.ebean.bean.BeanCollectionAdd;
|
||||
import io.ebean.bean.BeanCollectionLoader;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.common.BeanMap;
|
||||
import io.ebeaninternal.server.text.json.WriteJson;
|
||||
import io.ebeaninternal.server.text.json.SpiJsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -160,7 +160,7 @@ public final class BeanMapHelp<T> implements BeanCollectionHelp<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException {
|
||||
public void jsonWrite(SpiJsonWriter ctx, String name, Object collection, boolean explicitInclude) throws IOException {
|
||||
|
||||
Map<?, ?> map;
|
||||
if (collection instanceof BeanCollection<?>) {
|
||||
|
||||
@@ -24,7 +24,7 @@ import io.ebeaninternal.server.query.SplitName;
|
||||
import io.ebeaninternal.server.query.SqlBeanLoad;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.text.json.ReadJson;
|
||||
import io.ebeaninternal.server.text.json.WriteJson;
|
||||
import io.ebeaninternal.server.text.json.SpiJsonWriter;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
import io.ebeaninternal.server.type.ScalarType;
|
||||
import io.ebeaninternal.server.type.ScalarTypeBoolean;
|
||||
@@ -1360,21 +1360,55 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
return jsonSerialize;
|
||||
}
|
||||
|
||||
@SuppressWarnings(value = "unchecked")
|
||||
public void jsonWrite(WriteJson writeJson, EntityBean bean) throws IOException {
|
||||
/**
|
||||
* JSON write the property for 'insert only depth'.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void jsonWriteForInsert(SpiJsonWriter writeJson, EntityBean bean) throws IOException {
|
||||
if (!jsonSerialize) {
|
||||
return;
|
||||
}
|
||||
Object value = getValueIntercept(bean);
|
||||
Object value = getValue(bean);
|
||||
if (value != null) {
|
||||
jsonWriteScalar(writeJson, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON write the property value.
|
||||
*/
|
||||
public void jsonWriteValue(SpiJsonWriter writeJson, Object value) throws IOException {
|
||||
if (!jsonSerialize) {
|
||||
return;
|
||||
}
|
||||
jsonWriteVal(writeJson, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON write the bean property.
|
||||
*/
|
||||
public void jsonWrite(SpiJsonWriter writeJson, EntityBean bean) throws IOException {
|
||||
if (!jsonSerialize) {
|
||||
return;
|
||||
}
|
||||
jsonWriteVal(writeJson, getValueIntercept(bean));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void jsonWriteVal(SpiJsonWriter writeJson, Object value) throws IOException {
|
||||
if (value == null) {
|
||||
writeJson.writeNullField(name);
|
||||
} else {
|
||||
if (scalarType != null) {
|
||||
writeJson.writeFieldName(name);
|
||||
scalarType.jsonWrite(writeJson.gen(), value);
|
||||
} else {
|
||||
writeJson.writeValueUsingObjectMapper(name, value);
|
||||
}
|
||||
jsonWriteScalar(writeJson, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void jsonWriteScalar(SpiJsonWriter writeJson, Object value) throws IOException {
|
||||
if (scalarType != null) {
|
||||
writeJson.writeFieldName(name);
|
||||
scalarType.jsonWrite(writeJson.gen(), value);
|
||||
} else {
|
||||
writeJson.writeValueUsingObjectMapper(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1407,17 +1441,6 @@ public class BeanProperty implements ElPropertyValue, Property {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate diff map for insert if the property is not null.
|
||||
*/
|
||||
public void diffForInsert(String prefix, Map<String, ValuePair> map, EntityBean newBean) {
|
||||
Object newVal = (newBean == null) ? null : getValue(newBean);
|
||||
if (newVal != null) {
|
||||
String propName = (prefix == null) ? name : prefix + "." + name;
|
||||
map.put(propName, new ValuePair(newVal, null));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate diff map comparing the property values between the beans.
|
||||
*/
|
||||
|
||||
@@ -20,7 +20,7 @@ import io.ebeaninternal.server.el.ElPropertyChainBuilder;
|
||||
import io.ebeaninternal.server.el.ElPropertyValue;
|
||||
import io.ebeaninternal.server.query.SqlBeanLoad;
|
||||
import io.ebeaninternal.server.text.json.ReadJson;
|
||||
import io.ebeaninternal.server.text.json.WriteJson;
|
||||
import io.ebeaninternal.server.text.json.SpiJsonWriter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -263,7 +263,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
|
||||
Object value = getValue(bean);
|
||||
if (value instanceof BeanCollection) {
|
||||
// reset the collection back to empty
|
||||
((BeanCollection) value).reset(bean, name);
|
||||
((BeanCollection<?>) value).reset(bean, name);
|
||||
} else {
|
||||
createReference(bean);
|
||||
}
|
||||
@@ -962,8 +962,15 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
|
||||
return null != targetDescriptor.getId(otherBean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip JSON write value for ToMany property.
|
||||
*/
|
||||
public void jsonWriteValue(SpiJsonWriter writeJson, Object value) throws IOException {
|
||||
// do nothing, exclude ToMany properties
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(WriteJson ctx, EntityBean bean) throws IOException {
|
||||
public void jsonWrite(SpiJsonWriter ctx, EntityBean bean) throws IOException {
|
||||
if (!this.jsonSerialize) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class BeanPropertyAssocManyJsonHelp {
|
||||
return;
|
||||
}
|
||||
if (JsonToken.START_ARRAY != event) {
|
||||
throw new JsonParseException("Unexpected token " + event + " - expecting start_array ", parser.getCurrentLocation());
|
||||
throw new JsonParseException(parser, "Unexpected token " + event + " - expecting start_array ");
|
||||
}
|
||||
|
||||
if (many.isTransient()) {
|
||||
|
||||
@@ -18,7 +18,7 @@ import io.ebeaninternal.server.query.SplitName;
|
||||
import io.ebeaninternal.server.query.SqlBeanLoad;
|
||||
import io.ebeaninternal.server.query.SqlJoinType;
|
||||
import io.ebeaninternal.server.text.json.ReadJson;
|
||||
import io.ebeaninternal.server.text.json.WriteJson;
|
||||
import io.ebeaninternal.server.text.json.SpiJsonWriter;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.IOException;
|
||||
@@ -351,22 +351,6 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
return importedPrimaryKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void diffForInsert(String prefix, Map<String, ValuePair> map, EntityBean newBean) {
|
||||
Object newEmb = (newBean == null) ? null : getValue(newBean);
|
||||
if (newEmb != null) {
|
||||
prefix = (prefix == null) ? name : prefix + "." + name;
|
||||
if (embedded) {
|
||||
getTargetDescriptor().diffForInsert(prefix, map, (EntityBean) newEmb);
|
||||
} else {
|
||||
// we are only interested in the Id value
|
||||
BeanDescriptor<T> targetDescriptor = getTargetDescriptor();
|
||||
BeanProperty idProperty = targetDescriptor.getIdProperty();
|
||||
idProperty.diffForInsert(prefix, map, (EntityBean) newEmb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void diff(String prefix, Map<String, ValuePair> map, EntityBean newBean, EntityBean oldBean) {
|
||||
|
||||
@@ -625,13 +609,14 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the owner on the embedded bean property.
|
||||
* For embedded bean set the owner and all properties to be loaded (recursively).
|
||||
*/
|
||||
void setEmbeddedOwner(EntityBean owner) {
|
||||
|
||||
void setAllLoadedEmbedded(EntityBean owner) {
|
||||
Object emb = getValue(owner);
|
||||
if (emb != null) {
|
||||
setEmbeddedOwner(owner, emb);
|
||||
EntityBean embeddedBean = (EntityBean) emb;
|
||||
embeddedBean._ebean_getIntercept().setEmbeddedOwner(owner, propertyIndex);
|
||||
targetDescriptor.setAllLoaded(embeddedBean);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -676,8 +661,57 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON write property (non-recursive to other beans).
|
||||
*/
|
||||
@Override
|
||||
public void jsonWrite(WriteJson writeJson, EntityBean bean) throws IOException {
|
||||
public void jsonWriteForInsert(SpiJsonWriter writeJson, EntityBean bean) throws IOException {
|
||||
|
||||
if (!jsonSerialize) {
|
||||
return;
|
||||
}
|
||||
jsonWriteBean(writeJson, getValue(bean));
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON write property value (non-recursive to other beans).
|
||||
*/
|
||||
@Override
|
||||
public void jsonWriteValue(SpiJsonWriter writeJson, Object value) throws IOException {
|
||||
if (!jsonSerialize) {
|
||||
return;
|
||||
}
|
||||
jsonWriteBean(writeJson, value);
|
||||
}
|
||||
|
||||
private void jsonWriteBean(SpiJsonWriter writeJson, Object value) throws IOException {
|
||||
|
||||
if (value instanceof EntityBean) {
|
||||
if (embedded) {
|
||||
writeJson.writeFieldName(name);
|
||||
BeanDescriptor<?> refDesc = descriptor.getBeanDescriptor(value.getClass());
|
||||
refDesc.jsonWriteForInsert(writeJson, (EntityBean)value);
|
||||
|
||||
} else {
|
||||
jsonWriteTargetId(writeJson, (EntityBean)value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Just write the Id property of the ToOne property.
|
||||
*/
|
||||
private void jsonWriteTargetId(SpiJsonWriter writeJson, EntityBean childBean) throws IOException {
|
||||
BeanProperty idProperty = targetDescriptor.getIdProperty();
|
||||
if (idProperty != null) {
|
||||
writeJson.writeStartObject(name);
|
||||
idProperty.jsonWriteForInsert(writeJson, childBean);
|
||||
writeJson.writeEndObject();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(SpiJsonWriter writeJson, EntityBean bean) throws IOException {
|
||||
|
||||
if (!jsonSerialize) {
|
||||
return;
|
||||
@@ -688,7 +722,6 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
writeJson.writeNullField(name);
|
||||
|
||||
} else {
|
||||
//noinspection StatementWithEmptyBody
|
||||
if (writeJson.isParentBean(value)) {
|
||||
// bi-directional and already rendered parent
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import io.ebean.bean.BeanCollectionAdd;
|
||||
import io.ebean.bean.BeanCollectionLoader;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.common.BeanSet;
|
||||
import io.ebeaninternal.server.text.json.WriteJson;
|
||||
import io.ebeaninternal.server.text.json.SpiJsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashSet;
|
||||
@@ -124,7 +124,7 @@ public final class BeanSetHelp<T> implements BeanCollectionHelp<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(WriteJson ctx, String name, Object collection, boolean explicitInclude) throws IOException {
|
||||
public void jsonWrite(SpiJsonWriter ctx, String name, Object collection, boolean explicitInclude) throws IOException {
|
||||
|
||||
Set<?> set;
|
||||
if (collection instanceof BeanCollection<?>) {
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
/**
|
||||
* Class to hold the DDL-migration information that is needed to do correct alters.
|
||||
*
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*/
|
||||
public class DbMigrationInfo {
|
||||
@@ -18,8 +16,8 @@ public class DbMigrationInfo {
|
||||
private final List<String> postAdd;
|
||||
private final List<String> preAlter;
|
||||
private final List<String> postAlter;
|
||||
private final List<Platform> platforms;
|
||||
|
||||
private final List<Platform> platforms;
|
||||
|
||||
public DbMigrationInfo(String[] preAdd, String[] postAdd, String[] preAlter, String[] postAlter, Platform[] platforms) {
|
||||
this.preAdd = toList(preAdd);
|
||||
this.postAdd = toList(postAdd);
|
||||
@@ -35,7 +33,7 @@ public class DbMigrationInfo {
|
||||
return Collections.unmodifiableList(Arrays.asList(scripts));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<String> getPreAdd() {
|
||||
return preAdd;
|
||||
}
|
||||
@@ -51,7 +49,7 @@ public class DbMigrationInfo {
|
||||
public List<Platform> getPlatforms() {
|
||||
return platforms;
|
||||
}
|
||||
|
||||
|
||||
public String joinPlatforms() {
|
||||
if (platforms.isEmpty()) {
|
||||
return null;
|
||||
|
||||
@@ -9,6 +9,7 @@ import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertySimpleCollection;
|
||||
import io.ebeaninternal.server.deploy.InheritInfo;
|
||||
import io.ebeaninternal.server.deploy.TableJoin;
|
||||
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
import io.ebeaninternal.server.type.ScalarTypeString;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -345,6 +346,36 @@ public class DeployBeanPropertyLists {
|
||||
return tenant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties set via generated values on insert.
|
||||
*/
|
||||
public BeanProperty[] getGeneratedInsert() {
|
||||
|
||||
List<BeanProperty> list = new ArrayList<>();
|
||||
for (BeanProperty prop : nonTransients) {
|
||||
GeneratedProperty gen = prop.getGeneratedProperty();
|
||||
if (gen != null && gen.includeInInsert()) {
|
||||
list.add(prop);
|
||||
}
|
||||
}
|
||||
return list.toArray(new BeanProperty[list.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the properties set via generated values on update.
|
||||
*/
|
||||
public BeanProperty[] getGeneratedUpdate() {
|
||||
|
||||
List<BeanProperty> list = new ArrayList<>();
|
||||
for (BeanProperty prop : nonTransients) {
|
||||
GeneratedProperty gen = prop.getGeneratedProperty();
|
||||
if (gen != null && gen.includeInUpdate()) {
|
||||
list.add(prop);
|
||||
}
|
||||
}
|
||||
return list.toArray(new BeanProperty[list.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mode used to determine which BeanPropertyAssoc to include.
|
||||
*/
|
||||
|
||||
@@ -199,7 +199,11 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
prop.setEmbedded();
|
||||
prop.setDbInsertable(true);
|
||||
prop.setDbUpdateable(true);
|
||||
prop.setColumnPrefix(embedded.prefix());
|
||||
try {
|
||||
prop.setColumnPrefix(embedded.prefix());
|
||||
} catch (NoSuchMethodError e) {
|
||||
// using standard JPA API without prefix option, maybe in EE container
|
||||
}
|
||||
|
||||
readEmbeddedAttributeOverrides(prop);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.annotation.Formula;
|
||||
import io.ebean.annotation.Where;
|
||||
import io.ebean.config.NamingConvention;
|
||||
@@ -21,28 +21,28 @@ import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* Provides some base methods for processing deployment annotations. All findAnnotation* methods
|
||||
* are capable to search for meta-annotations (annotation that has an other annotation)
|
||||
*
|
||||
* are capable to search for meta-annotations (annotation that has an other annotation)
|
||||
*
|
||||
* <p>search algorithm for ONE annotation:</p>
|
||||
* <ul>
|
||||
* <li>Check if annotation is direct on the property</li>
|
||||
* <li>if not found: Check all annotations at the annotateElement
|
||||
* <li>if not found: Check all annotations at the annotateElement
|
||||
* if they have the needed annotation as meta annotation</li>
|
||||
* <li>if not found: go up to super class and try again
|
||||
* <li>if not found: go up to super class and try again
|
||||
* (only findAnnotationRecursive)</li>
|
||||
* </ul>
|
||||
* DFS (Depth-First-Search) is used. The algorithm is the same as it is used in Spring-Framework,
|
||||
* DFS (Depth-First-Search) is used. The algorithm is the same as it is used in Spring-Framework,
|
||||
* as the code is taken from there.
|
||||
*
|
||||
* <p>search algoritm for a Set<Annotation> works a litte bit different, as it does not stop
|
||||
*
|
||||
* <p>search algoritm for a Set<Annotation> works a litte bit different, as it does not stop
|
||||
* on the first match, but continues searching down to the last corner to find all annotations.</p>
|
||||
*
|
||||
*
|
||||
* <p>To prevent endless recursion, the search algoritm tracks all visited annotations</p>
|
||||
*
|
||||
*
|
||||
* <p>Supports also "java 1.6 repeatable containers" like{@link JoinColumn} / {@link JoinColumns}.</p>
|
||||
*
|
||||
* <p>This means, searching for <code>JoinColumn</code> will find them also if they are inside a
|
||||
* <code>JoinColumn<b>s</b></code> annotation</p>
|
||||
*
|
||||
* <p>This means, searching for <code>JoinColumn</code> will find them also if they are inside a
|
||||
* <code>JoinColumn<b>s</b></code> annotation</p>
|
||||
*/
|
||||
public abstract class AnnotationBase {
|
||||
|
||||
@@ -218,10 +218,10 @@ public abstract class AnnotationBase {
|
||||
while (clazz != null && clazz != Object.class) {
|
||||
findMetaAnnotations(clazz, annotationType, ret, visited);
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform the search algorithm avoiding endless recursion by tracking which
|
||||
* annotations have already been visited.
|
||||
@@ -305,7 +305,7 @@ public abstract class AnnotationBase {
|
||||
}
|
||||
|
||||
private static final ConcurrentMap<Annotation, Method> valueMethods = new ConcurrentHashMap<>();
|
||||
// only a non-null-marker the valueMethods - Cache
|
||||
// only a non-null-marker the valueMethods - Cache
|
||||
private static final Method nullMethod = getNullMethod();
|
||||
|
||||
|
||||
|
||||
@@ -49,8 +49,6 @@ public class DeployUtil {
|
||||
|
||||
private static final int DEFAULT_JSON_VARCHAR_LENGTH = 3000;
|
||||
|
||||
private static final int DEFAULT_ARRAY_VARCHAR_LENGTH = 1000;
|
||||
|
||||
private final NamingConvention namingConvention;
|
||||
|
||||
private final TypeManager typeManager;
|
||||
|
||||
@@ -59,6 +59,7 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
|
||||
List<SpiExpression> list = exprList.list;
|
||||
if (list.size() == 1 && list.get(0) instanceof JunctionExpression) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
JunctionExpression nested = (JunctionExpression) list.get(0);
|
||||
if (type == Type.AND && !nested.type.isText()) {
|
||||
// and (and (a, b, c)) -> and (a, b, c)
|
||||
@@ -204,7 +205,7 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
|
||||
@Override
|
||||
public boolean isSameByBind(SpiExpression other) {
|
||||
JunctionExpression that = (JunctionExpression) other;
|
||||
JunctionExpression<?> that = (JunctionExpression<?>) other;
|
||||
return type == that.type && exprList.isSameByBind(that.exprList);
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ public final class DeleteMeta {
|
||||
}
|
||||
|
||||
boolean publish = request.isPublish();
|
||||
switch (request.determineConcurrencyMode()) {
|
||||
switch (request.getConcurrencyMode()) {
|
||||
case NONE:
|
||||
return publish ? sqlNone : sqlDraftNone;
|
||||
|
||||
@@ -100,7 +100,7 @@ public final class DeleteMeta {
|
||||
return publish ? sqlVersion : sqlDraftVersion;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Invalid mode " + request.determineConcurrencyMode());
|
||||
throw new RuntimeException("Invalid mode " + request.getConcurrencyMode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ public class MetaFactory {
|
||||
DeleteMeta createDelete(BeanDescriptor<?> desc) {
|
||||
|
||||
BindableId id = idFact.createId(desc);
|
||||
Bindable version = versionFact.create(desc);
|
||||
Bindable version = versionFact.createForDelete(desc);
|
||||
Bindable tenantId = versionFact.createTenantId(desc);
|
||||
|
||||
return new DeleteMeta(emptyStringAsNull, desc, id, version, tenantId);
|
||||
|
||||
@@ -93,9 +93,7 @@ public final class UpdateMeta {
|
||||
return getDynamicUpdatePlan(request);
|
||||
}
|
||||
|
||||
// 'full bean' update...
|
||||
ConcurrencyMode mode = request.determineConcurrencyMode();
|
||||
switch (mode) {
|
||||
switch (request.getConcurrencyMode()) {
|
||||
case NONE:
|
||||
return modeNoneUpdatePlan;
|
||||
|
||||
@@ -103,7 +101,7 @@ public final class UpdateMeta {
|
||||
return modeVersionUpdatePlan;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Invalid mode " + mode);
|
||||
throw new RuntimeException("Invalid mode " + request.getConcurrencyMode());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +123,7 @@ public final class UpdateMeta {
|
||||
set.addToUpdate(persistRequest, list);
|
||||
BindableList bindableList = new BindableList(list);
|
||||
|
||||
ConcurrencyMode mode = persistRequest.determineConcurrencyMode();
|
||||
ConcurrencyMode mode = persistRequest.getConcurrencyMode();
|
||||
|
||||
// build the SQL for this update statement
|
||||
String sql = genSql(mode, bindableList, persistRequest.getUpdateTable());
|
||||
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
package io.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.server.core.PersistRequestBean;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Bindable for generated ManyToOne - likely 'who created'.
|
||||
*/
|
||||
class BindableAssocOneGeneratedInsert extends BindableAssocOne {
|
||||
|
||||
private final GeneratedProperty generatedProperty;
|
||||
|
||||
BindableAssocOneGeneratedInsert(BeanPropertyAssocOne<?> assocOne) {
|
||||
super(assocOne);
|
||||
this.generatedProperty = assocOne.getGeneratedProperty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
|
||||
throw new RuntimeException("never called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
|
||||
|
||||
Object objectValue = generatedProperty.getInsertValue(assocOne, bean, request.now());
|
||||
EntityBean generatedValue = castToEntityBean(objectValue);
|
||||
assocOne.setValue(bean, generatedValue);
|
||||
registerDeferred(request, bean, generatedValue);
|
||||
}
|
||||
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
package io.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.server.core.PersistRequestBean;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Bindable for generated ManyToOne - likely 'who modified'.
|
||||
*/
|
||||
class BindableAssocOneGeneratedUpdate extends BindableAssocOne {
|
||||
|
||||
private final GeneratedProperty generatedProperty;
|
||||
|
||||
BindableAssocOneGeneratedUpdate(BeanPropertyAssocOne<?> assocOne) {
|
||||
super(assocOne);
|
||||
this.generatedProperty = assocOne.getGeneratedProperty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
|
||||
if (generatedProperty.includeInAllUpdates() || request.isAddToUpdate(assocOne)) {
|
||||
list.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
|
||||
|
||||
Object objectValue = generatedProperty.getUpdateValue(assocOne, bean, request.now());
|
||||
EntityBean generatedValue = castToEntityBean(objectValue);
|
||||
assocOne.setValueChanged(bean, generatedValue);
|
||||
registerDeferred(request, bean, generatedValue);
|
||||
}
|
||||
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
package io.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
import io.ebeaninternal.server.persist.dml.GenerateDmlRequest;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Bindable for insert on a property with a GeneratedProperty.
|
||||
* <p>
|
||||
* This is typically a 'insert timestamp', 'update timestamp' or 'counter'.
|
||||
* </p>
|
||||
*/
|
||||
public class BindablePropertyInsertGenerated extends BindableProperty {
|
||||
|
||||
private final GeneratedProperty gen;
|
||||
|
||||
public BindablePropertyInsertGenerated(BeanProperty prop, GeneratedProperty gen) {
|
||||
super(prop);
|
||||
this.gen = gen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
|
||||
|
||||
Object value = gen.getInsertValue(prop, bean, request.now());
|
||||
|
||||
// generated value should be the correct type
|
||||
if (bean != null) {
|
||||
// support PropertyChangeSupport
|
||||
//prop.setValueIntercept(bean, value);
|
||||
prop.setValue(bean, value);
|
||||
}
|
||||
request.bind(value, prop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bind on Insert SET.
|
||||
*/
|
||||
@Override
|
||||
public void dmlAppend(GenerateDmlRequest request) {
|
||||
request.appendColumn(prop.getDbColumn());
|
||||
}
|
||||
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
package io.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.server.core.PersistRequestBean;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty;
|
||||
import io.ebeaninternal.server.persist.dml.GenerateDmlRequest;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Bindable for update on a property with a GeneratedProperty.
|
||||
* <p>
|
||||
* This is typically a 'update timestamp' or 'counter'.
|
||||
* </p>
|
||||
*/
|
||||
public class BindablePropertyUpdateGenerated extends BindableProperty {
|
||||
|
||||
private final GeneratedProperty gen;
|
||||
|
||||
public BindablePropertyUpdateGenerated(BeanProperty prop, GeneratedProperty gen) {
|
||||
super(prop);
|
||||
this.gen = gen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add BindablePropertyUpdateGenerated if the property is loaded.
|
||||
*/
|
||||
@Override
|
||||
public void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
|
||||
if (gen.includeInAllUpdates() || request.isLoadedProperty(prop)) {
|
||||
list.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
|
||||
|
||||
Object value = gen.getUpdateValue(prop, bean, request.now());
|
||||
|
||||
// generated value should be the correct type
|
||||
request.bind(value, prop);
|
||||
|
||||
if (prop.isVersion()) {
|
||||
if (request.getPersistRequest().isLoadedProperty(prop)) {
|
||||
// set to the bean after the where clause has been generated
|
||||
request.registerGeneratedVersion(value);
|
||||
}
|
||||
} else {
|
||||
// @WhenModified set without invoking interception
|
||||
prop.setValueChanged(bean, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bind on Insert SET.
|
||||
*/
|
||||
@Override
|
||||
public void dmlAppend(GenerateDmlRequest request) {
|
||||
request.appendColumn(prop.getDbColumn());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package io.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.server.core.PersistRequestBean;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.persist.dml.GenerateDmlRequest;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Bindable for a Version BeanProperty. Obtains value from 'old values'.
|
||||
*/
|
||||
public class BindablePropertyVersion implements Bindable {
|
||||
|
||||
protected final BeanProperty prop;
|
||||
|
||||
public BindablePropertyVersion(BeanProperty prop) {
|
||||
this.prop = prop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return prop.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDraftOnly() {
|
||||
return prop.isDraftOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
|
||||
if (request.isAddToUpdate(prop)) {
|
||||
list.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dmlAppend(GenerateDmlRequest request) {
|
||||
request.appendColumn(prop.getDbColumn());
|
||||
}
|
||||
|
||||
/**
|
||||
* Normal binding of a property value from the bean.
|
||||
*/
|
||||
@Override
|
||||
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
|
||||
|
||||
// get prior version value from 'old values'
|
||||
Object value = bean._ebean_getIntercept().getOrigValue(prop.getPropertyIndex());
|
||||
request.bind(value, prop);
|
||||
}
|
||||
}
|
||||
@@ -35,24 +35,7 @@ public class FactoryAssocOnes {
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (one.getGeneratedProperty() == null) {
|
||||
list.add(new BindableAssocOne(one));
|
||||
} else {
|
||||
// typically generated 'who' created/modified properties
|
||||
switch (mode) {
|
||||
case INSERT:
|
||||
if (one.getGeneratedProperty().includeInInsert()) {
|
||||
list.add(new BindableAssocOneGeneratedInsert(one));
|
||||
}
|
||||
break;
|
||||
case UPDATE:
|
||||
if (one.getGeneratedProperty().includeInUpdate()) {
|
||||
// A 'Who Created property' is never updated
|
||||
list.add(new BindableAssocOneGeneratedUpdate(one));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
list.add(new BindableAssocOne(one));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,26 +40,6 @@ public class FactoryProperty {
|
||||
}
|
||||
}
|
||||
|
||||
GeneratedProperty gen = prop.getGeneratedProperty();
|
||||
if (gen != null) {
|
||||
if (DmlMode.INSERT.equals(mode)) {
|
||||
if (gen.includeInInsert()) {
|
||||
return new BindablePropertyInsertGenerated(prop, gen);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
if (DmlMode.UPDATE.equals(mode)) {
|
||||
if (gen.includeInUpdate()) {
|
||||
return new BindablePropertyUpdateGenerated(prop, gen);
|
||||
} else {
|
||||
// An 'Insert Timestamp' is never updated
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return prop.isDbEncrypted() ? new BindableEncryptedProperty(prop, bindEncryptDataFirst) : new BindableProperty(prop);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,15 @@ public class FactoryVersion {
|
||||
*/
|
||||
public Bindable create(BeanDescriptor<?> desc) {
|
||||
|
||||
BeanProperty versionProperty = desc.getVersionProperty();
|
||||
return (versionProperty == null) ? null : new BindablePropertyVersion(versionProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Bindable for the version property(s) for a bean type.
|
||||
*/
|
||||
public Bindable createForDelete(BeanDescriptor<?> desc) {
|
||||
|
||||
BeanProperty versionProperty = desc.getVersionProperty();
|
||||
return (versionProperty == null) ? null : new BindableProperty(versionProperty);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* An object that represents a SqlSelect statement.
|
||||
@@ -561,16 +560,28 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
return collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update execution stats and check for slow query.
|
||||
*/
|
||||
void updateExecutionStatistics() {
|
||||
try {
|
||||
long exeNano = System.nanoTime() - startNano;
|
||||
executionTimeMicros = TimeUnit.NANOSECONDS.toMicros(exeNano);
|
||||
updateStatistics();
|
||||
request.slowQueryCheck(executionTimeMicros, rowCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update execution stats but skip slow query check as expected large query.
|
||||
*/
|
||||
void updateExecutionStatisticsIterator() {
|
||||
updateStatistics();
|
||||
}
|
||||
|
||||
private void updateStatistics() {
|
||||
try {
|
||||
executionTimeMicros = (System.nanoTime() - startNano) / 1000L;
|
||||
if (autoTuneProfiling) {
|
||||
profilingListener.collectQueryInfo(objectGraphNode, loadedBeanCount, executionTimeMicros);
|
||||
}
|
||||
queryPlan.executionTime(loadedBeanCount, executionTimeMicros, objectGraphNode);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error updating execution statistics", e);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.RawSql;
|
||||
import io.ebean.RawSql.ColumnMapping;
|
||||
import io.ebean.RawSql.ColumnMapping.Column;
|
||||
|
||||
@@ -50,7 +50,7 @@ class CQueryFetchSingleAttribute {
|
||||
|
||||
private String bindLog;
|
||||
|
||||
private int executionTimeMicros;
|
||||
private long executionTimeMicros;
|
||||
|
||||
private int rowCount;
|
||||
|
||||
@@ -91,20 +91,17 @@ class CQueryFetchSingleAttribute {
|
||||
|
||||
long startNano = System.nanoTime();
|
||||
try {
|
||||
|
||||
prepareExecute();
|
||||
|
||||
List<Object> result = new ArrayList<>();
|
||||
|
||||
while (dataReader.next()) {
|
||||
result.add(scalarType.read(dataReader));
|
||||
dataReader.resetColumnPosition();
|
||||
rowCount++;
|
||||
}
|
||||
|
||||
long exeNano = System.nanoTime() - startNano;
|
||||
executionTimeMicros = (int) exeNano / 1000;
|
||||
|
||||
executionTimeMicros = (System.nanoTime() - startNano) / 1000L;
|
||||
request.slowQueryCheck(executionTimeMicros, rowCount);
|
||||
return result;
|
||||
|
||||
} finally {
|
||||
|
||||
@@ -38,7 +38,7 @@ class CQueryIteratorSimple<T> implements QueryIterator<T> {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
cquery.updateExecutionStatistics();
|
||||
cquery.updateExecutionStatisticsIterator();
|
||||
cquery.close();
|
||||
request.endTransIfRequired();
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ class CQueryIteratorWithBuffer<T> implements QueryIterator<T> {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
cquery.updateExecutionStatistics();
|
||||
cquery.updateExecutionStatisticsIterator();
|
||||
cquery.close();
|
||||
request.endTransIfRequired();
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ class CQueryRowCount {
|
||||
|
||||
private String bindLog;
|
||||
|
||||
private int executionTimeMicros;
|
||||
private long executionTimeMicros;
|
||||
|
||||
private int rowCount;
|
||||
|
||||
@@ -99,7 +99,6 @@ class CQueryRowCount {
|
||||
|
||||
long startNano = System.nanoTime();
|
||||
try {
|
||||
|
||||
SpiTransaction t = request.getTransaction();
|
||||
Connection conn = t.getInternalConnection();
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
@@ -110,16 +109,14 @@ class CQueryRowCount {
|
||||
|
||||
bindLog = predicates.bind(pstmt, conn);
|
||||
rset = pstmt.executeQuery();
|
||||
|
||||
if (!rset.next()) {
|
||||
throw new PersistenceException("Expecting 1 row but got none?");
|
||||
}
|
||||
|
||||
rowCount = rset.getInt(1);
|
||||
|
||||
long exeNano = System.nanoTime() - startNano;
|
||||
executionTimeMicros = (int) exeNano / 1000;
|
||||
|
||||
executionTimeMicros = (System.nanoTime() - startNano) / 1000L;
|
||||
request.slowQueryCheck(executionTimeMicros, rowCount);
|
||||
return rowCount;
|
||||
|
||||
} finally {
|
||||
|
||||
@@ -39,7 +39,7 @@ class CQueryUpdate {
|
||||
|
||||
private String bindLog;
|
||||
|
||||
private int executionTimeMicros;
|
||||
private long executionTimeMicros;
|
||||
|
||||
private int rowCount;
|
||||
|
||||
@@ -90,7 +90,6 @@ class CQueryUpdate {
|
||||
|
||||
long startNano = System.nanoTime();
|
||||
try {
|
||||
|
||||
SpiTransaction t = request.getTransaction();
|
||||
Connection conn = t.getInternalConnection();
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
@@ -102,9 +101,8 @@ class CQueryUpdate {
|
||||
bindLog = predicates.bind(pstmt, conn);
|
||||
rowCount = pstmt.executeUpdate();
|
||||
|
||||
long exeNano = System.nanoTime() - startNano;
|
||||
executionTimeMicros = (int) exeNano / 1000;
|
||||
|
||||
executionTimeMicros = (System.nanoTime() - startNano) / 1000L;
|
||||
request.slowQueryCheck(executionTimeMicros, rowCount);
|
||||
return rowCount;
|
||||
|
||||
} finally {
|
||||
|
||||
@@ -147,7 +147,7 @@ class SqlTreeNodeBean implements SqlTreeNode {
|
||||
return children[0].getSingleAttributeScalarType();
|
||||
}
|
||||
if (properties[0] instanceof BeanPropertyAssocOne<?>) {
|
||||
BeanPropertyAssocOne assocOne = (BeanPropertyAssocOne<?>)properties[0];
|
||||
BeanPropertyAssocOne<?> assocOne = (BeanPropertyAssocOne<?>)properties[0];
|
||||
if (assocOne.isAssocId()) {
|
||||
return assocOne.getTargetDescriptor().getIdProperty().getScalarType();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.ebeaninternal.server.querydefn;
|
||||
|
||||
import io.ebeaninternal.api.HashQueryPlanBuilder;
|
||||
import io.ebeaninternal.server.deploy.DeployParser;
|
||||
import io.ebeaninternal.server.persist.Binder;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
@@ -190,17 +189,4 @@ public class OrmUpdateProperties {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a logical set clause to use for isSameByPlan() use.
|
||||
*/
|
||||
private String logicalSetClause() {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, Value> entry : values.entrySet()) {
|
||||
sb.append(", ");
|
||||
sb.append(entry.getKey()).append(entry.getValue().bindClause());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
package io.ebeaninternal.server.text.json;
|
||||
|
||||
import io.ebean.FetchPath;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.config.JsonConfig;
|
||||
import io.ebean.plugin.BeanType;
|
||||
import io.ebean.text.json.EJson;
|
||||
import io.ebean.text.json.JsonContext;
|
||||
import io.ebean.text.json.JsonIOException;
|
||||
import io.ebean.text.json.JsonReadOptions;
|
||||
import io.ebean.text.json.JsonWriteBeanVisitor;
|
||||
import io.ebean.text.json.JsonWriteOptions;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.type.TypeManager;
|
||||
import io.ebeaninternal.util.ParamTypeHelper;
|
||||
import io.ebeaninternal.util.ParamTypeHelper.ManyType;
|
||||
import io.ebeaninternal.util.ParamTypeHelper.TypeInfo;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import io.ebean.FetchPath;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.config.JsonConfig;
|
||||
import io.ebean.plugin.BeanType;
|
||||
import io.ebean.text.json.EJson;
|
||||
import io.ebean.text.json.JsonIOException;
|
||||
import io.ebean.text.json.JsonReadOptions;
|
||||
import io.ebean.text.json.JsonWriteBeanVisitor;
|
||||
import io.ebean.text.json.JsonWriteOptions;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiJsonContext;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.type.TypeManager;
|
||||
import io.ebeaninternal.util.ParamTypeHelper;
|
||||
import io.ebeaninternal.util.ParamTypeHelper.ManyType;
|
||||
import io.ebeaninternal.util.ParamTypeHelper.TypeInfo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
@@ -39,7 +39,7 @@ import java.util.Set;
|
||||
/**
|
||||
* Default implementation of JsonContext.
|
||||
*/
|
||||
public class DJsonContext implements JsonContext {
|
||||
public class DJsonContext implements SpiJsonContext {
|
||||
|
||||
private final SpiEbeanServer server;
|
||||
|
||||
@@ -179,7 +179,7 @@ public class DJsonContext implements JsonContext {
|
||||
if (currentToken != JsonToken.START_ARRAY) {
|
||||
JsonToken event = src.nextToken();
|
||||
if (event != JsonToken.START_ARRAY) {
|
||||
throw new JsonParseException("Expecting start_array event but got " + event, src.getCurrentLocation());
|
||||
throw new JsonParseException(src, "Expecting start_array event but got " + event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,9 +336,23 @@ public class DJsonContext implements JsonContext {
|
||||
BeanDescriptor<?> d = getDescriptor(value.getClass());
|
||||
WriteJson writeJson = createWriteJson(gen, options);
|
||||
d.jsonWrite(writeJson, (EntityBean) value, null);
|
||||
|
||||
} else {
|
||||
jsonScalar.write(gen, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiJsonWriter createJsonWriter(Writer writer) {
|
||||
JsonGenerator generator = createGenerator(writer);
|
||||
return createJsonWriter(generator, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiJsonWriter createJsonWriter(JsonGenerator gen, JsonWriteOptions options) {
|
||||
return createWriteJson(gen, options);
|
||||
}
|
||||
|
||||
private WriteJson createWriteJson(JsonGenerator gen, JsonWriteOptions options) {
|
||||
FetchPath pathProps = (options == null) ? null : options.getPathProperties();
|
||||
Map<String, JsonWriteBeanVisitor<?>> visitors = (options == null) ? null : options.getVisitorMap();
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package io.ebeaninternal.server.text.json;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.text.json.JsonWriter;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Internal API extensions for JSON writing of Bean properties.
|
||||
*/
|
||||
public interface SpiJsonWriter extends JsonWriter {
|
||||
|
||||
/**
|
||||
* Return true if the value is a parent bean.
|
||||
*/
|
||||
boolean isParentBean(Object value);
|
||||
|
||||
/**
|
||||
* Start an assoc one path.
|
||||
*/
|
||||
void beginAssocOne(String name, EntityBean bean);
|
||||
|
||||
/**
|
||||
* End an assoc one path.
|
||||
*/
|
||||
void endAssocOne();
|
||||
|
||||
/**
|
||||
* Return true if the many property should be included.
|
||||
*/
|
||||
Boolean includeMany(String name);
|
||||
|
||||
/**
|
||||
* Push the parent bean of a ToMany.
|
||||
*/
|
||||
void pushParentBeanMany(EntityBean bean);
|
||||
|
||||
/**
|
||||
* Pop the parent of a ToMany.
|
||||
*/
|
||||
void popParentBeanMany();
|
||||
|
||||
/**
|
||||
* Write the collection.
|
||||
*/
|
||||
void toJson(String name, Collection<?> collection);
|
||||
|
||||
/**
|
||||
* Start a Many.
|
||||
*/
|
||||
void beginAssocMany(String name);
|
||||
|
||||
/**
|
||||
* End a Many.
|
||||
*/
|
||||
void endAssocMany();
|
||||
|
||||
/**
|
||||
* Write value using underlying Jaskson object mapper if available.
|
||||
*/
|
||||
void writeValueUsingObjectMapper(String name, Object value);
|
||||
|
||||
/**
|
||||
* Write the bean properties.
|
||||
*/
|
||||
<T> void writeBean(BeanDescriptor<T> desc, EntityBean bean);
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
package io.ebeaninternal.server.text.json;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.ebean.FetchPath;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.config.JsonConfig;
|
||||
import io.ebean.text.json.EJson;
|
||||
import io.ebean.text.json.JsonIOException;
|
||||
import io.ebean.text.json.JsonWriteBeanVisitor;
|
||||
import io.ebean.text.json.JsonWriter;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.util.ArrayStack;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -21,7 +20,7 @@ import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class WriteJson implements JsonWriter {
|
||||
public class WriteJson implements SpiJsonWriter {
|
||||
|
||||
private final SpiEbeanServer server;
|
||||
|
||||
@@ -347,7 +346,7 @@ public class WriteJson implements JsonWriter {
|
||||
return !parentBeans.isEmpty() && parentBeans.contains(bean);
|
||||
}
|
||||
|
||||
public void pushParentBeanMany(Object parentBean) {
|
||||
public void pushParentBeanMany(EntityBean parentBean) {
|
||||
parentBeans.push(parentBean);
|
||||
}
|
||||
|
||||
@@ -355,7 +354,7 @@ public class WriteJson implements JsonWriter {
|
||||
parentBeans.pop();
|
||||
}
|
||||
|
||||
public void beginAssocOne(String key, Object bean) {
|
||||
public void beginAssocOne(String key, EntityBean bean) {
|
||||
parentBeans.push(bean);
|
||||
pathStack.pushPathKey(key);
|
||||
}
|
||||
@@ -384,10 +383,15 @@ public class WriteJson implements JsonWriter {
|
||||
}
|
||||
}
|
||||
|
||||
public WriteBean createWriteBean(BeanDescriptor<?> desc, EntityBean bean) {
|
||||
@Override
|
||||
public <T> void writeBean(BeanDescriptor<T> desc, EntityBean bean) {
|
||||
createWriteBean(desc, bean).write(this);
|
||||
}
|
||||
|
||||
private <T> WriteBean createWriteBean(BeanDescriptor<T> desc, EntityBean bean) {
|
||||
|
||||
String path = pathStack.peekWithNull();
|
||||
JsonWriteBeanVisitor visitor = (visitors == null) ? null : visitors.get(path);
|
||||
JsonWriteBeanVisitor<?> visitor = (visitors == null) ? null : visitors.get(path);
|
||||
if (fetchPath == null) {
|
||||
return new WriteBean(desc, bean, visitor);
|
||||
}
|
||||
@@ -407,10 +411,10 @@ public class WriteJson implements JsonWriter {
|
||||
|
||||
if (!isIncludeEmpty()) {
|
||||
// check for suppression of empty collection or map
|
||||
if (value instanceof Collection && ((Collection) value).isEmpty()) {
|
||||
if (value instanceof Collection && ((Collection<?>) value).isEmpty()) {
|
||||
// suppress empty collection
|
||||
return;
|
||||
} else if (value instanceof Map && ((Map) value).isEmpty()) {
|
||||
} else if (value instanceof Map && ((Map<?,?>) value).isEmpty()) {
|
||||
// suppress empty map
|
||||
return;
|
||||
}
|
||||
@@ -436,13 +440,15 @@ public class WriteJson implements JsonWriter {
|
||||
final Set<String> currentIncludeProps;
|
||||
final BeanDescriptor<?> desc;
|
||||
final EntityBean currentBean;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
final JsonWriteBeanVisitor visitor;
|
||||
|
||||
WriteBean(BeanDescriptor<?> desc, EntityBean currentBean, JsonWriteBeanVisitor visitor) {
|
||||
WriteBean(BeanDescriptor<?> desc, EntityBean currentBean, JsonWriteBeanVisitor<?> visitor) {
|
||||
this(desc, false, null, currentBean, visitor);
|
||||
}
|
||||
|
||||
WriteBean(BeanDescriptor<?> desc, boolean explicitAllProps, Set<String> currentIncludeProps, EntityBean currentBean, JsonWriteBeanVisitor visitor) {
|
||||
WriteBean(BeanDescriptor<?> desc, boolean explicitAllProps, Set<String> currentIncludeProps, EntityBean currentBean, JsonWriteBeanVisitor<?> visitor) {
|
||||
super();
|
||||
this.desc = desc;
|
||||
this.currentBean = currentBean;
|
||||
|
||||
@@ -3,7 +3,7 @@ package io.ebeaninternal.server.transaction;
|
||||
import io.ebean.TransactionCallback;
|
||||
import io.ebean.annotation.DocStoreMode;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.PersistBatch;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform.OnQueryOnly;
|
||||
import io.ebean.event.changelog.BeanChange;
|
||||
|
||||
@@ -2,7 +2,7 @@ package io.ebeaninternal.server.transaction;
|
||||
|
||||
import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.config.CurrentTenantProvider;
|
||||
import io.ebean.PersistBatch;
|
||||
import io.ebean.annotation.PersistBatch;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform.OnQueryOnly;
|
||||
import io.ebean.event.changelog.ChangeLogListener;
|
||||
|
||||
@@ -5,7 +5,7 @@ import io.ebean.annotation.DbEnumType;
|
||||
import io.ebean.annotation.DbEnumValue;
|
||||
import io.ebean.annotation.EnumValue;
|
||||
import io.ebean.config.JsonConfig;
|
||||
import io.ebean.Platform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.ScalarTypeConverter;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
@@ -239,8 +239,8 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
if (iterator.hasNext()) {
|
||||
// use the cacheFactory (via classpath service loader)
|
||||
ExtraTypeFactory plugin = iterator.next();
|
||||
List<? extends ScalarType> types = plugin.createTypes(config, objectMapper);
|
||||
for (ScalarType type : types) {
|
||||
List<? extends ScalarType<?>> types = plugin.createTypes(config, objectMapper);
|
||||
for (ScalarType<?> type : types) {
|
||||
logger.debug("adding ScalarType {}", type.getClass());
|
||||
addCustomType(type);
|
||||
}
|
||||
@@ -280,10 +280,10 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
}
|
||||
|
||||
private void logAdd(ScalarType<?> scalarType) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
String msg = "ScalarType register [" + scalarType.getClass().getName() + "]";
|
||||
msg += " for [" + scalarType.getType().getName() + "]";
|
||||
logger.debug(msg);
|
||||
logger.trace(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,13 +19,13 @@ import java.util.UUID;
|
||||
/**
|
||||
* Type mapped for DB ARRAY type (Postgres only effectively).
|
||||
*/
|
||||
public class ScalarTypeArraySet extends ScalarTypeJsonCollection<Set> implements ScalarTypeArray {
|
||||
public class ScalarTypeArraySet<T> extends ScalarTypeJsonCollection<Set<T>> implements ScalarTypeArray {
|
||||
|
||||
private static ScalarTypeArraySet UUID = new ScalarTypeArraySet("uuid", DocPropertyType.UUID, ArrayElementConverter.UUID);
|
||||
private static ScalarTypeArraySet LONG = new ScalarTypeArraySet("bigint", DocPropertyType.LONG, ArrayElementConverter.LONG);
|
||||
private static ScalarTypeArraySet INTEGER = new ScalarTypeArraySet("integer", DocPropertyType.INTEGER, ArrayElementConverter.INTEGER);
|
||||
private static ScalarTypeArraySet DOUBLE = new ScalarTypeArraySet("float", DocPropertyType.DOUBLE, ArrayElementConverter.DOUBLE);
|
||||
private static ScalarTypeArraySet STRING = new ScalarTypeArraySet("varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING);
|
||||
private static final ScalarTypeArraySet<UUID> UUID = new ScalarTypeArraySet<>("uuid", DocPropertyType.UUID, ArrayElementConverter.UUID);
|
||||
private static final ScalarTypeArraySet<Long> LONG = new ScalarTypeArraySet<>("bigint", DocPropertyType.LONG, ArrayElementConverter.LONG);
|
||||
private static final ScalarTypeArraySet<Integer> INTEGER = new ScalarTypeArraySet<>("integer", DocPropertyType.INTEGER, ArrayElementConverter.INTEGER);
|
||||
private static final ScalarTypeArraySet<Double> DOUBLE = new ScalarTypeArraySet<>("float", DocPropertyType.DOUBLE, ArrayElementConverter.DOUBLE);
|
||||
private static final ScalarTypeArraySet<String> STRING = new ScalarTypeArraySet<>("varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING);
|
||||
|
||||
static PlatformArrayTypeFactory factory() {
|
||||
return new Factory();
|
||||
@@ -37,7 +37,7 @@ public class ScalarTypeArraySet extends ScalarTypeJsonCollection<Set> implements
|
||||
* Return the ScalarType to use based on the List's generic parameter type.
|
||||
*/
|
||||
@Override
|
||||
public ScalarTypeArraySet typeFor(Type valueType) {
|
||||
public ScalarTypeArraySet<?> typeFor(Type valueType) {
|
||||
if (valueType.equals(UUID.class)) {
|
||||
return UUID;
|
||||
}
|
||||
@@ -59,10 +59,11 @@ public class ScalarTypeArraySet extends ScalarTypeJsonCollection<Set> implements
|
||||
|
||||
private final String arrayType;
|
||||
|
||||
private final ArrayElementConverter converter;
|
||||
private final ArrayElementConverter<T> converter;
|
||||
|
||||
public ScalarTypeArraySet(String arrayType, DocPropertyType docPropertyType, ArrayElementConverter converter) {
|
||||
super(Set.class, Types.ARRAY, docPropertyType);
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public ScalarTypeArraySet(String arrayType, DocPropertyType docPropertyType, ArrayElementConverter<T> converter) {
|
||||
super((Class)Set.class, Types.ARRAY, docPropertyType);
|
||||
this.arrayType = arrayType;
|
||||
this.converter = converter;
|
||||
}
|
||||
@@ -80,21 +81,20 @@ public class ScalarTypeArraySet extends ScalarTypeJsonCollection<Set> implements
|
||||
return arrayType + "[]";
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Set fromArray(Object[] array1) {
|
||||
Set set = new LinkedHashSet();
|
||||
private Set<T> fromArray(Object[] array1) {
|
||||
Set<T> set = new LinkedHashSet<>();
|
||||
for (Object element : array1) {
|
||||
set.add(converter.toElement(element));
|
||||
}
|
||||
return new ModifyAwareSet(set);
|
||||
return new ModifyAwareSet<>(set);
|
||||
}
|
||||
|
||||
protected Object[] toArray(Set value) {
|
||||
protected Object[] toArray(Set<T> value) {
|
||||
return value.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set read(DataReader reader) throws SQLException {
|
||||
public Set<T> read(DataReader reader) throws SQLException {
|
||||
Array array = reader.getArray();
|
||||
if (array == null) {
|
||||
return null;
|
||||
@@ -104,7 +104,7 @@ public class ScalarTypeArraySet extends ScalarTypeJsonCollection<Set> implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind bind, Set value) throws SQLException {
|
||||
public void bind(DataBind bind, Set<T> value) throws SQLException {
|
||||
if (value == null) {
|
||||
bind.setNull(Types.ARRAY);
|
||||
} else {
|
||||
@@ -113,7 +113,7 @@ public class ScalarTypeArraySet extends ScalarTypeJsonCollection<Set> implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatValue(Set value) {
|
||||
public String formatValue(Set<T> value) {
|
||||
try {
|
||||
return EJson.write(value);
|
||||
} catch (IOException e) {
|
||||
@@ -122,7 +122,7 @@ public class ScalarTypeArraySet extends ScalarTypeJsonCollection<Set> implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set parse(String value) {
|
||||
public Set<T> parse(String value) {
|
||||
try {
|
||||
return EJson.parseSet(value, false);
|
||||
} catch (IOException e) {
|
||||
@@ -131,12 +131,12 @@ public class ScalarTypeArraySet extends ScalarTypeJsonCollection<Set> implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set jsonRead(JsonParser parser) throws IOException {
|
||||
public Set<T> jsonRead(JsonParser parser) throws IOException {
|
||||
return EJson.parseSet(parser, parser.getCurrentToken());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator writer, Set value) throws IOException {
|
||||
public void jsonWrite(JsonGenerator writer, Set<T> value) throws IOException {
|
||||
EJson.write(value, writer);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,17 +6,17 @@ import java.lang.reflect.Type;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Set;
|
||||
|
||||
import java.util.UUID;
|
||||
/**
|
||||
* H2 database support for DB ARRAY.
|
||||
*/
|
||||
class ScalarTypeArraySetH2 extends ScalarTypeArraySet {
|
||||
class ScalarTypeArraySetH2<T> extends ScalarTypeArraySet<T> {
|
||||
|
||||
private static ScalarTypeArraySetH2 UUID = new ScalarTypeArraySetH2("uuid", DocPropertyType.UUID, ArrayElementConverter.UUID);
|
||||
private static ScalarTypeArraySetH2 LONG = new ScalarTypeArraySetH2("bigint", DocPropertyType.LONG, ArrayElementConverter.LONG);
|
||||
private static ScalarTypeArraySetH2 INTEGER = new ScalarTypeArraySetH2("integer", DocPropertyType.INTEGER, ArrayElementConverter.INTEGER);
|
||||
private static ScalarTypeArraySetH2 DOUBLE = new ScalarTypeArraySetH2("double", DocPropertyType.DOUBLE, ArrayElementConverter.DOUBLE);
|
||||
private static ScalarTypeArraySetH2 STRING = new ScalarTypeArraySetH2("varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING);
|
||||
private static final ScalarTypeArraySetH2<UUID> UUID = new ScalarTypeArraySetH2<>("uuid", DocPropertyType.UUID, ArrayElementConverter.UUID);
|
||||
private static final ScalarTypeArraySetH2<Long> LONG = new ScalarTypeArraySetH2<>("bigint", DocPropertyType.LONG, ArrayElementConverter.LONG);
|
||||
private static final ScalarTypeArraySetH2<Integer> INTEGER = new ScalarTypeArraySetH2<>("integer", DocPropertyType.INTEGER, ArrayElementConverter.INTEGER);
|
||||
private static final ScalarTypeArraySetH2<Double> DOUBLE = new ScalarTypeArraySetH2<>("double", DocPropertyType.DOUBLE, ArrayElementConverter.DOUBLE);
|
||||
private static final ScalarTypeArraySetH2<String> STRING = new ScalarTypeArraySetH2<>("varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING);
|
||||
|
||||
static PlatformArrayTypeFactory factory() {
|
||||
return new ScalarTypeArraySetH2.Factory();
|
||||
@@ -28,7 +28,7 @@ class ScalarTypeArraySetH2 extends ScalarTypeArraySet {
|
||||
* Return the ScalarType to use based on the List's generic parameter type.
|
||||
*/
|
||||
@Override
|
||||
public ScalarTypeArraySetH2 typeFor(Type valueType) {
|
||||
public ScalarTypeArraySetH2<?> typeFor(Type valueType) {
|
||||
if (valueType.equals(java.util.UUID.class)) {
|
||||
return UUID;
|
||||
}
|
||||
@@ -48,12 +48,12 @@ class ScalarTypeArraySetH2 extends ScalarTypeArraySet {
|
||||
}
|
||||
}
|
||||
|
||||
private ScalarTypeArraySetH2(String arrayType, DocPropertyType docPropertyType, ArrayElementConverter converter) {
|
||||
private ScalarTypeArraySetH2(String arrayType, DocPropertyType docPropertyType, ArrayElementConverter<T> converter) {
|
||||
super(arrayType, docPropertyType, converter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(DataBind bind, Set value) throws SQLException {
|
||||
public void bind(DataBind bind, Set<T> value) throws SQLException {
|
||||
if (value == null) {
|
||||
bind.setNull(Types.ARRAY);
|
||||
} else {
|
||||
|
||||
@@ -17,6 +17,7 @@ public interface TypeManager {
|
||||
/**
|
||||
* Register a ScalarType for an Enum with can have multiple classes.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
void addEnumType(ScalarType<?> type, Class<? extends Enum> myEnumClass);
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.util.StringHelper;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import org.tests.model.basic.Country;
|
||||
import org.avaje.agentloader.AgentLoader;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
public class BaseTestCase {
|
||||
@RunWith(ConditionalTestRunner.class)
|
||||
public abstract class BaseTestCase {
|
||||
|
||||
protected static Logger logger = LoggerFactory.getLogger(BaseTestCase.class);
|
||||
|
||||
@@ -75,6 +78,10 @@ public class BaseTestCase {
|
||||
return Platform.ORACLE == platform();
|
||||
}
|
||||
|
||||
public boolean isDb2() {
|
||||
return Platform.DB2 == platform();
|
||||
}
|
||||
|
||||
public boolean isPostgres() {
|
||||
return Platform.POSTGRES == platform();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.annotation.ForPlatform;
|
||||
import io.ebean.annotation.IgnorePlatform;
|
||||
import io.ebean.annotation.Platform;
|
||||
import org.junit.runner.notification.RunNotifier;
|
||||
import org.junit.runners.BlockJUnit4ClassRunner;
|
||||
import org.junit.runners.model.FrameworkMethod;
|
||||
import org.junit.runners.model.InitializationError;
|
||||
|
||||
/**
|
||||
* This testrunner checks for an {@link IgnorePlatform} annotation and ignores the test.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*/
|
||||
public class ConditionalTestRunner extends BlockJUnit4ClassRunner {
|
||||
public ConditionalTestRunner(Class<?> klass) throws InitializationError {
|
||||
super(klass);
|
||||
}
|
||||
@Override
|
||||
public void runChild(FrameworkMethod method, RunNotifier notifier) {
|
||||
ForPlatform forPlatform = method.getAnnotation(ForPlatform.class);
|
||||
if (forPlatform != null) {
|
||||
if (!platformMath(forPlatform.value())) {
|
||||
notifier.fireTestIgnored(describeChild(method));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
IgnorePlatform ignore = method.getAnnotation(IgnorePlatform.class);
|
||||
|
||||
if (ignore == null || !platformMath(ignore.value())) {
|
||||
super.runChild(method, notifier);
|
||||
} else {
|
||||
notifier.fireTestIgnored(describeChild(method));
|
||||
}
|
||||
|
||||
}
|
||||
private boolean platformMath(Platform[] platforms) {
|
||||
Platform current = Ebean.getDefaultServer().getPluginApi().getDatabasePlatform().getPlatform();
|
||||
for (Platform p : platforms) {
|
||||
if (p.equals(current)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user