mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
63
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4c7cf529d | ||
|
|
ba5c67f936 | ||
|
|
2bd7995ca1 | ||
|
|
cc8c860709 | ||
|
|
7d25e31289 | ||
|
|
936e56835c | ||
|
|
0d848e9311 | ||
|
|
b794b6c77e | ||
|
|
f45d240682 | ||
|
|
1a6f68edd3 | ||
|
|
81683c5d2a | ||
|
|
2b535d59b8 | ||
|
|
ae0bbaaaf8 | ||
|
|
aaca20f9c3 | ||
|
|
245cbb0ea1 | ||
|
|
dbe984c668 | ||
|
|
89088f9480 | ||
|
|
80253c4e07 | ||
|
|
f96ce11c73 | ||
|
|
b8f8cb5ae7 | ||
|
|
b8a2aac95a | ||
|
|
7b090a6346 | ||
|
|
b10c68489f | ||
|
|
2dbb2d9911 | ||
|
|
b3b4c72a77 | ||
|
|
1c040e4583 | ||
|
|
9677e585b6 | ||
|
|
c53806224f | ||
|
|
6fd5927c64 | ||
|
|
920635c6df | ||
|
|
fb1c29b57c | ||
|
|
89bed8be67 | ||
|
|
776e48a501 | ||
|
|
0666a72df7 | ||
|
|
55000a3515 | ||
|
|
8307e259ba | ||
|
|
95b7574d04 | ||
|
|
f6466d3211 | ||
|
|
160e4d7dd1 | ||
|
|
a00980c61f | ||
|
|
72d2fcb59e | ||
|
|
0f503b2a2f | ||
|
|
a79e2e786a | ||
|
|
c9ffa2673f | ||
|
|
0e0fa37f0d | ||
|
|
f7bbd5b3bb | ||
|
|
ba614cd287 | ||
|
|
7d028f3318 | ||
|
|
21b04c244b | ||
|
|
957c2def43 | ||
|
|
35f9cd3821 | ||
|
|
e95d3304bf | ||
|
|
0f7c9da5d2 | ||
|
|
b4008da70c | ||
|
|
34a0f16c74 | ||
|
|
a880109201 | ||
|
|
0607151ac8 | ||
|
|
5c4ad4c01c | ||
|
|
3564504e00 | ||
|
|
49babef495 | ||
|
|
9e3362d004 | ||
|
|
3f0dcdb6d1 | ||
|
|
481116251d |
@@ -1,5 +1,6 @@
|
||||
*.autofetch
|
||||
*.sql
|
||||
*.orig
|
||||
.classpath
|
||||
.project
|
||||
.settings/
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
[](https://waffle.io/ebean-orm/avaje-ebeanorm)
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm) - avaje-ebeanorm
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent) - avaje-ebeanorm-agent
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-mavenenhancer) - avaje-ebeanorm-mavenenhancer
|
||||
|
||||
|
||||
Ebean ORM
|
||||
==============
|
||||
|
||||
Project Website
|
||||
----------------
|
||||
[http://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Website")
|
||||
|
||||
|
||||
@@ -12,7 +13,7 @@ Maven Dependency
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>4.7.1</version>
|
||||
<version>4.7.3</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>4.7.3</version>
|
||||
<version>6.1.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>avaje-ebeanorm</name>
|
||||
@@ -43,6 +43,12 @@
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>13.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.persistence</groupId>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
@@ -152,7 +158,7 @@
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.27</version>
|
||||
<version>5.1.36</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.avaje.ebean;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -10,6 +9,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -101,7 +101,7 @@ import com.avaje.ebean.text.json.JsonContext;
|
||||
* specific database.
|
||||
* </p>
|
||||
*
|
||||
* <pre> {@code
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Get access to the Human Resources EbeanServer/Database
|
||||
* EbeanServer hrDb = Ebean.getServer("hr");
|
||||
@@ -146,9 +146,9 @@ public final class Ebean {
|
||||
private final Object monitor = new Object();
|
||||
|
||||
/**
|
||||
* The 'default/primary' EbeanServer.
|
||||
* The 'default' EbeanServer.
|
||||
*/
|
||||
private EbeanServer primaryServer;
|
||||
private EbeanServer defaultServer;
|
||||
|
||||
private ServerManager() {
|
||||
|
||||
@@ -162,10 +162,10 @@ public final class Ebean {
|
||||
|
||||
} else {
|
||||
// look to see if there is a default server defined
|
||||
String primaryName = PrimaryServer.getPrimaryServerName();
|
||||
logger.debug("primaryName:" + primaryName);
|
||||
if (primaryName != null && primaryName.trim().length() > 0) {
|
||||
primaryServer = getWithCreate(primaryName.trim());
|
||||
String defaultName = PrimaryServer.getDefaultServerName();
|
||||
logger.debug("defaultName:" + defaultName);
|
||||
if (defaultName != null && defaultName.trim().length() > 0) {
|
||||
defaultServer = getWithCreate(defaultName.trim());
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
@@ -174,19 +174,19 @@ public final class Ebean {
|
||||
}
|
||||
}
|
||||
|
||||
private EbeanServer getPrimaryServer() {
|
||||
if (primaryServer == null) {
|
||||
private EbeanServer getDefaultServer() {
|
||||
if (defaultServer == null) {
|
||||
String msg = "The default EbeanServer has not been defined?";
|
||||
msg += " This is normally set via the ebean.datasource.default property.";
|
||||
msg += " Otherwise it should be registered programatically via registerServer()";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
return primaryServer;
|
||||
return defaultServer;
|
||||
}
|
||||
|
||||
private EbeanServer get(String name) {
|
||||
if (name == null || name.length() == 0) {
|
||||
return primaryServer;
|
||||
return defaultServer;
|
||||
}
|
||||
// non-synchronized read
|
||||
EbeanServer server = concMap.get(name);
|
||||
@@ -221,12 +221,12 @@ public final class Ebean {
|
||||
registerWithName(server.getName(), server, isPrimaryServer);
|
||||
}
|
||||
|
||||
private void registerWithName(String name, EbeanServer server, boolean isPrimaryServer) {
|
||||
private void registerWithName(String name, EbeanServer server, boolean isDefaultServer) {
|
||||
synchronized (monitor) {
|
||||
concMap.put(name, server);
|
||||
syncMap.put(name, server);
|
||||
if (isPrimaryServer) {
|
||||
primaryServer = server;
|
||||
if (isDefaultServer) {
|
||||
defaultServer = server;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,12 +254,22 @@ public final class Ebean {
|
||||
* }</pre>
|
||||
*
|
||||
* @param name
|
||||
* the name of the server, use null for the 'default server'
|
||||
* the name of the server, can use null for the 'default server'
|
||||
*/
|
||||
public static EbeanServer getServer(String name) {
|
||||
return serverMgr.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default EbeanServer.
|
||||
* <p>
|
||||
* This is equivalent to <code>Ebean.getServer(null);</code>
|
||||
* </p>
|
||||
*/
|
||||
public static EbeanServer getDefaultServer() {
|
||||
return serverMgr.getDefaultServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ExpressionFactory from the default server.
|
||||
* <p>
|
||||
@@ -278,23 +288,23 @@ public final class Ebean {
|
||||
* </p>
|
||||
*/
|
||||
public static ExpressionFactory getExpressionFactory() {
|
||||
return serverMgr.getPrimaryServer().getExpressionFactory();
|
||||
return serverMgr.getDefaultServer().getExpressionFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the server with this Ebean singleton. Specify if the registered
|
||||
* server is the primary/default server.
|
||||
*/
|
||||
public static void register(EbeanServer server, boolean isPrimaryServer) {
|
||||
serverMgr.register(server, isPrimaryServer);
|
||||
public static void register(EbeanServer server, boolean defaultServer) {
|
||||
serverMgr.register(server, defaultServer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Backdoor for registering a mock implementation of EbeanServer as the default server.
|
||||
*/
|
||||
protected static EbeanServer mock(String name, EbeanServer server, boolean isPrimaryServer) {
|
||||
EbeanServer originalPrimaryServer = serverMgr.primaryServer;
|
||||
serverMgr.registerWithName(name, server, isPrimaryServer);
|
||||
protected static EbeanServer mock(String name, EbeanServer server, boolean defaultServer) {
|
||||
EbeanServer originalPrimaryServer = serverMgr.defaultServer;
|
||||
serverMgr.registerWithName(name, server, defaultServer);
|
||||
return originalPrimaryServer;
|
||||
}
|
||||
|
||||
@@ -311,7 +321,7 @@ public final class Ebean {
|
||||
* </p>
|
||||
*/
|
||||
public static Object nextId(Class<?> beanType) {
|
||||
return serverMgr.getPrimaryServer().nextId(beanType);
|
||||
return serverMgr.getDefaultServer().nextId(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,7 +369,7 @@ public final class Ebean {
|
||||
* </p>
|
||||
*/
|
||||
public static Transaction beginTransaction() {
|
||||
return serverMgr.getPrimaryServer().beginTransaction();
|
||||
return serverMgr.getDefaultServer().beginTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -370,7 +380,7 @@ public final class Ebean {
|
||||
*
|
||||
*/
|
||||
public static Transaction beginTransaction(TxIsolation isolation) {
|
||||
return serverMgr.getPrimaryServer().beginTransaction(isolation);
|
||||
return serverMgr.getDefaultServer().beginTransaction(isolation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -425,7 +435,7 @@ public final class Ebean {
|
||||
* }</pre>
|
||||
*/
|
||||
public static Transaction beginTransaction(TxScope scope){
|
||||
return serverMgr.getPrimaryServer().beginTransaction(scope);
|
||||
return serverMgr.getDefaultServer().beginTransaction(scope);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -433,7 +443,7 @@ public final class Ebean {
|
||||
* in scope.
|
||||
*/
|
||||
public static Transaction currentTransaction() {
|
||||
return serverMgr.getPrimaryServer().currentTransaction();
|
||||
return serverMgr.getDefaultServer().currentTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -446,21 +456,21 @@ public final class Ebean {
|
||||
* @throws PersistenceException if there is no currently active transaction
|
||||
*/
|
||||
public static void register(TransactionCallback transactionCallback) throws PersistenceException {
|
||||
serverMgr.getPrimaryServer().register(transactionCallback);
|
||||
serverMgr.getDefaultServer().register(transactionCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the current transaction.
|
||||
*/
|
||||
public static void commitTransaction() {
|
||||
serverMgr.getPrimaryServer().commitTransaction();
|
||||
serverMgr.getDefaultServer().commitTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the current transaction.
|
||||
*/
|
||||
public static void rollbackTransaction() {
|
||||
serverMgr.getPrimaryServer().rollbackTransaction();
|
||||
serverMgr.getDefaultServer().rollbackTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -489,7 +499,7 @@ public final class Ebean {
|
||||
* }</pre>
|
||||
*/
|
||||
public static void endTransaction() {
|
||||
serverMgr.getPrimaryServer().endTransaction();
|
||||
serverMgr.getDefaultServer().endTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -500,7 +510,7 @@ public final class Ebean {
|
||||
* </p>
|
||||
*/
|
||||
public static Map<String, ValuePair> diff(Object a, Object b) {
|
||||
return serverMgr.getPrimaryServer().diff(a, b);
|
||||
return serverMgr.getDefaultServer().diff(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -523,7 +533,6 @@ public final class Ebean {
|
||||
* public class Order { ...
|
||||
*
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* @JoinColumn(name="order_id")
|
||||
* List<OrderDetail> details;
|
||||
* ...
|
||||
* }
|
||||
@@ -537,7 +546,7 @@ public final class Ebean {
|
||||
* </p>
|
||||
*/
|
||||
public static void save(Object bean) throws OptimisticLockException {
|
||||
serverMgr.getPrimaryServer().save(bean);
|
||||
serverMgr.getDefaultServer().save(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -545,14 +554,14 @@ public final class Ebean {
|
||||
* want to explicitly insert it.
|
||||
*/
|
||||
public static void insert(Object bean) {
|
||||
serverMgr.getPrimaryServer().insert(bean);
|
||||
serverMgr.getDefaultServer().insert(bean);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Insert a collection of beans.
|
||||
*/
|
||||
public static void insert(Collection<?> beans) {
|
||||
serverMgr.getPrimaryServer().insert(beans);
|
||||
public static void insertAll(Collection<?> beans) {
|
||||
serverMgr.getDefaultServer().insertAll(beans);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -576,7 +585,7 @@ public final class Ebean {
|
||||
* }</pre>
|
||||
*/
|
||||
public static void markAsDirty(Object bean) throws OptimisticLockException {
|
||||
serverMgr.getPrimaryServer().markAsDirty(bean);
|
||||
serverMgr.getDefaultServer().markAsDirty(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -616,28 +625,21 @@ public final class Ebean {
|
||||
* @see ServerConfig#setUpdateChangesOnly(boolean)
|
||||
*/
|
||||
public static void update(Object bean) throws OptimisticLockException {
|
||||
serverMgr.getPrimaryServer().update(bean);
|
||||
serverMgr.getDefaultServer().update(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the beans in the collection.
|
||||
*/
|
||||
public static void update(Collection<?> beans) throws OptimisticLockException {
|
||||
serverMgr.getPrimaryServer().update(beans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save all the beans from an Iterator.
|
||||
*/
|
||||
public static int save(Iterator<?> iterator) throws OptimisticLockException {
|
||||
return serverMgr.getPrimaryServer().save(iterator);
|
||||
public static void updateAll(Collection<?> beans) throws OptimisticLockException {
|
||||
serverMgr.getDefaultServer().updateAll(beans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save all the beans from a Collection.
|
||||
*/
|
||||
public static int save(Collection<?> beans) throws OptimisticLockException {
|
||||
return serverMgr.getPrimaryServer().save(beans);
|
||||
public static int saveAll(Collection<?> beans) throws OptimisticLockException {
|
||||
return serverMgr.getDefaultServer().saveAll(beans);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -651,7 +653,7 @@ public final class Ebean {
|
||||
* @return the number of associations deleted (from the intersection table).
|
||||
*/
|
||||
public static int deleteManyToManyAssociations(Object ownerBean, String propertyName) {
|
||||
return serverMgr.getPrimaryServer().deleteManyToManyAssociations(ownerBean, propertyName);
|
||||
return serverMgr.getDefaultServer().deleteManyToManyAssociations(ownerBean, propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -669,7 +671,7 @@ public final class Ebean {
|
||||
* </p>
|
||||
*/
|
||||
public static void saveManyToManyAssociations(Object ownerBean, String propertyName) {
|
||||
serverMgr.getPrimaryServer().saveManyToManyAssociations(ownerBean, propertyName);
|
||||
serverMgr.getDefaultServer().saveManyToManyAssociations(ownerBean, propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -689,7 +691,7 @@ public final class Ebean {
|
||||
* the property we want to save
|
||||
*/
|
||||
public static void saveAssociation(Object ownerBean, String propertyName) {
|
||||
serverMgr.getPrimaryServer().saveAssociation(ownerBean, propertyName);
|
||||
serverMgr.getDefaultServer().saveAssociation(ownerBean, propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -700,35 +702,28 @@ public final class Ebean {
|
||||
* </p>
|
||||
*/
|
||||
public static void delete(Object bean) throws OptimisticLockException {
|
||||
serverMgr.getPrimaryServer().delete(bean);
|
||||
serverMgr.getDefaultServer().delete(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the bean given its type and id.
|
||||
*/
|
||||
public static int delete(Class<?> beanType, Object id) {
|
||||
return serverMgr.getPrimaryServer().delete(beanType, id);
|
||||
return serverMgr.getDefaultServer().delete(beanType, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete several beans given their type and id values.
|
||||
*/
|
||||
public static void delete(Class<?> beanType, Collection<?> ids) {
|
||||
serverMgr.getPrimaryServer().delete(beanType, ids);
|
||||
public static void deleteAll(Class<?> beanType, Collection<?> ids) {
|
||||
serverMgr.getDefaultServer().deleteAll(beanType, ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all the beans from an Iterator.
|
||||
* Delete all the beans in the Collection.
|
||||
*/
|
||||
public static int delete(Iterator<?> it) throws OptimisticLockException {
|
||||
return serverMgr.getPrimaryServer().delete(it);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all the beans from a Collection.
|
||||
*/
|
||||
public static int delete(Collection<?> c) throws OptimisticLockException {
|
||||
return delete(c.iterator());
|
||||
public static int deleteAll(Collection<?> beans) throws OptimisticLockException {
|
||||
return serverMgr.getDefaultServer().deleteAll(beans);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -739,7 +734,7 @@ public final class Ebean {
|
||||
* </p>
|
||||
*/
|
||||
public static void refresh(Object bean) {
|
||||
serverMgr.getPrimaryServer().refresh(bean);
|
||||
serverMgr.getDefaultServer().refresh(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -760,7 +755,7 @@ public final class Ebean {
|
||||
* the property name of the List Set or Map to refresh.
|
||||
*/
|
||||
public static void refreshMany(Object bean, String manyPropertyName) {
|
||||
serverMgr.getPrimaryServer().refreshMany(bean, manyPropertyName);
|
||||
serverMgr.getDefaultServer().refreshMany(bean, manyPropertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -788,7 +783,7 @@ public final class Ebean {
|
||||
* the id value
|
||||
*/
|
||||
public static <T> T getReference(Class<T> beanType, Object id) {
|
||||
return serverMgr.getPrimaryServer().getReference(beanType, id);
|
||||
return serverMgr.getDefaultServer().getReference(beanType, id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -834,7 +829,7 @@ public final class Ebean {
|
||||
* the properties to sort the list by
|
||||
*/
|
||||
public static <T> void sort(List<T> list, String sortByClause) {
|
||||
serverMgr.getPrimaryServer().sort(list, sortByClause);
|
||||
serverMgr.getDefaultServer().sort(list, sortByClause);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -883,8 +878,9 @@ public final class Ebean {
|
||||
* @param id
|
||||
* the id value
|
||||
*/
|
||||
@Nullable
|
||||
public static <T> T find(Class<T> beanType, Object id) {
|
||||
return serverMgr.getPrimaryServer().find(beanType, id);
|
||||
return serverMgr.getDefaultServer().find(beanType, id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -896,7 +892,7 @@ public final class Ebean {
|
||||
* </p>
|
||||
*/
|
||||
public static SqlQuery createSqlQuery(String sql) {
|
||||
return serverMgr.getPrimaryServer().createSqlQuery(sql);
|
||||
return serverMgr.getDefaultServer().createSqlQuery(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -909,7 +905,7 @@ public final class Ebean {
|
||||
* the name of the query
|
||||
*/
|
||||
public static SqlQuery createNamedSqlQuery(String namedQuery) {
|
||||
return serverMgr.getPrimaryServer().createNamedSqlQuery(namedQuery);
|
||||
return serverMgr.getDefaultServer().createNamedSqlQuery(namedQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -927,7 +923,7 @@ public final class Ebean {
|
||||
* </p>
|
||||
*/
|
||||
public static SqlUpdate createSqlUpdate(String sql) {
|
||||
return serverMgr.getPrimaryServer().createSqlUpdate(sql);
|
||||
return serverMgr.getDefaultServer().createSqlUpdate(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -936,7 +932,7 @@ public final class Ebean {
|
||||
* @see CallableSql
|
||||
*/
|
||||
public static CallableSql createCallableSql(String sql) {
|
||||
return serverMgr.getPrimaryServer().createCallableSql(sql);
|
||||
return serverMgr.getDefaultServer().createCallableSql(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -959,7 +955,7 @@ public final class Ebean {
|
||||
* }</pre>
|
||||
*/
|
||||
public static SqlUpdate createNamedSqlUpdate(String namedQuery) {
|
||||
return serverMgr.getPrimaryServer().createNamedSqlUpdate(namedQuery);
|
||||
return serverMgr.getDefaultServer().createNamedSqlUpdate(namedQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -987,7 +983,7 @@ public final class Ebean {
|
||||
*/
|
||||
public static <T> Query<T> createNamedQuery(Class<T> beanType, String namedQuery) {
|
||||
|
||||
return serverMgr.getPrimaryServer().createNamedQuery(beanType, namedQuery);
|
||||
return serverMgr.getDefaultServer().createNamedQuery(beanType, namedQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1015,7 +1011,7 @@ public final class Ebean {
|
||||
* the object query
|
||||
*/
|
||||
public static <T> Query<T> createQuery(Class<T> beanType, String query) {
|
||||
return serverMgr.getPrimaryServer().createQuery(beanType, query);
|
||||
return serverMgr.getDefaultServer().createQuery(beanType, query);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1074,7 +1070,7 @@ public final class Ebean {
|
||||
*/
|
||||
public static <T> Update<T> createNamedUpdate(Class<T> beanType, String namedUpdate) {
|
||||
|
||||
return serverMgr.getPrimaryServer().createNamedUpdate(beanType, namedUpdate);
|
||||
return serverMgr.getDefaultServer().createNamedUpdate(beanType, namedUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1108,7 +1104,7 @@ public final class Ebean {
|
||||
*/
|
||||
public static <T> Update<T> createUpdate(Class<T> beanType, String ormUpdate) {
|
||||
|
||||
return serverMgr.getPrimaryServer().createUpdate(beanType, ormUpdate);
|
||||
return serverMgr.getDefaultServer().createUpdate(beanType, ormUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1116,7 +1112,7 @@ public final class Ebean {
|
||||
*/
|
||||
public static <T> CsvReader<T> createCsvReader(Class<T> beanType) {
|
||||
|
||||
return serverMgr.getPrimaryServer().createCsvReader(beanType);
|
||||
return serverMgr.getDefaultServer().createCsvReader(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1173,7 +1169,7 @@ public final class Ebean {
|
||||
*/
|
||||
public static <T> Query<T> createQuery(Class<T> beanType) {
|
||||
|
||||
return serverMgr.getPrimaryServer().createQuery(beanType);
|
||||
return serverMgr.getDefaultServer().createQuery(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1190,7 +1186,7 @@ public final class Ebean {
|
||||
*/
|
||||
public static <T> Query<T> find(Class<T> beanType) {
|
||||
|
||||
return serverMgr.getPrimaryServer().find(beanType);
|
||||
return serverMgr.getDefaultServer().find(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1204,7 +1200,7 @@ public final class Ebean {
|
||||
* </p>
|
||||
*/
|
||||
public static <T> Filter<T> filter(Class<T> beanType) {
|
||||
return serverMgr.getPrimaryServer().filter(beanType);
|
||||
return serverMgr.getDefaultServer().filter(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1251,7 +1247,7 @@ public final class Ebean {
|
||||
* @see Ebean#execute(CallableSql)
|
||||
*/
|
||||
public static int execute(SqlUpdate sqlUpdate) {
|
||||
return serverMgr.getPrimaryServer().execute(sqlUpdate);
|
||||
return serverMgr.getDefaultServer().execute(sqlUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1280,7 +1276,7 @@ public final class Ebean {
|
||||
* @see Ebean#execute(SqlUpdate)
|
||||
*/
|
||||
public static int execute(CallableSql callableSql) {
|
||||
return serverMgr.getPrimaryServer().execute(callableSql);
|
||||
return serverMgr.getDefaultServer().execute(callableSql);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1305,7 +1301,7 @@ public final class Ebean {
|
||||
* }</pre>
|
||||
*/
|
||||
public static void execute(TxScope scope, TxRunnable r) {
|
||||
serverMgr.getPrimaryServer().execute(scope, r);
|
||||
serverMgr.getDefaultServer().execute(scope, r);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1333,7 +1329,7 @@ public final class Ebean {
|
||||
* }</pre>
|
||||
*/
|
||||
public static void execute(TxRunnable r) {
|
||||
serverMgr.getPrimaryServer().execute(r);
|
||||
serverMgr.getDefaultServer().execute(r);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1360,7 +1356,7 @@ public final class Ebean {
|
||||
*
|
||||
*/
|
||||
public static <T> T execute(TxScope scope, TxCallable<T> c) {
|
||||
return serverMgr.getPrimaryServer().execute(scope, c);
|
||||
return serverMgr.getDefaultServer().execute(scope, c);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1394,7 +1390,7 @@ public final class Ebean {
|
||||
* }</pre>
|
||||
*/
|
||||
public static <T> T execute(TxCallable<T> c) {
|
||||
return serverMgr.getPrimaryServer().execute(c);
|
||||
return serverMgr.getDefaultServer().execute(c);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1431,10 +1427,9 @@ public final class Ebean {
|
||||
* @param deletes
|
||||
* true if rows on the table where deleted
|
||||
*/
|
||||
public static void externalModification(String tableName, boolean inserts, boolean updates,
|
||||
boolean deletes) {
|
||||
public static void externalModification(String tableName, boolean inserts, boolean updates, boolean deletes) {
|
||||
|
||||
serverMgr.getPrimaryServer().externalModification(tableName, inserts, updates, deletes);
|
||||
serverMgr.getDefaultServer().externalModification(tableName, inserts, updates, deletes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1444,7 +1439,7 @@ public final class Ebean {
|
||||
* </p>
|
||||
*/
|
||||
public static BeanState getBeanState(Object bean) {
|
||||
return serverMgr.getPrimaryServer().getBeanState(bean);
|
||||
return serverMgr.getDefaultServer().getBeanState(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1452,7 +1447,7 @@ public final class Ebean {
|
||||
*
|
||||
*/
|
||||
public static ServerCacheManager getServerCacheManager() {
|
||||
return serverMgr.getPrimaryServer().getServerCacheManager();
|
||||
return serverMgr.getDefaultServer().getServerCacheManager();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1460,7 +1455,7 @@ public final class Ebean {
|
||||
* queries.
|
||||
*/
|
||||
public static BackgroundExecutor getBackgroundExecutor() {
|
||||
return serverMgr.getPrimaryServer().getBackgroundExecutor();
|
||||
return serverMgr.getDefaultServer().getBackgroundExecutor();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1471,7 +1466,7 @@ public final class Ebean {
|
||||
* </p>
|
||||
*/
|
||||
public static void runCacheWarming() {
|
||||
serverMgr.getPrimaryServer().runCacheWarming();
|
||||
serverMgr.getDefaultServer().runCacheWarming();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1483,22 +1478,14 @@ public final class Ebean {
|
||||
*/
|
||||
public static void runCacheWarming(Class<?> beanType) {
|
||||
|
||||
serverMgr.getPrimaryServer().runCacheWarming(beanType);
|
||||
serverMgr.getDefaultServer().runCacheWarming(beanType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JsonContext for reading/writing JSON.
|
||||
*/
|
||||
public static JsonContext json() {
|
||||
return serverMgr.getPrimaryServer().json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JsonContext for reading/writing JSON.
|
||||
* @deprecated Please use #json instead.
|
||||
*/
|
||||
public static JsonContext createJsonContext() {
|
||||
return json();
|
||||
return serverMgr.getDefaultServer().json();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -15,6 +14,7 @@ import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.meta.MetaInfoManager;
|
||||
import com.avaje.ebean.text.csv.CsvReader;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Provides the API for fetching and saving beans to a particular DataSource.
|
||||
@@ -904,19 +904,6 @@ public interface EbeanServer {
|
||||
*/
|
||||
<T> void findEachWhile(Query<T> query, QueryEachWhileConsumer<T> consumer, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Deprecated in favor of #findEachWhile which is functionally exactly the same
|
||||
* but has a much better name.
|
||||
* <p>
|
||||
* Execute the query visiting the results. This is similar to findIterate in
|
||||
* that not all the result beans need to be held in memory at the same time
|
||||
* and as such is go for processing large queries.
|
||||
* </p>
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
<T> void findVisit(Query<T> query, QueryResultVisitor<T> visitor, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute a query returning a list of beans.
|
||||
* <p>
|
||||
@@ -1109,6 +1096,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @see Query#findUnique()
|
||||
*/
|
||||
@Nullable
|
||||
<T> T findUnique(Query<T> query, Transaction transaction);
|
||||
|
||||
/**
|
||||
@@ -1185,6 +1173,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @see SqlQuery#findUnique()
|
||||
*/
|
||||
@Nullable
|
||||
SqlRow findUnique(SqlQuery query, Transaction transaction);
|
||||
|
||||
/**
|
||||
@@ -1222,15 +1211,10 @@ public interface EbeanServer {
|
||||
*/
|
||||
void save(Object bean) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Save all the beans in the iterator.
|
||||
*/
|
||||
int save(Iterator<?> it) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Save all the beans in the collection.
|
||||
*/
|
||||
int save(Collection<?> beans) throws OptimisticLockException;
|
||||
int saveAll(Collection<?> beans) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Delete the bean.
|
||||
@@ -1241,15 +1225,10 @@ public interface EbeanServer {
|
||||
*/
|
||||
void delete(Object bean) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Delete all the beans from an Iterator.
|
||||
*/
|
||||
int delete(Iterator<?> it) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Delete all the beans in the collection.
|
||||
*/
|
||||
int delete(Collection<?> c) throws OptimisticLockException;
|
||||
int deleteAll(Collection<?> beans) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Delete the bean given its type and id.
|
||||
@@ -1264,13 +1243,18 @@ public interface EbeanServer {
|
||||
/**
|
||||
* Delete several beans given their type and id values.
|
||||
*/
|
||||
void delete(Class<?> beanType, Collection<?> ids);
|
||||
void deleteAll(Class<?> beanType, Collection<?> ids);
|
||||
|
||||
/**
|
||||
* Delete several beans given their type and id values with an explicit
|
||||
* transaction.
|
||||
*/
|
||||
void delete(Class<?> beanType, Collection<?> ids, Transaction transaction);
|
||||
void deleteAll(Class<?> beanType, Collection<?> ids, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Delete the bean with an explicit transaction.
|
||||
*/
|
||||
void delete(Object bean, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Execute a Sql Update Delete or Insert statement. This returns the number of
|
||||
@@ -1328,7 +1312,7 @@ public interface EbeanServer {
|
||||
* Execute a ORM insert update or delete statement with an explicit
|
||||
* transaction.
|
||||
*/
|
||||
int execute(Update<?> update, Transaction t);
|
||||
int execute(Update<?> update, Transaction transaction);
|
||||
|
||||
/**
|
||||
* For making calls to stored procedures.
|
||||
@@ -1400,27 +1384,22 @@ public interface EbeanServer {
|
||||
* the type of entity bean to find
|
||||
* @param beanType
|
||||
* the type of entity bean to find
|
||||
* @param uid
|
||||
* @param id
|
||||
* the bean id value
|
||||
* @param transaction
|
||||
* the transaction to use (can be null)
|
||||
*/
|
||||
<T> T find(Class<T> beanType, Object uid, Transaction transaction);
|
||||
<T> T find(Class<T> beanType, Object id, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Insert or update a bean with an explicit transaction.
|
||||
*/
|
||||
void save(Object bean, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Save all the beans in the iterator with an explicit transaction.
|
||||
*/
|
||||
int save(Iterator<?> it, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Save all the beans in the collection with an explicit transaction.
|
||||
*/
|
||||
int save(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
|
||||
int saveAll(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Marks the entity bean as dirty.
|
||||
@@ -1485,7 +1464,7 @@ public interface EbeanServer {
|
||||
/**
|
||||
* Update a bean additionally specifying a transaction.
|
||||
*/
|
||||
void update(Object bean, Transaction t) throws OptimisticLockException;
|
||||
void update(Object bean, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Update a bean additionally specifying a transaction and the deleteMissingChildren setting.
|
||||
@@ -1505,13 +1484,13 @@ public interface EbeanServer {
|
||||
* Update a collection of beans. If there is no current transaction one is created and used to
|
||||
* update all the beans in the collection.
|
||||
*/
|
||||
void update(Collection<?> beans) throws OptimisticLockException;
|
||||
void updateAll(Collection<?> beans) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Update a collection of beans with an explicit transaction.
|
||||
*/
|
||||
void update(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
void updateAll(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Insert the bean.
|
||||
* <p>
|
||||
@@ -1525,18 +1504,18 @@ public interface EbeanServer {
|
||||
/**
|
||||
* Insert the bean with a transaction.
|
||||
*/
|
||||
void insert(Object bean, Transaction t);
|
||||
void insert(Object bean, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Insert a collection of beans. If there is no current transaction one is created and used to
|
||||
* insert all the beans in the collection.
|
||||
*/
|
||||
void insert(Collection<?> beans);
|
||||
void insertAll(Collection<?> beans);
|
||||
|
||||
/**
|
||||
* Insert a collection of beans with an explicit transaction.
|
||||
*/
|
||||
void insert(Collection<?> beans, Transaction t);
|
||||
void insertAll(Collection<?> beans, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Delete the associations (from the intersection table) of a ManyToMany given
|
||||
@@ -1545,7 +1524,7 @@ public interface EbeanServer {
|
||||
* Typically these deletions occur automatically when persisting a ManyToMany
|
||||
* collection and this provides a way to invoke those deletions directly.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return the number of associations deleted (from the intersection table).
|
||||
*/
|
||||
int deleteManyToManyAssociations(Object ownerBean, String propertyName);
|
||||
@@ -1560,10 +1539,10 @@ public interface EbeanServer {
|
||||
* Typically these deletions occur automatically when persisting a ManyToMany
|
||||
* collection and this provides a way to invoke those deletions directly.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @return the number of associations deleted (from the intersection table).
|
||||
*/
|
||||
int deleteManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
|
||||
int deleteManyToManyAssociations(Object ownerBean, String propertyName, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Save the associations of a ManyToMany given the owner bean and the
|
||||
@@ -1585,7 +1564,7 @@ public interface EbeanServer {
|
||||
* way to invoke those insertions directly.
|
||||
* </p>
|
||||
*/
|
||||
void saveManyToManyAssociations(Object ownerBean, String propertyName, Transaction t);
|
||||
void saveManyToManyAssociations(Object ownerBean, String propertyName, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Save the associated collection or bean given the property name.
|
||||
@@ -1622,27 +1601,18 @@ public interface EbeanServer {
|
||||
* @param propertyName
|
||||
* the property we want to save
|
||||
*/
|
||||
void saveAssociation(Object ownerBean, String propertyName, Transaction t);
|
||||
void saveAssociation(Object ownerBean, String propertyName, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Delete the bean with an explicit transaction.
|
||||
*/
|
||||
void delete(Object bean, Transaction t) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Delete all the beans from an iterator.
|
||||
*/
|
||||
int delete(Iterator<?> it, Transaction t) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Execute explicitly passing a transaction.
|
||||
*/
|
||||
int execute(SqlUpdate updSql, Transaction t);
|
||||
int execute(SqlUpdate updSql, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute explicitly passing a transaction.
|
||||
*/
|
||||
int execute(CallableSql callableSql, Transaction t);
|
||||
int execute(CallableSql callableSql, Transaction transaction);
|
||||
|
||||
/**
|
||||
* Execute a TxRunnable in a Transaction with an explicit scope.
|
||||
@@ -1665,7 +1635,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
void execute(TxScope scope, TxRunnable r);
|
||||
void execute(TxScope scope, TxRunnable runnable);
|
||||
|
||||
/**
|
||||
* Execute a TxRunnable in a Transaction with the default scope.
|
||||
@@ -1691,7 +1661,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
void execute(TxRunnable r);
|
||||
void execute(TxRunnable runnable);
|
||||
|
||||
/**
|
||||
* Execute a TxCallable in a Transaction with an explicit scope.
|
||||
@@ -1715,7 +1685,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
<T> T execute(TxScope scope, TxCallable<T> c);
|
||||
<T> T execute(TxScope scope, TxCallable<T> callable);
|
||||
|
||||
/**
|
||||
* Execute a TxCallable in a Transaction with the default scope.
|
||||
@@ -1747,7 +1717,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
<T> T execute(TxCallable<T> c);
|
||||
<T> T execute(TxCallable<T> callable);
|
||||
|
||||
/**
|
||||
* Return the manager of the server cache ("L2" cache).
|
||||
@@ -1777,12 +1747,6 @@ public interface EbeanServer {
|
||||
*/
|
||||
void runCacheWarming(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Return the JsonContext for reading/writing JSON.
|
||||
* @deprecated Please use #json instead.
|
||||
*/
|
||||
JsonContext createJsonContext();
|
||||
|
||||
/**
|
||||
* Return the JsonContext for reading/writing JSON.
|
||||
* <p>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
@@ -116,14 +117,6 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
void findEachWhile(QueryEachWhileConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Deprecated in favor of #findEachWhile which is functionally exactly the same
|
||||
* but has a much better name.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
void findVisit(QueryResultVisitor<T> visitor);
|
||||
|
||||
/**
|
||||
* Execute the query returning a list.
|
||||
*
|
||||
@@ -170,6 +163,7 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*
|
||||
* @see Query#findUnique()
|
||||
*/
|
||||
@Nullable
|
||||
T findUnique();
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,57 +22,57 @@ import java.io.Serializable;
|
||||
* efficient loaded as 2 SQL queries.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
* // Normal fetch join results in a single SQL query
|
||||
* List<Order> list = Ebean.find(Order.class).fetch("details").findList();
|
||||
* List<Order> list = Ebean.find(Order.class).fetch("details").findList();
|
||||
*
|
||||
* // Find Orders join details using a single SQL query
|
||||
* </pre>
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using a "query join" instead of a "fetch join" we instead use 2 SQL
|
||||
* queries
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
* // This will use 2 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
|
||||
* </pre>
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using 2 "query joins"
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .fetch("customer", new FetchConfig().queryFirst(5))
|
||||
* .fetch("details", new FetchConfig().query())
|
||||
* .fetch("customer", new FetchConfig().queryFirst(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
* // query 2) find orderDetails where order.id in (?,?...) // first 100 order id's
|
||||
* // query 3) find customer where id in (?,?,?,?,?) // first 5 customers
|
||||
* </pre>
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Example: Using "query joins" and partial objects
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
* // This will use 3 SQL queries to build this object graph
|
||||
* List<Order> list =
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .select("status, shipDate")
|
||||
* .fetch("details", "quantity, price", new FetchConfig().query())
|
||||
* .fetch("details.product", "sku, name")
|
||||
* .fetch("customer", "name", new FetchConfig().queryFirst(5))
|
||||
* .fetch("customer.contacts")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .select("status, shipDate")
|
||||
* .fetch("details", "quantity, price", new FetchConfig().query())
|
||||
* .fetch("details.product", "sku, name")
|
||||
* .fetch("customer", "name", new FetchConfig().queryFirst(5))
|
||||
* .fetch("customer.contacts")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order (status, shipDate)
|
||||
@@ -81,22 +81,22 @@ import java.io.Serializable;
|
||||
* // query 3) find customer (name) fetch contacts (*) fetch shippingAddress (*)
|
||||
* // where id in (?,?,?,?,?)
|
||||
*
|
||||
* // Note: the fetch of "details.product" is automatically included into the
|
||||
* // fetch of "details"
|
||||
* // Note: the fetch of "details.product" is automatically included into the
|
||||
* // fetch of "details"
|
||||
* //
|
||||
* // Note: the fetch of "customer.contacts" and "customer.shippingAddress"
|
||||
* // are automatically included in the fetch of "customer"
|
||||
* </pre>
|
||||
* // Note: the fetch of "customer.contacts" and "customer.shippingAddress"
|
||||
* // are automatically included in the fetch of "customer"
|
||||
* }</pre>
|
||||
* <p>
|
||||
* You can use query() and lazy together on a single join. The query is executed
|
||||
* immediately and the lazy defines the batch size to use for further lazy
|
||||
* loading (if lazy loading is invoked).
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* List<Order> list =
|
||||
* <pre>{@code
|
||||
* List<Order> list =
|
||||
* Ebean.find(Order.class)
|
||||
* .fetch("customer", new FetchConfig().query(10).lazy(5))
|
||||
* .fetch("customer", new FetchConfig().query(10).lazy(5))
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order
|
||||
@@ -104,7 +104,7 @@ import java.io.Serializable;
|
||||
* // .. then if lazy loading of customers is invoked
|
||||
* // .. use a batch size of 5 to load the customers
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Example of controlling the lazy loading query:
|
||||
@@ -114,12 +114,12 @@ import java.io.Serializable;
|
||||
* case.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer","name", new FetchConfig().lazy(5))
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .where().eq("status",Order.Status.NEW)
|
||||
* <pre>{@code
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer","name", new FetchConfig().lazy(5))
|
||||
* .fetch("customer.contacts","contactName, phone, email")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .where().eq("status",Order.Status.NEW)
|
||||
* .findList();
|
||||
*
|
||||
* // query 1) find order where status = Order.Status.NEW
|
||||
@@ -132,7 +132,7 @@ import java.io.Serializable;
|
||||
* fetch customer.shippingAddress (*)
|
||||
* where id in (?,?,?,?,?)
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @author mario
|
||||
* @author rbygrave
|
||||
|
||||
@@ -2,14 +2,13 @@ package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
import com.avaje.ebean.util.ClassUtil;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.*;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A MappedSuperclass base class that provides convenience methods for inserting, updating and
|
||||
@@ -152,7 +151,7 @@ public abstract class Model {
|
||||
* }</pre>
|
||||
*/
|
||||
public static EbeanServer db() {
|
||||
return Ebean.getServer(null);
|
||||
return Ebean.getDefaultServer();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -451,8 +450,8 @@ public abstract class Model {
|
||||
* Construct passing the class literal type of the entity type.
|
||||
*/
|
||||
protected Find(String serverName, Class<T> type) {
|
||||
this.type = type;
|
||||
this.serverName = serverName;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -514,6 +513,7 @@ public abstract class Model {
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class, Object)}
|
||||
*/
|
||||
@Nullable
|
||||
public T byId(I id) {
|
||||
return db().find(type, id);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class PrimaryServer {
|
||||
/**
|
||||
* Return the default server name.
|
||||
*/
|
||||
static synchronized String getPrimaryServerName() {
|
||||
static synchronized String getDefaultServerName() {
|
||||
getProperties();
|
||||
return defaultServerName;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
@@ -483,7 +484,7 @@ public interface Query<T> extends Serializable {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
Query<T> fetch(String path, FetchConfig joinConfig);
|
||||
Query<T> fetch(String path, FetchConfig fetchConfig);
|
||||
|
||||
/**
|
||||
* Apply the path properties replacing the select and fetch clauses.
|
||||
@@ -520,19 +521,7 @@ public interface Query<T> extends Serializable {
|
||||
*/
|
||||
QueryIterator<T> findIterate();
|
||||
|
||||
/**
|
||||
* This is deprecated in favor of #findEachWhile.
|
||||
* <p>
|
||||
* This is functionally exactly the same as #findEachWhile. It is
|
||||
* replaced by findEachWhile because the method name is much better.
|
||||
* </p>
|
||||
*
|
||||
* @param visitor
|
||||
* the visitor used to process the queried beans.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
void findVisit(QueryResultVisitor<T> visitor);
|
||||
|
||||
|
||||
/**
|
||||
* Execute the query processing the beans one at a time.
|
||||
@@ -716,6 +705,7 @@ public interface Query<T> extends Serializable {
|
||||
* ...
|
||||
* }</pre>
|
||||
*/
|
||||
@Nullable
|
||||
T findUnique();
|
||||
|
||||
/**
|
||||
@@ -878,6 +868,11 @@ public interface Query<T> extends Serializable {
|
||||
*/
|
||||
Query<T> setId(Object id);
|
||||
|
||||
/**
|
||||
* Return the Id value.
|
||||
*/
|
||||
Object getId();
|
||||
|
||||
/**
|
||||
* Add additional clause(s) to the where clause.
|
||||
* <p>
|
||||
@@ -1123,8 +1118,8 @@ public interface Query<T> extends Serializable {
|
||||
|
||||
/**
|
||||
* Set the first row to return for this query.
|
||||
*
|
||||
* @param firstRow
|
||||
*
|
||||
* @param firstRow the first row to include in the query result.
|
||||
*/
|
||||
Query<T> setFirstRow(int firstRow);
|
||||
|
||||
@@ -1235,4 +1230,10 @@ public interface Query<T> extends Serializable {
|
||||
* Set root table alias.
|
||||
*/
|
||||
Query<T> alias(String alias);
|
||||
|
||||
/**
|
||||
* Return the type of beans being queried.
|
||||
*/
|
||||
Class<T> getBeanType();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Used to process a query result one bean at a time via a callback to this
|
||||
* visitor.
|
||||
* <p>
|
||||
* If you wish to stop further processing return false from the accept method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Unlike findList() and findSet() using a QueryResultVisitor does not require
|
||||
* all the beans in the query result to be held in memory at once. This makes
|
||||
* QueryResultVisitor useful for processing large queries.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* query.findVisit(new QueryResultVisitor<Customer>() {
|
||||
*
|
||||
* public boolean accept(Customer customer) {
|
||||
* // do something with customer
|
||||
* System.out.println("-- visit " + customer);
|
||||
* return true;
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean being queried.
|
||||
*/
|
||||
public interface QueryResultVisitor<T> {
|
||||
|
||||
/**
|
||||
* Process the bean and return true if you want to continue processing more
|
||||
* beans. Return false if you want to stop processing further.
|
||||
*
|
||||
* @param bean
|
||||
* the entity bean to process
|
||||
* @return true to continue processing or false to stop.
|
||||
*/
|
||||
boolean accept(T bean);
|
||||
}
|
||||
@@ -480,6 +480,13 @@ public final class RawSql implements Serializable {
|
||||
this.queryHashCode = hc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the property is mapped.
|
||||
*/
|
||||
public boolean contains(String property) {
|
||||
return this.propertyColumnMap.containsKey(property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an immutable copy of this ColumnMapping.
|
||||
*
|
||||
|
||||
@@ -44,4 +44,12 @@ public @interface CacheTuning {
|
||||
* </p>
|
||||
*/
|
||||
int maxSecsToLive() default 0;
|
||||
|
||||
/**
|
||||
* The frequency (in seconds) that cache trimming should occur.
|
||||
* <p>
|
||||
* This is a hint for cache implementations that use background cache trimming.
|
||||
* </p>
|
||||
*/
|
||||
int trimFrequency() default 0;
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Deprecated - please use @DbHstore instead.
|
||||
* @see DbHstore
|
||||
*/
|
||||
@Deprecated
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface ColumnHstore {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Similar to Jackson JsonIgnore but provides the option to just ignore serialize or deserialize.
|
||||
* <p>
|
||||
* This provides the same features as Expose but from the opposite perspective which is probably
|
||||
* more common and more familiar to Jackson users.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface JsonIgnore {
|
||||
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is written out in the JSON while
|
||||
* serializing. If {@code false}, the field marked with this annotation is skipped from the
|
||||
* serialized output. Defaults to {@code false}.
|
||||
*/
|
||||
boolean serialize() default false;
|
||||
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is deserialized from the JSON.
|
||||
* If {@code false}, the field marked with this annotation is skipped during deserialization.
|
||||
* Defaults to {@code false}.
|
||||
*/
|
||||
boolean deserialize() default false;
|
||||
}
|
||||
@@ -48,12 +48,6 @@ public interface ServerCache {
|
||||
*/
|
||||
Object put(Object id, Object value);
|
||||
|
||||
/**
|
||||
* Put the value in the cache but only if a matching value is not already in
|
||||
* the cache.
|
||||
*/
|
||||
Object putIfAbsent(Object id, Object value);
|
||||
|
||||
/**
|
||||
* Remove a entry from the cache given its id.
|
||||
*/
|
||||
|
||||
+24
-5
@@ -10,6 +10,7 @@ public class ServerCacheOptions {
|
||||
private int maxSize;
|
||||
private int maxIdleSecs;
|
||||
private int maxSecsToLive;
|
||||
private int trimFrequency;
|
||||
|
||||
/**
|
||||
* Construct with no set options.
|
||||
@@ -25,15 +26,17 @@ public class ServerCacheOptions {
|
||||
this.maxSize = cacheTuning.maxSize();
|
||||
this.maxIdleSecs = cacheTuning.maxIdleSecs();
|
||||
this.maxSecsToLive = cacheTuning.maxSecsToLive();
|
||||
this.trimFrequency = cacheTuning.trimFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create merging default options with the deployment specified ones.
|
||||
*/
|
||||
public ServerCacheOptions(ServerCacheOptions d) {
|
||||
this.maxSize = d.getMaxSize();
|
||||
this.maxIdleSecs = d.getMaxIdleSecs();
|
||||
this.maxSecsToLive = d.getMaxIdleSecs();
|
||||
public ServerCacheOptions(ServerCacheOptions defaults) {
|
||||
this.maxSize = defaults.getMaxSize();
|
||||
this.maxIdleSecs = defaults.getMaxIdleSecs();
|
||||
this.maxSecsToLive = defaults.getMaxIdleSecs();
|
||||
this.trimFrequency = defaults.getTrimFrequency();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,6 +53,9 @@ public class ServerCacheOptions {
|
||||
if (maxSecsToLive == 0) {
|
||||
maxSecsToLive = defaults.getMaxSecsToLive();
|
||||
}
|
||||
if (trimFrequency == 0) {
|
||||
trimFrequency = defaults.getTrimFrequency();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,7 +67,7 @@ public class ServerCacheOptions {
|
||||
copy.maxSize = maxSize;
|
||||
copy.maxIdleSecs = maxIdleSecs;
|
||||
copy.maxSecsToLive = maxSecsToLive;
|
||||
|
||||
copy.trimFrequency = trimFrequency;
|
||||
return copy;
|
||||
}
|
||||
|
||||
@@ -107,4 +113,17 @@ public class ServerCacheOptions {
|
||||
this.maxSecsToLive = maxSecsToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the trim frequency in seconds.
|
||||
*/
|
||||
public int getTrimFrequency() {
|
||||
return trimFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the trim frequency in seconds.
|
||||
*/
|
||||
public void setTrimFrequency(int trimFrequency) {
|
||||
this.trimFrequency = trimFrequency;
|
||||
}
|
||||
}
|
||||
|
||||
+175
-23
@@ -5,9 +5,9 @@ package com.avaje.ebean.cache;
|
||||
* <p>
|
||||
* These can be monitored to review the effectiveness of a particular cache.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* <p>
|
||||
* Depending on the cache implementation not all the statistics may be collected.
|
||||
* </p>
|
||||
*/
|
||||
public class ServerCacheStatistics {
|
||||
|
||||
@@ -17,21 +17,63 @@ public class ServerCacheStatistics {
|
||||
|
||||
protected int size;
|
||||
|
||||
protected int hitCount;
|
||||
protected long hitCount;
|
||||
|
||||
protected int missCount;
|
||||
protected long missCount;
|
||||
|
||||
protected long insertCount;
|
||||
|
||||
protected long updateCount;
|
||||
|
||||
protected long removeCount;
|
||||
|
||||
protected long clearCount;
|
||||
|
||||
protected long evictionRunCount;
|
||||
|
||||
protected long evictionRunMicros;
|
||||
|
||||
protected long evictByIdle;
|
||||
|
||||
protected long evictByTTL;
|
||||
|
||||
protected long evictByLRU;
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(cacheName);
|
||||
sb.append(" maxSize:").append(maxSize);
|
||||
sb.append(" size:").append(size);
|
||||
sb.append(" hitRatio:").append(getHitRatio());
|
||||
sb.append(" hitCount:").append(hitCount);
|
||||
sb.append(" missCount:").append(missCount);
|
||||
sb.append(" maxSize:").append(maxSize);
|
||||
sb.append(" hit:").append(hitCount);
|
||||
sb.append(" miss:").append(missCount);
|
||||
sb.append(" insert:").append(insertCount);
|
||||
sb.append(" update:").append(updateCount);
|
||||
sb.append(" remove:").append(removeCount);
|
||||
sb.append(" clear:").append(clearCount);
|
||||
sb.append(" evictByIdle:").append(evictByIdle);
|
||||
sb.append(" evictByTTL:").append(evictByTTL);
|
||||
sb.append(" evictByLRU:").append(evictByLRU);
|
||||
sb.append(" evictionRunCount:").append(evictionRunCount);
|
||||
sb.append(" evictionRunMicros:").append(evictionRunMicros);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an int from 0 to 100 (percentage) for the hit ratio.
|
||||
* <p>
|
||||
* A hit ratio of 100 means every get request against the cache hits an entry.
|
||||
* </p>
|
||||
*/
|
||||
public int getHitRatio() {
|
||||
long totalCount = hitCount + missCount;
|
||||
if (totalCount == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return (int)(hitCount * 100 / totalCount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the cache.
|
||||
*/
|
||||
@@ -49,28 +91,28 @@ public class ServerCacheStatistics {
|
||||
/**
|
||||
* Return the hit count. The number of successful gets.
|
||||
*/
|
||||
public int getHitCount() {
|
||||
public long getHitCount() {
|
||||
return hitCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the hit count.
|
||||
*/
|
||||
public void setHitCount(int hitCount) {
|
||||
public void setHitCount(long hitCount) {
|
||||
this.hitCount = hitCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the miss count. The number of gets that returned null.
|
||||
*/
|
||||
public int getMissCount() {
|
||||
public long getMissCount() {
|
||||
return missCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the miss count.
|
||||
*/
|
||||
public void setMissCount(int missCount) {
|
||||
public void setMissCount(long missCount) {
|
||||
this.missCount = missCount;
|
||||
}
|
||||
|
||||
@@ -107,18 +149,128 @@ public class ServerCacheStatistics {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an int from 0 to 100 (percentage) for the hit ratio.
|
||||
* <p>
|
||||
* A hit ratio of 100 means every get request against the cache hits an entry.
|
||||
* </p>
|
||||
* Set the put insert count.
|
||||
*/
|
||||
public int getHitRatio() {
|
||||
int totalCount = hitCount + missCount;
|
||||
if (totalCount == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return hitCount * 100 / totalCount;
|
||||
}
|
||||
public void setInsertCount(long insertCount) {
|
||||
this.insertCount = insertCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the put insert count.
|
||||
*/
|
||||
public long getInsertCount() {
|
||||
return insertCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the put update count.
|
||||
*/
|
||||
public void setUpdateCount(long updateCount) {
|
||||
this.updateCount = updateCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the put update count.
|
||||
*/
|
||||
public long getUpdateCount() {
|
||||
return updateCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the remove count.
|
||||
*/
|
||||
public void setRemoveCount(long removeCount) {
|
||||
this.removeCount = removeCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the remove count.
|
||||
*/
|
||||
public long getRemoveCount() {
|
||||
return removeCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the clear count.
|
||||
*/
|
||||
public void setClearCount(long clearCount) {
|
||||
this.clearCount = clearCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the clear count.
|
||||
*/
|
||||
public long getClearCount() {
|
||||
return clearCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the eviction run count.
|
||||
*/
|
||||
public void setEvictionRunCount(long evictCount) {
|
||||
this.evictionRunCount = evictCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the eviction run count.
|
||||
*/
|
||||
public long getEvictionRunCount() {
|
||||
return evictionRunCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the eviction run time in micros.
|
||||
*/
|
||||
public void setEvictionRunMicros(long evictionRunMicros) {
|
||||
this.evictionRunMicros = evictionRunMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the eviction run time in micros.
|
||||
*/
|
||||
public long getEvictionRunMicros() {
|
||||
return evictionRunMicros;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the count of entries evicted due to idle time.
|
||||
*/
|
||||
public void setEvictByIdle(long evictByIdle) {
|
||||
this.evictByIdle = evictByIdle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of entries evicted due to idle time.
|
||||
*/
|
||||
public long getEvictByIdle() {
|
||||
return evictByIdle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the count of entries evicted due to time to live.
|
||||
*/
|
||||
public void setEvictByTTL(long evictByTTL) {
|
||||
this.evictByTTL = evictByTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of entries evicted due to time to live.
|
||||
*/
|
||||
public long getEvictByTTL() {
|
||||
return evictByTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the count of entries evicted due to time least recently used.
|
||||
*/
|
||||
public void setEvictByLRU(long evictByLRU) {
|
||||
this.evictByLRU = evictByLRU;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of entries evicted due to time least recently used.
|
||||
*/
|
||||
public long getEvictByLRU() {
|
||||
return evictByLRU;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,4 +26,22 @@ public abstract class JsonConfig {
|
||||
ISO8601
|
||||
}
|
||||
|
||||
|
||||
public enum Include {
|
||||
|
||||
/**
|
||||
* Include all values including null and empty collections.
|
||||
*/
|
||||
ALL,
|
||||
|
||||
/**
|
||||
* Exclude null values (include empty collections).
|
||||
*/
|
||||
NON_NULL,
|
||||
|
||||
/**
|
||||
* Exclude null values and empty collections.
|
||||
*/
|
||||
NON_EMPTY
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +123,12 @@ public class ServerConfig {
|
||||
*/
|
||||
private JsonConfig.DateTime jsonDateTime = JsonConfig.DateTime.MILLIS;
|
||||
|
||||
/**
|
||||
* For writing JSON specify if null values or empty collections should be exluded.
|
||||
* By default all values are included.
|
||||
*/
|
||||
private JsonConfig.Include jsonInclude = JsonConfig.Include.ALL;
|
||||
|
||||
/**
|
||||
* The database platform name. Used to imply a DatabasePlatform to use.
|
||||
*/
|
||||
@@ -304,7 +310,7 @@ public class ServerConfig {
|
||||
/**
|
||||
* Return the Jackson JsonFactory to use.
|
||||
* <p>
|
||||
* If not set a default implmentation will be used.
|
||||
* If not set a default implementation will be used.
|
||||
*/
|
||||
public JsonFactory getJsonFactory() {
|
||||
return jsonFactory;
|
||||
@@ -313,7 +319,7 @@ public class ServerConfig {
|
||||
/**
|
||||
* Set the Jackson JsonFactory to use.
|
||||
* <p>
|
||||
* If not set a default implmentation will be used.
|
||||
* If not set a default implementation will be used.
|
||||
*/
|
||||
public void setJsonFactory(JsonFactory jsonFactory) {
|
||||
this.jsonFactory = jsonFactory;
|
||||
@@ -333,6 +339,23 @@ public class ServerConfig {
|
||||
this.jsonDateTime = jsonDateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSON include mode used when writing JSON.
|
||||
*/
|
||||
public JsonConfig.Include getJsonInclude() {
|
||||
return jsonInclude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JSON include mode used when writing JSON.
|
||||
* <p>
|
||||
* Set to NON_NULL or NON_EMPTY to suppress nulls or null & empty collections respectively.
|
||||
* </p>
|
||||
*/
|
||||
public void setJsonInclude(JsonConfig.Include jsonInclude) {
|
||||
this.jsonInclude = jsonInclude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the EbeanServer.
|
||||
*/
|
||||
@@ -1784,7 +1807,7 @@ public class ServerConfig {
|
||||
int batchSize = p.getInt("batch.size", persistBatchSize);
|
||||
persistBatchSize = p.getInt("persistBatchSize", batchSize);
|
||||
|
||||
persistenceContextScope = PersistenceContextScope.valueOf(p.get("persistenceContextScope","TRANSACTION"));
|
||||
persistenceContextScope = PersistenceContextScope.valueOf(p.get("persistenceContextScope", "TRANSACTION"));
|
||||
|
||||
dataSourceJndiName = p.get("dataSourceJndiName", dataSourceJndiName);
|
||||
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
|
||||
@@ -1797,6 +1820,7 @@ public class ServerConfig {
|
||||
lazyLoadBatchSize = p.getInt("lazyLoadBatchSize", lazyLoadBatchSize);
|
||||
queryBatchSize = p.getInt("queryBatchSize", queryBatchSize);
|
||||
|
||||
jsonInclude = p.getEnum(JsonConfig.Include.class, "jsonInclude", jsonInclude);
|
||||
String jsonDateTimeFormat = p.get("jsonDateTime", null);
|
||||
if (jsonDateTimeFormat != null) {
|
||||
jsonDateTime = JsonConfig.DateTime.valueOf(jsonDateTimeFormat);
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
package com.avaje.ebean.event;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
|
||||
/**
|
||||
* Deprecated in favor of using BeanFindController.
|
||||
*
|
||||
* Used to override the finding implementation for a bean.
|
||||
* <p>
|
||||
* For beans that are not in a JDBC data source you can implement this handle
|
||||
* bean finding. For example, read a log file building each entry as a bean and
|
||||
* returning that.
|
||||
* </p>
|
||||
* <p>
|
||||
* There are a number of internal BeanFinders in Ebean to return meta data from
|
||||
* Ebean at runtime such as query execution statistics etc. See the beans in
|
||||
* com.avaje.ebean.meta and finders in com.avaje.ebean.server.meta.
|
||||
* </p>
|
||||
* @deprecated
|
||||
*/
|
||||
public interface BeanFinder<T> {
|
||||
|
||||
/**
|
||||
* Find a bean using its id or unique predicate.
|
||||
*/
|
||||
T find(BeanQueryRequest<T> request);
|
||||
|
||||
/**
|
||||
* Return a List, Set or Map for the given find request.
|
||||
* <p>
|
||||
* Note the returning object is cast to a List Set or Map so you do need to
|
||||
* get the return type right.
|
||||
* </p>
|
||||
*/
|
||||
BeanCollection<T> findMany(BeanQueryRequest<T> request);
|
||||
|
||||
}
|
||||
@@ -163,8 +163,6 @@ public interface JsonContext {
|
||||
/**
|
||||
* Deprecated in favour of using PathProperties by itself.
|
||||
* Write json to the JsonGenerator using the JsonWriteOptions.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
void toJson(Object value, JsonGenerator generator, JsonWriteOptions options) throws JsonIOException;
|
||||
|
||||
@@ -173,7 +171,6 @@ public interface JsonContext {
|
||||
* With additional options.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
* @deprecated
|
||||
*/
|
||||
void toJson(Object value, Writer writer, JsonWriteOptions options) throws JsonIOException;
|
||||
|
||||
@@ -182,7 +179,6 @@ public interface JsonContext {
|
||||
* Convert a bean or collection to json string.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
* @deprecated
|
||||
*/
|
||||
String toJson(Object value, JsonWriteOptions options) throws JsonIOException;
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ public class JsonReadOptions {
|
||||
|
||||
protected Map<String, JsonReadBeanVisitor<?>> visitorMap;
|
||||
|
||||
protected Object objectMapper;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
@@ -44,4 +46,17 @@ public class JsonReadOptions {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Jackson ObjectMapper to use (if not wanted to use the objectMapper set on the ServerConfig).
|
||||
*/
|
||||
public Object getObjectMapper() {
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Jackson ObjectMapper to use (if not wanted to use the objectMapper set on the ServerConfig).
|
||||
*/
|
||||
public void setObjectMapper(Object objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,23 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import com.avaje.ebean.config.JsonConfig;
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
|
||||
/**
|
||||
* Deprecated in favour of just using PathProperties.
|
||||
*
|
||||
* Provides options for customising the JSON write process.
|
||||
* <p>
|
||||
* You can explicitly state which properties to include in the JSON output for
|
||||
* the root level and each path.
|
||||
* </p>
|
||||
* @deprecated
|
||||
*/
|
||||
public class JsonWriteOptions {
|
||||
|
||||
protected PathProperties pathProperties;
|
||||
|
||||
protected Object objectMapper;
|
||||
|
||||
protected JsonConfig.Include include;
|
||||
|
||||
/**
|
||||
* Parse and return a PathProperties from nested string format like
|
||||
* (a,b,c(d,e),f(g)) where "c" is a path containing "d" and "e" and "f" is a
|
||||
@@ -51,4 +53,35 @@ public class JsonWriteOptions {
|
||||
return pathProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the include mode for this request.
|
||||
*/
|
||||
public JsonConfig.Include getInclude() {
|
||||
return include;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the include mode for this request.
|
||||
*/
|
||||
public void setInclude(JsonConfig.Include include) {
|
||||
this.include = include;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the jackson object mapper to use.
|
||||
* <p/>
|
||||
* If null the ObjectMapper from serverConfig will be used.
|
||||
*/
|
||||
public Object getObjectMapper() {
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the jackson object mapper to use.
|
||||
* <p/>
|
||||
* If null the ObjectMapper from serverConfig will be used.
|
||||
*/
|
||||
public void setObjectMapper(Object objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,88 +6,101 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Helper to find classes taking into account the context class loader.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class ClassUtil {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ClassUtil.class);
|
||||
|
||||
private static boolean preferContext = true;
|
||||
private static final Logger logger = LoggerFactory.getLogger(ClassUtil.class);
|
||||
|
||||
/**
|
||||
* Load a class taking into account a context class loader (if present).
|
||||
*/
|
||||
public static Class<?> forName(String name) throws ClassNotFoundException {
|
||||
return forName(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a class taking into account a context class loader (if present).
|
||||
*/
|
||||
public static Class<?> forName(String name, Class<?> caller) throws ClassNotFoundException {
|
||||
|
||||
if (caller == null){
|
||||
caller = ClassUtil.class;
|
||||
}
|
||||
ClassLoadContext ctx = ClassLoadContext.of(caller, preferContext);
|
||||
|
||||
return ctx.forName(name);
|
||||
}
|
||||
|
||||
private static boolean preferContext = true;
|
||||
|
||||
public static ClassLoader getClassLoader(Class<?> caller, boolean preferContext) {
|
||||
|
||||
if (caller == null){
|
||||
caller = ClassUtil.class;
|
||||
}
|
||||
ClassLoadContext ctx = ClassLoadContext.of(caller, preferContext);
|
||||
ClassLoader classLoader = ctx.getDefault(preferContext);
|
||||
if (ctx.isAmbiguous()){
|
||||
logger.info("Ambigous ClassLoader (Context vs Caller) chosen "+classLoader);
|
||||
}
|
||||
return classLoader;
|
||||
}
|
||||
/**
|
||||
* Load a class taking into account a context class loader (if present).
|
||||
*/
|
||||
public static Class<?> forName(String name) throws ClassNotFoundException {
|
||||
return forName(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given class is present.
|
||||
*/
|
||||
public static boolean isPresent(String className) {
|
||||
return isPresent(className, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given class is present.
|
||||
*/
|
||||
public static boolean isPresent(String className, Class<?> caller) {
|
||||
try {
|
||||
forName(className, caller);
|
||||
return true;
|
||||
} catch (Throwable ex) {
|
||||
// Class or one of its dependencies is not present...
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Load a class taking into account a context class loader (if present).
|
||||
*/
|
||||
public static Class<?> forName(String name, Class<?> caller) throws ClassNotFoundException {
|
||||
|
||||
/**
|
||||
* Return a new instance of the class using the default constructor.
|
||||
*/
|
||||
public static Object newInstance(String className) {
|
||||
return newInstance(className,null);
|
||||
if (caller == null) {
|
||||
caller = ClassUtil.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new instance of the class using the default constructor.
|
||||
*/
|
||||
public static Object newInstance(String className, Class<?> caller) {
|
||||
|
||||
try {
|
||||
Class<?> cls = forName(className, caller);
|
||||
return cls.newInstance();
|
||||
} catch (Exception e){
|
||||
String msg = "Error constructing "+className;
|
||||
throw new IllegalArgumentException(msg, e);
|
||||
}
|
||||
ClassLoadContext ctx = ClassLoadContext.of(caller, preferContext);
|
||||
|
||||
return ctx.forName(name);
|
||||
}
|
||||
|
||||
|
||||
public static ClassLoader getClassLoader(Class<?> caller, boolean preferContext) {
|
||||
|
||||
if (caller == null) {
|
||||
caller = ClassUtil.class;
|
||||
}
|
||||
ClassLoadContext ctx = ClassLoadContext.of(caller, preferContext);
|
||||
ClassLoader classLoader = ctx.getDefault(preferContext);
|
||||
if (ctx.isAmbiguous()) {
|
||||
logger.info("Ambigous ClassLoader (Context vs Caller) chosen " + classLoader);
|
||||
}
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Jackson annotations like JsonIgnore are present.
|
||||
*/
|
||||
public static boolean isJacksonAnnotationsPresent() {
|
||||
return isPresent("com.fasterxml.jackson.annotation.JsonIgnore", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Jackson ObjectMapper is present.
|
||||
*/
|
||||
public static boolean isJacksonObjectMapperPresent() {
|
||||
return isPresent("com.fasterxml.jackson.databind.ObjectMapper", null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the given class is present.
|
||||
*/
|
||||
public static boolean isPresent(String className) {
|
||||
return isPresent(className, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given class is present.
|
||||
*/
|
||||
public static boolean isPresent(String className, Class<?> caller) {
|
||||
try {
|
||||
forName(className, caller);
|
||||
return true;
|
||||
} catch (Throwable ex) {
|
||||
// Class or one of its dependencies is not present...
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new instance of the class using the default constructor.
|
||||
*/
|
||||
public static Object newInstance(String className) {
|
||||
return newInstance(className, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new instance of the class using the default constructor.
|
||||
*/
|
||||
public static Object newInstance(String className, Class<?> caller) {
|
||||
|
||||
try {
|
||||
Class<?> cls = forName(className, caller);
|
||||
return cls.newInstance();
|
||||
} catch (Exception e) {
|
||||
String msg = "Error constructing " + className;
|
||||
throw new IllegalArgumentException(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.ExpressionList;
|
||||
import com.avaje.ebean.OrderBy;
|
||||
import com.avaje.ebean.PersistenceContextScope;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.bean.BeanCollectionTouched;
|
||||
import com.avaje.ebean.bean.CallStack;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
@@ -22,6 +19,8 @@ import com.avaje.ebeaninternal.server.querydefn.NaturalKeyBindParam;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Object Relational query - Internal extension to Query object.
|
||||
*/
|
||||
@@ -148,6 +147,11 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
SpiQuery<T> copy();
|
||||
|
||||
/**
|
||||
* Return a copy of the query attaching to a different EbeanServer.
|
||||
*/
|
||||
SpiQuery<T> copy(EbeanServer server);
|
||||
|
||||
/**
|
||||
* Return the type of query (List, Set, Map, Bean, rowCount etc).
|
||||
*/
|
||||
@@ -171,18 +175,13 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
/**
|
||||
* This becomes a lazy loading query for a many relationship.
|
||||
*/
|
||||
void setLazyLoadForParents(List<Object> parentIds, BeanPropertyAssocMany<?> many);
|
||||
void setLazyLoadForParents(BeanPropertyAssocMany<?> many);
|
||||
|
||||
/**
|
||||
* Return the lazy loading 'many' property.
|
||||
*/
|
||||
BeanPropertyAssocMany<?> getLazyLoadForParentsProperty();
|
||||
|
||||
/**
|
||||
* Return the list of parent Id's for lazy loading.
|
||||
*/
|
||||
List<Object> getLazyLoadForParentIds();
|
||||
|
||||
/**
|
||||
* Set the load mode (+lazy or +query) and the load description.
|
||||
*/
|
||||
@@ -203,11 +202,6 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
ManyWhereJoins getManyWhereJoins();
|
||||
|
||||
/**
|
||||
* Convert this natural key query into a find by id query.
|
||||
*/
|
||||
void convertWhereNaturalKeyToId(Object idValue);
|
||||
|
||||
/**
|
||||
* Return a Natural Key bind parameter if supported by this query.
|
||||
*/
|
||||
@@ -341,11 +335,6 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
String getLazyLoadProperty();
|
||||
|
||||
/**
|
||||
* Return the lazy load path.
|
||||
*/
|
||||
String getLazyLoadManyPath();
|
||||
|
||||
/**
|
||||
* Used to hook back a lazy loading query to the original query (query
|
||||
* point).
|
||||
@@ -476,27 +465,11 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
Boolean isReadOnly();
|
||||
|
||||
/**
|
||||
* Adds this bean to the persistence context prior to executing the query.
|
||||
*/
|
||||
void contextAdd(EntityBean bean);
|
||||
|
||||
/**
|
||||
* Return the type of beans queries.
|
||||
*/
|
||||
Class<T> getBeanType();
|
||||
|
||||
/**
|
||||
* Return the query timeout.
|
||||
*/
|
||||
int getTimeout();
|
||||
|
||||
/**
|
||||
* Return the objects that should be added to the persistence context prior
|
||||
* to executing the query.
|
||||
*/
|
||||
ArrayList<EntityBean> getContextAdditions();
|
||||
|
||||
/**
|
||||
* Return the bind parameters.
|
||||
*/
|
||||
@@ -580,11 +553,6 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
String getRawWhereClause();
|
||||
|
||||
/**
|
||||
* Return the Id value.
|
||||
*/
|
||||
Object getId();
|
||||
|
||||
/**
|
||||
* Set the generated sql for debug purposes.
|
||||
*/
|
||||
|
||||
+354
-341
@@ -1,22 +1,18 @@
|
||||
package com.avaje.ebeaninternal.server.cache;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.cache.ServerCache;
|
||||
import com.avaje.ebean.cache.ServerCacheOptions;
|
||||
import com.avaje.ebean.cache.ServerCacheStatistics;
|
||||
import com.avaje.ebeaninternal.server.util.LongAdder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* The default cache implementation.
|
||||
@@ -27,375 +23,392 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class DefaultServerCache implements ServerCache {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultServerCache.class);
|
||||
protected static final Logger logger = LoggerFactory.getLogger(DefaultServerCache.class);
|
||||
|
||||
private static final CacheEntryComparator comparator = new CacheEntryComparator();
|
||||
|
||||
private final ConcurrentHashMap<Object, CacheEntry> map = new ConcurrentHashMap<Object, CacheEntry>();
|
||||
|
||||
private final AtomicInteger missCount = new AtomicInteger();
|
||||
|
||||
private final AtomicInteger removedHitCount = new AtomicInteger();
|
||||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final String name;
|
||||
|
||||
private int maxSize;
|
||||
|
||||
private long trimFrequency;
|
||||
|
||||
private int maxIdleSecs;
|
||||
|
||||
private int maxSecsToLive;
|
||||
|
||||
public DefaultServerCache(String name, ServerCacheOptions options) {
|
||||
this(name, options.getMaxSize(), options.getMaxIdleSecs(), options.getMaxSecsToLive());
|
||||
}
|
||||
|
||||
public DefaultServerCache(String name, int maxSize, int maxIdleSecs, int maxSecsToLive) {
|
||||
this.name = name;
|
||||
this.maxSize = maxSize;
|
||||
this.maxIdleSecs = maxIdleSecs;
|
||||
this.maxSecsToLive = maxSecsToLive;
|
||||
this.trimFrequency = 60;
|
||||
|
||||
}
|
||||
|
||||
public void init(EbeanServer server) {
|
||||
|
||||
TrimTask trim = new TrimTask();
|
||||
|
||||
BackgroundExecutor executor = server.getBackgroundExecutor();
|
||||
executor.executePeriodically(trim, trimFrequency, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public ServerCacheStatistics getStatistics(boolean reset) {
|
||||
|
||||
ServerCacheStatistics s = new ServerCacheStatistics();
|
||||
s.setCacheName(name);
|
||||
s.setMaxSize(maxSize);
|
||||
|
||||
// these counters won't necessarily be consistent with
|
||||
// respect to each other as activity can occur while
|
||||
// they are being calculated
|
||||
int mc = reset ? missCount.getAndSet(0) : missCount.get();
|
||||
int hc = getHitCount(reset);
|
||||
int size = size();
|
||||
|
||||
s.setSize(size);
|
||||
s.setHitCount(hc);
|
||||
s.setMissCount(mc);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public int getHitRatio() {
|
||||
|
||||
int mc = missCount.get();
|
||||
int hc = getHitCount(false);
|
||||
|
||||
int totalCount = hc + mc;
|
||||
if (totalCount == 0){
|
||||
return 0;
|
||||
} else {
|
||||
return hc * 100 / totalCount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private int getHitCount(boolean reset) {
|
||||
|
||||
int hc = reset ? removedHitCount.getAndSet(0) : removedHitCount.get();
|
||||
|
||||
for (CacheEntry cacheEntry : map.values()) {
|
||||
hc += cacheEntry.getHitCount(reset);
|
||||
}
|
||||
|
||||
return hc;
|
||||
}
|
||||
/**
|
||||
* Compare by last access time (for LRU eviction).
|
||||
*/
|
||||
public static final CompareByLastAccess BY_LAST_ACCESS = new CompareByLastAccess();
|
||||
|
||||
|
||||
public ServerCacheOptions getOptions() {
|
||||
synchronized (monitor) {
|
||||
ServerCacheOptions o = new ServerCacheOptions();
|
||||
o.setMaxIdleSecs(maxIdleSecs);
|
||||
o.setMaxSize(maxSize);
|
||||
o.setMaxSecsToLive(maxSecsToLive);
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
public void setOptions(ServerCacheOptions o) {
|
||||
synchronized (monitor) {
|
||||
maxIdleSecs = o.getMaxIdleSecs();
|
||||
maxSize = o.getMaxSize();
|
||||
maxSecsToLive = o.getMaxSecsToLive();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the max cache size.
|
||||
*/
|
||||
public int getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
/**
|
||||
* The underlying map (ConcurrentHashMap or similar)
|
||||
*/
|
||||
protected final Map<Object, CacheEntry> map;
|
||||
|
||||
/**
|
||||
* Set the max cache size.
|
||||
*/
|
||||
public void setMaxSize(int maxSize) {
|
||||
synchronized (monitor) {
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
}
|
||||
// LongAdder is a highly concurrent low latency counter (back ported from Java8)
|
||||
protected final LongAdder missCount = new LongAdder();
|
||||
protected final LongAdder hitCount = new LongAdder();
|
||||
protected final LongAdder insertCount = new LongAdder();
|
||||
protected final LongAdder updateCount = new LongAdder();
|
||||
protected final LongAdder removeCount = new LongAdder();
|
||||
protected final LongAdder clearCount = new LongAdder();
|
||||
|
||||
/**
|
||||
* Return the max idle time.
|
||||
*/
|
||||
public long getMaxIdleSecs() {
|
||||
return maxIdleSecs;
|
||||
}
|
||||
protected final LongAdder evictByIdle = new LongAdder();
|
||||
protected final LongAdder evictByTTL = new LongAdder();
|
||||
protected final LongAdder evictByLRU = new LongAdder();
|
||||
protected final LongAdder evictCount = new LongAdder();
|
||||
protected final LongAdder evictMicros = new LongAdder();
|
||||
|
||||
/**
|
||||
* Set the max idle time.
|
||||
*/
|
||||
public void setMaxIdleSecs(int maxIdleSecs) {
|
||||
synchronized (monitor) {
|
||||
this.maxIdleSecs = maxIdleSecs;
|
||||
}
|
||||
}
|
||||
protected final Object monitor = new Object();
|
||||
|
||||
/**
|
||||
* Return the maximum time to live.
|
||||
*/
|
||||
public long getMaxSecsToLive() {
|
||||
return maxSecsToLive;
|
||||
}
|
||||
protected final String name;
|
||||
|
||||
/**
|
||||
* Set the maximum time to live.
|
||||
*/
|
||||
public void setMaxSecsToLive(int maxSecsToLive) {
|
||||
synchronized (monitor) {
|
||||
this.maxSecsToLive = maxSecsToLive;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the cache.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
protected int maxSize;
|
||||
|
||||
/**
|
||||
* Clear the cache.
|
||||
*/
|
||||
public void clear() {
|
||||
map.clear();
|
||||
}
|
||||
protected int trimFrequency;
|
||||
|
||||
/**
|
||||
* Return a value from the cache.
|
||||
*/
|
||||
public Object get(Object key) {
|
||||
|
||||
CacheEntry entry = map.get(key);
|
||||
|
||||
if (entry == null){
|
||||
missCount.incrementAndGet();
|
||||
return null;
|
||||
|
||||
} else {
|
||||
// get value incrementing last
|
||||
// access time and hitCount
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
protected int maxIdleSecs;
|
||||
|
||||
/**
|
||||
* Put a value into the cache.
|
||||
*/
|
||||
public Object put(Object key, Object value) {
|
||||
// put new entry with create time
|
||||
CacheEntry entry = map.put(key, new CacheEntry(key, value));
|
||||
if (entry == null){
|
||||
return null;
|
||||
} else {
|
||||
int removedHits = entry.getHitCount(true);
|
||||
removedHitCount.addAndGet(removedHits);
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
protected int maxSecsToLive;
|
||||
|
||||
/**
|
||||
* Put a value into the cache but only if absent.
|
||||
*/
|
||||
public Object putIfAbsent(Object key, Object value) {
|
||||
CacheEntry entry = map.putIfAbsent(key, new CacheEntry(key, value));
|
||||
if (entry == null){
|
||||
return null;
|
||||
} else {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Construct using a ConcurrentHashMap and cache options.
|
||||
*/
|
||||
public DefaultServerCache(String name, ServerCacheOptions options) {
|
||||
this(name, new ConcurrentHashMap<Object, CacheEntry>(), options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an entry from the cache.
|
||||
*/
|
||||
public Object remove(Object key) {
|
||||
CacheEntry entry = map.remove(key);
|
||||
if (entry == null){
|
||||
return null;
|
||||
} else {
|
||||
int removedHits = entry.getHitCount(true);
|
||||
removedHitCount.addAndGet(removedHits);
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Construct passing in name, map and base eviction controls as ServerCacheOptions.
|
||||
*/
|
||||
public DefaultServerCache(String name, Map<Object, CacheEntry> map, ServerCacheOptions options) {
|
||||
this(name, map, options.getMaxSize(), options.getMaxIdleSecs(), options.getMaxSecsToLive(), options.getTrimFrequency());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of elements in the cache.
|
||||
*/
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
/**
|
||||
* Construct passing in name, map and base eviction controls.
|
||||
*/
|
||||
public DefaultServerCache(String name, Map<Object, CacheEntry> map, int maxSize, int maxIdleSecs, int maxSecsToLive, int trimFrequency) {
|
||||
this.name = name;
|
||||
this.map = map;
|
||||
this.maxSize = maxSize;
|
||||
this.maxIdleSecs = maxIdleSecs;
|
||||
this.maxSecsToLive = maxSecsToLive;
|
||||
this.trimFrequency = trimFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* The task used to periodically trim the cache.
|
||||
*/
|
||||
private class TrimTask implements Runnable {
|
||||
@Override
|
||||
public void init(EbeanServer server) {
|
||||
|
||||
public void run() {
|
||||
EvictionRunnable trim = new EvictionRunnable();
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
if (logger.isTraceEnabled()){
|
||||
logger.trace("trimming cache " + name);
|
||||
}
|
||||
|
||||
int trimmedByIdle = 0;
|
||||
int trimmedByTTL = 0;
|
||||
int trimmedByLRU = 0;
|
||||
// default to trimming the cache every 60 seconds
|
||||
long trimFreqSecs = (trimFrequency == 0) ? 60 : trimFrequency;
|
||||
|
||||
boolean trimMaxSize = maxSize > 0 && maxSize < size();
|
||||
BackgroundExecutor executor = server.getBackgroundExecutor();
|
||||
executor.executePeriodically(trim, trimFreqSecs, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
ArrayList<CacheEntry> activeList = new ArrayList<CacheEntry>();
|
||||
@Override
|
||||
public ServerCacheStatistics getStatistics(boolean reset) {
|
||||
|
||||
long idleExpire = System.currentTimeMillis() - (maxIdleSecs*1000);
|
||||
long ttlExpire = System.currentTimeMillis() - (maxSecsToLive*1000);
|
||||
ServerCacheStatistics cacheStats = new ServerCacheStatistics();
|
||||
cacheStats.setCacheName(name);
|
||||
cacheStats.setMaxSize(maxSize);
|
||||
|
||||
Iterator<CacheEntry> it = map.values().iterator();
|
||||
while (it.hasNext()) {
|
||||
CacheEntry cacheEntry = it.next();
|
||||
if (maxIdleSecs > 0 && idleExpire > cacheEntry.getLastAccessTime()) {
|
||||
it.remove();
|
||||
trimmedByIdle++;
|
||||
// these counters won't necessarily be consistent with
|
||||
// respect to each other as activity can occur while
|
||||
// they are being calculated here but they should be good enough
|
||||
// and we don't want to reduce concurrent use to make them consistent
|
||||
long clear = reset ? clearCount.sumThenReset() : clearCount.sum();
|
||||
long remove = reset ? removeCount.sumThenReset() : removeCount.sum();
|
||||
long update = reset ? updateCount.sumThenReset() : updateCount.sum();
|
||||
long insert = reset ? insertCount.sumThenReset() : insertCount.sum();
|
||||
long miss = reset ? missCount.sumThenReset() : missCount.sum();
|
||||
long hit = reset ? hitCount.sumThenReset() : hitCount.sum();
|
||||
|
||||
} else if (maxSecsToLive > 0 && ttlExpire > cacheEntry.getCreateTime()) {
|
||||
it.remove();
|
||||
trimmedByTTL++;
|
||||
long evict = reset ? evictCount.sumThenReset() : evictCount.sum();
|
||||
long evictTime = reset ? evictMicros.sumThenReset() : evictMicros.sum();
|
||||
long evictIdle = reset ? evictByIdle.sumThenReset() : evictByIdle.sum();
|
||||
long evictTTL = reset ? evictByTTL.sumThenReset() : evictByTTL.sum();
|
||||
long evictLRU = reset ? evictByLRU.sumThenReset() : evictByLRU.sum();
|
||||
|
||||
} else if (trimMaxSize) {
|
||||
activeList.add(cacheEntry);
|
||||
}
|
||||
}
|
||||
int size = size();
|
||||
|
||||
if (trimMaxSize) {
|
||||
trimmedByLRU = activeList.size() - maxSize;
|
||||
cacheStats.setSize(size);
|
||||
cacheStats.setHitCount(hit);
|
||||
cacheStats.setMissCount(miss);
|
||||
cacheStats.setInsertCount(insert);
|
||||
cacheStats.setUpdateCount(update);
|
||||
cacheStats.setRemoveCount(remove);
|
||||
cacheStats.setClearCount(clear);
|
||||
|
||||
if (trimmedByLRU > 0) {
|
||||
// sort into last access time ascending
|
||||
Collections.sort(activeList, comparator);
|
||||
for (int i = maxSize; i < activeList.size(); i++) {
|
||||
// remove if still in the cache
|
||||
map.remove(activeList.get(i).getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long exeTime = System.currentTimeMillis() - startTime;
|
||||
|
||||
if (logger.isDebugEnabled()){
|
||||
logger.debug("Executed trim of cache " + name + " in ["+exeTime
|
||||
+"]millis idle[" + trimmedByIdle + "] timeToLive["
|
||||
+ trimmedByTTL + "] accessTime["
|
||||
+ trimmedByLRU + "]");
|
||||
}
|
||||
cacheStats.setEvictionRunCount(evict);
|
||||
cacheStats.setEvictionRunMicros(evictTime);
|
||||
cacheStats.setEvictByIdle(evictIdle);
|
||||
cacheStats.setEvictByTTL(evictTTL);
|
||||
cacheStats.setEvictByLRU(evictLRU);
|
||||
|
||||
}
|
||||
return cacheStats;
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public int getHitRatio() {
|
||||
|
||||
/**
|
||||
* Comparator for sorting by last access time.
|
||||
*/
|
||||
private static class CacheEntryComparator implements Comparator<CacheEntry>, Serializable {
|
||||
long mc = missCount.sum();
|
||||
long hc = hitCount.sum();
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
long totalCount = hc + mc;
|
||||
if (totalCount == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return (int) (hc * 100 / totalCount);
|
||||
}
|
||||
}
|
||||
|
||||
public int compare(CacheEntry o1, CacheEntry o2) {
|
||||
|
||||
return o1.getLastAccessLong().compareTo(o2.getLastAccessLong());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the values to additionally hold createTime and lastAccessTime.
|
||||
*/
|
||||
public static class CacheEntry {
|
||||
/**
|
||||
* Return the options controlling the cache.
|
||||
*/
|
||||
@Override
|
||||
public ServerCacheOptions getOptions() {
|
||||
synchronized (monitor) {
|
||||
ServerCacheOptions options = new ServerCacheOptions();
|
||||
options.setMaxIdleSecs(maxIdleSecs);
|
||||
options.setMaxSize(maxSize);
|
||||
options.setMaxSecsToLive(maxSecsToLive);
|
||||
options.setTrimFrequency(trimFrequency);
|
||||
return options;
|
||||
}
|
||||
}
|
||||
|
||||
private final Object key;
|
||||
private final Object value;
|
||||
private final long createTime;
|
||||
private final AtomicInteger hitCount = new AtomicInteger();
|
||||
private Long lastAccessTime;
|
||||
/**
|
||||
* Set the options controlling the cache
|
||||
*/
|
||||
@Override
|
||||
public void setOptions(ServerCacheOptions options) {
|
||||
synchronized (monitor) {
|
||||
maxIdleSecs = options.getMaxIdleSecs();
|
||||
maxSize = options.getMaxSize();
|
||||
maxSecsToLive = options.getMaxSecsToLive();
|
||||
}
|
||||
}
|
||||
|
||||
public CacheEntry(Object key, Object value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.createTime = System.currentTimeMillis();
|
||||
this.lastAccessTime = Long.valueOf(createTime);
|
||||
}
|
||||
/**
|
||||
* Return the name of the cache.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Object getKey() {
|
||||
return key;
|
||||
}
|
||||
/**
|
||||
* Clear the cache.
|
||||
*/
|
||||
@Override
|
||||
public void clear() {
|
||||
clearCount.increment();
|
||||
map.clear();
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
// object assignment is atomic
|
||||
hitCount.incrementAndGet();
|
||||
this.lastAccessTime = Long.valueOf(System.currentTimeMillis());
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* Return a value from the cache.
|
||||
*/
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
CacheEntry entry = map.get(key);
|
||||
if (entry == null) {
|
||||
missCount.increment();
|
||||
return null;
|
||||
|
||||
public long getLastAccessTime() {
|
||||
return lastAccessTime.longValue();
|
||||
}
|
||||
} else {
|
||||
// Important that hitCount.increment() MUST be low latency under concurrent
|
||||
// use hence must use LongAdder or better here
|
||||
hitCount.increment();
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
public Long getLastAccessLong() {
|
||||
return lastAccessTime;
|
||||
}
|
||||
/**
|
||||
* Put a value into the cache.
|
||||
*/
|
||||
@Override
|
||||
public Object put(Object key, Object value) {
|
||||
CacheEntry entry = map.put(key, new CacheEntry(key, value));
|
||||
if (entry == null) {
|
||||
insertCount.increment();
|
||||
return null;
|
||||
} else {
|
||||
updateCount.increment();
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
public int getHitCount(boolean reset) {
|
||||
if (reset){
|
||||
return hitCount.getAndSet(0);
|
||||
/**
|
||||
* Remove an entry from the cache.
|
||||
*/
|
||||
@Override
|
||||
public Object remove(Object key) {
|
||||
CacheEntry entry = map.remove(key);
|
||||
if (entry == null) {
|
||||
return null;
|
||||
} else {
|
||||
removeCount.increment();
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of elements in the cache.
|
||||
*/
|
||||
@Override
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size to trim to based on the max size.
|
||||
* <p>
|
||||
* This returns 90% of the max size.
|
||||
* </p>
|
||||
*/
|
||||
protected int getTrimSize() {
|
||||
return (maxSize * 90 / 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the eviction based on Idle time, Time to live and LRU last access.
|
||||
*/
|
||||
public void runEviction() {
|
||||
|
||||
long trimForMaxSize;
|
||||
if (maxSize == 0) {
|
||||
trimForMaxSize = 0;
|
||||
} else {
|
||||
trimForMaxSize = size() - maxSize;
|
||||
}
|
||||
|
||||
if (maxIdleSecs == 0 && maxSecsToLive == 0 && trimForMaxSize < 0) {
|
||||
// nothing to trim on this cache
|
||||
return;
|
||||
}
|
||||
|
||||
long startNanos = System.nanoTime();
|
||||
|
||||
long trimmedByIdle = 0;
|
||||
long trimmedByTTL = 0;
|
||||
long trimmedByLRU = 0;
|
||||
|
||||
ArrayList<CacheEntry> activeList = new ArrayList<CacheEntry>();
|
||||
|
||||
long idleExpire = System.currentTimeMillis() - (maxIdleSecs * 1000);
|
||||
long ttlExpire = System.currentTimeMillis() - (maxSecsToLive * 1000);
|
||||
|
||||
Iterator<CacheEntry> it = map.values().iterator();
|
||||
while (it.hasNext()) {
|
||||
CacheEntry cacheEntry = it.next();
|
||||
if (maxIdleSecs > 0 && idleExpire > cacheEntry.getLastAccessTime()) {
|
||||
it.remove();
|
||||
trimmedByIdle++;
|
||||
|
||||
} else if (maxSecsToLive > 0 && ttlExpire > cacheEntry.getCreateTime()) {
|
||||
it.remove();
|
||||
trimmedByTTL++;
|
||||
|
||||
} else if (trimForMaxSize > 0) {
|
||||
activeList.add(cacheEntry);
|
||||
}
|
||||
}
|
||||
|
||||
if (trimForMaxSize > 0) {
|
||||
trimmedByLRU = activeList.size() - maxSize;
|
||||
if (trimmedByLRU > 0) {
|
||||
// sort into last access time ascending
|
||||
Collections.sort(activeList, BY_LAST_ACCESS);
|
||||
int trimSize = getTrimSize();
|
||||
for (int i = trimSize; i < activeList.size(); i++) {
|
||||
// remove if still in the cache
|
||||
map.remove(activeList.get(i).getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long exeNanos = System.nanoTime() - startNanos;
|
||||
long exeMicros = TimeUnit.MICROSECONDS.convert(exeNanos, TimeUnit.NANOSECONDS);
|
||||
|
||||
// increment the eviction statistics
|
||||
evictMicros.add(exeMicros);
|
||||
evictCount.increment();
|
||||
evictByIdle.add(trimmedByIdle);
|
||||
evictByTTL.add(trimmedByTTL);
|
||||
evictByLRU.add(trimmedByLRU);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Executed trim of cache {} in [{}]millis idle[{}] timeToLive[{}] accessTime[{}]"
|
||||
, name, exeMicros, trimmedByIdle, trimmedByTTL, trimmedByLRU);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runnable that calls the eviction routine.
|
||||
*/
|
||||
public class EvictionRunnable implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
runEviction();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparator for sorting by last access time.
|
||||
*/
|
||||
public static class CompareByLastAccess implements Comparator<CacheEntry>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public int compare(CacheEntry entry1, CacheEntry entry2) {
|
||||
return Long.compare(entry1.getLastAccessTime(), entry2.getLastAccessTime());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the value to additionally hold createTime and lastAccessTime and hit counter.
|
||||
*/
|
||||
public static class CacheEntry {
|
||||
|
||||
private final Object key;
|
||||
private final Object value;
|
||||
private final long createTime;
|
||||
private long lastAccessTime;
|
||||
|
||||
public CacheEntry(Object key, Object value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.createTime = System.currentTimeMillis();
|
||||
this.lastAccessTime = createTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the entry key.
|
||||
*/
|
||||
public Object getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the entry value.
|
||||
*/
|
||||
public Object getValue() {
|
||||
// long assignment should be atomic these days (Ref Cliff Click)
|
||||
lastAccessTime = System.currentTimeMillis();
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time the entry was created.
|
||||
*/
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time the entry was last accessed.
|
||||
*/
|
||||
public long getLastAccessTime() {
|
||||
return lastAccessTime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
return hitCount.get();
|
||||
}
|
||||
}
|
||||
public int getHitCount() {
|
||||
return hitCount.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ public class BootupClasses implements ClassPathSearchMatcher {
|
||||
|
||||
private ArrayList<Class<?>> transactionEventListenerList = new ArrayList<Class<?>>();
|
||||
|
||||
private ArrayList<Class<?>> beanFinderList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> beanFindControllerList = new ArrayList<Class<?>>();
|
||||
private ArrayList<Class<?>> beanQueryAdapterList = new ArrayList<Class<?>>();
|
||||
|
||||
@@ -282,13 +281,6 @@ public class BootupClasses implements ClassPathSearchMatcher {
|
||||
return transactionEventListenerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanFinders found.
|
||||
*/
|
||||
public List<Class<?>> getBeanFinders() {
|
||||
return beanFinderList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of BeanListeners found.
|
||||
*/
|
||||
@@ -351,11 +343,6 @@ public class BootupClasses implements ClassPathSearchMatcher {
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (BeanFinder.class.isAssignableFrom(cls)) {
|
||||
beanFinderList.add(cls);
|
||||
interesting = true;
|
||||
}
|
||||
|
||||
if (BeanFindController.class.isAssignableFrom(cls)) {
|
||||
beanFindControllerList.add(cls);
|
||||
interesting = true;
|
||||
|
||||
@@ -121,7 +121,7 @@ public class DefaultBeanLoader {
|
||||
query.where().raw(ew);
|
||||
}
|
||||
|
||||
query.setLazyLoadForParents(idList, many);
|
||||
query.setLazyLoadForParents(many);
|
||||
many.addWhereParentIdIn(query, idList);
|
||||
|
||||
query.setPersistenceContext(pc);
|
||||
|
||||
@@ -219,7 +219,16 @@ public class DefaultContainer implements SpiContainer {
|
||||
|
||||
ServerCacheFactory cacheFactory = serverConfig.getServerCacheFactory();
|
||||
if (cacheFactory == null) {
|
||||
cacheFactory = new DefaultServerCacheFactory();
|
||||
ServiceLoader<ServerCacheFactory> cacheFactories = ServiceLoader.load(ServerCacheFactory.class);
|
||||
Iterator<ServerCacheFactory> iterator = cacheFactories.iterator();
|
||||
if (iterator.hasNext()) {
|
||||
// use the cacheFactory (via classpath service loader)
|
||||
cacheFactory = iterator.next();
|
||||
logger.debug("using ServerCacheFactory {}", cacheFactory.getClass());
|
||||
} else {
|
||||
// use the built in default
|
||||
cacheFactory = new DefaultServerCacheFactory();
|
||||
}
|
||||
}
|
||||
|
||||
return new DefaultServerCacheManager(cacheFactory, beanOptions, queryOptions);
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.slf4j.LoggerFactory;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -1162,16 +1163,15 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
public <T> T findUnique(Query<T> query, Transaction t) {
|
||||
|
||||
// actually a find by Id type of query...
|
||||
// ... perhaps with joins and cache hints?
|
||||
SpiQuery<T> q = (SpiQuery<T>) query;
|
||||
Object id = q.getId();
|
||||
// ... perhaps with joins and cache hints
|
||||
Object id = query.getId();
|
||||
if (id != null) {
|
||||
return findId(query, t);
|
||||
}
|
||||
|
||||
BeanDescriptor<T> desc = beanDescriptorManager.getBeanDescriptor(q.getBeanType());
|
||||
BeanDescriptor<T> desc = beanDescriptorManager.getBeanDescriptor(query.getBeanType());
|
||||
|
||||
T bean = desc.cacheNaturalKeyLookup(q, (SpiTransaction)t);
|
||||
T bean = desc.cacheNaturalKeyLookup((SpiQuery<T>)query, (SpiTransaction) t);
|
||||
if (bean != null) {
|
||||
return bean;
|
||||
}
|
||||
@@ -1323,15 +1323,6 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
return new LimitOffsetPagedList<T>(this, (SpiQuery<T>)query, pageIndex, pageSize);
|
||||
}
|
||||
|
||||
public <T> void findVisit(Query<T> query, QueryResultVisitor<T> visitor, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
|
||||
|
||||
request.initTransIfRequired();
|
||||
request.findVisit(visitor);
|
||||
// no try finally - findVisit guarantee's cleanup of the transaction if required
|
||||
}
|
||||
|
||||
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ITERATE, query, t);
|
||||
@@ -1499,17 +1490,15 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
persister.update(checkEntityBean(bean), t, deleteMissingChildren);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all beans in the collection.
|
||||
*/
|
||||
public void update(Collection<?> beans) {
|
||||
update(beans, null);
|
||||
@Override
|
||||
public void updateAll(Collection<?> beans) throws OptimisticLockException {
|
||||
updateAll(beans, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update all beans in the collection with an explicit transaction.
|
||||
*/
|
||||
public void update(Collection<?> beans, Transaction t) {
|
||||
public void updateAll(Collection<?> beans, Transaction t) {
|
||||
|
||||
if (beans == null || beans.isEmpty()) {
|
||||
// Nothing to update?
|
||||
@@ -1547,14 +1536,14 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
/**
|
||||
* Insert all beans in the collection.
|
||||
*/
|
||||
public void insert(Collection<?> beans) {
|
||||
insert(beans, null);
|
||||
public void insertAll(Collection<?> beans) {
|
||||
insertAll(beans, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Insert all beans in the collection with a transaction.
|
||||
*/
|
||||
public void insert(Collection<?> beans, Transaction t) {
|
||||
public void insertAll(Collection<?> beans, Transaction t) {
|
||||
|
||||
if (beans == null || beans.isEmpty()) {
|
||||
// Nothing to insert?
|
||||
@@ -1669,34 +1658,20 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an update or insert on each bean in the iterator. Returns the
|
||||
* number of beans that where saved.
|
||||
*/
|
||||
public int save(Iterator<?> it) {
|
||||
return save(it, null);
|
||||
@Override
|
||||
public int saveAll(Collection<?> beans, Transaction transaction) throws OptimisticLockException {
|
||||
return saveAllInternal(beans.iterator(), transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an update or insert on each bean in the collection. Returns the
|
||||
* number of beans that where saved.
|
||||
*/
|
||||
public int save(Collection<?> c) {
|
||||
return save(c.iterator(), null);
|
||||
@Override
|
||||
public int saveAll(Collection<?> beans) throws OptimisticLockException {
|
||||
return saveAllInternal(beans.iterator(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an update or insert on each bean in the collection. Returns the
|
||||
* number of beans that where saved.
|
||||
*/
|
||||
public int save(Collection<?> c, Transaction t) {
|
||||
return save(c.iterator(), t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save all beans in the iterator with an explicit transaction.
|
||||
*/
|
||||
public int save(Iterator<?> it, Transaction t) {
|
||||
public int saveAllInternal(Iterator<?> it, Transaction t) {
|
||||
|
||||
TransWrapper wrap = initTransIfRequired(t);
|
||||
try {
|
||||
@@ -1739,11 +1714,13 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(Class<?> beanType, Collection<?> ids) {
|
||||
delete(beanType, ids, null);
|
||||
@Override
|
||||
public void deleteAll(Class<?> beanType, Collection<?> ids) {
|
||||
deleteAll(beanType, ids, null);
|
||||
}
|
||||
|
||||
public void delete(Class<?> beanType, Collection<?> ids, Transaction t) {
|
||||
@Override
|
||||
public void deleteAll(Class<?> beanType, Collection<?> ids, Transaction t) {
|
||||
|
||||
TransWrapper wrap = initTransIfRequired(t);
|
||||
try {
|
||||
@@ -1772,24 +1749,18 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
persister.delete(checkEntityBean(bean), t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all the beans in the iterator.
|
||||
*/
|
||||
public int delete(Iterator<?> it) {
|
||||
return delete(it, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all the beans in the collection.
|
||||
*/
|
||||
public int delete(Collection<?> c) {
|
||||
return delete(c.iterator(), null);
|
||||
@Override
|
||||
public int deleteAll(Collection<?> beans) {
|
||||
return deleteAllInternal(beans.iterator(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all the beans in the iterator with an explicit transaction.
|
||||
*/
|
||||
public int delete(Iterator<?> it, Transaction t) {
|
||||
private int deleteAllInternal(Iterator<?> it, Transaction t) {
|
||||
|
||||
TransWrapper wrap = initTransIfRequired(t);
|
||||
|
||||
@@ -2002,12 +1973,6 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
// immutable thread safe so return shared instance
|
||||
return jsonContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonContext createJsonContext() {
|
||||
return json();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void collectQueryStats(ObjectGraphNode node, long loadedBeanCount, long timeMicros) {
|
||||
|
||||
@@ -259,19 +259,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
}
|
||||
}
|
||||
|
||||
public void findVisit(QueryResultVisitor<T> visitor) {
|
||||
QueryIterator<T> it = queryEngine.findIterate(this);
|
||||
try {
|
||||
while (it.hasNext()) {
|
||||
if (!visitor.accept(it.next())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
it.close();
|
||||
}
|
||||
}
|
||||
|
||||
public QueryIterator<T> findIterate() {
|
||||
return queryEngine.findIterate(this);
|
||||
}
|
||||
|
||||
@@ -1,115 +1,104 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.QueryEachConsumer;
|
||||
import com.avaje.ebean.QueryEachWhileConsumer;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.QueryResultVisitor;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Defines the ORM query request api.
|
||||
*/
|
||||
public interface SpiOrmQueryRequest<T> {
|
||||
|
||||
/**
|
||||
* Return the query.
|
||||
*/
|
||||
public SpiQuery<T> getQuery();
|
||||
/**
|
||||
* Return the query.
|
||||
*/
|
||||
SpiQuery<T> getQuery();
|
||||
|
||||
/**
|
||||
* Return the associated BeanDescriptor.
|
||||
*/
|
||||
public BeanDescriptor<?> getBeanDescriptor();
|
||||
/**
|
||||
* Return the associated BeanDescriptor.
|
||||
*/
|
||||
BeanDescriptor<?> getBeanDescriptor();
|
||||
|
||||
/**
|
||||
* This will create a local (readOnly) transaction if no current transaction
|
||||
* exists.
|
||||
* <p>
|
||||
* A transaction may have been passed in explicitly or currently be active
|
||||
* in the thread local. If not, then a readOnly transaction is created to
|
||||
* execute this query.
|
||||
* </p>
|
||||
*/
|
||||
public void initTransIfRequired();
|
||||
/**
|
||||
* This will create a local (readOnly) transaction if no current transaction
|
||||
* exists.
|
||||
* <p>
|
||||
* A transaction may have been passed in explicitly or currently be active
|
||||
* in the thread local. If not, then a readOnly transaction is created to
|
||||
* execute this query.
|
||||
* </p>
|
||||
*/
|
||||
void initTransIfRequired();
|
||||
|
||||
/**
|
||||
* Will end a locally created transaction.
|
||||
* <p>
|
||||
* It ends the transaction by using a rollback() as the transaction is known
|
||||
* to be readOnly.
|
||||
* </p>
|
||||
*/
|
||||
public void endTransIfRequired();
|
||||
/**
|
||||
* Will end a locally created transaction.
|
||||
* <p>
|
||||
* It ends the transaction by using a rollback() as the transaction is known
|
||||
* to be readOnly.
|
||||
* </p>
|
||||
*/
|
||||
void endTransIfRequired();
|
||||
|
||||
/**
|
||||
* Execute the query as findById.
|
||||
*/
|
||||
public Object findId();
|
||||
/**
|
||||
* Execute the query as findById.
|
||||
*/
|
||||
Object findId();
|
||||
|
||||
/**
|
||||
* Execute the find row count query.
|
||||
*/
|
||||
public int findRowCount();
|
||||
/**
|
||||
* Execute the find row count query.
|
||||
*/
|
||||
int findRowCount();
|
||||
|
||||
/**
|
||||
* Execute the find ids query.
|
||||
*/
|
||||
public List<Object> findIds();
|
||||
|
||||
/**
|
||||
* Execute the find returning a QueryIterator and visitor pattern.
|
||||
*/
|
||||
public void findVisit(QueryResultVisitor<T> visitor);
|
||||
/**
|
||||
* Execute the find ids query.
|
||||
*/
|
||||
List<Object> findIds();
|
||||
|
||||
/**
|
||||
* Execute the find returning a QueryIterator and visitor pattern.
|
||||
*/
|
||||
public void findEach(QueryEachConsumer<T> consumer);
|
||||
void findEach(QueryEachConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the find returning a QueryIterator and visitor pattern.
|
||||
*/
|
||||
public void findEachWhile(QueryEachWhileConsumer<T> consumer);
|
||||
void findEachWhile(QueryEachWhileConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the find returning a QueryIterator.
|
||||
*/
|
||||
public QueryIterator<T> findIterate();
|
||||
|
||||
/**
|
||||
* Execute the query as findList.
|
||||
*/
|
||||
public List<T> findList();
|
||||
* Execute the find returning a QueryIterator.
|
||||
*/
|
||||
QueryIterator<T> findIterate();
|
||||
|
||||
/**
|
||||
* Execute the query as findSet.
|
||||
*/
|
||||
public Set<?> findSet();
|
||||
/**
|
||||
* Execute the query as findList.
|
||||
*/
|
||||
List<T> findList();
|
||||
|
||||
/**
|
||||
* Execute the query as findMap.
|
||||
*/
|
||||
public Map<?, ?> findMap();
|
||||
/**
|
||||
* Execute the query as findSet.
|
||||
*/
|
||||
Set<?> findSet();
|
||||
|
||||
/**
|
||||
* Try to get the object out of the persistence context.
|
||||
*/
|
||||
//public T getFromPersistenceContextOrCache();
|
||||
/**
|
||||
* Execute the query as findMap.
|
||||
*/
|
||||
Map<?, ?> findMap();
|
||||
|
||||
/**
|
||||
* Try to get the query result from the query cache.
|
||||
*/
|
||||
public BeanCollection<T> getFromQueryCache();
|
||||
/**
|
||||
* Try to get the query result from the query cache.
|
||||
*/
|
||||
BeanCollection<T> getFromQueryCache();
|
||||
|
||||
/**
|
||||
* Return the Database platform like clause.
|
||||
*/
|
||||
public String getDBLikeClause();
|
||||
/**
|
||||
* Return the Database platform like clause.
|
||||
*/
|
||||
String getDBLikeClause();
|
||||
|
||||
}
|
||||
@@ -631,7 +631,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
}
|
||||
|
||||
public boolean calculateUseCache(Boolean queryUseCache) {
|
||||
return (queryUseCache != null) ? queryUseCache.booleanValue() : isBeanCaching();
|
||||
return (queryUseCache != null) ? queryUseCache : isBeanCaching();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -303,7 +303,7 @@ public final class BeanDescriptorCacheHelp<T> {
|
||||
// try looking up into the bean cache using the id
|
||||
T cacheBean = beanCacheGetInternal(id, query.isReadOnly());
|
||||
if (cacheBean != null) {
|
||||
setupContext(cacheBean, query, getPersistenceContext(t));
|
||||
setupContext(cacheBean, getPersistenceContext(t));
|
||||
}
|
||||
return cacheBean;
|
||||
}
|
||||
@@ -320,7 +320,7 @@ public final class BeanDescriptorCacheHelp<T> {
|
||||
}
|
||||
|
||||
private boolean isNaturalKeyCaching(Boolean queryUseCache) {
|
||||
return naturalKeyCache != null && (queryUseCache == null || queryUseCache.booleanValue());
|
||||
return naturalKeyCache != null && (queryUseCache == null || queryUseCache);
|
||||
}
|
||||
|
||||
private boolean isNaturalKey(String propName) {
|
||||
@@ -332,7 +332,7 @@ public final class BeanDescriptorCacheHelp<T> {
|
||||
/**
|
||||
* For a bean built from the cache this sets up its persistence context for future lazy loading etc.
|
||||
*/
|
||||
private void setupContext(Object bean, SpiQuery<T> query, PersistenceContext context) {
|
||||
private void setupContext(Object bean, PersistenceContext context) {
|
||||
if (context == null) {
|
||||
context = new DefaultPersistenceContext();
|
||||
}
|
||||
@@ -408,7 +408,7 @@ public final class BeanDescriptorCacheHelp<T> {
|
||||
public T beanCacheGet(SpiQuery<T> query, PersistenceContext context) {
|
||||
T bean = beanCacheGetInternal(query.getId(), query.isReadOnly());
|
||||
if (bean != null) {
|
||||
setupContext(bean, query, context);
|
||||
setupContext(bean, context);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.event.BeanFindController;
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
import com.avaje.ebean.event.BeanQueryRequest;
|
||||
|
||||
/**
|
||||
* Wraps the old BeanFinder to make it implement BeanFindController.
|
||||
*/
|
||||
public class BeanFinderAdapter implements BeanFindController {
|
||||
|
||||
final BeanFinder beanFinder;
|
||||
|
||||
public BeanFinderAdapter(BeanFinder beanFinder) {
|
||||
this.beanFinder = beanFinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegisterFor(Class<?> cls) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInterceptFind(BeanQueryRequest<?> request) {
|
||||
// always intercept to support old behavior
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T find(BeanQueryRequest<T> request) {
|
||||
return (T)beanFinder.find(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> BeanCollection<T> findMany(BeanQueryRequest<T> request) {
|
||||
return beanFinder.findMany(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInterceptFindMany(BeanQueryRequest<?> request) {
|
||||
// always intercept to support old behavior
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,12 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.event.BeanFindController;
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
import com.avaje.ebeaninternal.server.core.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Default implementation for BeanFinderFactory.
|
||||
@@ -19,31 +15,14 @@ public class BeanFinderManager {
|
||||
|
||||
final Logger logger = LoggerFactory.getLogger(BeanFinderManager.class);
|
||||
|
||||
/**
|
||||
* Register of BeanFinder instances.
|
||||
*/
|
||||
final Map<Class<?>, BeanFinder<?>> registerFor = new HashMap<Class<?>, BeanFinder<?>>();
|
||||
|
||||
private final List<BeanFindController> list;
|
||||
|
||||
public BeanFinderManager(BootupClasses bootupClasses) {
|
||||
list = bootupClasses.getBeanFindControllers();
|
||||
|
||||
List<Class<?>> beanFinders = bootupClasses.getBeanFinders();
|
||||
for (Class<?> cls : beanFinders) {
|
||||
Class<?> entityType = getEntityClass(cls);
|
||||
try {
|
||||
BeanFinder<?> beanFinder = (BeanFinder<?>) cls.newInstance();
|
||||
registerFor.put(entityType, beanFinder);
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new PersistenceException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getRegisterCount() {
|
||||
return registerFor.size() + list.size();
|
||||
return list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,28 +37,6 @@ public class BeanFinderManager {
|
||||
deployDesc.setBeanFinder(c);
|
||||
}
|
||||
}
|
||||
// support the deprecated BeanFinder
|
||||
BeanFinder beanFinder = registerFor.get(deployDesc.getBeanType());
|
||||
if (beanFinder != null) {
|
||||
deployDesc.setBeanFinder(new BeanFinderAdapter(beanFinder));
|
||||
logger.debug("BeanFinder on[" + deployDesc.getFullName() + "] " + beanFinder.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the entity class given the controller class.
|
||||
* <p>
|
||||
* This uses reflection to find the generics parameter type.
|
||||
* </p>
|
||||
*/
|
||||
private Class<?> getEntityClass(Class<?> controller) {
|
||||
|
||||
Class<?> cls = ParamTypeUtil.findParamType(controller, BeanFinder.class);
|
||||
|
||||
if (cls == null) {
|
||||
String msg = "Could not determine the entity class (generics parameter type) from " + controller + " using reflection.";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
return cls;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
@@ -141,11 +140,13 @@ public final class BeanListHelp<T> implements BeanCollectionHelp<T> {
|
||||
list = (List<?>) collection;
|
||||
}
|
||||
|
||||
ctx.writeStartArray(name);
|
||||
for (int j = 0; j < list.size(); j++) {
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean) list.get(j));
|
||||
if (!list.isEmpty() || ctx.isIncludeEmpty()) {
|
||||
ctx.writeStartArray(name);
|
||||
for (int j = 0; j < list.size(); j++) {
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean) list.get(j));
|
||||
}
|
||||
ctx.writeEndArray();
|
||||
}
|
||||
ctx.writeEndArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -177,12 +177,14 @@ public final class BeanMapHelp<T> implements BeanCollectionHelp<T> {
|
||||
map = (Map<?, ?>) collection;
|
||||
}
|
||||
|
||||
ctx.writeStartArray(name);
|
||||
for (Entry<?, ?> entry : map.entrySet()) {
|
||||
//FIXME: json write map key ...
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean) entry.getValue());
|
||||
if (!map.isEmpty() || ctx.isIncludeEmpty()) {
|
||||
ctx.writeStartArray(name);
|
||||
for (Entry<?, ?> entry : map.entrySet()) {
|
||||
//FIXME: json write map key ...
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean) entry.getValue());
|
||||
}
|
||||
ctx.writeEndArray();
|
||||
}
|
||||
ctx.writeEndArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import com.avaje.ebeaninternal.server.text.json.WriteJson;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.DataInput;
|
||||
@@ -39,6 +41,8 @@ import java.util.Map;
|
||||
*/
|
||||
public class BeanProperty implements ElPropertyValue {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BeanProperty.class);
|
||||
|
||||
/**
|
||||
* Flag to mark this at part of the unique id.
|
||||
*/
|
||||
@@ -299,8 +303,8 @@ public class BeanProperty implements ElPropertyValue {
|
||||
this.elPlaceHolder = tableAliasIntern(descriptor, deploy.getElPlaceHolder(et), false, null);
|
||||
this.elPlaceHolderEncrypted = tableAliasIntern(descriptor, deploy.getElPlaceHolder(et), dbEncrypted, dbColumn);
|
||||
|
||||
this.jsonSerialize = deploy.isExposeSerialize();
|
||||
this.jsonDeserialize = deploy.isExposeDeserialize();
|
||||
this.jsonSerialize = deploy.isJsonSerialize();
|
||||
this.jsonDeserialize = deploy.isJsonDeserialize();
|
||||
}
|
||||
|
||||
private String tableAliasIntern(BeanDescriptor<?> descriptor, String s, boolean dbEncrypted, String dbColumn) {
|
||||
@@ -533,7 +537,7 @@ public class BeanProperty implements ElPropertyValue {
|
||||
sqlBeanLoad.load(this);
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(String prefix, List<String> selectChain) {
|
||||
public void buildRawSqlSelectChain(String prefix, List<String> selectChain) {
|
||||
if (prefix == null) {
|
||||
selectChain.add(name);
|
||||
} else {
|
||||
@@ -1070,24 +1074,42 @@ public class BeanProperty implements ElPropertyValue {
|
||||
}
|
||||
Object value = getValueIntercept(bean);
|
||||
if (value == null) {
|
||||
writeJson.writeNull(name);
|
||||
writeJson.writeNullField(name);
|
||||
} else {
|
||||
scalarType.jsonWrite(writeJson.gen(), name, value);
|
||||
if (scalarType != null) {
|
||||
scalarType.jsonWrite(writeJson, name, value);
|
||||
} else {
|
||||
writeJson.writeValueUsingObjectMapper(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void jsonRead(ReadJson ctx, EntityBean bean) throws IOException {
|
||||
if (!jsonDeserialize) {
|
||||
return;
|
||||
}
|
||||
|
||||
JsonToken event = ctx.nextToken();
|
||||
if (JsonToken.VALUE_NULL == event) {
|
||||
setValue(bean, null);
|
||||
if (jsonDeserialize) {
|
||||
setValue(bean, null);
|
||||
}
|
||||
} else {
|
||||
// expect to read non-null json value
|
||||
Object objValue = scalarType.jsonRead(ctx.getParser(), event);
|
||||
setValue(bean, objValue);
|
||||
Object objValue;
|
||||
if (scalarType != null) {
|
||||
objValue = scalarType.jsonRead(ctx.getParser(), event);
|
||||
} else {
|
||||
try {
|
||||
objValue = ctx.readValueUsingObjectMapper(propertyType);
|
||||
} catch (IOException e) {
|
||||
// change in behavior for #318
|
||||
objValue = null;
|
||||
String msg = "Error trying to use Jackson ObjectMapper to read transient property "
|
||||
+ getFullBeanName() +" - consider marking this property with @JsonIgnore";
|
||||
logger.error(msg, e);
|
||||
}
|
||||
}
|
||||
if (jsonDeserialize) {
|
||||
setValue(bean, objValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -225,7 +225,8 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
|
||||
return createElPropertyValue(propName, remainder, chain, propertyDeploy);
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(String prefix, List<String> selectChain) {
|
||||
@Override
|
||||
public void buildRawSqlSelectChain(String prefix, List<String> selectChain) {
|
||||
// do not add to the selectChain at the top level of the Many bean
|
||||
}
|
||||
|
||||
@@ -872,7 +873,14 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> {
|
||||
if (help != null) {
|
||||
help.jsonWrite(ctx, name, value, include != null);
|
||||
} else {
|
||||
ctx.toJson(name, (Collection<?>) value);
|
||||
if (isTransient) {
|
||||
ctx.writeValueUsingObjectMapper(name, value);
|
||||
} else {
|
||||
Collection<?> collection = (Collection<?>)value;
|
||||
if (!collection.isEmpty() || ctx.isIncludeEmpty()) {
|
||||
ctx.toJson(name, collection);
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.popParentBeanMany();
|
||||
}
|
||||
|
||||
+37
-2
@@ -1,23 +1,42 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.BeanCollectionAdd;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.server.text.json.ReadJson;
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Help BeanPropertyAssocMany with JSON processing.
|
||||
*/
|
||||
public class BeanPropertyAssocManyJsonHelp {
|
||||
|
||||
/**
|
||||
* The associated many property.
|
||||
*/
|
||||
private final BeanPropertyAssocMany<?> many;
|
||||
|
||||
/**
|
||||
* Helper used to read json for transient 'many' properties.
|
||||
*/
|
||||
private final BeanPropertyAssocManyJsonTransient jsonTransient;
|
||||
|
||||
/**
|
||||
* Construct for the owning many property.
|
||||
*/
|
||||
public BeanPropertyAssocManyJsonHelp(BeanPropertyAssocMany<?> many) {
|
||||
this.many = many;
|
||||
this.jsonTransient = !ClassUtil.isJacksonObjectMapperPresent() ? null : new BeanPropertyAssocManyJsonTransient();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the JSON for this property.
|
||||
*/
|
||||
public void jsonRead(ReadJson readJson, EntityBean parentBean) throws IOException {
|
||||
|
||||
if (!this.many.jsonDeserialize) {
|
||||
@@ -33,6 +52,11 @@ public class BeanPropertyAssocManyJsonHelp {
|
||||
throw new JsonParseException("Unexpected token " + event + " - expecting start_array ", parser.getCurrentLocation());
|
||||
}
|
||||
|
||||
if (many.isTransient()) {
|
||||
jsonReadTransientUsingObjectMapper(readJson, parentBean);
|
||||
return;
|
||||
}
|
||||
|
||||
BeanCollection<?> collection = many.createEmpty(parentBean);
|
||||
BeanCollectionAdd add = many.getBeanCollectionAdd(collection, null);
|
||||
do {
|
||||
@@ -51,4 +75,15 @@ public class BeanPropertyAssocManyJsonHelp {
|
||||
|
||||
many.setValue(parentBean, collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a Transient property using Jackson ObjectMapper.
|
||||
*/
|
||||
private void jsonReadTransientUsingObjectMapper(ReadJson readJson, EntityBean parentBean) throws IOException {
|
||||
|
||||
if (jsonTransient == null) {
|
||||
throw new IllegalStateException("Jackson ObjectMapper is required to read this Transient property "+many.getFullBeanName());
|
||||
}
|
||||
jsonTransient.jsonReadUsingObjectMapper(many, readJson, parentBean);
|
||||
}
|
||||
}
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.text.json.ReadJson;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.type.CollectionType;
|
||||
import com.fasterxml.jackson.databind.type.MapType;
|
||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
/**
|
||||
* Helper used to read transient many properties using Jackson ObjectMapper.
|
||||
*/
|
||||
public class BeanPropertyAssocManyJsonTransient {
|
||||
|
||||
/**
|
||||
* Use Jackson ObjectMapper to read the transient 'many' property.
|
||||
*/
|
||||
public void jsonReadUsingObjectMapper(BeanPropertyAssocMany<?> many, ReadJson readJson, EntityBean parentBean) throws IOException {
|
||||
|
||||
ObjectMapper mapper = readJson.getObjectMapper();
|
||||
|
||||
ManyType manyType = many.getManyType();
|
||||
|
||||
Object value;
|
||||
if (manyType.isMap()) {
|
||||
// read map using Jackson object mapper with unknown key type
|
||||
TypeFactory typeFactory = mapper.getTypeFactory();
|
||||
JavaType target = typeFactory.constructType(many.getTargetType());
|
||||
MapType jacksonType = typeFactory.constructMapType(LinkedHashMap.class, typeFactory.unknownType(), target);
|
||||
value = mapper.readValue(readJson.getParser(), jacksonType);
|
||||
|
||||
} else {
|
||||
// read list or set using Jackson object mapper
|
||||
CollectionType jacksonType = mapper.getTypeFactory().constructCollectionType(manyType.getCollectionType(), many.getTargetType());
|
||||
value = mapper.readValue(readJson.getParser(), jacksonType);
|
||||
}
|
||||
|
||||
many.setValue(parentBean, value);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -171,7 +171,7 @@ public class BeanPropertyCompound extends BeanProperty {
|
||||
}
|
||||
Object value = getValueIntercept(bean);
|
||||
if (value == null) {
|
||||
ctx.writeNull(name);
|
||||
ctx.writeNullField(name);
|
||||
} else {
|
||||
compoundType.jsonWrite(ctx, value, name);
|
||||
}
|
||||
|
||||
@@ -139,11 +139,13 @@ public final class BeanSetHelp<T> implements BeanCollectionHelp<T> {
|
||||
set = (Set<?>) collection;
|
||||
}
|
||||
|
||||
ctx.writeStartArray(name);
|
||||
Iterator<?> it = set.iterator();
|
||||
while (it.hasNext()) {
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean) it.next());
|
||||
if (!set.isEmpty() || ctx.isIncludeEmpty()) {
|
||||
ctx.writeStartArray(name);
|
||||
Iterator<?> it = set.iterator();
|
||||
while (it.hasNext()) {
|
||||
targetDescriptor.jsonWrite(ctx, (EntityBean) it.next());
|
||||
}
|
||||
ctx.writeEndArray();
|
||||
}
|
||||
ctx.writeEndArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,58 +2,76 @@ package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents the type of a OneToMany or ManyToMany property.
|
||||
*/
|
||||
public class ManyType {
|
||||
|
||||
public static final ManyType JAVA_LIST = new ManyType(Underlying.LIST);
|
||||
public static final ManyType JAVA_SET = new ManyType(Underlying.SET);
|
||||
public static final ManyType JAVA_MAP = new ManyType(Underlying.MAP);
|
||||
|
||||
public enum Underlying {
|
||||
LIST,
|
||||
SET,
|
||||
MAP
|
||||
}
|
||||
|
||||
private final SpiQuery.Type queryType;
|
||||
|
||||
private final Underlying underlying;
|
||||
|
||||
public static final ManyType JAVA_LIST = new ManyType(Underlying.LIST);
|
||||
public static final ManyType JAVA_SET = new ManyType(Underlying.SET);
|
||||
public static final ManyType JAVA_MAP = new ManyType(Underlying.MAP);
|
||||
|
||||
public ManyType(Underlying underlying) {
|
||||
this.underlying = underlying;
|
||||
switch (underlying) {
|
||||
case LIST:
|
||||
queryType = SpiQuery.Type.LIST;
|
||||
break;
|
||||
case SET:
|
||||
queryType = SpiQuery.Type.SET;
|
||||
break;
|
||||
public enum Underlying {
|
||||
|
||||
default:
|
||||
queryType = SpiQuery.Type.MAP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
LIST(List.class),
|
||||
SET(Set.class),
|
||||
MAP(null);
|
||||
|
||||
public boolean isMap() {
|
||||
return Underlying.MAP.equals(underlying);
|
||||
Class<? extends Collection> type;
|
||||
|
||||
Underlying(Class<? extends Collection> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the matching Query type.
|
||||
*/
|
||||
public SpiQuery.Type getQueryType() {
|
||||
return queryType;
|
||||
}
|
||||
|
||||
private final SpiQuery.Type queryType;
|
||||
|
||||
private final Underlying underlying;
|
||||
|
||||
|
||||
public ManyType(Underlying underlying) {
|
||||
this.underlying = underlying;
|
||||
switch (underlying) {
|
||||
case LIST:
|
||||
queryType = SpiQuery.Type.LIST;
|
||||
break;
|
||||
case SET:
|
||||
queryType = SpiQuery.Type.SET;
|
||||
break;
|
||||
|
||||
default:
|
||||
queryType = SpiQuery.Type.MAP;
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying type.
|
||||
*/
|
||||
public Underlying getUnderlying() {
|
||||
return underlying;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean isMap() {
|
||||
return Underlying.MAP.equals(underlying);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the matching Query type.
|
||||
*/
|
||||
public SpiQuery.Type getQueryType() {
|
||||
return queryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying type.
|
||||
*/
|
||||
public Underlying getUnderlying() {
|
||||
return underlying;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns List.class or Set.class and null for Map.
|
||||
* Not intended to be called for maps.
|
||||
*/
|
||||
public Class<? extends Collection> getCollectionType() {
|
||||
return underlying.type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.id;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
@@ -15,6 +8,12 @@ import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Binds id values to prepared statements.
|
||||
*/
|
||||
@@ -23,22 +22,22 @@ public interface IdBinder {
|
||||
/**
|
||||
* Initialise the binder.
|
||||
*/
|
||||
public void initialise();
|
||||
void initialise();
|
||||
|
||||
/**
|
||||
* Return true if this is a compound key and must use expanded and or form.
|
||||
*/
|
||||
public boolean isIdInExpandedForm();
|
||||
boolean isIdInExpandedForm();
|
||||
|
||||
/**
|
||||
* Write the Id value to binary DataOuput.
|
||||
*/
|
||||
public void writeData(DataOutput dataOutput, Object idValue) throws IOException;
|
||||
void writeData(DataOutput dataOutput, Object idValue) throws IOException;
|
||||
|
||||
/**
|
||||
* Read the Id value from the binary DataInput.
|
||||
*/
|
||||
public Object readData(DataInput dataInput) throws IOException;
|
||||
Object readData(DataInput dataInput) throws IOException;
|
||||
|
||||
/**
|
||||
* Return the name(s) of the Id property(s). Comma delimited if there is more
|
||||
@@ -47,36 +46,36 @@ public interface IdBinder {
|
||||
* This can be used to include in a query.
|
||||
* </p>
|
||||
*/
|
||||
public String getIdProperty();
|
||||
String getIdProperty();
|
||||
|
||||
/**
|
||||
* Return the Id BeanProperty.
|
||||
*/
|
||||
public BeanProperty getBeanProperty();
|
||||
BeanProperty getBeanProperty();
|
||||
|
||||
/**
|
||||
* Find a BeanProperty that is mapped to the database column.
|
||||
*/
|
||||
public BeanProperty findBeanProperty(String dbColumnName);
|
||||
BeanProperty findBeanProperty(String dbColumnName);
|
||||
|
||||
/**
|
||||
* Return the number of scalar properties for this id.
|
||||
*/
|
||||
public int getPropertyCount();
|
||||
int getPropertyCount();
|
||||
|
||||
/**
|
||||
* Return false if the id is a simple scalar and false if it is embedded or
|
||||
* concatenated.
|
||||
*/
|
||||
public boolean isComplexId();
|
||||
boolean isComplexId();
|
||||
|
||||
/**
|
||||
* Return the default order by that may need to be used if the query includes
|
||||
* a many property.
|
||||
*/
|
||||
public String getDefaultOrderBy();
|
||||
String getDefaultOrderBy();
|
||||
|
||||
public String getOrderBy(String pathPrefix, boolean ascending);
|
||||
String getOrderBy(String pathPrefix, boolean ascending);
|
||||
|
||||
/**
|
||||
* Return the values as an array of scalar bindable values.
|
||||
@@ -88,12 +87,12 @@ public interface IdBinder {
|
||||
* Added primarily for Query.addWhere().add(Expr.idEq()) support.
|
||||
* </p>
|
||||
*/
|
||||
public Object[] getBindValues(Object idValue);
|
||||
Object[] getBindValues(Object idValue);
|
||||
|
||||
/**
|
||||
* Return the id values for a given bean.
|
||||
*/
|
||||
public Object[] getIdValues(EntityBean bean);
|
||||
Object[] getIdValues(EntityBean bean);
|
||||
|
||||
/**
|
||||
* Build a string of the logical expressions.
|
||||
@@ -101,68 +100,68 @@ public interface IdBinder {
|
||||
* Typically used to build a id = ? string.
|
||||
* </p>
|
||||
*/
|
||||
public String getAssocOneIdExpr(String prefix, String operator);
|
||||
String getAssocOneIdExpr(String prefix, String operator);
|
||||
|
||||
/**
|
||||
* Return the logical id in expression taking into account embedded id's.
|
||||
*/
|
||||
public String getAssocIdInExpr(String prefix);
|
||||
String getAssocIdInExpr(String prefix);
|
||||
|
||||
/**
|
||||
* Binds an id value to a prepared statement.
|
||||
*/
|
||||
public void bindId(DataBind dataBind, Object value) throws SQLException;
|
||||
void bindId(DataBind dataBind, Object value) throws SQLException;
|
||||
|
||||
/**
|
||||
* Bind the id value to a SqlUpdate statement.
|
||||
*/
|
||||
public void bindId(DefaultSqlUpdate sqlUpdate, Object value);
|
||||
void bindId(DefaultSqlUpdate sqlUpdate, Object value);
|
||||
|
||||
public void addIdInBindValue(SpiExpressionRequest request, Object value);
|
||||
void addIdInBindValue(SpiExpressionRequest request, Object value);
|
||||
|
||||
/**
|
||||
* Return the sql for binding the id using an IN clause.
|
||||
*/
|
||||
public String getBindIdInSql(String baseTableAlias);
|
||||
String getBindIdInSql(String baseTableAlias);
|
||||
|
||||
/**
|
||||
* Return the binding expression (like "?" or "(?,?)")for the Id.
|
||||
*/
|
||||
public String getIdInValueExpr(int size);
|
||||
String getIdInValueExpr(int size);
|
||||
|
||||
/**
|
||||
* Same as getIdInValueExpr but for delete by id.
|
||||
*/
|
||||
public String getIdInValueExprDelete(int size);
|
||||
String getIdInValueExprDelete(int size);
|
||||
|
||||
public void buildSelectExpressionChain(String prefix, List<String> selectChain);
|
||||
void buildRawSqlSelectChain(String prefix, List<String> selectChain);
|
||||
|
||||
/**
|
||||
* Read the id value from the result set and set it to the bean also returning
|
||||
* it.
|
||||
*/
|
||||
public Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException;
|
||||
Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException;
|
||||
|
||||
/**
|
||||
* Ignore the appropriate number of scalar properties for this id.
|
||||
*/
|
||||
public void loadIgnore(DbReadContext ctx);
|
||||
void loadIgnore(DbReadContext ctx);
|
||||
|
||||
/**
|
||||
* Read the id value from the result set and return it.
|
||||
*/
|
||||
public Object read(DbReadContext ctx) throws SQLException;
|
||||
Object read(DbReadContext ctx) throws SQLException;
|
||||
|
||||
/**
|
||||
* Append to the select clause.
|
||||
*/
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery);
|
||||
void appendSelect(DbSqlContext ctx, boolean subQuery);
|
||||
|
||||
/**
|
||||
* Return the sql for binding the id to. This includes table alias and columns
|
||||
* that make up the id.
|
||||
*/
|
||||
public String getBindIdSql(String baseTableAlias);
|
||||
String getBindIdSql(String baseTableAlias);
|
||||
|
||||
/**
|
||||
* Cast or convert the Id value if necessary and optionally set it.
|
||||
@@ -175,6 +174,6 @@ public interface IdBinder {
|
||||
* If the bean is not null, then the value is set to the bean.
|
||||
* </p>
|
||||
*/
|
||||
public Object convertSetId(Object idValue, EntityBean bean);
|
||||
Object convertSetId(Object idValue, EntityBean bean);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.id;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
@@ -17,6 +11,12 @@ import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import com.avaje.ebeaninternal.server.query.SplitName;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Bind an Id that is an Embedded bean.
|
||||
*/
|
||||
@@ -115,12 +115,12 @@ public final class IdBinderEmbedded implements IdBinder {
|
||||
return embIdProperty.getName();
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(String prefix, List<String> selectChain) {
|
||||
public void buildRawSqlSelectChain(String prefix, List<String> selectChain) {
|
||||
|
||||
prefix = SplitName.add(prefix, embIdProperty.getName());
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
props[i].buildSelectExpressionChain(prefix, selectChain);
|
||||
props[i].buildRawSqlSelectChain(prefix, selectChain);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.id;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
@@ -15,6 +8,12 @@ import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* For beans with no id properties AKA report type beans.
|
||||
*/
|
||||
@@ -38,7 +37,7 @@ public final class IdBinderEmpty implements IdBinder {
|
||||
return pathPrefix;
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(String prefix, List<String> selectChain) {
|
||||
public void buildRawSqlSelectChain(String prefix, List<String> selectChain) {
|
||||
}
|
||||
|
||||
public int getPropertyCount() {
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.id;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
@@ -17,6 +10,12 @@ import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Bind an Id where the Id is made of a single property (not embedded).
|
||||
*/
|
||||
@@ -59,9 +58,9 @@ public final class IdBinderSimple implements IdBinder {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(String prefix, List<String> selectChain) {
|
||||
public void buildRawSqlSelectChain(String prefix, List<String> selectChain) {
|
||||
|
||||
idProperty.buildSelectExpressionChain(prefix, selectChain);
|
||||
idProperty.buildRawSqlSelectChain(prefix, selectChain);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+795
-808
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,22 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import com.avaje.ebean.annotation.*;
|
||||
import com.avaje.ebean.annotation.CreatedTimestamp;
|
||||
import com.avaje.ebean.annotation.DbHstore;
|
||||
import com.avaje.ebean.annotation.DbJson;
|
||||
import com.avaje.ebean.annotation.DbJsonB;
|
||||
import com.avaje.ebean.annotation.EmbeddedColumns;
|
||||
import com.avaje.ebean.annotation.Encrypted;
|
||||
import com.avaje.ebean.annotation.Expose;
|
||||
import com.avaje.ebean.annotation.Formula;
|
||||
import com.avaje.ebean.annotation.Index;
|
||||
import com.avaje.ebean.annotation.JsonIgnore;
|
||||
import com.avaje.ebean.annotation.UpdatedTimestamp;
|
||||
import com.avaje.ebean.config.EncryptDeploy;
|
||||
import com.avaje.ebean.config.EncryptDeploy.Mode;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncrypt;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
|
||||
import com.avaje.ebean.config.dbplatform.IdType;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
@@ -13,7 +24,12 @@ import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.idgen.UuidIdGenerator;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.type.*;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundType;
|
||||
import com.avaje.ebeaninternal.server.type.DataEncryptSupport;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeBytesBase;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeBytesEncrypted;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeEncryptedWrapper;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
@@ -27,6 +43,11 @@ import java.util.UUID;
|
||||
*/
|
||||
public class AnnotationFields extends AnnotationParser {
|
||||
|
||||
/**
|
||||
* If present read Jackson JsonIgnore.
|
||||
*/
|
||||
private boolean jacksonAnnotationsPresent = ClassUtil.isJacksonAnnotationsPresent();
|
||||
|
||||
/**
|
||||
* By default we lazy load Lob properties.
|
||||
*/
|
||||
@@ -101,10 +122,25 @@ public class AnnotationFields extends AnnotationParser {
|
||||
if (column != null) {
|
||||
readColumn(column, prop);
|
||||
}
|
||||
|
||||
if (jacksonAnnotationsPresent) {
|
||||
com.fasterxml.jackson.annotation.JsonIgnore jsonIgnore = get(prop, com.fasterxml.jackson.annotation.JsonIgnore.class);
|
||||
if (jsonIgnore != null) {
|
||||
prop.setJsonSerialize(!jsonIgnore.value());
|
||||
prop.setJsonDeserialize(!jsonIgnore.value());
|
||||
}
|
||||
}
|
||||
|
||||
Expose expose = get(prop, Expose.class);
|
||||
if (expose != null) {
|
||||
prop.setExposeSerialize(expose.serialize());
|
||||
prop.setExposeDeserialize(expose.deserialize());
|
||||
prop.setJsonSerialize(expose.serialize());
|
||||
prop.setJsonDeserialize(expose.deserialize());
|
||||
}
|
||||
|
||||
JsonIgnore jsonIgnore = get(prop, JsonIgnore.class);
|
||||
if (jsonIgnore != null) {
|
||||
prop.setJsonSerialize(jsonIgnore.serialize());
|
||||
prop.setJsonDeserialize(jsonIgnore.deserialize());
|
||||
}
|
||||
|
||||
if (prop.getDbColumn() == null) {
|
||||
@@ -143,9 +179,7 @@ public class AnnotationFields extends AnnotationParser {
|
||||
util.setDbJsonBType(prop);
|
||||
}
|
||||
}
|
||||
if (get(prop, ColumnHstore.class) != null) {
|
||||
util.setDbHstore(prop);
|
||||
}
|
||||
|
||||
if (get(prop, DbHstore.class) != null) {
|
||||
util.setDbHstore(prop);
|
||||
}
|
||||
|
||||
+14
-6
@@ -1,12 +1,16 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import com.avaje.ebean.annotation.ColumnHstore;
|
||||
import com.avaje.ebean.annotation.DbHstore;
|
||||
import com.avaje.ebean.annotation.DbJson;
|
||||
import com.avaje.ebean.annotation.DbJsonB;
|
||||
import com.avaje.ebeaninternal.server.deploy.DetermineManyType;
|
||||
import com.avaje.ebeaninternal.server.deploy.ManyType;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.*;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertySimpleCollection;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundType;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
@@ -17,7 +21,11 @@ import org.slf4j.LoggerFactory;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.Transient;
|
||||
import java.lang.reflect.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Create the properties for a bean.
|
||||
@@ -259,7 +267,8 @@ public class DeployCreateProperties {
|
||||
}
|
||||
|
||||
if (isTransientField(field)) {
|
||||
return null;
|
||||
// return with no ScalarType (still support JSON features)
|
||||
return new DeployBeanProperty(desc, propertyType, null, null);
|
||||
}
|
||||
try {
|
||||
CheckImmutableResponse checkImmutable = typeManager.checkImmutable(propertyType);
|
||||
@@ -293,8 +302,7 @@ public class DeployCreateProperties {
|
||||
private boolean isMappedType(Field field) {
|
||||
return (field.getAnnotation(DbJson.class) != null)
|
||||
|| (field.getAnnotation(DbJsonB.class) != null)
|
||||
|| (field.getAnnotation(DbHstore.class) != null)
|
||||
|| (field.getAnnotation(ColumnHstore.class) != null);
|
||||
|| (field.getAnnotation(DbHstore.class) != null);
|
||||
}
|
||||
|
||||
private boolean isTransientField(Field field) {
|
||||
|
||||
@@ -173,19 +173,27 @@ public class DeployUtil {
|
||||
// Note that Temporal types already have dbType
|
||||
// set via annotations
|
||||
Class<?> propType = property.getPropertyType();
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(propType, property.getDbType());
|
||||
if (scalarType != null) {
|
||||
return scalarType;
|
||||
}
|
||||
try {
|
||||
ScalarType<?> scalarType = typeManager.getScalarType(propType, property.getDbType());
|
||||
if (scalarType != null) {
|
||||
return scalarType;
|
||||
}
|
||||
|
||||
String msg = property.getFullBeanName() + " has no ScalarType - type[" + propType.getName() + "]";
|
||||
if (!property.isTransient()) {
|
||||
throw new PersistenceException(msg);
|
||||
String msg = property.getFullBeanName() + " has no ScalarType - type[" + propType.getName() + "]";
|
||||
if (!property.isTransient()) {
|
||||
throw new PersistenceException(msg);
|
||||
|
||||
} else {
|
||||
// this is ok...
|
||||
logger.trace("... transient property " + msg);
|
||||
return null;
|
||||
} else {
|
||||
// this is ok...
|
||||
logger.trace("... transient property " + msg);
|
||||
return null;
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (property.isTransient()) {
|
||||
// expected for transient properties with unknown/non-mapped types
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -252,11 +252,6 @@ abstract class JunctionExpression<T> implements Junction<T>, SpiExpression, Expr
|
||||
exprList.findEachWhile(consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findVisit(QueryResultVisitor<T> visitor) {
|
||||
exprList.findVisit(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryIterator<T> findIterate() {
|
||||
return exprList.findIterate();
|
||||
|
||||
@@ -265,7 +265,7 @@ public class CQueryBuilder implements Constants {
|
||||
propertyName = SplitName.parent(propertyName);
|
||||
} else if (beanProperty instanceof BeanPropertyAssocOne<?>) {
|
||||
String msg = "Column [" + column.getDbColumn() + "] mapped to complex Property[" + propertyName + "]";
|
||||
msg += ". It should be mapped to a simple property (proably the Id property). ";
|
||||
msg += ". It should be mapped to a simple property (probably the Id property). ";
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
if (propertyName != null) {
|
||||
@@ -284,8 +284,16 @@ public class CQueryBuilder implements Constants {
|
||||
detail.getChunk(path, true).setDefaultProperties(null, props);
|
||||
}
|
||||
|
||||
// check if @Id property included in RawSql
|
||||
boolean rawNoId = true;
|
||||
BeanProperty idProperty = descriptor.getIdProperty();
|
||||
if (idProperty != null && columnMapping.contains(idProperty.getName())) {
|
||||
// contains the @Id property for the root level bean
|
||||
rawNoId = false;
|
||||
}
|
||||
|
||||
// build SqlTree based on OrmQueryDetail of the RawSql
|
||||
return new SqlTreeBuilder(request, predicates, detail).build();
|
||||
return new SqlTreeBuilder(request, predicates, detail, rawNoId).build();
|
||||
}
|
||||
|
||||
private SqlLimitResponse buildSql(String selectClause, OrmQueryRequest<?> request, CQueryPredicates predicates, SqlTree select) {
|
||||
|
||||
@@ -31,9 +31,11 @@ public class CQueryPlanRawSql extends CQueryPlan {
|
||||
|
||||
private int[] createIndexPositions(OrmQueryRequest<?> request, SqlTree sqlTree) {
|
||||
|
||||
List<String> chain = sqlTree.buildSelectExpressionChain();
|
||||
List<String> chain = sqlTree.buildRawSqlSelectChain();
|
||||
ColumnMapping columnMapping = request.getQuery().getRawSql().getColumnMapping();
|
||||
|
||||
// if the top level bean has inheritance expect first column
|
||||
// to be the discriminator type column (and use offset 1)
|
||||
InheritInfo inheritInfo = request.getBeanDescriptor().getInheritInfo();
|
||||
boolean addDiscriminator = inheritInfo != null;
|
||||
int offset = addDiscriminator ? 1 : 0;
|
||||
@@ -43,12 +45,25 @@ public class CQueryPlanRawSql extends CQueryPlan {
|
||||
// discriminator column must always be first in the query
|
||||
indexPositions[0] = 1;
|
||||
}
|
||||
|
||||
// set the resultSet index positions for the property expressions
|
||||
for (int i = 0; i < chain.size(); i++) {
|
||||
String expr = chain.get(i);
|
||||
int indexPos = 1 + columnMapping.getIndexPosition(expr);
|
||||
indexPositions[i + offset] = indexPos;
|
||||
}
|
||||
|
||||
// check and handle the case where a discriminator column for
|
||||
// an associated bean is in the raw SQL but is mapped columnIgnore
|
||||
for (int i = 0; i <indexPositions.length ; i++) {
|
||||
if (indexPositions[i] == 0) {
|
||||
if (i < indexPositions.length) {
|
||||
// expect discriminator column to immediately proceed id column
|
||||
indexPositions[i] = indexPositions[i+1] - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return indexPositions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents the SELECT clause part of the SQL query.
|
||||
*/
|
||||
@@ -83,9 +83,9 @@ public class SqlTree {
|
||||
/**
|
||||
* Build a select expression chain for RawSql.
|
||||
*/
|
||||
public List<String> buildSelectExpressionChain() {
|
||||
public List<String> buildRawSqlSelectChain() {
|
||||
ArrayList<String> list = new ArrayList<String>();
|
||||
rootNode.buildSelectExpressionChain(list);
|
||||
rootNode.buildRawSqlSelectChain(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@@ -66,15 +66,21 @@ public class SqlTreeBuilder {
|
||||
|
||||
private final boolean rawSql;
|
||||
|
||||
/**
|
||||
* rawNoId true if the RawSql does not include the @Id property
|
||||
*/
|
||||
private final boolean rawNoId;
|
||||
|
||||
private SqlTreeNode rootNode;
|
||||
|
||||
/**
|
||||
* Construct for RawSql query.
|
||||
*/
|
||||
public SqlTreeBuilder(OrmQueryRequest<?> request, CQueryPredicates predicates, OrmQueryDetail queryDetail) {
|
||||
public SqlTreeBuilder(OrmQueryRequest<?> request, CQueryPredicates predicates, OrmQueryDetail queryDetail, boolean rawNoId) {
|
||||
|
||||
this.rawSql = true;
|
||||
this.desc = request.getBeanDescriptor();
|
||||
this.rawNoId = rawNoId;
|
||||
this.query = null;
|
||||
this.subQuery = false;
|
||||
this.queryDetail = queryDetail;
|
||||
@@ -95,6 +101,7 @@ public class SqlTreeBuilder {
|
||||
OrmQueryRequest<?> request, CQueryPredicates predicates) {
|
||||
|
||||
this.rawSql = false;
|
||||
this.rawNoId = false;
|
||||
this.desc = request.getBeanDescriptor();
|
||||
this.query = request.getQuery();
|
||||
|
||||
@@ -257,7 +264,7 @@ public class SqlTreeBuilder {
|
||||
|
||||
// Optional many property for lazy loading query
|
||||
BeanPropertyAssocMany<?> lazyLoadMany = (query == null) ? null : query.getLazyLoadForParentsProperty();
|
||||
boolean withId = !subQuery && (query == null || !query.isDistinct());
|
||||
boolean withId = !rawNoId && !subQuery && (query == null || !query.isDistinct());
|
||||
return new SqlTreeNodeRoot(desc, props, myList, withId, includeJoin, lazyLoadMany);
|
||||
|
||||
} else if (prop instanceof BeanPropertyAssocMany<?>) {
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
public interface SqlTreeNode {
|
||||
|
||||
String COMMA = ", ";
|
||||
|
||||
void buildSelectExpressionChain(List<String> selectChain);
|
||||
/**
|
||||
* Build the select chain for a RawSql query.
|
||||
*/
|
||||
void buildRawSqlSelectChain(List<String> selectChain);
|
||||
|
||||
/**
|
||||
* Append the required column information to the SELECT part of the sql
|
||||
|
||||
@@ -137,18 +137,18 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
}
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(List<String> selectChain) {
|
||||
public void buildRawSqlSelectChain(List<String> selectChain) {
|
||||
if (readId) {
|
||||
idBinder.buildSelectExpressionChain(prefix, selectChain);
|
||||
idBinder.buildRawSqlSelectChain(prefix, selectChain);
|
||||
}
|
||||
for (int i = 0, x = properties.length; i < x; i++) {
|
||||
properties[i].buildSelectExpressionChain(prefix, selectChain);
|
||||
properties[i].buildRawSqlSelectChain(prefix, selectChain);
|
||||
}
|
||||
// recursively continue reading...
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
// read each child... and let them set their
|
||||
// values back to this localBean
|
||||
children[i].buildSelectExpressionChain(selectChain);
|
||||
children[i].buildRawSqlSelectChain(selectChain);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ public class SqlTreeNodeBean implements SqlTreeNode {
|
||||
if (Mode.LAZYLOAD_BEAN.equals(queryMode)) {
|
||||
// Lazy Load does not reset the dirty state
|
||||
ebi.setLoadedLazy();
|
||||
} else {
|
||||
} else if (readId) {
|
||||
// normal bean loading
|
||||
ebi.setLoaded();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssoc;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
@@ -11,6 +7,10 @@ import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The purpose is to add an extra join to the query.
|
||||
* <p>
|
||||
@@ -35,7 +35,8 @@ public class SqlTreeNodeExtraJoin implements SqlTreeNode {
|
||||
this.manyJoin = assocBeanProperty instanceof BeanPropertyAssocMany<?>;
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(List<String> selectChain) {
|
||||
@Override
|
||||
public void buildRawSqlSelectChain(List<String> selectChain) {
|
||||
// nothing to add
|
||||
}
|
||||
|
||||
@@ -49,7 +50,6 @@ public class SqlTreeNodeExtraJoin implements SqlTreeNode {
|
||||
return manyJoin;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssoc;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
@@ -12,6 +8,9 @@ import com.avaje.ebeaninternal.server.deploy.DbReadContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.DbSqlContext;
|
||||
import com.avaje.ebeaninternal.server.deploy.TableJoin;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Join to Many (or child of a many) to support where clause predicates on many properties.
|
||||
*/
|
||||
@@ -76,7 +75,7 @@ public class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
|
||||
}
|
||||
}
|
||||
|
||||
public void buildSelectExpressionChain(List<String> selectChain) {
|
||||
public void buildRawSqlSelectChain(List<String> selectChain) {
|
||||
// nothing to add
|
||||
}
|
||||
|
||||
|
||||
@@ -51,11 +51,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
private transient final ExpressionFactory expressionFactory;
|
||||
|
||||
/**
|
||||
* Used to add beans to the PersistanceContext prior to query.
|
||||
*/
|
||||
private transient ArrayList<EntityBean> contextAdditions;
|
||||
|
||||
/**
|
||||
* For lazy loading of ManyToMany we need to add a join to the intersection table. This is that
|
||||
* join to the intersection table.
|
||||
@@ -137,7 +132,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
private List<Object> partialIds;
|
||||
|
||||
private int timeout = -1;
|
||||
private int timeout;
|
||||
|
||||
/**
|
||||
* The property used to get the key value for a Map.
|
||||
@@ -194,7 +189,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
/**
|
||||
* Root table alias. For {@link Query#alias(String)} command.
|
||||
*/
|
||||
private String rootTableAlias=null;
|
||||
private String rootTableAlias;
|
||||
|
||||
/**
|
||||
* The node of the bean or collection that fired lazy loading. Not null if profiling is on and
|
||||
@@ -205,8 +200,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
private BeanPropertyAssocMany<?> lazyLoadForParentsProperty;
|
||||
|
||||
private List<Object> lazyLoadForParentsIds;
|
||||
|
||||
/**
|
||||
* Hash of final query after AutoFetch tuning.
|
||||
*/
|
||||
@@ -313,10 +306,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
this.lazyLoadProperty = lazyLoadProperty;
|
||||
}
|
||||
|
||||
public String getLazyLoadManyPath() {
|
||||
return lazyLoadManyPath;
|
||||
}
|
||||
|
||||
public ExpressionFactory getExpressionFactory() {
|
||||
return expressionFactory;
|
||||
}
|
||||
@@ -389,11 +378,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
select(beanDescriptor.getIdBinder().getIdProperty());
|
||||
}
|
||||
|
||||
public void convertWhereNaturalKeyToId(Object idValue) {
|
||||
whereExpressions = new DefaultExpressionList<T>(this, null);
|
||||
setId(idValue);
|
||||
}
|
||||
|
||||
public NaturalKeyBindParam getNaturalKeyBindParam() {
|
||||
NaturalKeyBindParam namedBind = null;
|
||||
if (bindParams != null) {
|
||||
@@ -426,6 +410,10 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
}
|
||||
|
||||
public DefaultOrmQuery<T> copy() {
|
||||
return copy(server);
|
||||
}
|
||||
|
||||
public DefaultOrmQuery<T> copy(EbeanServer server) {
|
||||
// Not including these in the copy:
|
||||
// contextAdditions
|
||||
// queryListener
|
||||
@@ -535,16 +523,10 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLazyLoadForParents(List<Object> parentIds, BeanPropertyAssocMany<?> many) {
|
||||
this.lazyLoadForParentsIds = parentIds;
|
||||
public void setLazyLoadForParents(BeanPropertyAssocMany<?> many) {
|
||||
this.lazyLoadForParentsProperty = many;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> getLazyLoadForParentIds() {
|
||||
return lazyLoadForParentsIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanPropertyAssocMany<?> getLazyLoadForParentsProperty() {
|
||||
return lazyLoadForParentsProperty;
|
||||
@@ -753,8 +735,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
hc = hc * 31 + (whereExpressions == null ? 0 : whereExpressions.queryBindHash());
|
||||
hc = hc * 31 + (havingExpressions == null ? 0 : havingExpressions.queryBindHash());
|
||||
hc = hc * 31 + (bindParams == null ? 0 : bindParams.queryBindHash());
|
||||
hc = hc * 31 + (contextAdditions == null ? 0 : contextAdditions.hashCode());
|
||||
|
||||
return hc;
|
||||
}
|
||||
|
||||
@@ -917,10 +897,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return server.findRowCount(this, null);
|
||||
}
|
||||
|
||||
public void findVisit(QueryResultVisitor<T> visitor) {
|
||||
server.findVisit(this, visitor, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findEachWhile(QueryEachWhileConsumer<T> consumer) {
|
||||
server.findEachWhile(this, consumer, null);
|
||||
@@ -1096,26 +1072,6 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return detail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any beans that should be added to the persistence context prior to executing the query.
|
||||
*/
|
||||
public final ArrayList<EntityBean> getContextAdditions() {
|
||||
return contextAdditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a bean to the context additions.
|
||||
* <p>
|
||||
* These are added to the persistence context before executing the query.
|
||||
* </p>
|
||||
*/
|
||||
public void contextAdd(EntityBean bean) {
|
||||
if (contextAdditions == null) {
|
||||
contextAdditions = new ArrayList<EntityBean>();
|
||||
}
|
||||
contextAdditions.add(bean);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Query [" + whereExpressions + "]";
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.text.json;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.config.JsonConfig;
|
||||
import com.avaje.ebean.text.json.*;
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
@@ -24,9 +25,15 @@ public class DJsonContext implements JsonContext {
|
||||
|
||||
private final JsonFactory jsonFactory;
|
||||
|
||||
private final Object defaultObjectMapper;
|
||||
|
||||
private final JsonConfig.Include defaultInclude;
|
||||
|
||||
public DJsonContext(SpiEbeanServer server, JsonFactory jsonFactory) {
|
||||
this.server = server;
|
||||
this.jsonFactory = (jsonFactory != null) ? jsonFactory : new JsonFactory();
|
||||
this.defaultObjectMapper = this.server.getServerConfig().getObjectMapper();
|
||||
this.defaultInclude = this.server.getServerConfig().getJsonInclude();
|
||||
}
|
||||
|
||||
public boolean isSupportedType(Type genericType) {
|
||||
@@ -72,7 +79,7 @@ public class DJsonContext implements JsonContext {
|
||||
|
||||
public <T> T toBean(Class<T> cls, JsonParser parser, JsonReadOptions options) throws JsonIOException {
|
||||
|
||||
ReadJson readJson = new ReadJson(parser, options);
|
||||
ReadJson readJson = new ReadJson(parser, options, determineObjectMapper(options));
|
||||
try {
|
||||
BeanDescriptor<T> d = getDescriptor(cls);
|
||||
return d.jsonRead(readJson, null);
|
||||
@@ -104,7 +111,7 @@ public class DJsonContext implements JsonContext {
|
||||
|
||||
public <T> List<T> toList(Class<T> cls, JsonParser src, JsonReadOptions options) throws JsonIOException {
|
||||
|
||||
ReadJson readJson = new ReadJson(src, options);
|
||||
ReadJson readJson = new ReadJson(src, options, determineObjectMapper(options));
|
||||
try {
|
||||
BeanDescriptor<T> d = getDescriptor(cls);
|
||||
|
||||
@@ -271,7 +278,7 @@ public class DJsonContext implements JsonContext {
|
||||
|
||||
private WriteJson createWriteJson(JsonGenerator gen, JsonWriteOptions options) {
|
||||
PathProperties pathProps = (options == null) ? null : options.getPathProperties();
|
||||
return new WriteJson(server, gen, pathProps);
|
||||
return new WriteJson(server, gen, pathProps, determineObjectMapper(options), determineInclude(options));
|
||||
}
|
||||
|
||||
private <T> void toJsonFromCollection(Collection<T> collection, String key, JsonGenerator gen, JsonWriteOptions options) throws IOException {
|
||||
@@ -320,11 +327,47 @@ public class DJsonContext implements JsonContext {
|
||||
gen.writeEndObject();
|
||||
}
|
||||
|
||||
private <T> BeanDescriptor<T> getDescriptor(Class<T> cls) {
|
||||
BeanDescriptor<T> d = server.getBeanDescriptor(cls);
|
||||
/**
|
||||
* Return the BeanDescriptor for the given bean type.
|
||||
*/
|
||||
private <T> BeanDescriptor<T> getDescriptor(Class<T> beanType) {
|
||||
BeanDescriptor<T> d = server.getBeanDescriptor(beanType);
|
||||
if (d == null) {
|
||||
throw new RuntimeException("No BeanDescriptor found for " + cls);
|
||||
throw new RuntimeException("No BeanDescriptor found for " + beanType);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the object mapper to use for a JSON read request.
|
||||
*/
|
||||
private Object determineObjectMapper(JsonReadOptions options) {
|
||||
if (options == null) {
|
||||
return defaultObjectMapper;
|
||||
}
|
||||
Object mapper = options.getObjectMapper();
|
||||
return (mapper != null) ? mapper : defaultObjectMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the object mapper to use for a JSON write request.
|
||||
*/
|
||||
private Object determineObjectMapper(JsonWriteOptions options) {
|
||||
if (options == null) {
|
||||
return defaultObjectMapper;
|
||||
}
|
||||
Object mapper = options.getObjectMapper();
|
||||
return (mapper != null) ? mapper : defaultObjectMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the include mode to use for a JSON write request.
|
||||
*/
|
||||
private JsonConfig.Include determineInclude(JsonWriteOptions options) {
|
||||
if (options == null) {
|
||||
return defaultInclude;
|
||||
}
|
||||
JsonConfig.Include include = options.getInclude();
|
||||
return (include != null) ? include : defaultInclude;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.avaje.ebean.text.json.JsonReadBeanVisitor;
|
||||
import com.avaje.ebean.text.json.JsonReadOptions;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
@@ -28,17 +29,33 @@ public class ReadJson {
|
||||
*/
|
||||
final Map<String, JsonReadBeanVisitor<?>> visitorMap;
|
||||
|
||||
final Object objectMapper;
|
||||
|
||||
/**
|
||||
* Construct with parser and readOptions.
|
||||
*/
|
||||
public ReadJson(JsonParser parser, JsonReadOptions readOptions) {
|
||||
public ReadJson(JsonParser parser, JsonReadOptions readOptions, Object objectMapper) {
|
||||
|
||||
this.parser = parser;
|
||||
this.objectMapper = objectMapper;
|
||||
|
||||
// only create visitorMap, pathStack if needed ...
|
||||
this.visitorMap = (readOptions == null) ? null : readOptions.getVisitorMap();
|
||||
this.pathStack = (visitorMap == null) ? null : new PathStack();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the objectMapper used for this request.
|
||||
*/
|
||||
public ObjectMapper getObjectMapper() {
|
||||
if (objectMapper == null) {
|
||||
throw new IllegalStateException(
|
||||
"Jackson ObjectMapper required but has not set. The ObjectMapper can be set on"
|
||||
+" either the ServerConfig or on JsonReadOptions.");
|
||||
}
|
||||
return (ObjectMapper)objectMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JsonParser.
|
||||
*/
|
||||
@@ -84,4 +101,13 @@ public class ReadJson {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the property value using Jackson ObjectMapper.
|
||||
* <p/>
|
||||
* Typically this is used to read Transient properties where the type is unknown to Ebean.
|
||||
*/
|
||||
public Object readValueUsingObjectMapper(Class<?> propertyType) throws IOException {
|
||||
return getObjectMapper().readValue(parser, propertyType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
package com.avaje.ebeaninternal.server.text.json;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.config.JsonConfig;
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.type.JsonWriter;
|
||||
import com.avaje.ebeaninternal.server.util.ArrayStack;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class WriteJson {
|
||||
public class WriteJson implements JsonWriter {
|
||||
|
||||
private final SpiEbeanServer server;
|
||||
|
||||
@@ -24,16 +30,107 @@ public class WriteJson {
|
||||
|
||||
private final ArrayStack<Object> parentBeans = new ArrayStack<Object>();
|
||||
|
||||
public WriteJson(SpiEbeanServer server, JsonGenerator generator, PathProperties pathProperties){
|
||||
private final Object objectMapper;
|
||||
|
||||
private final JsonConfig.Include include;
|
||||
|
||||
public WriteJson(SpiEbeanServer server, JsonGenerator generator, PathProperties pathProperties, Object objectMapper, JsonConfig.Include include){
|
||||
this.server = server;
|
||||
this.generator = generator;
|
||||
this.pathProperties = pathProperties;
|
||||
this.objectMapper = objectMapper;
|
||||
this.include = include;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for testing purposes only.
|
||||
*/
|
||||
public WriteJson(JsonGenerator generator, JsonConfig.Include include) {
|
||||
this(null, generator, null, null, include);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if null values should be included in JSON output.
|
||||
*/
|
||||
public boolean isIncludeNull() {
|
||||
return include == JsonConfig.Include.ALL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if empty collections should be included in the JSON output.
|
||||
*/
|
||||
public boolean isIncludeEmpty() {
|
||||
return include != JsonConfig.Include.NON_EMPTY;
|
||||
}
|
||||
|
||||
public JsonGenerator gen() {
|
||||
return generator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeFieldName(String name) throws IOException {
|
||||
generator.writeFieldName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNullField(String name) throws IOException {
|
||||
if (isIncludeNull()) {
|
||||
generator.writeNullField(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNumberField(String name, Long value) throws IOException {
|
||||
generator.writeNumberField(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNumberField(String name, Double value) throws IOException {
|
||||
generator.writeNumberField(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNumberField(String name, int value) throws IOException {
|
||||
generator.writeNumberField(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNumberField(String name, Short value) throws IOException {
|
||||
generator.writeNumberField(name, value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void writeNumberField(String name, Float value) throws IOException {
|
||||
generator.writeNumberField(name, value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void writeNumberField(String name, BigDecimal value) throws IOException {
|
||||
generator.writeNumberField(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeStringField(String name, String value) throws IOException {
|
||||
generator.writeStringField(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBinary(InputStream is, int length) throws IOException {
|
||||
generator.writeBinary(is, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBinaryField(String name, byte[] value) throws IOException {
|
||||
generator.writeBinaryField(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeBooleanField(String name, Boolean value) throws IOException {
|
||||
generator.writeBooleanField(name, value);
|
||||
}
|
||||
|
||||
public boolean isParentBean(Object bean) {
|
||||
return !parentBeans.isEmpty() && parentBeans.contains(bean);
|
||||
}
|
||||
@@ -73,6 +170,31 @@ public class WriteJson {
|
||||
return new WriteBean(desc, explicitAllProps, currentIncludeProps, bean);
|
||||
}
|
||||
|
||||
public void writeValueUsingObjectMapper(String name, Object value) throws IOException {
|
||||
|
||||
if (!isIncludeEmpty()) {
|
||||
// check for suppression of empty collection or map
|
||||
if (value instanceof Collection && ((Collection)value).isEmpty()) {
|
||||
// suppress empty collection
|
||||
return;
|
||||
} else if (value instanceof Map && ((Map)value).isEmpty()) {
|
||||
// suppress empty map
|
||||
return;
|
||||
}
|
||||
}
|
||||
generator.writeFieldName(name);
|
||||
objectMapper().writeValue(generator, value);
|
||||
}
|
||||
|
||||
private ObjectMapper objectMapper() {
|
||||
if (objectMapper == null) {
|
||||
throw new IllegalStateException(
|
||||
"Jackson ObjectMapper required but not set. Expected to be set on either"
|
||||
+" serverConfig");
|
||||
}
|
||||
return (ObjectMapper)objectMapper;
|
||||
}
|
||||
|
||||
public static class WriteBean {
|
||||
|
||||
final boolean explicitAllProps;
|
||||
@@ -197,10 +319,6 @@ public class WriteJson {
|
||||
}
|
||||
generator.writeStartObject();
|
||||
}
|
||||
|
||||
public void writeNull(String name) throws IOException {
|
||||
generator.writeNullField(name);
|
||||
}
|
||||
|
||||
public void writeEndObject() throws IOException {
|
||||
generator.writeEndObject();
|
||||
|
||||
@@ -115,7 +115,7 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
/**
|
||||
* Set to true if the connection has autoCommit=true initially.
|
||||
*/
|
||||
protected final boolean autoCommit;
|
||||
protected boolean autoCommit;
|
||||
|
||||
protected IdentityHashMap<Object, Object> persistingBeans;
|
||||
|
||||
@@ -146,11 +146,13 @@ public class JdbcTransaction implements SpiTransaction {
|
||||
this.batchOnCascadeMode = manager == null ? PersistBatch.NONE : manager.getPersistBatchOnCascade();
|
||||
this.onQueryOnly = manager == null ? OnQueryOnly.ROLLBACK : manager.getOnQueryOnly();
|
||||
this.persistenceContext = new DefaultPersistenceContext();
|
||||
this.autoCommit = connection.getAutoCommit();
|
||||
if (this.autoCommit) {
|
||||
connection.setAutoCommit(false);
|
||||
|
||||
if (connection != null) {
|
||||
this.autoCommit = connection.getAutoCommit();
|
||||
if (this.autoCommit) {
|
||||
connection.setAutoCommit(false);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ public final class CtCompoundType<V> implements ScalarDataReader<V> {
|
||||
((CtCompoundType) propReaders[i]).jsonWrite(ctx, value, propName);
|
||||
|
||||
} else {
|
||||
((ScalarType) propReaders[i]).jsonWrite(ctx.gen(), propName, value);
|
||||
((ScalarType) propReaders[i]).jsonWrite(ctx, propName, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
this.typeMap = new ConcurrentHashMap<Class<?>, ScalarType<?>>();
|
||||
this.nativeMap = new ConcurrentHashMap<Integer, ScalarType<?>>();
|
||||
|
||||
this.objectMapperPresent = ClassUtil.isPresent("com.fasterxml.jackson.databind.ObjectMapper", this.getClass());
|
||||
this.objectMapperPresent = ClassUtil.isJacksonObjectMapperPresent();
|
||||
|
||||
this.extraTypeFactory = new DefaultTypeFactory(config);
|
||||
|
||||
@@ -384,7 +384,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
return (ScalarType<T>) extraTypeFactory.createCalendar(jsonDateTime, jdbcType);
|
||||
}
|
||||
|
||||
throw new RuntimeException("Unmatched ScalarType for " + type + " jdbcType:" + jdbcType);
|
||||
throw new IllegalArgumentException("Unmatched ScalarType for " + type + " jdbcType:" + jdbcType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* Wraps an underlying JsonGenerator taking into account null suppression and exposing isIncludeEmpty() etc.
|
||||
*/
|
||||
public interface JsonWriter {
|
||||
|
||||
/**
|
||||
* Return the Jackson core JsonGenerator.
|
||||
*/
|
||||
JsonGenerator gen();
|
||||
|
||||
/**
|
||||
* Return true if null values should be included in JSON output.
|
||||
*/
|
||||
boolean isIncludeNull();
|
||||
|
||||
/**
|
||||
* Return true if empty collections should be included in the JSON output.
|
||||
*/
|
||||
boolean isIncludeEmpty();
|
||||
|
||||
/**
|
||||
* Write the field name.
|
||||
*/
|
||||
void writeFieldName(String name) throws IOException;
|
||||
|
||||
/**
|
||||
* Write a null value taking into account null value suppression.
|
||||
*/
|
||||
void writeNullField(String name) throws IOException;
|
||||
|
||||
/**
|
||||
* Write a number field.
|
||||
*/
|
||||
void writeNumberField(String name, int value) throws IOException;
|
||||
|
||||
/**
|
||||
* Write a number field.
|
||||
*/
|
||||
void writeNumberField(String name, Short value) throws IOException;
|
||||
|
||||
/**
|
||||
* Write a number field.
|
||||
*/
|
||||
void writeNumberField(String name, Long value) throws IOException;
|
||||
|
||||
/**
|
||||
* Write a number field.
|
||||
*/
|
||||
void writeNumberField(String name, Double value) throws IOException;
|
||||
|
||||
/**
|
||||
* Write a number field.
|
||||
*/
|
||||
void writeNumberField(String name, Float value) throws IOException;
|
||||
|
||||
/**
|
||||
* Write a number field.
|
||||
*/
|
||||
void writeNumberField(String name, BigDecimal value) throws IOException;
|
||||
|
||||
/**
|
||||
* Write a sting field.
|
||||
*/
|
||||
void writeStringField(String name, String value) throws IOException;
|
||||
|
||||
/**
|
||||
* Write a binary field.
|
||||
*/
|
||||
void writeBinary(InputStream is, int length) throws IOException;
|
||||
|
||||
/**
|
||||
* Write a binary field.
|
||||
*/
|
||||
void writeBinaryField(String name, byte[] value) throws IOException;
|
||||
|
||||
/**
|
||||
* Write a boolean field.
|
||||
*/
|
||||
void writeBooleanField(String name, Boolean value) throws IOException;
|
||||
}
|
||||
@@ -197,11 +197,11 @@ public interface ScalarType<T> extends StringParser, StringFormatter, ScalarData
|
||||
/**
|
||||
* Read the value from JsonParser.
|
||||
*/
|
||||
T jsonRead(JsonParser ctx, JsonToken event) throws IOException;
|
||||
T jsonRead(JsonParser parser, JsonToken event) throws IOException;
|
||||
|
||||
/**
|
||||
* Write the value to the JsonGenerator.
|
||||
*/
|
||||
void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException;
|
||||
void jsonWrite(JsonWriter writer, String name, T value) throws IOException;
|
||||
|
||||
}
|
||||
|
||||
@@ -69,17 +69,17 @@ public abstract class ScalarTypeBaseDate<T> extends ScalarTypeBase<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
public T jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
if (JsonToken.VALUE_NUMBER_INT == event) {
|
||||
return convertFromMillis(ctx.getLongValue());
|
||||
return convertFromMillis(parser.getLongValue());
|
||||
} else {
|
||||
return convertFromDate(Date.valueOf(ctx.getText()));
|
||||
return convertFromDate(Date.valueOf(parser.getText()));
|
||||
}
|
||||
}
|
||||
|
||||
public void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException {
|
||||
public void jsonWrite(JsonWriter writer, String name, T value) throws IOException {
|
||||
long millis = convertToMillis(value);
|
||||
ctx.writeNumberField(name, millis);
|
||||
writer.writeNumberField(name, millis);
|
||||
}
|
||||
|
||||
public T readData(DataInput dataInput) throws IOException {
|
||||
|
||||
@@ -84,40 +84,40 @@ public abstract class ScalarTypeBaseDateTime<T> extends ScalarTypeBase<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
public T jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
|
||||
switch (event) {
|
||||
case VALUE_NUMBER_INT: {
|
||||
return convertFromMillis(ctx.getLongValue());
|
||||
return convertFromMillis(parser.getLongValue());
|
||||
}
|
||||
case VALUE_NUMBER_FLOAT: {
|
||||
BigDecimal value = ctx.getDecimalValue();
|
||||
BigDecimal value = parser.getDecimalValue();
|
||||
Timestamp timestamp = DecimalUtils.toTimestamp(value);
|
||||
return convertFromTimestamp(timestamp);
|
||||
}
|
||||
default: {
|
||||
String jsonDateTime = ctx.getText();
|
||||
String jsonDateTime = parser.getText();
|
||||
return convertFromTimestamp(dateTimeParser.parse(jsonDateTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator generator, String name, T value) throws IOException {
|
||||
public void jsonWrite(JsonWriter writer, String name, T value) throws IOException {
|
||||
|
||||
switch (mode) {
|
||||
case ISO8601: {
|
||||
generator.writeFieldName(name);
|
||||
generator.writeString(toJsonISO8601(value));
|
||||
writer.writeFieldName(name);
|
||||
writer.gen().writeString(toJsonISO8601(value));
|
||||
break;
|
||||
}
|
||||
case NANOS: {
|
||||
generator.writeFieldName(name);
|
||||
generator.writeNumber(toJsonNanos(value));
|
||||
writer.writeFieldName(name);
|
||||
writer.gen().writeNumber(toJsonNanos(value));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
generator.writeNumberField(name, convertToMillis(value));
|
||||
writer.gen().writeNumberField(name, convertToMillis(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,12 +123,12 @@ public abstract class ScalarTypeBaseVarchar<T> extends ScalarTypeBase<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
return parse(ctx.getValueAsString());
|
||||
public T jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
return parse(parser.getValueAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException {
|
||||
ctx.writeStringField(name, format(value));
|
||||
public void jsonWrite(JsonWriter writer, String name, T value) throws IOException {
|
||||
writer.writeStringField(name, format(value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
@@ -7,11 +11,6 @@ import java.math.BigDecimal;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
/**
|
||||
* ScalarType for BigDecimal.
|
||||
*/
|
||||
@@ -78,12 +77,13 @@ public class ScalarTypeBigDecimal extends ScalarTypeBase<BigDecimal> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
return ctx.getDecimalValue();
|
||||
public BigDecimal jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
return parser.getDecimalValue();
|
||||
}
|
||||
|
||||
public void jsonWrite(JsonGenerator ctx, String name, BigDecimal value) throws IOException {
|
||||
ctx.writeNumberField(name, value);
|
||||
@Override
|
||||
public void jsonWrite(JsonWriter writer, String name, BigDecimal value) throws IOException {
|
||||
writer.writeNumberField(name, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -280,12 +280,13 @@ public class ScalarTypeBoolean {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean jsonRead(JsonParser ctx, JsonToken event) {
|
||||
public Boolean jsonRead(JsonParser parser, JsonToken event) {
|
||||
return JsonToken.VALUE_TRUE == event ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
public void jsonWrite(JsonGenerator ctx, String name, Boolean value) throws IOException {
|
||||
ctx.writeBooleanField(name, value);
|
||||
@Override
|
||||
public void jsonWrite(JsonWriter writer, String name, Boolean value) throws IOException {
|
||||
writer.writeBooleanField(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,12 +42,12 @@ public class ScalarTypeByte extends ScalarTypeBase<Byte> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, Byte value) throws IOException {
|
||||
public void jsonWrite(JsonWriter writer, String name, Byte value) throws IOException {
|
||||
throw new IOException("Not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Byte jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
public Byte jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
throw new IOException("Not supported");
|
||||
}
|
||||
|
||||
|
||||
@@ -41,14 +41,14 @@ public abstract class ScalarTypeBytesBase extends ScalarTypeBase<byte[]> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, byte[] value) throws IOException {
|
||||
ctx.writeBinaryField(name, value);
|
||||
public void jsonWrite(JsonWriter writer, String name, byte[] value) throws IOException {
|
||||
writer.writeBinaryField(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
public byte[] jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(500);
|
||||
ctx.readBinaryValue(out);
|
||||
parser.readBinaryValue(out);
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
@@ -64,14 +64,14 @@ public class ScalarTypeBytesEncrypted implements ScalarType<byte[]> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, byte[] value) throws IOException {
|
||||
ctx.writeBinaryField(name, value);
|
||||
public void jsonWrite(JsonWriter writer, String name, byte[] value) throws IOException {
|
||||
writer.writeBinaryField(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
public byte[] jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(500);
|
||||
ctx.readBinaryValue(out);
|
||||
parser.readBinaryValue(out);
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
@@ -64,8 +64,8 @@ public class ScalarTypeCharArray extends ScalarTypeBaseVarchar<char[]> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
return ctx.getValueAsString().toCharArray();
|
||||
public char[] jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
return parser.getValueAsString().toCharArray();
|
||||
}
|
||||
|
||||
public void jsonWrite(JsonGenerator ctx, String name, char[] value) throws IOException {
|
||||
|
||||
@@ -85,12 +85,12 @@ public class ScalarTypeDouble extends ScalarTypeBase<Double> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
return ctx.getDoubleValue();
|
||||
public Double jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
return parser.getDoubleValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, Double value) throws IOException {
|
||||
ctx.writeNumberField(name, value);
|
||||
public void jsonWrite(JsonWriter writer, String name, Double value) throws IOException {
|
||||
writer.writeNumberField(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,12 +102,12 @@ public class ScalarTypeDuration extends ScalarTypeBase<Duration> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
return Duration.parse(ctx.getValueAsString());
|
||||
public Duration jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
return Duration.parse(parser.getValueAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, Duration value) throws IOException {
|
||||
ctx.writeStringField(name, value.toString());
|
||||
public void jsonWrite(JsonWriter writer, String name, Duration value) throws IOException {
|
||||
writer.writeStringField(name, value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,12 +133,12 @@ public class ScalarTypeEncryptedWrapper<T> implements ScalarType<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
return wrapped.jsonRead(ctx, event);
|
||||
public T jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
return wrapped.jsonRead(parser, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, T value) throws IOException {
|
||||
wrapped.jsonWrite(ctx, name, value);
|
||||
public void jsonWrite(JsonWriter writer, String name, T value) throws IOException {
|
||||
wrapped.jsonWrite(writer, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public class ScalarTypeEnumStandard {
|
||||
Object[] ea = enumType.getEnumConstants();
|
||||
for (int i = 0; i < ea.length; i++) {
|
||||
Enum<?> e = (Enum<?>) ea[i];
|
||||
maxLen = Math.max(maxLen, e.toString().length());
|
||||
maxLen = Math.max(maxLen, e.name().length());
|
||||
}
|
||||
|
||||
return maxLen;
|
||||
@@ -232,13 +232,13 @@ public class ScalarTypeEnumStandard {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
return parse(ctx.getValueAsString());
|
||||
public Object jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
return parse(parser.getValueAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, Object value) throws IOException {
|
||||
ctx.writeStringField(name, formatValue(value));
|
||||
public void jsonWrite(JsonWriter writer, String name, Object value) throws IOException {
|
||||
writer.writeStringField(name, formatValue(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -102,17 +102,17 @@ public class ScalarTypeFile extends ScalarTypeBase<File> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, File value) throws IOException {
|
||||
ctx.writeFieldName(name);
|
||||
public void jsonWrite(JsonWriter writer, String name, File value) throws IOException {
|
||||
writer.writeFieldName(name);
|
||||
InputStream is = getInputStream(value);
|
||||
ctx.writeBinary(is, (int) value.length());
|
||||
writer.writeBinary(is, (int) value.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public File jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
public File jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
File tempFile = File.createTempFile(prefix, suffix, directory);
|
||||
OutputStream os = getOutputStream(tempFile);
|
||||
ctx.readBinaryValue(os);
|
||||
parser.readBinaryValue(os);
|
||||
os.flush();
|
||||
os.close();
|
||||
return tempFile;
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
/**
|
||||
* ScalarType for Float and float.
|
||||
*/
|
||||
@@ -85,12 +84,12 @@ public class ScalarTypeFloat extends ScalarTypeBase<Float> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
return ctx.getFloatValue();
|
||||
public Float jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
return parser.getFloatValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, Float value) throws IOException {
|
||||
ctx.writeNumberField(name, value);
|
||||
public void jsonWrite(JsonWriter writer, String name, Float value) throws IOException {
|
||||
writer.writeNumberField(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,12 +85,12 @@ public class ScalarTypeInteger extends ScalarTypeBase<Integer> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
return ctx.getIntValue();
|
||||
public Integer jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
return parser.getIntValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, Integer value) throws IOException {
|
||||
ctx.writeNumberField(name, value);
|
||||
public void jsonWrite(JsonWriter writer, String name, Integer value) throws IOException {
|
||||
writer.writeNumberField(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,17 +72,17 @@ public class ScalarTypeJodaLocalTime extends ScalarTypeBase<LocalTime> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, LocalTime value) throws IOException {
|
||||
ctx.writeStringField(name, value.toString());
|
||||
public void jsonWrite(JsonWriter writer, String name, LocalTime value) throws IOException {
|
||||
writer.writeStringField(name, value.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTime jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
public LocalTime jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
if (JsonToken.VALUE_NUMBER_INT == event) {
|
||||
long millis = ctx.getLongValue();
|
||||
long millis = parser.getLongValue();
|
||||
return convertFromMillis(millis);
|
||||
} else {
|
||||
String string = ctx.getValueAsString();
|
||||
String string = parser.getValueAsString();
|
||||
throw new RuntimeException("convert " + string);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,22 +193,24 @@ public abstract class ScalarTypeJsonMap extends ScalarTypeBase<Map> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, Map value) throws IOException {
|
||||
public void jsonWrite(JsonWriter writer, String name, Map value) throws IOException {
|
||||
// write the field name followed by the Map/JSON Object
|
||||
if (value == null) {
|
||||
ctx.writeNullField(name);
|
||||
writer.writeNullField(name);
|
||||
} else {
|
||||
ctx.writeFieldName(name);
|
||||
EJson.write(value, ctx);
|
||||
if (!value.isEmpty() || writer.isIncludeEmpty()) {
|
||||
writer.writeFieldName(name);
|
||||
EJson.write(value, writer.gen());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
public Map jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
// at this point the BeanProperty has read the START_OBJECT token
|
||||
// to check for a null value. Pass the START_OBJECT token through to
|
||||
// the EJson parsing so that it knows the first token has been read
|
||||
return EJson.parseObject(ctx, event);
|
||||
return EJson.parseObject(parser, event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -207,21 +207,21 @@ public abstract class ScalarTypeJsonNode extends ScalarTypeBase<JsonNode> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, JsonNode value) throws IOException {
|
||||
public void jsonWrite(JsonWriter writer, String name, JsonNode value) throws IOException {
|
||||
// write the field name followed by the JsonNode object
|
||||
if (value == null) {
|
||||
ctx.writeNullField(name);
|
||||
writer.writeNullField(name);
|
||||
} else {
|
||||
ctx.writeFieldName(name);
|
||||
objectMapper.writeTree(ctx, value);
|
||||
writer.writeFieldName(name);
|
||||
objectMapper.writeTree(writer.gen(), value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonNode jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
public JsonNode jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
// at this point the BeanProperty has read the START_OBJECT token
|
||||
// to check for a null value.
|
||||
return objectMapper.readValue(ctx, JsonNode.class);
|
||||
return objectMapper.readValue(parser, JsonNode.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -94,12 +94,12 @@ public class ScalarTypeLocalTime extends ScalarTypeBase<LocalTime> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTime jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
return LocalTime.parse(ctx.getValueAsString());
|
||||
public LocalTime jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
return LocalTime.parse(parser.getValueAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, LocalTime value) throws IOException {
|
||||
ctx.writeStringField(name, value.toString());
|
||||
public void jsonWrite(JsonWriter writer, String name, LocalTime value) throws IOException {
|
||||
writer.writeStringField(name, value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,12 +85,12 @@ public class ScalarTypeLong extends ScalarTypeBase<Long> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
return ctx.getLongValue();
|
||||
public Long jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
return parser.getLongValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, Long value) throws IOException {
|
||||
ctx.writeNumberField(name, value);
|
||||
public void jsonWrite(JsonWriter writer, String name, Long value) throws IOException {
|
||||
writer.writeNumberField(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,13 +92,13 @@ public class ScalarTypeMathBigInteger extends ScalarTypeBase<BigInteger> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
return ctx.getDecimalValue().toBigInteger();
|
||||
public BigInteger jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
return parser.getDecimalValue().toBigInteger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, BigInteger value) throws IOException {
|
||||
ctx.writeNumberField(name, value.longValue());
|
||||
public void jsonWrite(JsonWriter writer, String name, BigInteger value) throws IOException {
|
||||
writer.writeNumberField(name, value.longValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -119,13 +119,13 @@ public class ScalarTypeMonthDay extends ScalarTypeBase<MonthDay> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonthDay jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
return parse(ctx.getValueAsString());
|
||||
public MonthDay jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
return parse(parser.getValueAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, MonthDay value) throws IOException {
|
||||
ctx.writeStringField(name, format(value));
|
||||
public void jsonWrite(JsonWriter writer, String name, MonthDay value) throws IOException {
|
||||
writer.writeStringField(name, format(value));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -112,22 +112,22 @@ public class ScalarTypePostgresHstore extends ScalarTypeBase<Map> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, Map value) throws IOException {
|
||||
public void jsonWrite(JsonWriter writer, String name, Map value) throws IOException {
|
||||
// write the field name followed by the Map/JSON Object
|
||||
if (value == null) {
|
||||
ctx.writeNullField(name);
|
||||
writer.writeNullField(name);
|
||||
} else {
|
||||
ctx.writeFieldName(name);
|
||||
EJson.write(value, ctx);
|
||||
writer.writeFieldName(name);
|
||||
EJson.write(value, writer.gen());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
public Map jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
// at this point the BeanProperty has read the START_OBJECT token
|
||||
// to check for a null value. Pass the START_OBJECT token through to
|
||||
// the EJson parsing so that it knows the first token has been read
|
||||
return EJson.parseObject(ctx, event);
|
||||
return EJson.parseObject(parser, event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -86,12 +86,12 @@ public class ScalarTypeShort extends ScalarTypeBase<Short> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Short jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
return ctx.getShortValue();
|
||||
public Short jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
return parser.getShortValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, Short value) throws IOException {
|
||||
ctx.writeNumberField(name, value);
|
||||
public void jsonWrite(JsonWriter writer, String name, Short value) throws IOException {
|
||||
writer.writeNumberField(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,12 +85,12 @@ public class ScalarTypeString extends ScalarTypeBase<String> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
return ctx.getValueAsString();
|
||||
public String jsonRead(JsonParser parser, JsonToken event) throws IOException {
|
||||
return parser.getValueAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, String value) throws IOException {
|
||||
ctx.writeStringField(name, value);
|
||||
public void jsonWrite(JsonWriter writer, String name, String value) throws IOException {
|
||||
writer.writeStringField(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user