mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
30
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c18d1fa288 | ||
|
|
5287d93a58 | ||
|
|
6e6055fb84 | ||
|
|
c2ea8b3d56 | ||
|
|
5885d724c4 | ||
|
|
90d028640d | ||
|
|
b8d92f1846 | ||
|
|
e41d2eed7f | ||
|
|
8c7a84be9c | ||
|
|
63116f25ec | ||
|
|
eac05571c8 | ||
|
|
a6ad043142 | ||
|
|
bcc8040afe | ||
|
|
ee73fd47d5 | ||
|
|
064b3ceaa4 | ||
|
|
54ada6e07b | ||
|
|
14181932ec | ||
|
|
0faa6a8efd | ||
|
|
f94eb9b75e | ||
|
|
817436b00d | ||
|
|
a089a36f9d | ||
|
|
1f1868fdd3 | ||
|
|
8ac49e537d | ||
|
|
133cf95c6d | ||
|
|
2caf4bcccd | ||
|
|
e8f0e2f4bf | ||
|
|
8bde42fb16 | ||
|
|
2bb1e40c44 | ||
|
|
1ac1e19db0 | ||
|
|
85a0eb0afb |
+7
-6
@@ -1,17 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
<version>12.5.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ebean-api</artifactId>
|
||||
|
||||
<properties>
|
||||
<jackson-core.version>2.10.0</jackson-core.version>
|
||||
<jackson-databind.version>2.10.0</jackson-databind.version>
|
||||
<jackson-core.version>2.11.3</jackson-core.version>
|
||||
<jackson-databind.version>2.11.3</jackson-databind.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -30,7 +30,7 @@
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>avaje-config</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
@@ -65,7 +65,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-datasource</artifactId>
|
||||
<version>5.1</version>
|
||||
<version>6.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -79,6 +79,7 @@
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson-core.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope for JsonNode support -->
|
||||
|
||||
@@ -9,6 +9,7 @@ import javax.persistence.PersistenceException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Creates Database instances.
|
||||
@@ -30,6 +31,7 @@ import java.util.ServiceLoader;
|
||||
*/
|
||||
public class DatabaseFactory {
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock(false);
|
||||
private static SpiContainer container;
|
||||
|
||||
static {
|
||||
@@ -42,44 +44,63 @@ public class DatabaseFactory {
|
||||
* Call this prior to creating any Database instances or alternatively set the
|
||||
* ContainerConfig on the DatabaseConfig when creating the first Database instance.
|
||||
*/
|
||||
public static synchronized void initialiseContainer(ContainerConfig containerConfig) {
|
||||
getContainer(containerConfig);
|
||||
public static void initialiseContainer(ContainerConfig containerConfig) {
|
||||
lock.lock();
|
||||
try {
|
||||
getContainer(containerConfig);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using properties to configure the database.
|
||||
*/
|
||||
public static synchronized Database create(String name) {
|
||||
// construct based on loading properties files
|
||||
return getContainer(null).createServer(name);
|
||||
public static Database create(String name) {
|
||||
lock.lock();
|
||||
try {
|
||||
return getContainer(null).createServer(name);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using the DatabaseConfig object to configure the database.
|
||||
*/
|
||||
public static synchronized Database create(DatabaseConfig config) {
|
||||
if (config.getName() == null) {
|
||||
throw new PersistenceException("The name is null (it is required)");
|
||||
public static Database create(DatabaseConfig config) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (config.getName() == null) {
|
||||
throw new PersistenceException("The name is null (it is required)");
|
||||
}
|
||||
Database server = createInternal(config);
|
||||
if (config.isRegister()) {
|
||||
DbPrimary.setSkip(true);
|
||||
DbContext.getInstance().register(server, config.isDefaultServer());
|
||||
}
|
||||
return server;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
Database server = createInternal(config);
|
||||
if (config.isRegister()) {
|
||||
DbPrimary.setSkip(true);
|
||||
DbContext.getInstance().register(server, config.isDefaultServer());
|
||||
}
|
||||
return server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using the DatabaseConfig additionally specifying a classLoader to use as the context class loader.
|
||||
*/
|
||||
public static synchronized Database createWithContextClassLoader(DatabaseConfig config, ClassLoader classLoader) {
|
||||
ClassLoader currentContextLoader = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
public static Database createWithContextClassLoader(DatabaseConfig config, ClassLoader classLoader) {
|
||||
lock.lock();
|
||||
try {
|
||||
return DatabaseFactory.create(config);
|
||||
ClassLoader currentContextLoader = Thread.currentThread().getContextClassLoader();
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
try {
|
||||
return DatabaseFactory.create(config);
|
||||
} finally {
|
||||
// set the currentContextLoader back
|
||||
Thread.currentThread().setContextClassLoader(currentContextLoader);
|
||||
}
|
||||
} finally {
|
||||
// set the currentContextLoader back
|
||||
Thread.currentThread().setContextClassLoader(currentContextLoader);
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,8 +110,13 @@ public class DatabaseFactory {
|
||||
* This is typically invoked via JVM shutdown hook and not explicitly called.
|
||||
* </p>
|
||||
*/
|
||||
public static synchronized void shutdown() {
|
||||
container.shutdown();
|
||||
public static void shutdown() {
|
||||
lock.lock();
|
||||
try {
|
||||
container.shutdown();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private static Database createInternal(DatabaseConfig config) {
|
||||
@@ -103,8 +129,7 @@ public class DatabaseFactory {
|
||||
* @param containerConfig the configuration controlling clustering communication
|
||||
*/
|
||||
private static SpiContainer getContainer(ContainerConfig containerConfig) {
|
||||
|
||||
// thread safe in that all calling methods are synchronized
|
||||
// thread safe in that all calling methods hold lock
|
||||
if (container != null) {
|
||||
return container;
|
||||
}
|
||||
@@ -123,7 +148,6 @@ public class DatabaseFactory {
|
||||
* Create the container instance using the configuration.
|
||||
*/
|
||||
protected static SpiContainer createContainer(ContainerConfig containerConfig) {
|
||||
|
||||
Iterator<SpiContainerFactory> factories = ServiceLoader.load(SpiContainerFactory.class).iterator();
|
||||
if (factories.hasNext()) {
|
||||
return factories.next().create(containerConfig);
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory;
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Holds Database instances.
|
||||
@@ -22,17 +23,11 @@ final class DbContext {
|
||||
|
||||
private static final DbContext INSTANCE = new DbContext();
|
||||
|
||||
/**
|
||||
* Cache for fast concurrent read access.
|
||||
*/
|
||||
private final ConcurrentHashMap<String, Database> concMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Cache for synchronized read, creation and put. Protected by the monitor object.
|
||||
*/
|
||||
private final HashMap<String, Database> syncMap = new HashMap<>();
|
||||
|
||||
private final Object monitor = new Object();
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
/**
|
||||
* The 'default' Database.
|
||||
@@ -91,27 +86,28 @@ final class DbContext {
|
||||
if (name == null || name.isEmpty()) {
|
||||
return defaultDatabase;
|
||||
}
|
||||
// non-synchronized read
|
||||
Database server = concMap.get(name);
|
||||
if (server != null) {
|
||||
return server;
|
||||
}
|
||||
// synchronized read, create and put
|
||||
return getWithCreate(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronized read, create and put of Databases.
|
||||
* Read, create and put of Databases.
|
||||
*/
|
||||
private Database getWithCreate(String name) {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
Database server = syncMap.get(name);
|
||||
if (server == null) {
|
||||
// register when creating server this way
|
||||
server = EbeanServerFactory.create(name);
|
||||
server = DatabaseFactory.create(name);
|
||||
register(server, false);
|
||||
}
|
||||
return server;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,12 +119,15 @@ final class DbContext {
|
||||
}
|
||||
|
||||
private void registerWithName(String name, Database server, boolean isDefault) {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
concMap.put(name, server);
|
||||
syncMap.put(name, server);
|
||||
if (isDefault) {
|
||||
defaultDatabase = server;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebean;
|
||||
import io.avaje.config.Config;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Provides singleton state for the default database.
|
||||
@@ -11,47 +12,66 @@ import java.util.Properties;
|
||||
*/
|
||||
class DbPrimary {
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock(false);
|
||||
private static String defaultServerName;
|
||||
|
||||
private static boolean skip;
|
||||
|
||||
/**
|
||||
* Set whether to skip automatically creating the primary database.
|
||||
*/
|
||||
static synchronized void setSkip(boolean skip) {
|
||||
DbPrimary.skip = skip;
|
||||
static void setSkip(boolean skip) {
|
||||
lock.lock();
|
||||
try {
|
||||
DbPrimary.skip = skip;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true to skip automatically creating the primary database.
|
||||
*/
|
||||
static synchronized boolean isSkip() {
|
||||
return skip;
|
||||
static boolean isSkip() {
|
||||
lock.lock();
|
||||
try {
|
||||
return skip;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default database name.
|
||||
*/
|
||||
static synchronized String getDefaultServerName() {
|
||||
getProperties();
|
||||
return defaultServerName;
|
||||
static String getDefaultServerName() {
|
||||
lock.lock();
|
||||
try {
|
||||
getProperties();
|
||||
return defaultServerName;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default configuration Properties.
|
||||
*/
|
||||
static synchronized Properties getProperties() {
|
||||
if (defaultServerName == null) {
|
||||
defaultServerName = determineDefaultServerName();
|
||||
static Properties getProperties() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (defaultServerName == null) {
|
||||
defaultServerName = determineDefaultServerName();
|
||||
}
|
||||
return Config.asProperties();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return Config.asProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine and return the default server name checking system environment variables and then global properties.
|
||||
*/
|
||||
private static String determineDefaultServerName() {
|
||||
|
||||
String defaultServerName = System.getenv("EBEAN_DB");
|
||||
defaultServerName = System.getProperty("db", defaultServerName);
|
||||
defaultServerName = System.getProperty("ebean_db", defaultServerName);
|
||||
|
||||
@@ -39,28 +39,28 @@ public class EbeanServerFactory {
|
||||
* Call this prior to creating any EbeanServer instances or alternatively set the
|
||||
* ContainerConfig on the ServerConfig when creating the first EbeanServer instance.
|
||||
*/
|
||||
public static synchronized void initialiseContainer(ContainerConfig containerConfig) {
|
||||
public static void initialiseContainer(ContainerConfig containerConfig) {
|
||||
DatabaseFactory.initialiseContainer(containerConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using ebean.properties to configure the database.
|
||||
*/
|
||||
public static synchronized EbeanServer create(String name) {
|
||||
public static EbeanServer create(String name) {
|
||||
return (EbeanServer)DatabaseFactory.create(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using the ServerConfig object to configure the database.
|
||||
*/
|
||||
public static synchronized EbeanServer create(ServerConfig config) {
|
||||
public static EbeanServer create(ServerConfig config) {
|
||||
return (EbeanServer)DatabaseFactory.create(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using the ServerConfig additionally specifying a classLoader to use as the context class loader.
|
||||
*/
|
||||
public static synchronized EbeanServer createWithContextClassLoader(ServerConfig config, ClassLoader classLoader) {
|
||||
public static EbeanServer createWithContextClassLoader(ServerConfig config, ClassLoader classLoader) {
|
||||
return (EbeanServer)DatabaseFactory.createWithContextClassLoader(config, classLoader);
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public class EbeanServerFactory {
|
||||
* This is typically invoked via JVM shutdown hook and not explicitly called.
|
||||
* </p>
|
||||
*/
|
||||
public static synchronized void shutdown() {
|
||||
public static void shutdown() {
|
||||
DatabaseFactory.shutdown();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.ebean.bean;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
/**
|
||||
* Loads a entity bean.
|
||||
* <p>
|
||||
@@ -18,4 +20,9 @@ public interface BeanLoader {
|
||||
*/
|
||||
void loadBean(EntityBeanIntercept ebi);
|
||||
|
||||
/**
|
||||
* Obtain a lock on the loader.
|
||||
*/
|
||||
Lock lock();
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* This is the object added to every entity bean using byte code enhancement.
|
||||
@@ -30,6 +32,8 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
private static final int STATE_REFERENCE = 1;
|
||||
private static final int STATE_LOADED = 2;
|
||||
|
||||
private transient final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private transient NodeUsageCollector nodeUsageCollector;
|
||||
|
||||
private transient PersistenceContext persistenceContext;
|
||||
@@ -803,7 +807,8 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
* Load the bean when it is a reference.
|
||||
*/
|
||||
protected void loadBean(int loadProperty) {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (beanLoader == null) {
|
||||
final Database database = DB.byName(ebeanServerName);
|
||||
if (database == null) {
|
||||
@@ -811,14 +816,19 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
// For stand alone reference bean or after deserialisation lazy load
|
||||
// using the ebeanServer. Synchronise only on the bean.
|
||||
loadBeanInternal(loadProperty, database.getPluginApi());
|
||||
loadBeanInternal(loadProperty, database.getPluginApi().beanLoader());
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
synchronized (beanLoader) {
|
||||
final Lock lock = beanLoader.lock();
|
||||
try {
|
||||
// Lazy loading using LoadBeanContext which supports batch loading
|
||||
// Synchronise on the beanLoader (a 'node' of the LoadBeanContext 'tree')
|
||||
loadBeanInternal(loadProperty, beanLoader);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,16 @@ package io.ebean.bean;
|
||||
|
||||
import io.ebean.Database;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* BeanLoader used when single beans are loaded (which is usually not ideal / N+1).
|
||||
*/
|
||||
public abstract class SingleBeanLoader implements BeanLoader {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
protected final Database database;
|
||||
|
||||
SingleBeanLoader(Database database) {
|
||||
@@ -18,6 +23,12 @@ public abstract class SingleBeanLoader implements BeanLoader {
|
||||
return database.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lock lock() {
|
||||
lock.lock();
|
||||
return lock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Single bean lazy loaded when bean from L2 cache.
|
||||
*/
|
||||
@@ -45,4 +56,18 @@ public abstract class SingleBeanLoader implements BeanLoader {
|
||||
database.getPluginApi().loadBeanRef(ebi);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Single bean lazy loaded when a reference bean.
|
||||
*/
|
||||
public static class Dflt extends SingleBeanLoader {
|
||||
public Dflt(Database database) {
|
||||
super(database);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
database.getPluginApi().loadBean(ebi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import io.ebean.bean.BeanCollectionLoader;
|
||||
import io.ebean.bean.EntityBean;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Base class for List Set and Map implementations of BeanCollection.
|
||||
@@ -15,6 +16,8 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
private static final long serialVersionUID = 3365725236140187588L;
|
||||
|
||||
protected final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
protected boolean readOnly;
|
||||
|
||||
protected boolean disableLazyLoad;
|
||||
|
||||
@@ -115,7 +115,8 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
}
|
||||
|
||||
private void initClear() {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (list == null) {
|
||||
if (!disableLazyLoad && modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
@@ -123,11 +124,14 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (list == null) {
|
||||
if (disableLazyLoad) {
|
||||
list = new ArrayList<>();
|
||||
@@ -135,6 +139,8 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,8 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
}
|
||||
|
||||
private void initClear() {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (map == null) {
|
||||
if (!disableLazyLoad && modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
@@ -129,11 +130,14 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
map = new LinkedHashMap<>();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (map == null) {
|
||||
if (disableLazyLoad) {
|
||||
map = new LinkedHashMap<>();
|
||||
@@ -141,6 +145,8 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
lazyLoadCollection(false);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,8 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
}
|
||||
|
||||
private void initClear() {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (set == null) {
|
||||
if (!disableLazyLoad && modifyListening) {
|
||||
lazyLoadCollection(true);
|
||||
@@ -122,11 +123,14 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
set = new LinkedHashSet<>();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (set == null) {
|
||||
if (disableLazyLoad) {
|
||||
set = new LinkedHashSet<>();
|
||||
@@ -134,6 +138,8 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
lazyLoadCollection(true);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,25 +6,27 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
/**
|
||||
* List that copies itself on first write access. Needed to keep memory footprint low and the ability
|
||||
* to modify lists from cache.
|
||||
*
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*/
|
||||
public final class CopyOnFirstWriteList<E> extends AbstractList<E> implements List<E>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
/**
|
||||
* The underlying List implementation.
|
||||
*/
|
||||
private List<E> list;
|
||||
|
||||
|
||||
|
||||
public CopyOnFirstWriteList(List<E> list) {
|
||||
super();
|
||||
this.list = list;
|
||||
@@ -166,14 +168,17 @@ public final class CopyOnFirstWriteList<E> extends AbstractList<E> implements Li
|
||||
public int lastIndexOf(Object o) {
|
||||
return list.lastIndexOf(o);
|
||||
}
|
||||
|
||||
|
||||
private void checkCopyOnWrite() {
|
||||
if (!copied) {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (!copied) {
|
||||
list = new ArrayList<>(list);
|
||||
copied = true;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,10 @@ public class ClassLoadConfig {
|
||||
return isPresent("com.fasterxml.jackson.annotation.JsonIgnore");
|
||||
}
|
||||
|
||||
public boolean isJacksonCorePresent() {
|
||||
return isPresent("com.fasterxml.jackson.core.JsonParser");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Jackson ObjectMapper is present.
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Database sequence based IdGenerator.
|
||||
@@ -24,15 +25,9 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger("io.ebean.SEQ");
|
||||
|
||||
/**
|
||||
* Used to synchronise the idList access.
|
||||
*/
|
||||
protected final Object monitor = new Object();
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
/**
|
||||
* Used to synchronise background loading (loadBatchInBackground).
|
||||
*/
|
||||
protected final Object backgroundLoadMonitor = new Object();
|
||||
private final ReentrantLock loadLock = new ReentrantLock(false);
|
||||
|
||||
/**
|
||||
* The actual sequence name.
|
||||
@@ -97,7 +92,8 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
*/
|
||||
@Override
|
||||
public Object nextId(Transaction t) {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
int size = idList.size();
|
||||
if (size > 0) {
|
||||
maybeLoadMoreInBackground(size);
|
||||
@@ -105,6 +101,8 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
loadMore(allocationSize);
|
||||
}
|
||||
return idList.pollFirst();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,8 +116,11 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
|
||||
private void loadMore(int requestSize) {
|
||||
List<Long> newIds = getMoreIds(requestSize);
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
idList.addAll(newIds);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,23 +128,26 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
* Load another batch of Id's using a background thread.
|
||||
*/
|
||||
protected void loadInBackground(final int requestSize) {
|
||||
|
||||
// single threaded processing...
|
||||
synchronized (backgroundLoadMonitor) {
|
||||
loadLock.lock();
|
||||
try {
|
||||
if (currentlyBackgroundLoading) {
|
||||
// skip as already background loading
|
||||
logger.debug("... skip background sequence load (another load in progress)");
|
||||
return;
|
||||
}
|
||||
|
||||
currentlyBackgroundLoading = true;
|
||||
|
||||
backgroundExecutor.execute(() -> {
|
||||
loadMore(requestSize);
|
||||
synchronized (backgroundLoadMonitor) {
|
||||
loadLock.lock();
|
||||
try {
|
||||
currentlyBackgroundLoading = false;
|
||||
} finally {
|
||||
loadLock.unlock();
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
loadLock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Manages the shutdown of the JVM Runtime.
|
||||
@@ -22,6 +23,8 @@ public final class ShutdownManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ShutdownManager.class);
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private static final List<Database> databases = new ArrayList<>();
|
||||
|
||||
private static final ShutdownHook shutdownHook = new ShutdownHook();
|
||||
@@ -56,9 +59,11 @@ public final class ShutdownManager {
|
||||
* Return true if the system is in the process of stopping.
|
||||
*/
|
||||
public static boolean isStopping() {
|
||||
//noinspection SynchronizationOnStaticField
|
||||
synchronized (databases) {
|
||||
lock.lock();
|
||||
try {
|
||||
return stopping;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,15 +79,15 @@ public final class ShutdownManager {
|
||||
* </p>
|
||||
*/
|
||||
public static void deregisterShutdownHook() {
|
||||
//noinspection SynchronizationOnStaticField
|
||||
synchronized (databases) {
|
||||
try {
|
||||
Runtime.getRuntime().removeShutdownHook(shutdownHook);
|
||||
} catch (IllegalStateException ex) {
|
||||
if (!ex.getMessage().equals("Shutdown in progress")) {
|
||||
throw ex;
|
||||
}
|
||||
lock.lock();
|
||||
try {
|
||||
Runtime.getRuntime().removeShutdownHook(shutdownHook);
|
||||
} catch (IllegalStateException ex) {
|
||||
if (!ex.getMessage().equals("Shutdown in progress")) {
|
||||
throw ex;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,18 +95,18 @@ public final class ShutdownManager {
|
||||
* Register the shutdown hook with the Runtime.
|
||||
*/
|
||||
protected static void registerShutdownHook() {
|
||||
//noinspection SynchronizationOnStaticField
|
||||
synchronized (databases) {
|
||||
try {
|
||||
String value = System.getProperty("ebean.registerShutdownHook");
|
||||
if (value == null || !value.trim().equalsIgnoreCase("false")) {
|
||||
Runtime.getRuntime().addShutdownHook(shutdownHook);
|
||||
}
|
||||
} catch (IllegalStateException ex) {
|
||||
if (!ex.getMessage().equals("Shutdown in progress")) {
|
||||
throw ex;
|
||||
}
|
||||
lock.lock();
|
||||
try {
|
||||
String value = System.getProperty("ebean.registerShutdownHook");
|
||||
if (value == null || !value.trim().equalsIgnoreCase("false")) {
|
||||
Runtime.getRuntime().addShutdownHook(shutdownHook);
|
||||
}
|
||||
} catch (IllegalStateException ex) {
|
||||
if (!ex.getMessage().equals("Shutdown in progress")) {
|
||||
throw ex;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,8 +117,8 @@ public final class ShutdownManager {
|
||||
* </p>
|
||||
*/
|
||||
public static void shutdown() {
|
||||
//noinspection SynchronizationOnStaticField
|
||||
synchronized (databases) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (stopping) {
|
||||
// Already run shutdown...
|
||||
return;
|
||||
@@ -157,6 +162,8 @@ public final class ShutdownManager {
|
||||
if ("true".equalsIgnoreCase(System.getProperty("ebean.datasource.deregisterAllDrivers", "false"))) {
|
||||
deregisterAllJdbcDrivers();
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,9 +185,11 @@ public final class ShutdownManager {
|
||||
* Register an ebeanServer to be shutdown when the JVM is shutdown.
|
||||
*/
|
||||
public static void registerDatabase(Database server) {
|
||||
//noinspection SynchronizationOnStaticField
|
||||
synchronized (databases) {
|
||||
lock.lock();
|
||||
try {
|
||||
databases.add(server);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,9 +200,11 @@ public final class ShutdownManager {
|
||||
* </p>
|
||||
*/
|
||||
public static void unregisterDatabase(Database server) {
|
||||
//noinspection SynchronizationOnStaticField
|
||||
synchronized (databases) {
|
||||
lock.lock();
|
||||
try {
|
||||
databases.remove(server);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.util.List;
|
||||
/**
|
||||
* Extensions to Database API made available to plugins.
|
||||
*/
|
||||
public interface SpiServer extends EbeanServer, BeanLoader {
|
||||
public interface SpiServer extends EbeanServer {
|
||||
|
||||
/**
|
||||
* Return the DatabaseConfig.
|
||||
@@ -54,6 +54,11 @@ public interface SpiServer extends EbeanServer, BeanLoader {
|
||||
*/
|
||||
DataSource getReadOnlyDataSource();
|
||||
|
||||
/**
|
||||
* Return a BeanLoader.
|
||||
*/
|
||||
BeanLoader beanLoader();
|
||||
|
||||
/**
|
||||
* Invoke lazy loading on this single bean (reference bean).
|
||||
*/
|
||||
|
||||
+20
-7
@@ -1,20 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<!-- <parent>-->
|
||||
<!-- <artifactId>ebean-parent</artifactId>-->
|
||||
<!-- <groupId>io.ebean</groupId>-->
|
||||
<!-- <version>12.5.2-SNAPSHOT</version>-->
|
||||
<!-- </parent>-->
|
||||
<parent>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>java8-oss</artifactId>
|
||||
<version>2.2</version>
|
||||
</parent>
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
|
||||
<artifactId>ebean-autotune</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.2-SNAPSHOT</version>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<version>12.5.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- needed for java 11+ -->
|
||||
@@ -39,7 +52,7 @@
|
||||
<plugin>
|
||||
<groupId>io.repaint.maven</groupId>
|
||||
<artifactId>tiles-maven-plugin</artifactId>
|
||||
<version>2.17</version>
|
||||
<version>2.18</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<tiles>
|
||||
|
||||
+11
-4
@@ -14,6 +14,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Implementation of the AutoTuneService which is comprised of profiling and query tuning.
|
||||
@@ -22,6 +23,8 @@ public class DefaultAutoTuneService implements AutoTuneService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultAutoTuneService.class);
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private final SpiEbeanServer server;
|
||||
|
||||
private final long defaultGarbageCollectionWait;
|
||||
@@ -127,8 +130,8 @@ public class DefaultAutoTuneService implements AutoTuneService {
|
||||
* Collect profiling, check for new/diff to existing tuning and apply changes.
|
||||
*/
|
||||
private void runtimeTuningUpdate() {
|
||||
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
try {
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
@@ -150,12 +153,14 @@ public class DefaultAutoTuneService implements AutoTuneService {
|
||||
} catch (Throwable e) {
|
||||
logger.error("Error collecting or applying automatic query tuning", e);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void saveProfilingOnShutdown(boolean reset) {
|
||||
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (isRuntimeTuningUpdates()) {
|
||||
runtimeTuningUpdate();
|
||||
outputAllTuning();
|
||||
@@ -174,6 +179,8 @@ public class DefaultAutoTuneService implements AutoTuneService {
|
||||
logger.info("writing new:{} diff:{} profiling entries for server:{}", event.getNewCount(), event.getDiffCount(), serverName);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-3
@@ -11,12 +11,15 @@ import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Manages the collection of object graph usage profiling.
|
||||
*/
|
||||
public class ProfileManager implements ProfilingListener {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private final boolean queryTuningAddVersion;
|
||||
|
||||
/**
|
||||
@@ -32,8 +35,6 @@ public class ProfileManager implements ProfilingListener {
|
||||
*/
|
||||
private final Map<String, ProfileOrigin> profileMap = new ConcurrentHashMap<>();
|
||||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final SpiEbeanServer server;
|
||||
|
||||
public ProfileManager(AutoTuneConfig config, SpiEbeanServer server) {
|
||||
@@ -101,8 +102,11 @@ public class ProfileManager implements ProfilingListener {
|
||||
}
|
||||
|
||||
private ProfileOrigin getProfileOrigin(ObjectGraphOrigin originQueryPoint) {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
return profileMap.computeIfAbsent(originQueryPoint.getKey(), k -> new ProfileOrigin(originQueryPoint, queryTuningAddVersion, profilingBase, profilingRate));
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-6
@@ -12,9 +12,12 @@ import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class ProfileOrigin {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private static final long RESET_COUNT = -1000000000L;
|
||||
|
||||
private final ObjectGraphOrigin origin;
|
||||
@@ -29,8 +32,6 @@ public class ProfileOrigin {
|
||||
|
||||
private final Map<String, ProfileOriginNodeUsage> nodeUsageMap = new ConcurrentHashMap<>();
|
||||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final AtomicLong requestCount = new AtomicLong();
|
||||
|
||||
private final AtomicLong profileCount = new AtomicLong();
|
||||
@@ -74,8 +75,8 @@ public class ProfileOrigin {
|
||||
* Collect profiling information with the option to reset the underlying profiling detail.
|
||||
*/
|
||||
public void profilingCollection(BeanDescriptor<?> rootDesc, AutoTuneCollection req, boolean reset) {
|
||||
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (nodeUsageMap.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -94,6 +95,8 @@ public class ProfileOrigin {
|
||||
profileCount.set(0);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,8 +158,8 @@ public class ProfileOrigin {
|
||||
}
|
||||
|
||||
private ProfileOriginNodeUsage getNodeStats(String path) {
|
||||
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
// handle null paths as using ConcurrentHashMap
|
||||
path = (path == null) ? "" : path;
|
||||
ProfileOriginNodeUsage nodeStats = nodeUsageMap.get(path);
|
||||
@@ -165,6 +168,8 @@ public class ProfileOrigin {
|
||||
nodeUsageMap.put(path, nodeStats);
|
||||
}
|
||||
return nodeStats;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-7
@@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Collects usages statistics for a given node in the object graph.
|
||||
@@ -20,7 +21,7 @@ public class ProfileOriginNodeUsage {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProfileOriginNodeUsage.class);
|
||||
|
||||
private final Object monitor = new Object();
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private final String path;
|
||||
|
||||
@@ -38,9 +39,8 @@ public class ProfileOriginNodeUsage {
|
||||
}
|
||||
|
||||
protected void buildTunedFetch(PathProperties pathProps, BeanDescriptor<?> rootDesc, boolean addVersionProperty) {
|
||||
|
||||
synchronized (monitor) {
|
||||
|
||||
lock.lock();
|
||||
try {
|
||||
BeanDescriptor<?> desc = rootDesc;
|
||||
if (path != null) {
|
||||
ElPropertyValue elGetValue = rootDesc.getElGetValue(path);
|
||||
@@ -95,6 +95,8 @@ public class ProfileOriginNodeUsage {
|
||||
ElPropertyValue assocOne = rootDesc.getElGetValue(path);
|
||||
pathProps.addToPath(SplitName.parent(path), assocOne.getName());
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,9 +104,8 @@ public class ProfileOriginNodeUsage {
|
||||
* Collect usage from a node.
|
||||
*/
|
||||
protected void collectUsageInfo(NodeUsageCollector profile) {
|
||||
|
||||
synchronized (monitor) {
|
||||
|
||||
lock.lock();
|
||||
try {
|
||||
Set<String> used = profile.getUsed();
|
||||
|
||||
profileCount++;
|
||||
@@ -115,6 +116,8 @@ public class ProfileOriginNodeUsage {
|
||||
if (profile.isModified()) {
|
||||
modified = true;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
<version>12.5.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ebean-bom</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
+4
-10
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
<version>12.5.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core</artifactId>
|
||||
@@ -18,8 +18,8 @@
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<jackson-core.version>2.10.0</jackson-core.version>
|
||||
<jackson-databind.version>2.10.0</jackson-databind.version>
|
||||
<jackson-core.version>2.11.3</jackson-core.version>
|
||||
<jackson-databind.version>2.11.3</jackson-databind.version>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
@@ -91,12 +91,6 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>io.ebean</groupId>-->
|
||||
<!-- <artifactId>ebean-migration</artifactId>-->
|
||||
<!-- <version>12.1.4</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.transaction</groupId>
|
||||
<artifactId>jta</artifactId>
|
||||
@@ -131,9 +125,9 @@
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson-core.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- provided scope for JsonNode support -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
|
||||
+6
-5
@@ -18,6 +18,7 @@ import org.slf4j.LoggerFactory;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Manages the construction of caches.
|
||||
@@ -26,17 +27,14 @@ class DefaultCacheHolder {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger("io.ebean.cache.ALL");
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ConcurrentHashMap<String, ServerCache> allCaches = new ConcurrentHashMap<>();
|
||||
|
||||
private final ConcurrentHashMap<String, Set<String>> collectIdCaches = new ConcurrentHashMap<>();
|
||||
|
||||
private final ServerCacheFactory cacheFactory;
|
||||
|
||||
private final ServerCacheOptions beanDefault;
|
||||
private final ServerCacheOptions queryDefault;
|
||||
|
||||
private final CurrentTenantProvider tenantProvider;
|
||||
|
||||
private final QueryCacheEntryValidate queryCacheEntryValidate;
|
||||
|
||||
DefaultCacheHolder(CacheManagerOptions builder) {
|
||||
@@ -87,8 +85,11 @@ class DefaultCacheHolder {
|
||||
private ServerCache createCache(Class<?> beanType, ServerCacheType type, String key, String shortName) {
|
||||
ServerCacheOptions options = getCacheOptions(beanType, type);
|
||||
if (type == ServerCacheType.COLLECTION_IDS) {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
collectIdCaches.computeIfAbsent(beanType.getName(), s -> new ConcurrentSkipListSet<>()).add(key);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
return cacheFactory.createCache(new ServerCacheConfig(type, key, shortName, options, tenantProvider, queryCacheEntryValidate));
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
|
||||
import java.util.Iterator;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Manages the cluster service.
|
||||
@@ -17,6 +18,8 @@ public class ClusterManager implements ServerLookup {
|
||||
|
||||
private static final Logger clusterLogger = LoggerFactory.getLogger("io.ebean.Cluster");
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private final ConcurrentHashMap<String, EbeanServer> serverMap = new ConcurrentHashMap<>();
|
||||
|
||||
private final Object monitor = new Object();
|
||||
@@ -51,18 +54,24 @@ public class ClusterManager implements ServerLookup {
|
||||
}
|
||||
|
||||
public void registerServer(EbeanServer server) {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
serverMap.put(server.getName(), server);
|
||||
if (!started) {
|
||||
startup();
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EbeanServer getServer(String name) {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
return serverMap.get(name);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Default Server side implementation of ServerFactory.
|
||||
@@ -34,6 +35,7 @@ public class DefaultContainer implements SpiContainer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("io.ebean.internal.DefaultContainer");
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ClusterManager clusterManager;
|
||||
|
||||
public DefaultContainer(ContainerConfig containerConfig) {
|
||||
@@ -72,7 +74,8 @@ public class DefaultContainer implements SpiContainer {
|
||||
*/
|
||||
@Override
|
||||
public SpiEbeanServer createServer(DatabaseConfig config) {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
applyConfigServices(config);
|
||||
setNamingConvention(config);
|
||||
BootupClasses bootupClasses = getBootupClasses(config);
|
||||
@@ -114,6 +117,8 @@ public class DefaultContainer implements SpiContainer {
|
||||
}
|
||||
DbOffline.reset();
|
||||
return server;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,11 +36,13 @@ import io.ebean.Version;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.annotation.TxIsolation;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.bean.BeanLoader;
|
||||
import io.ebean.bean.CallOrigin;
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebean.bean.EntityBeanIntercept;
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebean.bean.PersistenceContext.WithOption;
|
||||
import io.ebean.bean.SingleBeanLoader;
|
||||
import io.ebean.cache.ServerCacheManager;
|
||||
import io.ebean.common.CopyOnFirstWriteList;
|
||||
import io.ebean.config.CurrentTenantProvider;
|
||||
@@ -142,6 +144,7 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.Spliterator;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
@@ -157,98 +160,47 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultServer.class);
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final DatabaseConfig config;
|
||||
|
||||
private final String serverName;
|
||||
|
||||
private final DatabasePlatform databasePlatform;
|
||||
|
||||
private final TransactionManager transactionManager;
|
||||
|
||||
private final QueryPlanManager queryPlanManager;
|
||||
|
||||
private final ExtraMetrics extraMetrics;
|
||||
|
||||
private final DataTimeZone dataTimeZone;
|
||||
|
||||
/**
|
||||
* Clock to use for WhenModified and WhenCreated.
|
||||
*/
|
||||
private final ClockService clockService;
|
||||
|
||||
private final CallOriginFactory callStackFactory;
|
||||
|
||||
/**
|
||||
* Handles the save, delete, updateSql CallableSql.
|
||||
*/
|
||||
private final Persister persister;
|
||||
|
||||
private final OrmQueryEngine queryEngine;
|
||||
|
||||
private final RelationalQueryEngine relationalQueryEngine;
|
||||
private final DtoQueryEngine dtoQueryEngine;
|
||||
|
||||
private final ServerCacheManager serverCacheManager;
|
||||
|
||||
private final DtoBeanManager dtoBeanManager;
|
||||
private final BeanDescriptorManager beanDescriptorManager;
|
||||
|
||||
private final AutoTuneService autoTuneService;
|
||||
|
||||
private final ReadAuditPrepare readAuditPrepare;
|
||||
|
||||
private final ReadAuditLogger readAuditLogger;
|
||||
|
||||
private final CQueryEngine cqueryEngine;
|
||||
|
||||
private final List<Plugin> serverPlugins;
|
||||
|
||||
private final SpiDdlGenerator ddlGenerator;
|
||||
|
||||
private final ScriptRunner scriptRunner;
|
||||
|
||||
private final ExpressionFactory expressionFactory;
|
||||
|
||||
private final SpiBackgroundExecutor backgroundExecutor;
|
||||
|
||||
private final DefaultBeanLoader beanLoader;
|
||||
|
||||
private final EncryptKeyManager encryptKeyManager;
|
||||
|
||||
private final SpiJsonContext jsonContext;
|
||||
|
||||
private final DocumentStore documentStore;
|
||||
|
||||
private final MetaInfoManager metaInfoManager;
|
||||
|
||||
private final CurrentTenantProvider currentTenantProvider;
|
||||
|
||||
private final SpiLogManager logManager;
|
||||
|
||||
/**
|
||||
* The default PersistenceContextScope used if it is not explicitly set on a query.
|
||||
*/
|
||||
private final PersistenceContextScope defaultPersistenceContextScope;
|
||||
|
||||
/**
|
||||
* Flag set when the server has shutdown.
|
||||
*/
|
||||
private boolean shutdown;
|
||||
|
||||
/**
|
||||
* The default batch size for lazy loading beans or collections.
|
||||
*/
|
||||
private final int lazyLoadBatchSize;
|
||||
|
||||
private final int queryBatchSize;
|
||||
|
||||
private final boolean updateAllPropertiesInBatch;
|
||||
|
||||
private final long slowQueryMicros;
|
||||
|
||||
private final SlowQueryListener slowQueryListener;
|
||||
|
||||
private final boolean disableL2Cache;
|
||||
private boolean shutdown;
|
||||
|
||||
/**
|
||||
* Create the DefaultServer.
|
||||
@@ -452,8 +404,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
shutdownInternal(true, false);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,10 +417,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
*/
|
||||
@Override
|
||||
public void shutdown(boolean shutdownDataSource, boolean deregisterDriver) {
|
||||
synchronized (this) {
|
||||
// Unregister from JVM Shutdown hook
|
||||
lock.lock();
|
||||
try {
|
||||
ShutdownManager.unregisterDatabase(this);
|
||||
shutdownInternal(shutdownDataSource, deregisterDriver);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,6 +532,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
beanLoader.loadBean(loadRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanLoader beanLoader() {
|
||||
return new SingleBeanLoader.Dflt(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
beanLoader.loadBean(ebi);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Used to reduce memory consumption of strings used in deployment processing.
|
||||
@@ -12,6 +13,8 @@ public final class InternString {
|
||||
|
||||
private static final HashMap<String, String> map = new HashMap<>();
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
/**
|
||||
* Return the shared instance of this string.
|
||||
*/
|
||||
@@ -19,8 +22,8 @@ public final class InternString {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
//noinspection SynchronizationOnStaticField
|
||||
synchronized (map) {
|
||||
lock.lock();
|
||||
try {
|
||||
String v = map.get(s);
|
||||
if (v != null) {
|
||||
return v;
|
||||
@@ -28,6 +31,8 @@ public final class InternString {
|
||||
map.put(s, s);
|
||||
return s;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,69 +118,41 @@ public class InternalConfiguration {
|
||||
private static final Logger logger = LoggerFactory.getLogger(InternalConfiguration.class);
|
||||
|
||||
private final TableModState tableModState;
|
||||
|
||||
private final boolean online;
|
||||
|
||||
private final DatabaseConfig config;
|
||||
|
||||
private final BootupClasses bootupClasses;
|
||||
|
||||
private final DatabasePlatform databasePlatform;
|
||||
|
||||
private final DeployInherit deployInherit;
|
||||
|
||||
private final TypeManager typeManager;
|
||||
|
||||
private final DtoBeanManager dtoBeanManager;
|
||||
|
||||
private final ClockService clockService;
|
||||
|
||||
private final DataTimeZone dataTimeZone;
|
||||
|
||||
private final Binder binder;
|
||||
|
||||
private final DeployCreateProperties deployCreateProperties;
|
||||
|
||||
private final DeployUtil deployUtil;
|
||||
|
||||
private final BeanDescriptorManager beanDescriptorManager;
|
||||
|
||||
private final CQueryEngine cQueryEngine;
|
||||
|
||||
private final ClusterManager clusterManager;
|
||||
|
||||
private final SpiCacheManager cacheManager;
|
||||
|
||||
private final ServerCachePlugin serverCachePlugin;
|
||||
|
||||
private ServerCacheNotify cacheNotify;
|
||||
|
||||
private boolean localL2Caching;
|
||||
|
||||
private final boolean jacksonCorePresent;
|
||||
private final ExpressionFactory expressionFactory;
|
||||
|
||||
private final SpiBackgroundExecutor backgroundExecutor;
|
||||
|
||||
private final JsonFactory jsonFactory;
|
||||
|
||||
private final DocStoreFactory docStoreFactory;
|
||||
|
||||
/**
|
||||
* List of plugins (that ultimately the DefaultServer configures late in construction).
|
||||
*/
|
||||
private final List<Plugin> plugins = new ArrayList<>();
|
||||
|
||||
private final MultiValueBind multiValueBind;
|
||||
|
||||
private final SpiLogManager logManager;
|
||||
|
||||
private final ExtraMetrics extraMetrics = new ExtraMetrics();
|
||||
private ServerCacheNotify cacheNotify;
|
||||
private boolean localL2Caching;
|
||||
|
||||
InternalConfiguration(boolean online, ClusterManager clusterManager, SpiBackgroundExecutor backgroundExecutor,
|
||||
DatabaseConfig config, BootupClasses bootupClasses) {
|
||||
|
||||
this.online = online;
|
||||
this.config = config;
|
||||
this.jacksonCorePresent = config.getClassLoadConfig().isJacksonCorePresent();
|
||||
this.clockService = new ClockService(config.getClock());
|
||||
this.tableModState = new TableModState();
|
||||
this.logManager = initLogManager();
|
||||
@@ -210,6 +182,10 @@ public class InternalConfiguration {
|
||||
this.cQueryEngine = new CQueryEngine(config, databasePlatform, binder, asOfTableMapping, draftTableMap);
|
||||
}
|
||||
|
||||
public boolean isJacksonCorePresent() {
|
||||
return jacksonCorePresent;
|
||||
}
|
||||
|
||||
private InternalConfigXmlMap initExternalMapping() {
|
||||
final List<XmapEbean> xmEbeans = readExternalMapping();
|
||||
return new InternalConfigXmlMap(xmEbeans, config.getClassLoadConfig().getClassLoader());
|
||||
@@ -307,7 +283,7 @@ public class InternalConfiguration {
|
||||
* Return the ChangeLogListener to use with a default implementation if none defined.
|
||||
*/
|
||||
public ChangeLogListener changeLogListener(ChangeLogListener listener) {
|
||||
return plugin((listener != null) ? listener : new DefaultChangeLogListener());
|
||||
return plugin((listener != null) ? listener : jacksonCorePresent ? new DefaultChangeLogListener() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,7 +291,7 @@ public class InternalConfiguration {
|
||||
*/
|
||||
ReadAuditLogger getReadAuditLogger() {
|
||||
ReadAuditLogger found = bootupClasses.getReadAuditLogger();
|
||||
return plugin(found != null ? found : new DefaultReadAuditLogger());
|
||||
return plugin(found != null ? found : jacksonCorePresent? new DefaultReadAuditLogger(): null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -356,7 +332,7 @@ public class InternalConfiguration {
|
||||
}
|
||||
|
||||
SpiJsonContext createJsonContext(SpiEbeanServer server) {
|
||||
return new DJsonContext(server, jsonFactory, typeManager);
|
||||
return jacksonCorePresent ? new DJsonContext(server, jsonFactory, typeManager) : null;
|
||||
}
|
||||
|
||||
AutoTuneService createAutoTuneService(SpiEbeanServer server) {
|
||||
|
||||
@@ -432,7 +432,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
boolean noRelationships = propertiesOne.length + propertiesMany.length == 0;
|
||||
this.cacheSharableBeans = noRelationships && deploy.getCacheOptions().isReadOnly();
|
||||
this.cacheHelp = new BeanDescriptorCacheHelp<>(this, owner.getCacheManager(), deploy.getCacheOptions(), cacheSharableBeans, propertiesOneImported);
|
||||
this.jsonHelp = new BeanDescriptorJsonHelp<>(this);
|
||||
this.jsonHelp = initJsonHelp();
|
||||
this.draftHelp = new BeanDescriptorDraftHelp<>(this);
|
||||
this.docStoreAdapter = owner.createDocStoreBeanAdapter(this, deploy);
|
||||
this.docStoreQueueId = docStoreAdapter.getQueueId();
|
||||
@@ -469,6 +469,14 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isJacksonCorePresent() {
|
||||
return owner.isJacksonCorePresent();
|
||||
}
|
||||
|
||||
private BeanDescriptorJsonHelp<T> initJsonHelp() {
|
||||
return isJacksonCorePresent() ? new BeanDescriptorJsonHelp<>(this) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the bean should be treated as a reference bean when it only has its id populated.
|
||||
* To be true it has other scalar properties that are not generated on insert.
|
||||
|
||||
+10
-46
@@ -95,87 +95,47 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
private static final BeanDescComparator beanDescComparator = new BeanDescComparator();
|
||||
|
||||
private final ReadAnnotations readAnnotations;
|
||||
|
||||
private final TransientProperties transientProperties;
|
||||
|
||||
/**
|
||||
* Helper to derive inheritance information.
|
||||
*/
|
||||
private final DeployInherit deplyInherit;
|
||||
|
||||
private final BeanPropertyAccess beanPropertyAccess = new EnhanceBeanPropertyAccess();
|
||||
|
||||
private final DeployUtil deployUtil;
|
||||
|
||||
private final PersistControllerManager persistControllerManager;
|
||||
|
||||
private final PostLoadManager postLoadManager;
|
||||
|
||||
private final PostConstructManager postConstructManager;
|
||||
|
||||
private final BeanFinderManager beanFinderManager;
|
||||
|
||||
private final PersistListenerManager persistListenerManager;
|
||||
|
||||
private final BeanQueryAdapterManager beanQueryAdapterManager;
|
||||
|
||||
private final NamingConvention namingConvention;
|
||||
|
||||
private final DeployCreateProperties createProperties;
|
||||
|
||||
private final BeanManagerFactory beanManagerFactory;
|
||||
|
||||
private final DatabaseConfig config;
|
||||
|
||||
private final ChangeLogListener changeLogListener;
|
||||
|
||||
private final ChangeLogRegister changeLogRegister;
|
||||
|
||||
private final ChangeLogPrepare changeLogPrepare;
|
||||
|
||||
private final DocStoreFactory docStoreFactory;
|
||||
|
||||
private final MultiValueBind multiValueBind;
|
||||
|
||||
private final TypeManager typeManager;
|
||||
|
||||
private int entityBeanCount;
|
||||
|
||||
private final BootupClasses bootupClasses;
|
||||
|
||||
private final String serverName;
|
||||
|
||||
private final Map<Class<?>, BeanTable> beanTableMap = new HashMap<>();
|
||||
|
||||
private final Map<String, BeanDescriptor<?>> descMap = new HashMap<>();
|
||||
|
||||
private final Map<String, BeanDescriptor<?>> descQueueMap = new HashMap<>();
|
||||
|
||||
private final Map<String, BeanManager<?>> beanManagerMap = new HashMap<>();
|
||||
|
||||
private final Map<String, List<BeanDescriptor<?>>> tableToDescMap = new HashMap<>();
|
||||
|
||||
private final Map<String, List<BeanDescriptor<?>>> tableToViewDescMap = new HashMap<>();
|
||||
|
||||
private List<BeanDescriptor<?>> immutableDescriptorList;
|
||||
|
||||
private final DbIdentity dbIdentity;
|
||||
|
||||
private final DataSource dataSource;
|
||||
|
||||
private final DatabasePlatform databasePlatform;
|
||||
|
||||
private final SpiCacheManager cacheManager;
|
||||
|
||||
private final BackgroundExecutor backgroundExecutor;
|
||||
|
||||
private final EncryptKeyManager encryptKeyManager;
|
||||
|
||||
private final IdBinderFactory idBinderFactory;
|
||||
|
||||
private final BeanLifecycleAdapterFactory beanLifecycleAdapterFactory;
|
||||
|
||||
private final String asOfViewSuffix;
|
||||
private final boolean jacksonCorePresent;
|
||||
private final int queryPlanTTLSeconds;
|
||||
private int entityBeanCount;
|
||||
private List<BeanDescriptor<?>> immutableDescriptorList;
|
||||
|
||||
/**
|
||||
* Map of base tables to 'with history views' used to support 'as of' queries.
|
||||
@@ -187,8 +147,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
*/
|
||||
private final Map<String, String> draftTableMap = new HashMap<>();
|
||||
|
||||
private final int queryPlanTTLSeconds;
|
||||
|
||||
// temporary collections used during startup and then cleared
|
||||
|
||||
private Map<Class<?>, DeployBeanInfo<?>> deployInfoMap = new HashMap<>();
|
||||
@@ -232,6 +190,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
this.changeLogPrepare = config.changeLogPrepare(bootupClasses.getChangeLogPrepare());
|
||||
this.changeLogListener = config.changeLogListener(bootupClasses.getChangeLogListener());
|
||||
this.changeLogRegister = config.changeLogRegister(bootupClasses.getChangeLogRegister());
|
||||
this.jacksonCorePresent = config.isJacksonCorePresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJacksonCorePresent() {
|
||||
return jacksonCorePresent;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -71,4 +71,9 @@ public interface BeanDescriptorMap {
|
||||
* Return the scalarType for the given logical type.
|
||||
*/
|
||||
ScalarType<?> getScalarType(String cast);
|
||||
|
||||
/**
|
||||
* Return true if Jackson core is present on the classpath.
|
||||
*/
|
||||
boolean isJacksonCorePresent();
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
|
||||
}
|
||||
this.inverseJoin = deploy.createInverseTableJoin();
|
||||
this.modifyListenMode = deploy.getModifyListenMode();
|
||||
this.jsonHelp = new BeanPropertyAssocManyJsonHelp(this);
|
||||
this.jsonHelp = descriptor.isJacksonCorePresent() ? new BeanPropertyAssocManyJsonHelp(this) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.security.SecureRandom;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -44,6 +45,8 @@ public class UuidV1RndIdGenerator implements PlatformIdGenerator {
|
||||
|
||||
private AtomicLong nanoToMilliOffset = new AtomicLong(currentUuidTime());
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the uuid epoch.
|
||||
@@ -106,7 +109,8 @@ public class UuidV1RndIdGenerator implements PlatformIdGenerator {
|
||||
logger.info("Clock skew of {} ms detected", delta / -10000);
|
||||
// The clock was adjusted back about 2 seconds, or we were generating a lot of ids too fast
|
||||
// if so, we try to set the current as last and also increment the clockSeq.
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (clockSeq.compareAndSet(seq, seq + 1)) {
|
||||
timeStamp.set(current);
|
||||
saveState();
|
||||
@@ -114,6 +118,8 @@ public class UuidV1RndIdGenerator implements PlatformIdGenerator {
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
// If current is in the future (most of the cases) try to set it.
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* A "CachedThreadPool" based on Daemon threads.
|
||||
@@ -16,6 +17,8 @@ public final class DaemonExecutorService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DaemonExecutorService.class);
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private final String namePrefix;
|
||||
|
||||
private final int shutdownWaitSeconds;
|
||||
@@ -49,7 +52,8 @@ public final class DaemonExecutorService {
|
||||
* </p>
|
||||
*/
|
||||
public void shutdown() {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (service.isShutdown()) {
|
||||
logger.debug("DaemonExecutorService[{}] already shut down", namePrefix);
|
||||
return;
|
||||
@@ -66,6 +70,8 @@ public final class DaemonExecutorService {
|
||||
logger.error("Error during shutdown of DaemonThreadPool[" + namePrefix + "]", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Daemon based ScheduleThreadPool.
|
||||
@@ -16,6 +17,8 @@ public final class DaemonScheduleThreadPool extends ScheduledThreadPoolExecutor
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DaemonScheduleThreadPool.class);
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private final String namePrefix;
|
||||
|
||||
private final int shutdownWaitSeconds;
|
||||
@@ -38,7 +41,8 @@ public final class DaemonScheduleThreadPool extends ScheduledThreadPoolExecutor
|
||||
*/
|
||||
@Override
|
||||
public void shutdown() {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (super.isShutdown()) {
|
||||
logger.debug("DaemonScheduleThreadPool {} already shut down", namePrefix);
|
||||
return;
|
||||
@@ -55,6 +59,8 @@ public final class DaemonScheduleThreadPool extends ScheduledThreadPoolExecutor
|
||||
logger.error("Error during shutdown of " + namePrefix, e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,15 @@ import io.ebeaninternal.api.SpiQuery;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Base class for Bean and BeanCollection loading (lazy loading and query join loading).
|
||||
*/
|
||||
abstract class DLoadBaseContext {
|
||||
|
||||
protected final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
protected final DLoadContext parent;
|
||||
|
||||
protected final BeanDescriptor<?> desc;
|
||||
|
||||
@@ -17,6 +17,8 @@ import io.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* ToOne bean load context.
|
||||
@@ -86,11 +88,11 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
|
||||
|
||||
@Override
|
||||
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, boolean forEach) {
|
||||
|
||||
if (!queryFetch) {
|
||||
throw new IllegalStateException("Not expecting loadSecondaryQuery() to be called?");
|
||||
}
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (bufferList != null) {
|
||||
for (LoadBuffer loadBuffer : bufferList) {
|
||||
if (!loadBuffer.list.isEmpty()) {
|
||||
@@ -108,6 +110,8 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +120,7 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
|
||||
*/
|
||||
static class LoadBuffer implements BeanLoader, LoadBeanBuffer {
|
||||
|
||||
private final ReentrantLock bufferLock = new ReentrantLock(false);
|
||||
private final DLoadBeanContext context;
|
||||
private final int batchSize;
|
||||
private final List<EntityBeanIntercept> list;
|
||||
@@ -127,6 +132,12 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
|
||||
this.list = new ArrayList<>(batchSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lock lock() {
|
||||
bufferLock.lock();
|
||||
return bufferLock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
@@ -182,7 +193,7 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
|
||||
|
||||
@Override
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
// A synchronized (this) is effectively held by EntityBeanIntercept.loadBean()
|
||||
// A lock is effectively held by EntityBeanIntercept.loadBean()
|
||||
if (context.desc.lazyLoadMany(ebi, context)) {
|
||||
// lazy load property was a Many
|
||||
return;
|
||||
|
||||
@@ -16,6 +16,7 @@ import io.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* ToMany bean load context.
|
||||
@@ -94,11 +95,11 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
|
||||
|
||||
@Override
|
||||
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, boolean forEach) {
|
||||
|
||||
if (!queryFetch) {
|
||||
throw new IllegalStateException("Not expecting loadSecondaryQuery() to be called?");
|
||||
}
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (bufferList != null) {
|
||||
for (LoadBuffer loadBuffer : bufferList) {
|
||||
if (!loadBuffer.list.isEmpty()) {
|
||||
@@ -118,6 +119,8 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
|
||||
this.bufferList = null;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +130,7 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
|
||||
*/
|
||||
static class LoadBuffer implements BeanCollectionLoader, LoadManyBuffer {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final PersistenceContext persistenceContext;
|
||||
private final DLoadManyContext context;
|
||||
private final int batchSize;
|
||||
@@ -208,7 +212,8 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
|
||||
@Override
|
||||
public void loadMany(BeanCollection<?> bc, boolean onlyIds) {
|
||||
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
boolean useCache = !onlyIds && context.hitCache && context.property.isUseCache();
|
||||
if (useCache) {
|
||||
EntityBean ownerBean = bc.getOwnerBean();
|
||||
@@ -231,6 +236,8 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
|
||||
|
||||
LoadManyRequest req = new LoadManyRequest(this, onlyIds, useCache);
|
||||
context.parent.getEbeanServer().loadMany(req);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* An object that represents a SqlSelect statement.
|
||||
@@ -58,6 +59,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
|
||||
private static final CQueryCollectionAddNoop NOOP_ADD = new CQueryCollectionAddNoop();
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
/**
|
||||
* The resultSet rows read.
|
||||
*/
|
||||
@@ -288,7 +291,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
this.cancelled = true;
|
||||
if (pstmt != null) {
|
||||
try {
|
||||
@@ -298,6 +302,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
throw new PersistenceException(msg, e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,8 +332,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
}
|
||||
|
||||
ResultSet prepareResultSet(boolean forwardOnlyHint) throws SQLException {
|
||||
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (cancelled || query.isCancelled()) {
|
||||
// cancelled before we started
|
||||
cancelled = true;
|
||||
@@ -370,6 +376,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
|
||||
// executeQuery
|
||||
return pstmt.executeQuery();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,8 +532,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
}
|
||||
|
||||
boolean hasNext() throws SQLException {
|
||||
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (noMoreRows || cancelled) {
|
||||
return false;
|
||||
}
|
||||
@@ -534,6 +542,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
}
|
||||
hasNextCache = readNextBean();
|
||||
return hasNextCache;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,13 @@ import io.ebeaninternal.api.SpiQueryBindCapture;
|
||||
import io.ebeaninternal.api.SpiQueryPlan;
|
||||
import io.ebeaninternal.server.type.bindcapture.BindCapture;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
class CQueryBindCapture implements SpiQueryBindCapture {
|
||||
|
||||
private static final double multiplier = 1.3d;
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final CQueryPlanManager manager;
|
||||
private final SpiQueryPlan queryPlan;
|
||||
|
||||
@@ -35,13 +38,16 @@ class CQueryBindCapture implements SpiQueryBindCapture {
|
||||
|
||||
@Override
|
||||
public void setBind(BindCapture bindCapture, long queryTimeMicros, long startNanos) {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
this.thresholdMicros = Math.round(queryTimeMicros * multiplier);
|
||||
this.captureCount++;
|
||||
this.bindCapture = bindCapture;
|
||||
this.queryTimeMicros = queryTimeMicros;
|
||||
lastBindCapture = System.currentTimeMillis();
|
||||
manager.notifyBindCapture(this, startNanos);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
package io.ebeaninternal.server.query;
|
||||
|
||||
import io.ebean.PagedList;
|
||||
import io.ebeaninternal.api.Monitor;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.SpiQuery;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* PagedList implementation based on limit offset types of queries.
|
||||
*
|
||||
* @param <T> the entity bean type
|
||||
*/
|
||||
public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
|
||||
private final transient SpiEbeanServer server;
|
||||
|
||||
private final transient ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private final SpiQuery<T> query;
|
||||
|
||||
private final int firstRow;
|
||||
|
||||
private final int maxRows;
|
||||
|
||||
private final Monitor monitor = new Monitor();
|
||||
|
||||
private int foregroundTotalRowCount = -1;
|
||||
|
||||
private Future<Integer> futureRowCount;
|
||||
@@ -49,21 +47,27 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
|
||||
@Override
|
||||
public Future<Integer> getFutureCount() {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (futureRowCount == null) {
|
||||
futureRowCount = server.findFutureCount(query, null);
|
||||
}
|
||||
return futureRowCount;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getList() {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (list == null) {
|
||||
list = server.findList(query, null);
|
||||
}
|
||||
return list;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +81,6 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
|
||||
@Override
|
||||
public int getTotalPageCount() {
|
||||
|
||||
int rowCount = getTotalCount();
|
||||
if (rowCount == 0) {
|
||||
return 0;
|
||||
@@ -88,7 +91,8 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
|
||||
@Override
|
||||
public int getTotalCount() {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (futureRowCount != null) {
|
||||
try {
|
||||
// background query already initiated so get it with a wait
|
||||
@@ -103,6 +107,8 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
// just using foreground thread
|
||||
foregroundTotalRowCount = server.findCount(query, null);
|
||||
return foregroundTotalRowCount;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,11 +129,9 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
|
||||
@Override
|
||||
public String getDisplayXtoYofZ(String to, String of) {
|
||||
|
||||
int first = firstRow + 1;
|
||||
int last = firstRow + getList().size();
|
||||
int total = getTotalCount();
|
||||
|
||||
return first + to + last + of + total;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
@@ -88,6 +89,8 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
private static final FetchConfig FETCH_LAZY = new FetchConfig().lazy();
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private final Class<T> beanType;
|
||||
|
||||
private final ExpressionFactory expressionFactory;
|
||||
@@ -1992,8 +1995,11 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
@Override
|
||||
public void setCancelableQuery(CancelableQuery cancelableQuery) {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
this.cancelableQuery = cancelableQuery;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2026,18 +2032,24 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
cancelled = true;
|
||||
if (cancelableQuery != null) {
|
||||
cancelableQuery.cancel();
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
return cancelled;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+46
-13
@@ -1,12 +1,12 @@
|
||||
package io.ebeaninternal.server.transaction;
|
||||
|
||||
import io.ebean.bean.PersistenceContext;
|
||||
import io.ebeaninternal.api.Monitor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Default implementation of PersistenceContext.
|
||||
@@ -32,7 +32,7 @@ public final class DefaultPersistenceContext implements PersistenceContext {
|
||||
*/
|
||||
private final HashMap<Class<?>, ClassContext> typeCache = new HashMap<>();
|
||||
|
||||
private final Monitor monitor = new Monitor();
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private int putCount;
|
||||
|
||||
@@ -68,7 +68,8 @@ public final class DefaultPersistenceContext implements PersistenceContext {
|
||||
}
|
||||
|
||||
public boolean resetLimit() {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (putCount < 100) {
|
||||
return false;
|
||||
}
|
||||
@@ -80,6 +81,8 @@ public final class DefaultPersistenceContext implements PersistenceContext {
|
||||
}
|
||||
// checking after another 100 puts
|
||||
return false;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,17 +91,23 @@ public final class DefaultPersistenceContext implements PersistenceContext {
|
||||
*/
|
||||
@Override
|
||||
public void put(Class<?> rootType, Object id, Object bean) {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
putCount++;
|
||||
getClassContext(rootType).put(id, bean);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object putIfAbsent(Class<?> rootType, Object id, Object bean) {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
putCount++;
|
||||
return getClassContext(rootType).putIfAbsent(id, bean);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,15 +116,21 @@ public final class DefaultPersistenceContext implements PersistenceContext {
|
||||
*/
|
||||
@Override
|
||||
public Object get(Class<?> rootType, Object id) {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
return getClassContext(rootType).get(id);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WithOption getWithOption(Class<?> rootType, Object id) {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
return getClassContext(rootType).getWithOption(id);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,9 +139,12 @@ public final class DefaultPersistenceContext implements PersistenceContext {
|
||||
*/
|
||||
@Override
|
||||
public int size(Class<?> rootType) {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
ClassContext classMap = typeCache.get(rootType);
|
||||
return classMap == null ? 0 : classMap.size();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,45 +153,60 @@ public final class DefaultPersistenceContext implements PersistenceContext {
|
||||
*/
|
||||
@Override
|
||||
public void clear() {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
typeCache.clear();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(Class<?> rootType) {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
ClassContext classMap = typeCache.get(rootType);
|
||||
if (classMap != null) {
|
||||
classMap.clear();
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleted(Class<?> rootType, Object id) {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
ClassContext classMap = typeCache.get(rootType);
|
||||
if (classMap != null && id != null) {
|
||||
classMap.deleted(id);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(Class<?> rootType, Object id) {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
ClassContext classMap = typeCache.get(rootType);
|
||||
if (classMap != null && id != null) {
|
||||
classMap.remove(id);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
return typeCache.toString();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-2
@@ -21,6 +21,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
|
||||
import static java.time.temporal.ChronoField.HOUR_OF_DAY;
|
||||
@@ -65,6 +66,8 @@ public class DefaultProfileHandler implements SpiProfileHandler, Plugin {
|
||||
|
||||
private final ExecutorService executor;
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private final File dir;
|
||||
|
||||
private final long minMicros;
|
||||
@@ -117,7 +120,8 @@ public class DefaultProfileHandler implements SpiProfileHandler, Plugin {
|
||||
}
|
||||
|
||||
private void flushCurrentFile() {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
@@ -126,6 +130,8 @@ public class DefaultProfileHandler implements SpiProfileHandler, Plugin {
|
||||
log.error("Failed to flush and close transaction profiling file ", e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +139,8 @@ public class DefaultProfileHandler implements SpiProfileHandler, Plugin {
|
||||
* Move to the next file to write to.
|
||||
*/
|
||||
private void incrementFile() {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
flushCurrentFile();
|
||||
try {
|
||||
String now = DTF.format(LocalDateTime.now());
|
||||
@@ -142,6 +149,8 @@ public class DefaultProfileHandler implements SpiProfileHandler, Plugin {
|
||||
} catch (IOException e) {
|
||||
log.error("Not expected", e);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static java.util.Collections.EMPTY_LIST;
|
||||
|
||||
@@ -33,6 +34,7 @@ public class ScalarTypeArrayList extends ScalarTypeArrayBase<List> implements Sc
|
||||
|
||||
static class Factory implements PlatformArrayTypeFactory {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final Map<String, ScalarTypeArrayList> cache = new HashMap<>();
|
||||
|
||||
/**
|
||||
@@ -40,7 +42,8 @@ public class ScalarTypeArrayList extends ScalarTypeArrayBase<List> implements Sc
|
||||
*/
|
||||
@Override
|
||||
public ScalarTypeArrayList typeFor(Type valueType, boolean nullable) {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
String key = valueType + ":" + nullable;
|
||||
if (valueType.equals(UUID.class)) {
|
||||
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayList(nullable, "uuid", DocPropertyType.UUID, ArrayElementConverter.UUID));
|
||||
@@ -58,6 +61,8 @@ public class ScalarTypeArrayList extends ScalarTypeArrayBase<List> implements Sc
|
||||
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayList(nullable, "varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING));
|
||||
}
|
||||
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static java.util.Collections.EMPTY_LIST;
|
||||
|
||||
@@ -24,6 +25,7 @@ class ScalarTypeArrayListH2 extends ScalarTypeArrayList {
|
||||
|
||||
static class Factory implements PlatformArrayTypeFactory {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final Map<String, ScalarTypeArrayListH2> cache = new HashMap<>();
|
||||
|
||||
/**
|
||||
@@ -31,7 +33,8 @@ class ScalarTypeArrayListH2 extends ScalarTypeArrayList {
|
||||
*/
|
||||
@Override
|
||||
public ScalarType<?> typeFor(Type valueType, boolean nullable) {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
String key = valueType + ":" + nullable;
|
||||
if (valueType.equals(UUID.class)) {
|
||||
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayListH2(nullable, "uuid", DocPropertyType.UUID, ArrayElementConverter.UUID));
|
||||
@@ -49,6 +52,8 @@ class ScalarTypeArrayListH2 extends ScalarTypeArrayList {
|
||||
return cache.computeIfAbsent(key, s -> new ScalarTypeArrayListH2(nullable, "varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING));
|
||||
}
|
||||
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static java.util.Collections.EMPTY_SET;
|
||||
|
||||
@@ -33,6 +34,7 @@ public class ScalarTypeArraySet extends ScalarTypeArrayBase<Set> implements Scal
|
||||
|
||||
static class Factory implements PlatformArrayTypeFactory {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final Map<String, ScalarTypeArraySet> cache = new HashMap<>();
|
||||
|
||||
/**
|
||||
@@ -40,7 +42,8 @@ public class ScalarTypeArraySet extends ScalarTypeArrayBase<Set> implements Scal
|
||||
*/
|
||||
@Override
|
||||
public ScalarType<?> typeFor(Type valueType, boolean nullable) {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
String key = valueType + ":" + nullable;
|
||||
if (valueType.equals(UUID.class)) {
|
||||
return cache.computeIfAbsent(key, s -> new ScalarTypeArraySet(nullable, "uuid", DocPropertyType.UUID, ArrayElementConverter.UUID));
|
||||
@@ -58,6 +61,8 @@ public class ScalarTypeArraySet extends ScalarTypeArrayBase<Set> implements Scal
|
||||
return cache.computeIfAbsent(key, s -> new ScalarTypeArraySet(nullable, "varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING));
|
||||
}
|
||||
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static java.util.Collections.EMPTY_SET;
|
||||
|
||||
@@ -24,6 +25,7 @@ class ScalarTypeArraySetH2 extends ScalarTypeArraySet {
|
||||
|
||||
static class Factory implements PlatformArrayTypeFactory {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final Map<String, ScalarTypeArraySetH2> cache = new HashMap<>();
|
||||
|
||||
/**
|
||||
@@ -31,7 +33,8 @@ class ScalarTypeArraySetH2 extends ScalarTypeArraySet {
|
||||
*/
|
||||
@Override
|
||||
public ScalarType<?> typeFor(Type valueType, boolean nullable) {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
String key = valueType + ":" + nullable;
|
||||
if (valueType.equals(UUID.class)) {
|
||||
return cache.computeIfAbsent(key, s -> new ScalarTypeArraySetH2(nullable, "uuid", DocPropertyType.UUID, ArrayElementConverter.UUID));
|
||||
@@ -49,6 +52,8 @@ class ScalarTypeArraySetH2 extends ScalarTypeArraySet {
|
||||
return cache.computeIfAbsent(key, s -> new ScalarTypeArraySetH2(nullable, "varchar", DocPropertyType.TEXT, ArrayElementConverter.STRING));
|
||||
}
|
||||
throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping");
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.ebean;
|
||||
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.event.ServerConfigStartup;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.UTDetail;
|
||||
@@ -13,7 +12,7 @@ public class EbeanServerFactory_ServerConfigStart_Test {
|
||||
@Test
|
||||
public void test() throws InterruptedException {
|
||||
|
||||
ServerConfig config = new ServerConfig();
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
config.setName("h2");
|
||||
config.loadFromProperties();
|
||||
config.setName("h2other");
|
||||
@@ -30,17 +29,17 @@ public class EbeanServerFactory_ServerConfigStart_Test {
|
||||
OnStartup onStartup = new OnStartup();
|
||||
config.addServerConfigStartup(onStartup);
|
||||
|
||||
EbeanServer ebeanServer = EbeanServerFactory.create(config);
|
||||
Database db = DatabaseFactory.create(config);
|
||||
|
||||
assertThat(onStartup.calledWithConfig).isSameAs(config);
|
||||
assertThat(OnStartupViaClass.calledWithConfig).isSameAs(config);
|
||||
|
||||
assertThat(ebeanServer).isNotNull();
|
||||
assertThat(db).isNotNull();
|
||||
|
||||
// test server shutdown and restart using the same ServerConfig
|
||||
ebeanServer.shutdown(true, false);
|
||||
db.shutdown(true, false);
|
||||
|
||||
EbeanServer restartedServer = EbeanServerFactory.create(config);
|
||||
Database restartedServer = DatabaseFactory.create(config);
|
||||
restartedServer.shutdown(true, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package io.ebean.config;
|
||||
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.EbeanServerFactory;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.annotation.Platform;
|
||||
import io.ebean.config.dbplatform.DbIdentity;
|
||||
import io.ebean.config.dbplatform.IdType;
|
||||
import io.ebean.config.dbplatform.h2.H2Platform;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.EBasicVer;
|
||||
import org.tests.model.draftable.BasicDraftableBean;
|
||||
@@ -15,7 +16,12 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class PlatformNoGeneratedKeysTest {
|
||||
|
||||
static EbeanServer server = testH2Server();
|
||||
static Database server = testH2Server();
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() {
|
||||
server.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void global_serverConfig_setDisableLazyLoading() {
|
||||
@@ -79,9 +85,9 @@ public class PlatformNoGeneratedKeysTest {
|
||||
assertThat(one.isDraft()).isFalse();
|
||||
}
|
||||
|
||||
private static EbeanServer testH2Server() {
|
||||
private static Database testH2Server() {
|
||||
|
||||
ServerConfig config = new ServerConfig();
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
config.setName("h2_noGeneratedKeys");
|
||||
|
||||
OtherH2Platform platform = new OtherH2Platform();
|
||||
@@ -108,7 +114,7 @@ public class PlatformNoGeneratedKeysTest {
|
||||
config.getClasses().add(BasicDraftableBean.class);
|
||||
|
||||
|
||||
return EbeanServerFactory.create(config);
|
||||
return DatabaseFactory.create(config);
|
||||
}
|
||||
|
||||
public static class OtherH2Platform extends H2Platform {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package io.ebean.event;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.EbeanServerFactory;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.bean.BeanCollection;
|
||||
import io.ebean.common.BeanList;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import org.junit.Test;
|
||||
import org.tests.example.ModUuidGenerator;
|
||||
import org.tests.model.basic.EBasic;
|
||||
@@ -23,7 +23,7 @@ public class BeanFindControllerTest extends BaseTestCase {
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
ServerConfig config = new ServerConfig();
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
|
||||
config.setName("h2otherfind");
|
||||
config.loadFromProperties();
|
||||
@@ -40,27 +40,27 @@ public class BeanFindControllerTest extends BaseTestCase {
|
||||
EBasicFindController findController = new EBasicFindController();
|
||||
config.getFindControllers().add(findController);
|
||||
|
||||
EbeanServer ebeanServer = EbeanServerFactory.create(config);
|
||||
Database db = DatabaseFactory.create(config);
|
||||
|
||||
assertFalse(findController.calledInterceptFind);
|
||||
ebeanServer.find(EBasic.class, 42);
|
||||
db.find(EBasic.class, 42);
|
||||
assertTrue(findController.calledInterceptFind);
|
||||
|
||||
findController.findIntercept = true;
|
||||
EBasic eBasic = ebeanServer.find(EBasic.class, 42);
|
||||
EBasic eBasic = db.find(EBasic.class, 42);
|
||||
|
||||
assertEquals(Integer.valueOf(47), eBasic.getId());
|
||||
assertEquals("47", eBasic.getName());
|
||||
|
||||
assertFalse(findController.calledInterceptFindMany);
|
||||
|
||||
List<EBasic> list = ebeanServer.find(EBasic.class).where().eq("name", "AnInvalidNameSoEmpty").findList();
|
||||
List<EBasic> list = db.find(EBasic.class).where().eq("name", "AnInvalidNameSoEmpty").findList();
|
||||
assertEquals(0, list.size());
|
||||
assertTrue(findController.calledInterceptFindMany);
|
||||
|
||||
findController.findManyIntercept = true;
|
||||
|
||||
list = ebeanServer.find(EBasic.class).where().eq("name", "AnInvalidNameSoEmpty").findList();
|
||||
list = db.find(EBasic.class).where().eq("name", "AnInvalidNameSoEmpty").findList();
|
||||
assertEquals(1, list.size());
|
||||
|
||||
eBasic = list.get(0);
|
||||
@@ -68,8 +68,9 @@ public class BeanFindControllerTest extends BaseTestCase {
|
||||
assertEquals("47", eBasic.getName());
|
||||
|
||||
ECustomId bean = new ECustomId("check");
|
||||
ebeanServer.save(bean);
|
||||
db.save(bean);
|
||||
assertNotNull(bean.getId());
|
||||
db.shutdown();
|
||||
}
|
||||
|
||||
static class EBasicFindController implements BeanFindController {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package io.ebean.event;
|
||||
|
||||
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.EbeanServerFactory;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.EBasicVer;
|
||||
import org.tests.model.basic.UTDetail;
|
||||
@@ -25,15 +25,15 @@ public class BeanPersistControllerTest {
|
||||
@Test
|
||||
public void issue_1341() {
|
||||
|
||||
EbeanServer ebeanServer = getEbeanServer(continuePersistingAdapter);
|
||||
Database db = getDatabase(continuePersistingAdapter);
|
||||
|
||||
UTMaster bean0 = new UTMaster("one0");
|
||||
UTDetail detail0 = new UTDetail("detail0", 12, 23D);
|
||||
bean0.getDetails().add(detail0);
|
||||
|
||||
ebeanServer.save(bean0);
|
||||
db.save(bean0);
|
||||
|
||||
UTMaster master = ebeanServer.find(UTMaster.class)
|
||||
UTMaster master = db.find(UTMaster.class)
|
||||
.setId(bean0.getId())
|
||||
.fetch("details", "name, version")
|
||||
.findOne();
|
||||
@@ -41,79 +41,82 @@ public class BeanPersistControllerTest {
|
||||
UTDetail utDetail = master.getDetails().get(0);
|
||||
utDetail.setName("detail0 mod");
|
||||
|
||||
Transaction txn = ebeanServer.beginTransaction();
|
||||
Transaction txn = db.beginTransaction();
|
||||
try {
|
||||
txn.setBatchMode(true);
|
||||
ebeanServer.save(master);
|
||||
db.save(master);
|
||||
txn.commit();
|
||||
} finally {
|
||||
txn.end();
|
||||
}
|
||||
|
||||
db.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertUpdateDelete_given_continuePersistingAdapter() {
|
||||
|
||||
EbeanServer ebeanServer = getEbeanServer(continuePersistingAdapter);
|
||||
|
||||
Database db = getDatabase(continuePersistingAdapter);
|
||||
|
||||
EBasicVer bean = new EBasicVer("testController");
|
||||
|
||||
ebeanServer.save(bean);
|
||||
db.save(bean);
|
||||
assertThat(continuePersistingAdapter.methodsCalled).hasSize(2);
|
||||
assertThat(continuePersistingAdapter.methodsCalled).containsExactly("preInsert", "postInsert");
|
||||
continuePersistingAdapter.methodsCalled.clear();
|
||||
|
||||
bean.setName("modified");
|
||||
ebeanServer.save(bean);
|
||||
db.save(bean);
|
||||
assertThat(continuePersistingAdapter.methodsCalled).hasSize(2);
|
||||
assertThat(continuePersistingAdapter.methodsCalled).containsExactly("preUpdate", "postUpdate");
|
||||
continuePersistingAdapter.methodsCalled.clear();
|
||||
|
||||
ebeanServer.delete(bean);
|
||||
db.delete(bean);
|
||||
assertThat(continuePersistingAdapter.methodsCalled).hasSize(2);
|
||||
assertThat(continuePersistingAdapter.methodsCalled).containsExactly("preDelete", "postDelete");
|
||||
|
||||
db.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertUpdateDelete_given_stopPersistingAdapter() {
|
||||
|
||||
EbeanServer ebeanServer = getEbeanServer(stopPersistingAdapter);
|
||||
Database db = getDatabase(stopPersistingAdapter);
|
||||
|
||||
EBasicVer bean = new EBasicVer("testController");
|
||||
|
||||
ebeanServer.save(bean);
|
||||
db.save(bean);
|
||||
assertThat(stopPersistingAdapter.methodsCalled).hasSize(1);
|
||||
assertThat(stopPersistingAdapter.methodsCalled).containsExactly("preInsert");
|
||||
stopPersistingAdapter.methodsCalled.clear();
|
||||
|
||||
bean.setName("modified");
|
||||
ebeanServer.update(bean);
|
||||
db.update(bean);
|
||||
assertThat(stopPersistingAdapter.methodsCalled).hasSize(1);
|
||||
assertThat(stopPersistingAdapter.methodsCalled).containsExactly("preUpdate");
|
||||
stopPersistingAdapter.methodsCalled.clear();
|
||||
|
||||
ebeanServer.delete(bean);
|
||||
db.delete(bean);
|
||||
assertThat(stopPersistingAdapter.methodsCalled).hasSize(1);
|
||||
assertThat(stopPersistingAdapter.methodsCalled).containsExactly("preDelete");
|
||||
stopPersistingAdapter.methodsCalled.clear();
|
||||
|
||||
ebeanServer.delete(EBasicVer.class, 22);
|
||||
db.delete(EBasicVer.class, 22);
|
||||
assertThat(stopPersistingAdapter.methodsCalled).hasSize(1);
|
||||
assertThat(stopPersistingAdapter.methodsCalled).containsExactly("preDeleteById");
|
||||
stopPersistingAdapter.methodsCalled.clear();
|
||||
|
||||
ebeanServer.deleteAll(EBasicVer.class, Arrays.asList(22,23,24));
|
||||
db.deleteAll(EBasicVer.class, Arrays.asList(22,23,24));
|
||||
assertThat(stopPersistingAdapter.methodsCalled).hasSize(3);
|
||||
assertThat(stopPersistingAdapter.methodsCalled).containsExactly("preDeleteById", "preDeleteById", "preDeleteById");
|
||||
stopPersistingAdapter.methodsCalled.clear();
|
||||
|
||||
db.shutdown();
|
||||
}
|
||||
|
||||
private EbeanServer getEbeanServer(PersistAdapter persistAdapter) {
|
||||
private Database getDatabase(PersistAdapter persistAdapter) {
|
||||
|
||||
ServerConfig config = new ServerConfig();
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
config.setName("h2ebasicver");
|
||||
config.loadFromProperties();
|
||||
config.setDdlGenerate(true);
|
||||
@@ -128,7 +131,7 @@ public class BeanPersistControllerTest {
|
||||
|
||||
config.add(persistAdapter);
|
||||
|
||||
return EbeanServerFactory.create(config);
|
||||
return DatabaseFactory.create(config);
|
||||
}
|
||||
|
||||
static class PersistAdapter extends BeanPersistAdapter {
|
||||
|
||||
@@ -3,10 +3,10 @@ package io.ebean.event;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.BeanState;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebean.EbeanServerFactory;
|
||||
import io.ebean.config.ServerConfig;
|
||||
import io.ebean.config.DatabaseConfig;
|
||||
import org.tests.model.basic.EBasicVer;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -22,15 +22,15 @@ public class BeanPostLoadTest extends BaseTestCase {
|
||||
@Test
|
||||
public void testPostLoad() {
|
||||
|
||||
EbeanServer ebeanServer = getEbeanServer();
|
||||
Database db = createDatabase();
|
||||
|
||||
EBasicVer bean = new EBasicVer("testPostLoad");
|
||||
bean.setDescription("someDescription");
|
||||
bean.setOther("other");
|
||||
|
||||
ebeanServer.save(bean);
|
||||
db.save(bean);
|
||||
|
||||
EBasicVer found = ebeanServer.find(EBasicVer.class)
|
||||
EBasicVer found = db.find(EBasicVer.class)
|
||||
.select("name, other")
|
||||
.setId(bean.getId())
|
||||
.findOne();
|
||||
@@ -40,13 +40,14 @@ public class BeanPostLoadTest extends BaseTestCase {
|
||||
assertThat(postLoad.beanState.getLoadedProps()).containsExactly("id", "name", "other");
|
||||
assertThat(postLoad.bean).isSameAs(found);
|
||||
|
||||
ebeanServer.delete(bean);
|
||||
db.delete(bean);
|
||||
db.shutdown();
|
||||
}
|
||||
|
||||
|
||||
private EbeanServer getEbeanServer() {
|
||||
private Database createDatabase() {
|
||||
|
||||
ServerConfig config = new ServerConfig();
|
||||
DatabaseConfig config = new DatabaseConfig();
|
||||
|
||||
config.setName("h2ebasicver");
|
||||
config.loadFromProperties();
|
||||
@@ -60,7 +61,7 @@ public class BeanPostLoadTest extends BaseTestCase {
|
||||
|
||||
config.add(postLoad);
|
||||
|
||||
return EbeanServerFactory.create(config);
|
||||
return DatabaseFactory.create(config);
|
||||
}
|
||||
|
||||
static class PostLoad implements BeanPostLoad {
|
||||
|
||||
+8
-8
@@ -4,7 +4,6 @@ import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Database;
|
||||
import io.ebean.DatabaseFactory;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.Transaction;
|
||||
import io.ebean.annotation.ForPlatform;
|
||||
import io.ebean.annotation.Platform;
|
||||
@@ -25,7 +24,7 @@ public class DefaultTransactionThreadLocalTest extends BaseTestCase {
|
||||
@ForPlatform({Platform.H2})
|
||||
@Test
|
||||
public void get() {
|
||||
Ebean.execute(() -> {
|
||||
DB.execute(() -> {
|
||||
SpiTransaction txn = getInScopeTransaction();
|
||||
assertNotNull(txn);
|
||||
});
|
||||
@@ -38,12 +37,12 @@ public class DefaultTransactionThreadLocalTest extends BaseTestCase {
|
||||
@Test
|
||||
public void tryWithResources_expect_scopeCleanup() {
|
||||
|
||||
try (Transaction transaction = Ebean.beginTransaction()) {
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
assertNotNull(transaction);
|
||||
SpiTransaction txn = getInScopeTransaction();
|
||||
assertSame(txn, transaction);
|
||||
|
||||
try (Transaction nested = Ebean.beginTransaction()) {
|
||||
try (Transaction nested = DB.beginTransaction()) {
|
||||
assertNotNull(nested);
|
||||
SpiTransaction txnNested = getInScopeTransaction();
|
||||
assertSame(txnNested, nested);
|
||||
@@ -59,7 +58,7 @@ public class DefaultTransactionThreadLocalTest extends BaseTestCase {
|
||||
@Test
|
||||
public void afterCommit_expect_scopeCleanup() {
|
||||
|
||||
try (Transaction transaction = Ebean.beginTransaction()) {
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.commit();
|
||||
assertNull(getInScopeTransaction());
|
||||
}
|
||||
@@ -70,7 +69,7 @@ public class DefaultTransactionThreadLocalTest extends BaseTestCase {
|
||||
@Test
|
||||
public void afterRollback_expect_scopeCleanup() {
|
||||
|
||||
try (Transaction transaction = Ebean.beginTransaction()) {
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
|
||||
transaction.rollback();
|
||||
assertNull(getInScopeTransaction());
|
||||
@@ -82,8 +81,8 @@ public class DefaultTransactionThreadLocalTest extends BaseTestCase {
|
||||
@Test
|
||||
public void end_withoutActiveTransaction_isFine() {
|
||||
|
||||
assertNull(Ebean.currentTransaction());
|
||||
Ebean.endTransaction();
|
||||
assertNull(DB.currentTransaction());
|
||||
DB.endTransaction();
|
||||
}
|
||||
|
||||
@ForPlatform({Platform.H2})
|
||||
@@ -128,6 +127,7 @@ public class DefaultTransactionThreadLocalTest extends BaseTestCase {
|
||||
assertNull(foundDefaultDb);
|
||||
|
||||
otherDb.delete(bean);
|
||||
otherDb.shutdown();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.tests.basic;
|
||||
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Database;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.ESimple;
|
||||
@@ -22,6 +23,11 @@ public class TestQueryUsingDatabase {
|
||||
DB.byName(SOME_OTHER_DB_NAME).insert(RECORD2);
|
||||
}
|
||||
|
||||
@After
|
||||
public void shutdown() {
|
||||
DB.byName(SOME_OTHER_DB_NAME).shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usingNonDefaultDatabase() {
|
||||
final Database nonDefaultDb = DB.byName(SOME_OTHER_DB_NAME);
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ public class TestCacheViaComplexNaturalKey extends BaseTestCase {
|
||||
return server().getServerCacheManager();
|
||||
}
|
||||
|
||||
private static synchronized void insertSome() {
|
||||
private static void insertSome() {
|
||||
if (!loadOnce) {
|
||||
Ebean.find(OCachedNatKeyBean.class).delete();
|
||||
for (String store : Arrays.asList("abc", "def")) {
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase {
|
||||
return server().getServerCacheManager();
|
||||
}
|
||||
|
||||
private static synchronized void insertSome() {
|
||||
private static void insertSome() {
|
||||
if (!loadOnce) {
|
||||
Ebean.find(OCachedNatKeyBean3.class).delete();
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ datasource.h2.poolListener=org.tests.basic.MyTestDataSourcePoolListener
|
||||
|
||||
datasource.h2multitenant.username=sa
|
||||
datasource.h2multitenant.password=
|
||||
datasource.h2multitenant.url=jdbc:h2:mem:h2multitenant
|
||||
datasource.h2multitenant.url=jdbc:h2:mem:h2multitenant;DB_CLOSE_ON_EXIT=FALSE
|
||||
|
||||
datasource.h2autocommit.autoCommit=true
|
||||
datasource.h2autocommit.username=sa
|
||||
@@ -100,11 +100,11 @@ datasource.h2autocommit2.url=jdbc:h2:mem:autocommit2tests
|
||||
|
||||
datasource.h2other.username=sa
|
||||
datasource.h2other.password=
|
||||
datasource.h2other.url=jdbc:h2:mem:h2other
|
||||
datasource.h2other.url=jdbc:h2:mem:h2other;DB_CLOSE_ON_EXIT=FALSE
|
||||
|
||||
datasource.h2otherfind.username=sa
|
||||
datasource.h2otherfind.password=
|
||||
datasource.h2otherfind.url=jdbc:h2:mem:h2otherfind
|
||||
datasource.h2otherfind.url=jdbc:h2:mem:h2otherfind;DB_CLOSE_ON_EXIT=FALSE
|
||||
|
||||
datasource.h2ebasicver.username=sa
|
||||
datasource.h2ebasicver.password=
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
<version>12.5.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ebean-ddlgen</artifactId>
|
||||
|
||||
|
||||
+1
-1
@@ -562,7 +562,7 @@ public class PlatformDdl {
|
||||
|
||||
/**
|
||||
* Return true if unique constraints for nullable columns can be inlined as normal.
|
||||
* Returns false for MsSqlServer & DB2 due to it's not possible to to put a constraint
|
||||
* Returns false for MsSqlServer and DB2 due to it's not possible to to put a constraint
|
||||
* on a nullable column
|
||||
*/
|
||||
public boolean isInlineUniqueWhenNullable() {
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import io.ebeaninternal.dbmigration.model.MTable;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Vilmos Nagy <vilmos.nagy@outlook.com>
|
||||
* @author Vilmos Nagy
|
||||
*/
|
||||
public class SqlServerHistoryDdl implements PlatformHistoryDdl {
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
<version>12.5.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<!-- <parent>-->
|
||||
<!-- <artifactId>ebean-parent</artifactId>-->
|
||||
<!-- <groupId>io.ebean</groupId>-->
|
||||
<!-- <version>12.5.1-SNAPSHOT</version>-->
|
||||
<!-- <version>12.5.2-SNAPSHOT</version>-->
|
||||
<!-- </parent>-->
|
||||
<parent>
|
||||
<groupId>org.avaje</groupId>
|
||||
@@ -13,14 +14,12 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-externalmapping-xml-12.5.0</tag>
|
||||
<tag>ebean-externalmapping-xml-12.5.1</tag>
|
||||
</scm>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ebean-externalmapping-xml</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.0</version>
|
||||
<version>12.5.1</version>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -34,7 +33,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
<version>12.5.0</version>
|
||||
<version>12.5.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -53,14 +52,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.5.0</version>
|
||||
<version>12.5.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddlgen</artifactId>
|
||||
<version>12.5.0</version>
|
||||
<version>12.5.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -78,7 +77,7 @@
|
||||
<plugin>
|
||||
<groupId>io.repaint.maven</groupId>
|
||||
<artifactId>tiles-maven-plugin</artifactId>
|
||||
<version>2.17</version>
|
||||
<version>2.18</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<tiles>
|
||||
|
||||
+21
-9
@@ -1,13 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<!-- <parent>-->
|
||||
<!-- <artifactId>ebean-parent</artifactId>-->
|
||||
<!-- <groupId>io.ebean</groupId>-->
|
||||
<!-- <version>12.5.2-SNAPSHOT</version>-->
|
||||
<!-- </parent>-->
|
||||
<parent>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>java8-oss</artifactId>
|
||||
<version>2.2</version>
|
||||
</parent>
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -15,7 +27,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
<version>12.5.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -48,14 +60,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddlgen</artifactId>
|
||||
<version>12.5.0</version>
|
||||
<version>12.5.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
<version>12.5.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -82,7 +94,7 @@
|
||||
<plugin>
|
||||
<groupId>io.repaint.maven</groupId>
|
||||
<artifactId>tiles-maven-plugin</artifactId>
|
||||
<version>2.17</version>
|
||||
<version>2.18</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<tiles>
|
||||
|
||||
@@ -5,6 +5,9 @@ import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.example.domain.otherpackage.GenericType;
|
||||
import org.example.domain.otherpackage.GenericTypeArgument;
|
||||
|
||||
/**
|
||||
* Address entity bean.
|
||||
*/
|
||||
@@ -24,8 +27,10 @@ public class Address extends BaseModel {
|
||||
@ManyToOne
|
||||
Country country;
|
||||
|
||||
GenericType<GenericTypeArgument> metadata;
|
||||
|
||||
/**
|
||||
* Create a copy of the address. Used to provide a 'snapshot' of
|
||||
* Create a copy of the address. Used to provide a 'snapshot' of
|
||||
* the shippingAddress for a give order.
|
||||
*/
|
||||
public Address createCopy() {
|
||||
@@ -36,7 +41,7 @@ public class Address extends BaseModel {
|
||||
copy.setCountry(country);
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return id + " " + line1 + " " + line2 + " " + city + " " + country;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.example.domain.otherpackage;
|
||||
|
||||
public class GenericType<T> {
|
||||
private T data;
|
||||
|
||||
public GenericType(final T data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(final T data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.example.domain.otherpackage;
|
||||
|
||||
public enum GenericTypeArgument {
|
||||
FOO,
|
||||
BAR;
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package org.example.domain.otherpackage;
|
||||
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
|
||||
@Converter
|
||||
public class GenericTypeAttributeConverter implements AttributeConverter<GenericType<GenericTypeArgument>, String> {
|
||||
@Override
|
||||
public String convertToDatabaseColumn(final GenericType<GenericTypeArgument> attribute) {
|
||||
return attribute.getData().name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericType<GenericTypeArgument> convertToEntityAttribute(final String dbData) {
|
||||
return new GenericType<>(GenericTypeArgument.valueOf(dbData));
|
||||
}
|
||||
}
|
||||
+32
-10
@@ -1,14 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<!-- <parent>-->
|
||||
<!-- <artifactId>ebean-parent</artifactId>-->
|
||||
<!-- <groupId>io.ebean</groupId>-->
|
||||
<!-- <version>12.5.2-SNAPSHOT</version>-->
|
||||
<!-- </parent>-->
|
||||
<parent>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>java8-oss</artifactId>
|
||||
<version>2.2</version>
|
||||
</parent>
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<jackson-databind.version>2.11.3</jackson-databind.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -22,14 +37,21 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
<version>12.5.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddlgen</artifactId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
<version>12.5.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson-databind.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -118,7 +140,7 @@
|
||||
<plugin>
|
||||
<groupId>io.repaint.maven</groupId>
|
||||
<artifactId>tiles-maven-plugin</artifactId>
|
||||
<version>2.17</version>
|
||||
<version>2.18</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<tiles>
|
||||
|
||||
@@ -2,15 +2,23 @@ package io.ebean.test.config;
|
||||
|
||||
import io.ebeaninternal.api.DbOffline;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
class RunOnceMarker {
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock(false);
|
||||
private static boolean hasRun;
|
||||
|
||||
static synchronized boolean isRun() {
|
||||
if (DbOffline.isSet() || hasRun) {
|
||||
return false;
|
||||
static boolean isRun() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (DbOffline.isSet() || hasRun) {
|
||||
return false;
|
||||
}
|
||||
hasRun = true;
|
||||
return true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
hasRun = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
<version>12.5.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ebean</artifactId>
|
||||
|
||||
|
||||
@@ -1,20 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
<version>12.5.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>kotlin-querybean-generator</artifactId>
|
||||
|
||||
<properties>
|
||||
<kotlin.version>1.4.10</kotlin.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.composite</groupId>
|
||||
<artifactId>composite-testing</artifactId>
|
||||
<version>3.1</version>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>5.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-test</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddlgen</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
<version>1.1.0.Final</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -22,11 +62,60 @@
|
||||
|
||||
|
||||
<build>
|
||||
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<version>${kotlin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-kapt</id>
|
||||
<goals>
|
||||
<goal>test-kapt</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sourceDirs>
|
||||
<sourceDir>src/test/kotlin</sourceDir>
|
||||
</sourceDirs>
|
||||
<annotationProcessorPaths>
|
||||
<annotationProcessorPath>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>kotlin-querybean-generator</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</annotationProcessorPath>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<jvmTarget>1.8</jvmTarget>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-testCompile</id>
|
||||
<phase>none</phase>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>java-test-compile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
@@ -34,6 +123,25 @@
|
||||
<compilerArgument>-proc:none</compilerArgument>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>12.5.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
<phase>process-test-classes</phase>
|
||||
<configuration>
|
||||
<transformArgs>debug=1</transformArgs>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>testEnhance</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
+2
-2
@@ -333,9 +333,9 @@ class ProcessingContext implements Constants {
|
||||
return result;
|
||||
} else {
|
||||
if (typeInstanceOf(typeMirror, "java.lang.Comparable")) {
|
||||
return new PropertyTypeScalarComparable(typeDef(typeMirror));
|
||||
return new PropertyTypeScalarComparable(typeMirror.toString());
|
||||
} else {
|
||||
return new PropertyTypeScalar(typeDef(typeMirror));
|
||||
return new PropertyTypeScalar(typeMirror.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-10
@@ -1,17 +1,18 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Property type for associated beans (OneToMany, ManyToOne etc).
|
||||
* Property type for fields handled by ScalarTypes
|
||||
*/
|
||||
class PropertyTypeScalar extends PropertyType {
|
||||
|
||||
/**
|
||||
* The package name for this associated query bean.
|
||||
*/
|
||||
private final String assocPackage;
|
||||
private final String attributeSimpleName;
|
||||
private final Set<String> assocImports;
|
||||
private final String attributeCompleteSignature;
|
||||
|
||||
/**
|
||||
* Construct given the associated bean type name and package.
|
||||
@@ -19,20 +20,26 @@ class PropertyTypeScalar extends PropertyType {
|
||||
* @param attributeClass the type in the database bean that will be serialized via ScalarType
|
||||
*/
|
||||
PropertyTypeScalar(String attributeClass) {
|
||||
super("PScalar");
|
||||
int split = attributeClass.lastIndexOf('.');
|
||||
this.assocPackage = attributeClass.substring(0, split);
|
||||
this.attributeSimpleName = attributeClass.substring(split + 1);
|
||||
this("PScalar", attributeClass);
|
||||
}
|
||||
|
||||
protected PropertyTypeScalar(String propertyType, String attributeClass) {
|
||||
super(propertyType);
|
||||
|
||||
final Entry<String, Set<String>> signature = Split.genericsSplit(attributeClass);
|
||||
|
||||
this.attributeCompleteSignature = signature.getKey();
|
||||
this.assocImports = signature.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
String getTypeDefn(String shortName, boolean assoc) {
|
||||
if (assoc) {
|
||||
// PScalarType<R, PhoneNumber>
|
||||
return "PScalar<R, " + attributeSimpleName + ">";
|
||||
return propertyType + "<R, " + attributeCompleteSignature + ">";
|
||||
} else {
|
||||
// PScalarType<QCustomer, PhoneNumber>
|
||||
return "PScalar<Q" + shortName + ", " + attributeSimpleName + ">";
|
||||
return propertyType + "<Q" + shortName + ", " + attributeCompleteSignature + ">";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +49,7 @@ class PropertyTypeScalar extends PropertyType {
|
||||
@Override
|
||||
void addImports(Set<String> allImports) {
|
||||
super.addImports(allImports);
|
||||
allImports.add(assocPackage + "." + attributeSimpleName);
|
||||
allImports.addAll(assocImports);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-35
@@ -1,17 +1,9 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Property type for associated beans (OneToMany, ManyToOne etc).
|
||||
* Property type for fields handled by ScalarTypes
|
||||
*/
|
||||
class PropertyTypeScalarComparable extends PropertyType {
|
||||
|
||||
/**
|
||||
* The package name for this associated query bean.
|
||||
*/
|
||||
private final String assocPackage;
|
||||
private final String attributeSimpleName;
|
||||
class PropertyTypeScalarComparable extends PropertyTypeScalar {
|
||||
|
||||
/**
|
||||
* Construct given the associated bean type name and package.
|
||||
@@ -19,30 +11,6 @@ class PropertyTypeScalarComparable extends PropertyType {
|
||||
* @param attributeClass the type in the database bean that will be serialized via ScalarType
|
||||
*/
|
||||
PropertyTypeScalarComparable(String attributeClass) {
|
||||
super("PScalarComparable");
|
||||
int split = attributeClass.lastIndexOf('.');
|
||||
this.assocPackage = attributeClass.substring(0, split);
|
||||
this.attributeSimpleName = attributeClass.substring(split + 1);
|
||||
super("PScalarComparable", attributeClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getTypeDefn(String shortName, boolean assoc) {
|
||||
if (assoc) {
|
||||
// PScalarType<R, PhoneNumber>
|
||||
return "PScalarComparable<R, " + attributeSimpleName + ">";
|
||||
} else {
|
||||
// PScalarType<QCustomer, PhoneNumber>
|
||||
return "PScalarComparable<Q" + shortName + ", " + attributeSimpleName + ">";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All required imports to the allImports set.
|
||||
*/
|
||||
@Override
|
||||
void addImports(Set<String> allImports) {
|
||||
super.addImports(allImports);
|
||||
allImports.add(assocPackage + "." + attributeSimpleName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Helper for splitting package and class name.
|
||||
*/
|
||||
@@ -41,4 +47,20 @@ class Split {
|
||||
return fullType;
|
||||
}
|
||||
|
||||
static Entry<String, Set<String>> genericsSplit(String signature) {
|
||||
StringBuilder simpleSignature = new StringBuilder();
|
||||
final StringTokenizer tokenizer = new StringTokenizer(signature, ",<> ", true);
|
||||
|
||||
Set<String> assocImports = new HashSet<>();
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
final String token = tokenizer.nextToken();
|
||||
if (token.length() == 1 && ",<> ".indexOf(token.charAt(0)) >= 0) {
|
||||
simpleSignature.append(token);
|
||||
} else {
|
||||
simpleSignature.append(Split.shortName(token));
|
||||
assocImports.add(token);
|
||||
}
|
||||
}
|
||||
return new SimpleEntry<>(simpleSignature.toString(), assocImports);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNull;
|
||||
|
||||
public class SplitTest {
|
||||
|
||||
@Test
|
||||
public void trimType() {
|
||||
assertEquals(Split.trimType("com.foo.domain.Customer"), "com.foo.domain.Customer");
|
||||
assertEquals(Split.trimType("? extends com.foo.domain.Customer"), "com.foo.domain.Customer");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shortName() {
|
||||
assertEquals(Split.shortName("com.foo.domain.Customer"), "Customer");
|
||||
assertEquals(Split.shortName("Customer"), "Customer");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void split_normal() {
|
||||
|
||||
String[] split = Split.split("com.foo.domain.Customer");
|
||||
|
||||
assertEquals(split[0], "com.foo.domain");
|
||||
assertEquals(split[1], "Customer");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void split_noPackage() {
|
||||
|
||||
String[] split = Split.split("Customer");
|
||||
|
||||
assertNull(split[0]);
|
||||
assertEquals(split[1], "Customer");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package io.ebean.querybean.generator
|
||||
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertNull
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.lang.Exception
|
||||
import java.util.Arrays
|
||||
import java.util.HashSet
|
||||
|
||||
class SplitTest {
|
||||
@Test
|
||||
fun trimType() {
|
||||
assertEquals(Split.trimType("com.foo.domain.Customer"), "com.foo.domain.Customer")
|
||||
assertEquals(Split.trimType("? extends com.foo.domain.Customer"), "com.foo.domain.Customer")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shortName() {
|
||||
assertEquals(Split.shortName("com.foo.domain.Customer"), "Customer")
|
||||
assertEquals(Split.shortName("Customer"), "Customer")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun split_normal() {
|
||||
val split = Split.split("com.foo.domain.Customer")
|
||||
assertEquals(split[0], "com.foo.domain")
|
||||
assertEquals(split[1], "Customer")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun split_noPackage() {
|
||||
val split = Split.split("Customer")
|
||||
assertNull(split[0])
|
||||
assertEquals(split[1], "Customer")
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun split_generics() {
|
||||
assertEquals("Foo<Bar, XFoo<XBar>>", Split.genericsSplit("com.Foo<com.Bar, org.XFoo<org.XBar>>").key)
|
||||
assertEquals(
|
||||
HashSet(Arrays.asList("com.Foo", "com.Bar", "org.XFoo", "org.XBar")),
|
||||
Split.genericsSplit("com.Foo<com.Bar, org.XFoo<org.XBar>>").value
|
||||
)
|
||||
assertEquals("Foo", Split.genericsSplit("com.bar.Foo").key)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.example.domain;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.example.otherpackage.GenericType;
|
||||
import org.example.otherpackage.GenericTypeArgument;
|
||||
|
||||
/**
|
||||
* Address entity bean.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "o_address")
|
||||
class Address(
|
||||
@Size(max = 100)
|
||||
var line1: String,
|
||||
@Size(max = 100)
|
||||
var line2: String,
|
||||
@Size(max = 100)
|
||||
var city: String,
|
||||
// Dummy metadata field just to test generation
|
||||
val metadata: GenericType<GenericTypeArgument>
|
||||
) : BaseModel()
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.example.domain;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import io.ebean.Model;
|
||||
import io.ebean.annotation.WhenCreated;
|
||||
import io.ebean.annotation.WhenModified;
|
||||
|
||||
@MappedSuperclass
|
||||
abstract class BaseModel : Model() {
|
||||
@Id
|
||||
val id: Long? = null
|
||||
|
||||
@Version
|
||||
val version: Int = 0
|
||||
|
||||
@WhenCreated
|
||||
val whenCreated: Instant? = null
|
||||
|
||||
@WhenModified
|
||||
val whenModified: Instant? = null
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
interface Email<T> : Comparable<T>
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
class GenericType<T>(
|
||||
val data: T
|
||||
)
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
enum class GenericTypeArgument {
|
||||
FOO,
|
||||
BAR,
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
import javax.persistence.AttributeConverter
|
||||
import javax.persistence.Converter
|
||||
|
||||
@Converter
|
||||
class GenericTypeAttributeConverter : AttributeConverter<GenericType<GenericTypeArgument>, String> {
|
||||
override fun convertToDatabaseColumn(attribute: GenericType<GenericTypeArgument>): String {
|
||||
return attribute.data.name
|
||||
}
|
||||
|
||||
override fun convertToEntityAttribute(dbData: String): GenericType<GenericTypeArgument> {
|
||||
return GenericType(GenericTypeArgument.valueOf(dbData))
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
import javax.persistence.AttributeConverter
|
||||
import javax.persistence.Converter
|
||||
|
||||
@Converter
|
||||
class PhoneAttributeConverter : AttributeConverter<PhoneNumber, String> {
|
||||
override fun convertToDatabaseColumn(attribute: PhoneNumber): String {
|
||||
return attribute.msisdn
|
||||
}
|
||||
|
||||
override fun convertToEntityAttribute(dbData: String): PhoneNumber {
|
||||
return PhoneNumber(dbData)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
class PhoneNumber(
|
||||
val msisdn: String
|
||||
)
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
class ValidEmail(
|
||||
val emailAddress: String
|
||||
) : Email<ValidEmail> {
|
||||
override fun compareTo(other: ValidEmail): Int {
|
||||
return emailAddress.compareTo(other.emailAddress)
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.example.otherpackage
|
||||
|
||||
import javax.persistence.AttributeConverter
|
||||
import javax.persistence.Converter
|
||||
|
||||
@Converter
|
||||
class ValidEmailAttributeConverter : AttributeConverter<ValidEmail, String> {
|
||||
override fun convertToDatabaseColumn(attribute: ValidEmail): String {
|
||||
return attribute.emailAddress
|
||||
}
|
||||
|
||||
override fun convertToEntityAttribute(dbData: String): ValidEmail {
|
||||
return ValidEmail(dbData)
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
<version>12.5.2-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<parent>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.5.1-SNAPSHOT</version>
|
||||
<version>12.5.2-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
|
||||
|
||||
+2
-2
@@ -298,9 +298,9 @@ class ProcessingContext implements Constants {
|
||||
return result;
|
||||
} else {
|
||||
if (typeInstanceOf(typeMirror, "java.lang.Comparable")) {
|
||||
return new PropertyTypeScalarComparable(typeDef(typeMirror));
|
||||
return new PropertyTypeScalarComparable(typeMirror.toString());
|
||||
} else {
|
||||
return new PropertyTypeScalar(typeDef(typeMirror));
|
||||
return new PropertyTypeScalar(typeMirror.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-12
@@ -1,17 +1,17 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Property type for associated beans (OneToMany, ManyToOne etc).
|
||||
* Property type for fields handled by ScalarTypes
|
||||
*/
|
||||
class PropertyTypeScalar extends PropertyType {
|
||||
|
||||
/**
|
||||
* The package name for this associated query bean.
|
||||
*/
|
||||
private final String assocPackage;
|
||||
private final String attributeSimpleName;
|
||||
private final Set<String> assocImports;
|
||||
private final String attributeCompleteSignature;
|
||||
|
||||
/**
|
||||
* Construct given the associated bean type name and package.
|
||||
@@ -19,20 +19,26 @@ class PropertyTypeScalar extends PropertyType {
|
||||
* @param attributeClass the type in the database bean that will be serialized via ScalarType
|
||||
*/
|
||||
PropertyTypeScalar(String attributeClass) {
|
||||
super("PScalar");
|
||||
int split = attributeClass.lastIndexOf('.');
|
||||
this.assocPackage = attributeClass.substring(0, split);
|
||||
this.attributeSimpleName = attributeClass.substring(split + 1);
|
||||
this("PScalar", attributeClass);
|
||||
}
|
||||
|
||||
protected PropertyTypeScalar(String propertyType, String attributeClass) {
|
||||
super(propertyType);
|
||||
|
||||
final Entry<String, Set<String>> signature = Split.genericsSplit(attributeClass);
|
||||
|
||||
this.attributeCompleteSignature = signature.getKey();
|
||||
this.assocImports = signature.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
String getTypeDefn(String shortName, boolean assoc) {
|
||||
if (assoc) {
|
||||
// PScalarType<R, PhoneNumber>
|
||||
return "PScalar<R, " + attributeSimpleName + ">";
|
||||
return propertyType + "<R, " + attributeCompleteSignature + ">";
|
||||
} else {
|
||||
// PScalarType<QCustomer, PhoneNumber>
|
||||
return "PScalar<Q" + shortName + ", " + attributeSimpleName + ">";
|
||||
return propertyType + "<Q" + shortName + ", " + attributeCompleteSignature + ">";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +48,6 @@ class PropertyTypeScalar extends PropertyType {
|
||||
@Override
|
||||
void addImports(Set<String> allImports) {
|
||||
super.addImports(allImports);
|
||||
allImports.add(assocPackage + "." + attributeSimpleName);
|
||||
allImports.addAll(assocImports);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-34
@@ -1,17 +1,9 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Property type for associated beans (OneToMany, ManyToOne etc).
|
||||
*/
|
||||
class PropertyTypeScalarComparable extends PropertyType {
|
||||
|
||||
/**
|
||||
* The package name for this associated query bean.
|
||||
*/
|
||||
private final String assocPackage;
|
||||
private final String attributeSimpleName;
|
||||
class PropertyTypeScalarComparable extends PropertyTypeScalar {
|
||||
|
||||
/**
|
||||
* Construct given the associated bean type name and package.
|
||||
@@ -19,30 +11,6 @@ class PropertyTypeScalarComparable extends PropertyType {
|
||||
* @param attributeClass the type in the database bean that will be serialized via ScalarType
|
||||
*/
|
||||
PropertyTypeScalarComparable(String attributeClass) {
|
||||
super("PScalarComparable");
|
||||
int split = attributeClass.lastIndexOf('.');
|
||||
this.assocPackage = attributeClass.substring(0, split);
|
||||
this.attributeSimpleName = attributeClass.substring(split + 1);
|
||||
super("PScalarComparable", attributeClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getTypeDefn(String shortName, boolean assoc) {
|
||||
if (assoc) {
|
||||
// PScalarType<R, PhoneNumber>
|
||||
return "PScalarComparable<R, " + attributeSimpleName + ">";
|
||||
} else {
|
||||
// PScalarType<QCustomer, PhoneNumber>
|
||||
return "PScalarComparable<Q" + shortName + ", " + attributeSimpleName + ">";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All required imports to the allImports set.
|
||||
*/
|
||||
@Override
|
||||
void addImports(Set<String> allImports) {
|
||||
super.addImports(allImports);
|
||||
allImports.add(assocPackage + "." + attributeSimpleName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Helper for splitting package and class name.
|
||||
*/
|
||||
@@ -31,4 +37,21 @@ class Split {
|
||||
return className.substring(startPos + 1);
|
||||
}
|
||||
|
||||
static Entry<String, Set<String>> genericsSplit(String signature) {
|
||||
StringBuilder simpleSignature = new StringBuilder();
|
||||
final StringTokenizer tokenizer = new StringTokenizer(signature, ",<> ", true);
|
||||
|
||||
Set<String> assocImports = new HashSet<>();
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
final String token = tokenizer.nextToken();
|
||||
if (token.length() == 1 && ",<> ".indexOf(token.charAt(0)) >= 0) {
|
||||
simpleSignature.append(token);
|
||||
} else {
|
||||
simpleSignature.append(Split.shortName(token));
|
||||
assocImports.add(token);
|
||||
}
|
||||
}
|
||||
return new SimpleEntry<>(simpleSignature.toString(), assocImports);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package io.ebean.querybean.generator;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class SplitTest {
|
||||
|
||||
@Test
|
||||
@@ -32,4 +35,9 @@ public class SplitTest {
|
||||
assertEquals(split[1], "Customer");
|
||||
}
|
||||
|
||||
}
|
||||
@Test
|
||||
public void split_generics() throws Exception {
|
||||
assertEquals("Foo<Bar, XFoo<XBar>>", Split.genericsSplit("com.Foo<com.Bar, org.XFoo<org.XBar>>").getKey());
|
||||
assertEquals(new HashSet<>(asList("com.Foo", "com.Bar", "org.XFoo", "org.XBar")), Split.genericsSplit("com.Foo<com.Bar, org.XFoo<org.XBar>>").getValue());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user