Compare commits

..
Author SHA1 Message Date
Robin Bygrave b4c7cf529d [maven-release-plugin] prepare release avaje-ebeanorm-6.1.1 2015-07-20 20:08:42 +12:00
Robin Bygrave ba5c67f936 #346 - ENH: Add @Nullable annotation on find by id and findUnique() methods 2015-07-20 20:06:55 +12:00
Robin Bygrave 2bd7995ca1 Bump pom to 6.1.1-SNAPSHOT 2015-07-20 12:55:33 +12:00
Robin Bygrave cc8c860709 Internal DefaultOrmQuery cleanup : timeout can default to 0 (rather than -1) 2015-07-20 12:51:24 +12:00
Robin Bygrave 7d25e31289 No effective change - unused imports 2015-07-20 12:48:08 +12:00
Robin Bygrave 936e56835c Internal SpiQuery : remove unused lazyLoadForParentsIds 2015-07-20 12:47:09 +12:00
Robin Bygrave 0d848e9311 Internal SpiQuery : remove unused context additions 2015-07-20 12:44:26 +12:00
Robin Bygrave b794b6c77e Internal SpiQuery : remove unused convertWhereNaturalKeyToId() 2015-07-20 12:40:08 +12:00
Robin Bygrave f45d240682 #345 - Expose Query.getId() and Query.getBeanType() methods ... (previously on SpiQuery) 2015-07-20 12:24:56 +12:00
Robin Bygrave 1a6f68edd3 No effective change - javadoc 2015-07-20 11:55:24 +12:00
Robin Bygrave 81683c5d2a No effective change - javadoc 2015-07-20 11:50:38 +12:00
Robin Bygrave 2b535d59b8 No effective change - javadoc 2015-07-20 11:41:23 +12:00
Robin Bygrave ae0bbaaaf8 #344 - Remove deprecated annotation @ColumnHstore ... migrate to @DbHstore 2015-07-20 11:38:40 +12:00
Robin Bygrave aaca20f9c3 #343 - Remove deprecated interface BeanFinder<T> ... migrate to BeanFindController 2015-07-20 11:34:05 +12:00
Robin Bygrave 245cbb0ea1 #342 - Remove deprecated method - JsonContext createJsonContext() ... migrate to json() 2015-07-20 11:27:00 +12:00
Robin Bygrave dbe984c668 #341 - Remove deprecated method - insert(Collection<?> beans); ... migrate to insertAll() 2015-07-20 11:22:16 +12:00
Robin Bygrave 89088f9480 #340 - Remove deprecated method - update(Collection<?> beans) ... migrate to updateAll() 2015-07-20 11:18:51 +12:00
Robin Bygrave 80253c4e07 #339 - Remove deprecated method - save(Collection<?> beans, Transaction transaction) ... migrate to saveAll() 2015-07-20 11:15:10 +12:00
Robin Bygrave f96ce11c73 #338 - Remove deprecated method - save(Iterator<?> it, Transaction transaction) ... please change to iterate yourself and save. 2015-07-20 11:11:45 +12:00
Robin Bygrave b8f8cb5ae7 #337 - Remove deprecated method - delete(Class<?> beanType, Collection<?> ids) ... migrate to deleteAll() 2015-07-20 11:07:52 +12:00
Robin Bygrave b8a2aac95a #336 - Remove deprecated method - delete(Iterator<?> it, Transaction transaction) 2015-07-20 10:59:52 +12:00
Robin Bygrave 7b090a6346 #335 - Remove deprecated method - delete(Collection<?> beans) ... migrate to deleteAll() 2015-07-20 10:54:18 +12:00
Robin Bygrave b10c68489f #334 - Remove deprecated method - delete(Iterator<?> it) ... change to iterate yourself and delete() 2015-07-20 10:47:51 +12:00
Robin Bygrave 2dbb2d9911 #333 - Remove deprecated method - save(Iterator<?> it) ... change to iterate yourself and save() 2015-07-20 10:43:37 +12:00
Robin Bygrave b3b4c72a77 #332 - Remove deprecated method - save(Collection<?> beans) ... migrate to saveAll(beans) 2015-07-20 10:39:15 +12:00
Robin Bygrave 1c040e4583 No effective change - code format 2015-07-20 10:24:10 +12:00
Robin Bygrave 9677e585b6 #331 - Remove deprecated method - EbeanServer.findVisit() ... in favor of findEachWhile() or findEach() 2015-07-20 10:22:50 +12:00
Robin Bygrave c53806224f [maven-release-plugin] prepare for next development iteration 2015-07-20 09:53:59 +12:00
Robin Bygrave 6fd5927c64 [maven-release-plugin] prepare release avaje-ebeanorm-5.1.1 2015-07-20 09:53:35 +12:00
Robin Bygrave 920635c6df #326 - API Addition - saveAll(), deleteAll() etc 2015-07-20 09:51:36 +12:00
Robin Bygrave fb1c29b57c Bump pom to 5.1.1-SNAPSHOT 2015-07-20 09:46:31 +12:00
Robin Bygrave 89bed8be67 #326 - API Addition - saveAll(), deleteAll() etc 2015-07-20 09:42:05 +12:00
Robin Bygrave 776e48a501 [maven-release-plugin] prepare for next development iteration 2015-07-20 09:06:01 +12:00
Robin Bygrave 0666a72df7 [maven-release-plugin] prepare release avaje-ebeanorm-4.9.1 2015-07-20 09:05:34 +12:00
Robin Bygrave 55000a3515 No effective change - rename parameter ctx -> parser 2015-07-20 09:01:54 +12:00
Robin Bygrave 8307e259ba bump pom to 4.9.1-SNAPSHOT 2015-07-20 08:50:54 +12:00
Robin Bygrave 95b7574d04 No effective change - format 2015-07-20 08:49:31 +12:00
Robin Bygrave f6466d3211 #280 - ENH: Add ServerConfig.setJsonInclude(...) ALL, NON_NULL, NON_EMPTY 2015-07-20 08:45:46 +12:00
Robin Bygrave 160e4d7dd1 #318 - JSON - toBean error at Transient (with support for #327, #328, #329) 2015-07-19 21:41:20 +12:00
Robin Bygrave a00980c61f #329 - JSON - Remove @Deprecated from JsonWriteOptions ... to support ObjectMapper which can be used for serialize/deserialize of @Transient properties 2015-07-19 21:38:27 +12:00
Robin Bygrave 72d2fcb59e #330 - JSON - Add ebean @JsonIgnore ... with serialize() default false and deserialize() default false 2015-07-19 21:37:37 +12:00
Robin Bygrave 0f503b2a2f No effective change - format code 2015-07-19 09:35:27 +12:00
Robin Bygrave a79e2e786a #324 - on effective change, sync internal name from primaryServer to defaultServer 2015-07-19 09:20:03 +12:00
Robin Bygrave c9ffa2673f #324 - ENH: Add Ebean.getDefaultServer() 2015-07-18 07:46:53 +12:00
Robin Bygrave 0e0fa37f0d #324 - ENH: Add Ebean.getDefaultServer() 2015-07-18 07:46:42 +12:00
Robin Bygrave f7bbd5b3bb No effective change - code format (fix variable names) 2015-07-18 07:35:19 +12:00
Robin Bygrave ba614cd287 No effective change - code format 2015-07-18 07:34:56 +12:00
Robin Bygrave 7d028f3318 [maven-release-plugin] prepare for next development iteration 2015-07-14 23:28:55 +12:00
Robin Bygrave 21b04c244b [maven-release-plugin] prepare release avaje-ebeanorm-4.8.1 2015-07-14 23:28:32 +12:00
Robin Bygrave 957c2def43 bump pom to 4.8.1-SNAPSHOT 2015-07-14 23:24:34 +12:00
Robin Bygrave 35f9cd3821 Bump pom to 4.8.1-SNAPSHOT 2015-07-14 23:18:51 +12:00
Robin Bygrave e95d3304bf #322 - RawSql fetch object with inheritance 2015-07-14 23:09:38 +12:00
rbygrave 0f7c9da5d2 #319 - Beans loaded without an @Id value ... return in NEW state rather than LOADED state (also refer to #317) 2015-07-09 22:18:03 +12:00
rbygrave b4008da70c #317 - RawSql getting error - Caused by: java.sql.SQLException: Column Index out of range, 0 < 1. 2015-07-09 21:44:45 +12:00
rbygrave 34a0f16c74 No effective change - bump mysql-connector-java test dependency version 2015-07-07 23:07:10 +12:00
Rob Bygrave a880109201 Merge pull request #316 from castovoid/master
Resolve NullPointerException on JtaTransacionManager constructor
2015-06-30 21:17:27 +12:00
Rob Bygrave 0607151ac8 Merge pull request #315 from ossd/patch-1
Update ScalarTypeEnumStandard.java
2015-06-30 21:15:47 +12:00
Leone Parise 5c4ad4c01c Resolve NullPointerException on JtaTransacionManager 2015-06-30 01:01:35 -03:00
ossd 3564504e00 Update ScalarTypeEnumStandard.java
Using toString() to calculate the Enum length is wrong. If you overwrite the Enum's toString() the length may be shorter. In this situation, the ddl script will create a to small varchar field for the value and you get an exception on save
2015-06-29 22:36:24 +02:00
rbygrave 49babef495 #314 - ServerCache API - change from int to long for ServerCacheStatistics (hitCount, missCount) and ServerCache remove putIfAbsent() method 2015-06-30 00:56:11 +12:00
rbygrave 9e3362d004 No effective change - tidy 2015-06-26 23:05:40 +12:00
Rob Bygrave 3f0dcdb6d1 Update README.md 2015-06-25 00:12:16 +12:00
rbygrave 481116251d [maven-release-plugin] prepare for next development iteration 2015-06-24 23:50:22 +12:00
149 changed files with 4830 additions and 4750 deletions
+1
View File
@@ -1,5 +1,6 @@
*.autofetch
*.sql
*.orig
.classpath
.project
.settings/
+6 -5
View File
@@ -1,9 +1,10 @@
[![Stories in Ready](https://badge.waffle.io/ebean-orm/avaje-ebeanorm.png?label=ready&title=Ready)](https://waffle.io/ebean-orm/avaje-ebeanorm)
* [![Maven Central : avaje-ebeanorm](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm) - avaje-ebeanorm
* [![Maven Central : avaje-ebeanorm-agent](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-agent) - avaje-ebeanorm-agent
* [![Maven Central : avaje-ebeanorm-agent](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebeanorm/avaje-ebeanorm-mavenenhancer/badge.svg)](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>
+8 -2
View File
@@ -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>
+96 -109
View File
@@ -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();
}
}
+34 -70
View File
@@ -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();
/**
+36 -36
View File
@@ -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&lt;Order&gt; list = Ebean.find(Order.class).fetch(&quot;details&quot;).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&lt;Order&gt; list =
* List<Order> list =
* Ebean.find(Order.class)
* .fetch(&quot;details&quot;, 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&lt;Order&gt; list =
* List<Order> list =
* Ebean.find(Order.class)
* .fetch(&quot;details&quot;, new FetchConfig().query())
* .fetch(&quot;customer&quot;, 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&lt;Order&gt; list =
* List<Order> list =
* Ebean.find(Order.class)
* .select(&quot;status, shipDate&quot;)
* .fetch(&quot;details&quot;, &quot;quantity, price&quot;, new FetchConfig().query())
* .fetch(&quot;details.product&quot;, &quot;sku, name&quot;)
* .fetch(&quot;customer&quot;, &quot;name&quot;, new FetchConfig().queryFirst(5))
* .fetch(&quot;customer.contacts&quot;)
* .fetch(&quot;customer.shippingAddress&quot;)
* .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 &quot;details.product&quot; is automatically included into the
* // fetch of &quot;details&quot;
* // Note: the fetch of "details.product" is automatically included into the
* // fetch of "details"
* //
* // Note: the fetch of &quot;customer.contacts&quot; and &quot;customer.shippingAddress&quot;
* // are automatically included in the fetch of &quot;customer&quot;
* </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&lt;Order&gt; list =
* <pre>{@code
* List<Order> list =
* Ebean.find(Order.class)
* .fetch(&quot;customer&quot;, 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&lt;Order&gt; list = Ebean.find(Order.class)
* .fetch(&quot;customer&quot;,&quot;name&quot;, new FetchConfig().lazy(5))
* .fetch(&quot;customer.contacts&quot;,&quotcontactName, phone, email&quot)
* .fetch(&quot;customer.shippingAddress&quot;)
* .where().eq(&quot;status&quot;,Order.Status.NEW)
* <pre>{@code
* List<Order> list = Ebean.find(Order.class)
* .fetch("customer","name", new FetchConfig().lazy(5))
* .fetch("customer.contacts",&quotcontactName, phone, email&quot)
* .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
+8 -8
View File
@@ -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;
}
+17 -16
View File
@@ -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&lt;Customer&gt; query = server.find(Customer.class)
* .fetch(&quot;contacts&quot;, new FetchConfig().query(2))
* .where().gt(&quot;id&quot;, 0)
* .orderBy(&quot;id&quot;)
* .setMaxRows(2);
*
* query.findVisit(new QueryResultVisitor&lt;Customer&gt;() {
*
* public boolean accept(Customer customer) {
* // do something with customer
* System.out.println(&quot;-- visit &quot; + 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;
}
-6
View File
@@ -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
View File
@@ -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
View File
@@ -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.
*/
@@ -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();
}
@@ -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);
}
}
@@ -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);
}
/**
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);
}
@@ -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