mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
167
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f26160e1b | ||
|
|
cb66aaf66c | ||
|
|
78b1c05de1 | ||
|
|
c70a4f80eb | ||
|
|
cc788e281f | ||
|
|
d55a7b26f8 | ||
|
|
2195d7ecbc | ||
|
|
983391af94 | ||
|
|
478053263f | ||
|
|
1cd31e13b9 | ||
|
|
374d7faae9 | ||
|
|
6a6cff2236 | ||
|
|
d5d6ac675b | ||
|
|
8ea1f51c7f | ||
|
|
6ecb77dcc2 | ||
|
|
216806074c | ||
|
|
65cb2ae94d | ||
|
|
6677a6199c | ||
|
|
55eaa0b484 | ||
|
|
353f662d70 | ||
|
|
c95d76d6f6 | ||
|
|
e04d6979d1 | ||
|
|
b8078083b1 | ||
|
|
07cdb69a5b | ||
|
|
98f6e1e6af | ||
|
|
fd4d757f87 | ||
|
|
b71b0fc8e2 | ||
|
|
4303bcfd13 | ||
|
|
7f30dc7b1e | ||
|
|
4a882b537c | ||
|
|
641385aab5 | ||
|
|
33ab7eb7a5 | ||
|
|
f6674f8e3b | ||
|
|
4e8b3f22de | ||
|
|
55e43ddc36 | ||
|
|
97d75c06a1 | ||
|
|
adcfa939e4 | ||
|
|
8a4d78a3f5 | ||
|
|
04e77d9949 | ||
|
|
76e7b8d199 | ||
|
|
00f85a42f8 | ||
|
|
e649a70509 | ||
|
|
2ec50d2c71 | ||
|
|
eaee3a9c02 | ||
|
|
221272328c | ||
|
|
1677917465 | ||
|
|
bfefdbac41 | ||
|
|
58755a51a9 | ||
|
|
b313809894 | ||
|
|
0f3b1eb812 | ||
|
|
306cc4adf4 | ||
|
|
ed88978173 | ||
|
|
ae266968b4 | ||
|
|
aa86454cc4 | ||
|
|
c99bec4940 | ||
|
|
7426274ef6 | ||
|
|
130b7e3327 | ||
|
|
de201715fc | ||
|
|
241f6f3d6d | ||
|
|
1210aca027 | ||
|
|
e653c34211 | ||
|
|
131750cf85 | ||
|
|
17b16fd5d9 | ||
|
|
1065a84709 | ||
|
|
13791a2e58 | ||
|
|
277703d750 | ||
|
|
637cbc6489 | ||
|
|
5d09ca16d6 | ||
|
|
6ed1f25e22 | ||
|
|
b8ae443074 | ||
|
|
ab9762bbd9 | ||
|
|
2c90b239cd | ||
|
|
13806767a3 | ||
|
|
40e43b9d5f | ||
|
|
29f1e63146 | ||
|
|
5cf008b521 | ||
|
|
3e788d4598 | ||
|
|
8a29454893 | ||
|
|
62c083a6ea | ||
|
|
7f8e4be396 | ||
|
|
2ad39974e8 | ||
|
|
664e95d87b | ||
|
|
5cf668f65b | ||
|
|
31f56621ff | ||
|
|
11a6cd04ea | ||
|
|
fdb573bfe2 | ||
|
|
ae0e1fe691 | ||
|
|
0511e01273 | ||
|
|
f3bd38536c | ||
|
|
139a558165 | ||
|
|
53b40f7ce0 | ||
|
|
e50656871d | ||
|
|
f7ece0f13c | ||
|
|
562c6fafc9 | ||
|
|
63e9f603ec | ||
|
|
0c4fc4eea3 | ||
|
|
2dca1bdf5b | ||
|
|
6403a83e0e | ||
|
|
b57b91ffef | ||
|
|
4ba5702211 | ||
|
|
2e7aeae004 | ||
|
|
3f2676ab49 | ||
|
|
3f29acb25c | ||
|
|
6d1a41f979 | ||
|
|
aee46955a7 | ||
|
|
38a93b9814 | ||
|
|
5f2ad0dc62 | ||
|
|
ece7f481bc | ||
|
|
fa4d0380e5 | ||
|
|
713ba4889d | ||
|
|
0543745e18 | ||
|
|
4e2bc6cce6 | ||
|
|
f2d422ff5a | ||
|
|
176197513d | ||
|
|
1e3035c558 | ||
|
|
17f7143447 | ||
|
|
394dfc96d1 | ||
|
|
452ce78c3d | ||
|
|
4cb13760c2 | ||
|
|
5cc2eff0d4 | ||
|
|
af9a01be77 | ||
|
|
cceb7c035c | ||
|
|
1ddc103582 | ||
|
|
b973cc3b86 | ||
|
|
10f0ea9bae | ||
|
|
c49dd54500 | ||
|
|
bf0944bb2a | ||
|
|
59ba6244c1 | ||
|
|
f88524b34c | ||
|
|
0ceda6406e | ||
|
|
6838b4df4f | ||
|
|
5db7ae504e | ||
|
|
723ae6bffc | ||
|
|
33b173dd55 | ||
|
|
7966d74eb3 | ||
|
|
28cb2e210d | ||
|
|
1109d412e7 | ||
|
|
3e33ece65a | ||
|
|
1dd200fba2 | ||
|
|
f0ea977f91 | ||
|
|
e830d8efc7 | ||
|
|
0b2ba2a82e | ||
|
|
df526b8f3c | ||
|
|
8fe1f32e78 | ||
|
|
c5ea93fb8e | ||
|
|
dd83bc4d26 | ||
|
|
9b4b7a1a01 | ||
|
|
548fa745d6 | ||
|
|
7d83e3f49e | ||
|
|
974284bf8a | ||
|
|
b446f00cd8 | ||
|
|
a4095b4ae5 | ||
|
|
af6dbd0dbe | ||
|
|
db17ddd069 | ||
|
|
b6b85225e7 | ||
|
|
b57abfa732 | ||
|
|
4a4927b1f3 | ||
|
|
6ac34bec97 | ||
|
|
82725e6a98 | ||
|
|
a744c8b375 | ||
|
|
5e2a34de39 | ||
|
|
8a9ab39a01 | ||
|
|
515256abfd | ||
|
|
84e5a6145e | ||
|
|
1f5618d0e3 | ||
|
|
b1de821817 | ||
|
|
f4dceb97b0 |
@@ -6,6 +6,7 @@
|
||||
target/
|
||||
logs/
|
||||
log/
|
||||
/db
|
||||
/mydb.db
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
[](https://waffle.io/ebean-orm/avaje-ebeanorm)
|
||||
avaje-ebeanorm
|
||||
==============
|
||||
Release - 4.0.2 - May 19th: https://github.com/ebean-orm/avaje-ebeanorm/wiki/4.0.2-Release
|
||||
|
||||
Maven Dependency
|
||||
----------------
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>4.0.2</version>
|
||||
<version>4.3.0</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm</artifactId>
|
||||
<version>4.0.3</version>
|
||||
<version>4.3.1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>avaje-ebeanorm</name>
|
||||
@@ -48,6 +48,18 @@
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.7</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.4.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.transaction</groupId>
|
||||
@@ -77,13 +89,6 @@
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-agentloader</artifactId>
|
||||
@@ -94,7 +99,7 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-agent</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<version>4.1.9</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -177,7 +182,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<version>3.2</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
@@ -186,20 +191,9 @@
|
||||
<plugin>
|
||||
<groupId>org.avaje.ebeanorm</groupId>
|
||||
<artifactId>avaje-ebeanorm-mavenenhancer</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<version>4.1.9</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>main</id>
|
||||
<phase>process-classes</phase>
|
||||
<configuration>
|
||||
<classSource>target/classes</classSource>
|
||||
<packages>com.avaje.ebean.meta.**</packages>
|
||||
<transformArgs>debug=1</transformArgs>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>enhance</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<!-- Not going to enhance Model bean -->
|
||||
<execution>
|
||||
<id>test</id>
|
||||
<phase>process-test-classes</phase>
|
||||
@@ -229,9 +223,37 @@
|
||||
</includes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<doctitle>Ebean 4</doctitle>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
<!-- <excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util</excludePackageNames> -->
|
||||
<additionalparam>-Xdoclint:none</additionalparam>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
||||
|
||||
@@ -63,34 +63,38 @@ import com.avaje.ebean.text.json.JsonContext;
|
||||
* created automatically they are configured using information in the
|
||||
* ebean.properties file.
|
||||
* </p>
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch shipped orders (and also their customer)
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .where()
|
||||
* .eq("status.code", Order.Status.SHIPPED)
|
||||
* .findList();
|
||||
*
|
||||
* // read/use the order list ...
|
||||
* for (Order order : list) {
|
||||
* Customer customer = order.getCustomer();
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // fetch shipped orders (and also their customer)
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .where()
|
||||
* .eq("status.code", Order.Status.SHIPPED)
|
||||
* .findList();
|
||||
* <pre>{@code
|
||||
*
|
||||
* // fetch order 10, modify and save
|
||||
* Order order = Ebean.find(Order.class, 10);
|
||||
*
|
||||
* // read/use the order list ...
|
||||
* for (Order order : list) {
|
||||
* Customer customer = order.getCustomer();
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
* OrderStatus shipped = Ebean.getReference(OrderStatus.class,"SHIPPED");
|
||||
* order.setStatus(shipped);
|
||||
* order.setShippedDate(shippedDate);
|
||||
* ...
|
||||
*
|
||||
* <pre class="code">
|
||||
* // fetch order 10, modify and save
|
||||
* Order order = Ebean.find(Order.class, 10);
|
||||
*
|
||||
* OrderStatus shipped = Ebean.getReference(OrderStatus.class,"SHIPPED");
|
||||
* order.setStatus(shipped);
|
||||
* order.setShippedDate(shippedDate);
|
||||
* ...
|
||||
*
|
||||
* // implicitly creates a transaction and commits
|
||||
* Ebean.save(order);
|
||||
* </pre>
|
||||
* // implicitly creates a transaction and commits
|
||||
* Ebean.save(order);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* When you have multiple databases and need access to a specific one the
|
||||
@@ -98,20 +102,22 @@ import com.avaje.ebean.text.json.JsonContext;
|
||||
* specific database.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // Get access to the Human Resources EbeanServer/Database
|
||||
* EbeanServer hrDb = Ebean.getServer("hr");
|
||||
* <pre> {@code
|
||||
*
|
||||
* // Get access to the Human Resources EbeanServer/Database
|
||||
* EbeanServer hrDb = Ebean.getServer("hr");
|
||||
*
|
||||
*
|
||||
* // fetch contact 3 from the HR database
|
||||
* Contact contact = hrDb.find(Contact.class, 3);
|
||||
* // fetch contact 3 from the HR database
|
||||
* Contact contact = hrDb.find(Contact.class, 3);
|
||||
*
|
||||
* contact.setName("I'm going to change");
|
||||
* ...
|
||||
* contact.setName("I'm going to change");
|
||||
* ...
|
||||
*
|
||||
* // save the contact back to the HR database
|
||||
* hrDb.save(contact);
|
||||
* </pre>
|
||||
* // save the contact back to the HR database
|
||||
* hrDb.save(contact);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public final class Ebean {
|
||||
private static final Logger logger = LoggerFactory.getLogger(Ebean.class);
|
||||
@@ -242,12 +248,12 @@ public final class Ebean {
|
||||
* Ebean.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // use the "hr" database
|
||||
* EbeanServer hrDatabase = Ebean.getServer("hr");
|
||||
* <pre>{@code
|
||||
* // use the "hr" database
|
||||
* EbeanServer hrDatabase = Ebean.getServer("hr");
|
||||
*
|
||||
* Person person = hrDatabase.find(Person.class, 10);
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @param name
|
||||
* the name of the server, use null for the 'default server'
|
||||
@@ -281,7 +287,7 @@ public final class Ebean {
|
||||
* Register the server with this Ebean singleton. Specify if the registered
|
||||
* server is the primary/default server.
|
||||
*/
|
||||
protected static void register(EbeanServer server, boolean isPrimaryServer) {
|
||||
public static void register(EbeanServer server, boolean isPrimaryServer) {
|
||||
serverMgr.register(server, isPrimaryServer);
|
||||
}
|
||||
|
||||
@@ -323,22 +329,24 @@ public final class Ebean {
|
||||
* etc.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // start a transaction (stored in a ThreadLocal)
|
||||
* Ebean.beginTransaction();
|
||||
* try {
|
||||
* Order order = Ebean.find(Order.class,10); ...
|
||||
* <pre>{@code
|
||||
*
|
||||
* // start a transaction (stored in a ThreadLocal)
|
||||
* Ebean.beginTransaction();
|
||||
* try {
|
||||
* Order order = Ebean.find(Order.class,10); ...
|
||||
*
|
||||
* Ebean.save(order);
|
||||
*
|
||||
* Ebean.save(order);
|
||||
* Ebean.commitTransaction();
|
||||
*
|
||||
* Ebean.commitTransaction();
|
||||
*
|
||||
* } finally {
|
||||
* // rollback if we didn't commit
|
||||
* // i.e. an exception occurred before commitTransaction().
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
* </pre>
|
||||
* } finally {
|
||||
* // rollback if we didn't commit
|
||||
* // i.e. an exception occurred before commitTransaction().
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* If you want to externalise the transaction management then you should be
|
||||
@@ -372,6 +380,19 @@ public final class Ebean {
|
||||
return serverMgr.getPrimaryServer().currentTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a TransactionCallback on the currently active transaction.
|
||||
* <p/>
|
||||
* If there is no currently active transaction then a PersistenceException is thrown.
|
||||
*
|
||||
* @param transactionCallback the transaction callback to be registered with the current transaction
|
||||
*
|
||||
* @throws PersistenceException if there is no currently active transaction
|
||||
*/
|
||||
public static void register(TransactionCallback transactionCallback) throws PersistenceException {
|
||||
serverMgr.getPrimaryServer().register(transactionCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the current transaction.
|
||||
*/
|
||||
@@ -397,17 +418,19 @@ public final class Ebean {
|
||||
* Code example:
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Ebean.beginTransaction();
|
||||
* try {
|
||||
* // do some fetching and or persisting
|
||||
* // commit at the end Ebean.commitTransaction();
|
||||
* <pre>{@code
|
||||
* Ebean.beginTransaction();
|
||||
* try {
|
||||
* // do some fetching and or persisting
|
||||
*
|
||||
* // commit at the end
|
||||
* Ebean.commitTransaction();
|
||||
*
|
||||
* } finally {
|
||||
* // if commit didn't occur then rollback the transaction
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
* </pre>
|
||||
* } finally {
|
||||
* // if commit didn't occur then rollback the transaction
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
* }</pre>
|
||||
*/
|
||||
public static void endTransaction() {
|
||||
serverMgr.getPrimaryServer().endTransaction();
|
||||
@@ -440,15 +463,15 @@ public final class Ebean {
|
||||
* saving an order will also save all its details.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* public class Order { ...
|
||||
* <pre>{@code
|
||||
* public class Order { ...
|
||||
*
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* @JoinColumn(name="order_id")
|
||||
* List<OrderDetail> details;
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
* @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
|
||||
* @JoinColumn(name="order_id")
|
||||
* List<OrderDetail> details;
|
||||
* ...
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* When a save cascades via a OneToMany or ManyToMany Ebean will automatically
|
||||
@@ -475,7 +498,31 @@ public final class Ebean {
|
||||
public static void insert(Collection<?> beans) {
|
||||
serverMgr.getPrimaryServer().insert(beans);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Marks the entity bean as dirty.
|
||||
* <p>
|
||||
* This is used so that when a bean that is otherwise unmodified is updated with the version
|
||||
* property updated.
|
||||
* <p>
|
||||
* An unmodified bean that is saved or updated is normally skipped and this marks the bean as
|
||||
* dirty so that it is not skipped.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer = Ebean.find(Customer, id);
|
||||
*
|
||||
* // mark the bean as dirty so that a save() or update() will
|
||||
* // increment the version property
|
||||
* Ebean.markAsDirty(customer);
|
||||
* Ebean.save(customer);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static void markAsDirty(Object bean) throws OptimisticLockException {
|
||||
serverMgr.getPrimaryServer().markAsDirty(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the bean using an update. If you know you are updating a bean then it is preferrable to
|
||||
* use this update() method rather than save().
|
||||
@@ -499,15 +546,15 @@ public final class Ebean {
|
||||
* properties are included instead.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
*
|
||||
* // A 'stateless update' example
|
||||
* Customer customer = new Customer();
|
||||
* customer.setId(7);
|
||||
* customer.setName("ModifiedNameNoOCC");
|
||||
* ebeanServer.update(customer);
|
||||
* // A 'stateless update' example
|
||||
* Customer customer = new Customer();
|
||||
* customer.setId(7);
|
||||
* customer.setName("ModifiedNameNoOCC");
|
||||
* ebeanServer.update(customer);
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @see ServerConfig#setUpdatesDeleteMissingChildren(boolean)
|
||||
* @see ServerConfig#setUpdateChangesOnly(boolean)
|
||||
@@ -641,12 +688,14 @@ public final class Ebean {
|
||||
/**
|
||||
* Refresh a 'many' property of a bean.
|
||||
*
|
||||
* <pre class="code">
|
||||
* Order order = ...;
|
||||
* ...
|
||||
* // refresh the order details...
|
||||
* Ebean.refreshMany(order, "details");
|
||||
* </pre>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Order order = ...;
|
||||
* ...
|
||||
* // refresh the order details...
|
||||
* Ebean.refreshMany(order, "details");
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param bean
|
||||
* the entity bean containing the List Set or Map to refresh.
|
||||
@@ -663,16 +712,18 @@ public final class Ebean {
|
||||
* This is sometimes described as a proxy (with lazy loading).
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Product product = Ebean.getReference(Product.class, 1);
|
||||
* <pre>{@code
|
||||
*
|
||||
* Product product = Ebean.getReference(Product.class, 1);
|
||||
*
|
||||
* // You can get the id without causing a fetch/lazy load
|
||||
* Integer productId = product.getId();
|
||||
* // You can get the id without causing a fetch/lazy load
|
||||
* Integer productId = product.getId();
|
||||
*
|
||||
* // If you try to get any other property a fetch/lazy loading will occur
|
||||
* // This will cause a query to execute...
|
||||
* String name = product.getName();
|
||||
* </pre>
|
||||
* // If you try to get any other property a fetch/lazy loading will occur
|
||||
* // This will cause a query to execute...
|
||||
* String name = product.getName();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType
|
||||
* the type of entity bean
|
||||
@@ -702,23 +753,23 @@ public final class Ebean {
|
||||
* not invoke a DB query.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
*
|
||||
* // find orders and their customers
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .orderBy("id")
|
||||
* // find orders and their customers
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .orderBy("id")
|
||||
* .findList();
|
||||
*
|
||||
* // sort by customer name ascending, then by order shipDate
|
||||
* // ... then by the order status descending
|
||||
* Ebean.sort(list, "customer.name, shipDate, status desc");
|
||||
* // sort by customer name ascending, then by order shipDate
|
||||
* // ... then by the order status descending
|
||||
* Ebean.sort(list, "customer.name, shipDate, status desc");
|
||||
*
|
||||
* // sort by customer name descending (with nulls low)
|
||||
* // ... then by the order id
|
||||
* Ebean.sort(list, "customer.name desc nullsLow, id");
|
||||
* // sort by customer name descending (with nulls low)
|
||||
* // ... then by the order id
|
||||
* Ebean.sort(list, "customer.name desc nullsLow, id");
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @param list
|
||||
* the list of entity beans
|
||||
@@ -732,41 +783,43 @@ public final class Ebean {
|
||||
/**
|
||||
* Find a bean using its unique id. This will not use caching.
|
||||
*
|
||||
* <pre class="code">
|
||||
* // Fetch order 1
|
||||
* Order order = Ebean.find(Order.class, 1);
|
||||
* </pre>
|
||||
* <pre>{@code
|
||||
* // Fetch order 1
|
||||
* Order order = Ebean.find(Order.class, 1);
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* If you want more control over the query then you can use createQuery() and
|
||||
* Query.findUnique();
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // ... additionally fetching customer, customer shipping address,
|
||||
* // order details, and the product associated with each order detail.
|
||||
* // note: only product id and name is fetch (its a "partial object").
|
||||
* // note: all other objects use "*" and have all their properties fetched.
|
||||
* <pre>{@code
|
||||
* // ... additionally fetching customer, customer shipping address,
|
||||
* // order details, and the product associated with each order detail.
|
||||
* // note: only product id and name is fetch (its a "partial object").
|
||||
* // note: all other objects use "*" and have all their properties fetched.
|
||||
*
|
||||
* Query<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.setId(1);
|
||||
* query.fetch("customer");
|
||||
* query.fetch("customer.shippingAddress");
|
||||
* query.fetch("details");
|
||||
* Query<Order> query = Ebean.find(Order.class)
|
||||
* .setId(1)
|
||||
* .fetch("customer")
|
||||
* .fetch("customer.shippingAddress")
|
||||
* .fetch("details")
|
||||
* .query();
|
||||
*
|
||||
* // fetch associated products but only fetch their product id and name
|
||||
* query.fetch("details.product", "name");
|
||||
* // fetch associated products but only fetch their product id and name
|
||||
* query.fetch("details.product", "name");
|
||||
*
|
||||
* // traverse the object graph...
|
||||
* // traverse the object graph...
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
* Customer customer = order.getCustomer();
|
||||
* Address shippingAddress = customer.getShippingAddress();
|
||||
* List<OrderDetail> details = order.getDetails();
|
||||
* OrderDetail detail0 = details.get(0);
|
||||
* Product product = detail0.getProduct();
|
||||
* String productName = product.getName();
|
||||
* </pre>
|
||||
* Order order = query.findUnique();
|
||||
* Customer customer = order.getCustomer();
|
||||
* Address shippingAddress = customer.getShippingAddress();
|
||||
* List<OrderDetail> details = order.getDetails();
|
||||
* OrderDetail detail0 = details.get(0);
|
||||
* Product product = detail0.getProduct();
|
||||
* String productName = product.getName();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType
|
||||
* the type of entity bean to fetch
|
||||
@@ -778,7 +831,7 @@ public final class Ebean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a <a href="SqlQuery.html">SqlQuery</a> for executing native sql
|
||||
* Create a SqlQuery for executing native sql
|
||||
* query statements.
|
||||
* <p>
|
||||
* Note that you can use raw SQL with entity beans, refer to the SqlSelect
|
||||
@@ -836,15 +889,17 @@ public final class Ebean {
|
||||
* deployment orm xml file.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // Use a namedQuery
|
||||
* UpdateSql update = Ebean.createNamedSqlUpdate("update.topic.count");
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Use a namedQuery
|
||||
* UpdateSql update = Ebean.createNamedSqlUpdate("update.topic.count");
|
||||
*
|
||||
* update.setParameter("count", 1);
|
||||
* update.setParameter("topicId", 50);
|
||||
* update.setParameter("count", 1);
|
||||
* update.setParameter("topicId", 50);
|
||||
*
|
||||
* int modifiedCount = update.execute();
|
||||
* </pre>
|
||||
* int modifiedCount = update.execute();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static SqlUpdate createNamedSqlUpdate(String namedQuery) {
|
||||
return serverMgr.getPrimaryServer().createNamedSqlUpdate(namedQuery);
|
||||
@@ -859,12 +914,14 @@ public final class Ebean {
|
||||
* need to bind required parameters and then execute the query.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // example
|
||||
* Query<Order> query = Ebean.createNamedQuery(Order.class, "new.for.customer");
|
||||
* query.setParameter("customerId", 23);
|
||||
* List<Order> newOrders = query.findList();
|
||||
* </pre>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // example
|
||||
* Query<Order> query = Ebean.createNamedQuery(Order.class, "new.for.customer");
|
||||
* query.setParameter("customerId", 23);
|
||||
* List<Order> newOrders = query.findList();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType
|
||||
* the class of entity to be fetched
|
||||
@@ -887,14 +944,15 @@ public final class Ebean {
|
||||
* moved to {@link #createNamedQuery(Class, String)}.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
*
|
||||
* String q = "find order fetch details where status = :st";
|
||||
* String q = "find order fetch details where status = :st";
|
||||
*
|
||||
* List<Order> newOrders = Ebean.createQuery(Order.class, q)
|
||||
* .setParameter("st", Order.Status.NEW)
|
||||
* List<Order> newOrders = Ebean.>findOrder.class, q)
|
||||
* .setParameter("st", Order.Status.NEW)
|
||||
* .findList();
|
||||
* </pre>
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param query
|
||||
* the object query
|
||||
@@ -919,40 +977,43 @@ public final class Ebean {
|
||||
* Example named updates:
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* package app.data;
|
||||
* <pre>{@code
|
||||
* package app.data;
|
||||
*
|
||||
* import ...
|
||||
* import ...
|
||||
*
|
||||
* @NamedUpdates(value = {
|
||||
* @NamedUpdate( name = "setTitle",
|
||||
* isSql = false,
|
||||
* notifyCache = false,
|
||||
* update = "update topic set title = :title, postCount = :postCount where id = :id"),
|
||||
* @NamedUpdate( name = "setPostCount",
|
||||
* notifyCache = false,
|
||||
* update = "update f_topic set post_count = :postCount where id = :id"),
|
||||
* @NamedUpdate( name = "incrementPostCount",
|
||||
* notifyCache = false,
|
||||
* isSql = false,
|
||||
* update = "update Topic set postCount = postCount + 1 where id = :id") })
|
||||
* @Entity
|
||||
* @Table(name = "f_topic")
|
||||
* public class Topic { ...
|
||||
* </pre>
|
||||
* @NamedUpdates(value = {
|
||||
* @NamedUpdate( name = "setTitle",
|
||||
* isSql = false,
|
||||
* notifyCache = false,
|
||||
* update = "update topic set title = :title, postCount = :postCount where id = :id"),
|
||||
* @NamedUpdate( name = "setPostCount",
|
||||
* notifyCache = false,
|
||||
* update = "update f_topic set post_count = :postCount where id = :id"),
|
||||
* @NamedUpdate( name = "incrementPostCount",
|
||||
* notifyCache = false,
|
||||
* isSql = false,
|
||||
* update = "update Topic set postCount = postCount + 1 where id = :id") })
|
||||
* @Entity
|
||||
* @Table(name = "f_topic")
|
||||
* public class Topic { ...
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* Example using a named update:
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Update<Topic> update = Ebean.createNamedUpdate(Topic.class, "setPostCount");
|
||||
* update.setParameter("postCount", 10);
|
||||
* update.setParameter("id", 3);
|
||||
* <pre>{@code
|
||||
*
|
||||
* Update<Topic> update = Ebean.createNamedUpdate(Topic.class, "setPostCount");
|
||||
* update.setParameter("postCount", 10);
|
||||
* update.setParameter("id", 3);
|
||||
*
|
||||
* int rows = update.execute();
|
||||
* System.out.println("rows updated: " + rows);
|
||||
* </pre>
|
||||
* int rows = update.execute();
|
||||
* System.out.println("rows updated: " + rows);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static <T> Update<T> createNamedUpdate(Class<T> beanType, String namedUpdate) {
|
||||
|
||||
@@ -971,21 +1032,22 @@ public final class Ebean {
|
||||
* An example:
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
*
|
||||
* // The bean name and properties - "topic","postCount" and "id"
|
||||
* // The bean name and properties - "topic","postCount" and "id"
|
||||
*
|
||||
* // will be converted into their associated table and column names
|
||||
* String updStatement = "update topic set postCount = :pc where id = :id";
|
||||
* // will be converted into their associated table and column names
|
||||
* String updStatement = "update topic set postCount = :pc where id = :id";
|
||||
*
|
||||
* Update<Topic> update = Ebean.createUpdate(Topic.class, updStatement);
|
||||
* Update<Topic> update = Ebean.createUpdate(Topic.class, updStatement);
|
||||
*
|
||||
* update.set("pc", 9);
|
||||
* update.set("id", 3);
|
||||
* update.set("pc", 9);
|
||||
* update.set("id", 3);
|
||||
*
|
||||
* int rows = update.execute();
|
||||
* System.out.println("rows updated:" + rows);
|
||||
* </pre>
|
||||
* int rows = update.execute();
|
||||
* System.out.println("rows updated:" + rows);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static <T> Update<T> createUpdate(Class<T> beanType, String ormUpdate) {
|
||||
|
||||
@@ -1016,38 +1078,37 @@ public final class Ebean {
|
||||
* which is was created.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // Find order 2 additionally fetching the customer, details and details.product
|
||||
* // name.
|
||||
* <pre>{@code
|
||||
* // Find order 2 additionally fetching the customer, details and details.product
|
||||
* // name.
|
||||
*
|
||||
* Query<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.fetch("customer");
|
||||
* query.fetch("details");
|
||||
* query.fetch("detail.product", "name");
|
||||
* query.setId(2);
|
||||
* Order order = Ebean.find(Order.class)
|
||||
* .fetch("customer")
|
||||
* .fetch("details")
|
||||
* .fetch("detail.product", "name")
|
||||
* .setId(2)
|
||||
* .findUnique();
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
* // Find order 2 additionally fetching the customer, details and details.product
|
||||
* // name.
|
||||
* // Note: same query as above but using the query language
|
||||
* // Note: using a named query would be preferred practice
|
||||
*
|
||||
* // Find order 2 additionally fetching the customer, details and details.product
|
||||
* // name.
|
||||
* // Note: same query as above but using the query language
|
||||
* // Note: using a named query would be preferred practice
|
||||
* String oql = "find order fetch customer fetch details fetch details.product (name) where id = :orderId ";
|
||||
*
|
||||
* String oql = "find order fetch customer fetch details fetch details.product (name) where id = :orderId ";
|
||||
* Query<Order> query = Ebean.find(Order.class);
|
||||
* query.setQuery(oql);
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* Query<Order> query = Ebean.createQuery(Order.class);
|
||||
* query.setQuery(oql);
|
||||
* query.setParameter("orderId", 2);
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
* // Using a named query
|
||||
* Query<Order> query = Ebean.find(Order.class, "with.details");
|
||||
* query.setParameter("orderId", 2);
|
||||
*
|
||||
* // Using a named query
|
||||
* Query<Order> query = Ebean.createQuery(Order.class, "with.details");
|
||||
* query.setParameter("orderId", 2);
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* Order order = query.findUnique();
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType
|
||||
* the class of entity to be fetched
|
||||
@@ -1107,19 +1168,21 @@ public final class Ebean {
|
||||
* Example:
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // example that uses 'named' parameters
|
||||
* String s = "UPDATE f_topic set post_count = :count where id = :id"
|
||||
* <pre>{@code
|
||||
*
|
||||
* // example that uses 'named' parameters
|
||||
* String s = "UPDATE f_topic set post_count = :count where id = :id"
|
||||
*
|
||||
* SqlUpdate update = Ebean.createSqlUpdate(s);
|
||||
* SqlUpdate update = Ebean.createSqlUpdate(s);
|
||||
*
|
||||
* update.setParameter("id", 1);
|
||||
* update.setParameter("count", 50);
|
||||
* update.setParameter("id", 1);
|
||||
* update.setParameter("count", 50);
|
||||
*
|
||||
* int modifiedCount = Ebean.execute(update);
|
||||
* int modifiedCount = Ebean.execute(update);
|
||||
*
|
||||
* String msg = "There where " + modifiedCount + "rows updated";
|
||||
* </pre>
|
||||
* String msg = "There where " + modifiedCount + "rows updated";
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param sqlUpdate
|
||||
* the update sql potentially with bind values
|
||||
@@ -1140,19 +1203,21 @@ public final class Ebean {
|
||||
* Example:
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* String sql = "{call sp_order_modify(?,?,?)}";
|
||||
* <pre>{@code
|
||||
*
|
||||
* String sql = "{call sp_order_modify(?,?,?)}";
|
||||
*
|
||||
* CallableSql cs = Ebean.createCallableSql(sql);
|
||||
* cs.setParameter(1, 27);
|
||||
* cs.setParameter(2, "SHIPPED");
|
||||
* cs.registerOut(3, Types.INTEGER);
|
||||
* CallableSql cs = Ebean.createCallableSql(sql);
|
||||
* cs.setParameter(1, 27);
|
||||
* cs.setParameter(2, "SHIPPED");
|
||||
* cs.registerOut(3, Types.INTEGER);
|
||||
*
|
||||
* Ebean.execute(cs);
|
||||
* Ebean.execute(cs);
|
||||
*
|
||||
* // read the out parameter
|
||||
* Integer returnValue = (Integer) cs.getObject(3);
|
||||
* </pre>
|
||||
* // read the out parameter
|
||||
* Integer returnValue = (Integer) cs.getObject(3);
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @see CallableSql
|
||||
* @see Ebean#execute(SqlUpdate)
|
||||
@@ -1168,18 +1233,19 @@ public final class Ebean {
|
||||
* semantics.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // set specific transactional scope settings
|
||||
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
|
||||
*
|
||||
* Ebean.execute(scope, new TxRunnable() {
|
||||
* public void run() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* ...
|
||||
*
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set specific transactional scope settings
|
||||
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
|
||||
*
|
||||
* Ebean.execute(scope, new TxRunnable() {
|
||||
* public void run() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* ...
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static void execute(TxScope scope, TxRunnable r) {
|
||||
serverMgr.getPrimaryServer().execute(scope, r);
|
||||
@@ -1192,20 +1258,22 @@ public final class Ebean {
|
||||
* exception (checked or runtime).
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Ebean.execute(new TxRunnable() {
|
||||
* public void run() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* User u2 = Ebean.find(User.class, 2);
|
||||
* <pre>{@code
|
||||
*
|
||||
* Ebean.execute(new TxRunnable() {
|
||||
* public void run() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* User u2 = Ebean.find(User.class, 2);
|
||||
*
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
*
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static void execute(TxRunnable r) {
|
||||
serverMgr.getPrimaryServer().execute(r);
|
||||
@@ -1218,18 +1286,20 @@ public final class Ebean {
|
||||
* semantics.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // set specific transactional scope settings
|
||||
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
|
||||
*
|
||||
* Ebean.execute(scope, new TxCallable<String>() {
|
||||
* public String call() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* ...
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // set specific transactional scope settings
|
||||
* TxScope scope = TxScope.requiresNew().setIsolation(TxIsolation.SERIALIZABLE);
|
||||
*
|
||||
* Ebean.execute(scope, new TxCallable<String>() {
|
||||
* public String call() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* ...
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
*/
|
||||
public static <T> T execute(TxScope scope, TxCallable<T> c) {
|
||||
@@ -1247,22 +1317,24 @@ public final class Ebean {
|
||||
* (and you specify the return type via generics).
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* Ebean.execute(new TxCallable<String>() {
|
||||
* public String call() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* User u2 = Ebean.find(User.class, 2);
|
||||
* <pre>{@code
|
||||
*
|
||||
* Ebean.execute(new TxCallable<String>() {
|
||||
* public String call() {
|
||||
* User u1 = Ebean.find(User.class, 1);
|
||||
* User u2 = Ebean.find(User.class, 2);
|
||||
*
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
* u1.setName("u1 mod");
|
||||
* u2.setName("u2 mod");
|
||||
*
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
* Ebean.save(u1);
|
||||
* Ebean.save(u2);
|
||||
*
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* });
|
||||
* </pre>
|
||||
* return u1.getEmail();
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public static <T> T execute(TxCallable<T> c) {
|
||||
return serverMgr.getPrimaryServer().execute(c);
|
||||
@@ -1283,7 +1355,7 @@ public final class Ebean {
|
||||
* </p>
|
||||
* <p>
|
||||
* If there is a transaction then this information is placed into the current
|
||||
* transactions event information. When the transaction is commited this
|
||||
* transactions event information. When the transaction is committed this
|
||||
* information is registered (with the transaction manager). If this
|
||||
* transaction is rolled back then none of the transaction event information
|
||||
* registers including the information you put in via this method.
|
||||
@@ -1359,10 +1431,18 @@ public final class Ebean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a JsonContext that will use the default configuration options.
|
||||
* 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 serverMgr.getPrimaryServer().createJsonContext();
|
||||
return json();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.OptimisticLockException;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheStrategy;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
@@ -48,18 +49,18 @@ import com.avaje.ebean.text.json.JsonContext;
|
||||
* Example: Get a EbeanServer
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
* // Get access to the Human Resources EbeanServer/Database
|
||||
* EbeanServer hrServer = Ebean.getServer("HR");
|
||||
* EbeanServer hrServer = Ebean.getServer("HR");
|
||||
*
|
||||
*
|
||||
* // fetch contact 3 from the HR database Contact contact =
|
||||
* hrServer.find(Contact.class, new Integer(3));
|
||||
*
|
||||
* contact.setStatus("INACTIVE"); ...
|
||||
* contact.setStatus("INACTIVE"); ...
|
||||
*
|
||||
* // save the contact back to the HR database hrServer.save(contact);
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* <p>
|
||||
* <b>EbeanServer has more API than Ebean</b><br/>
|
||||
@@ -127,7 +128,6 @@ public interface EbeanServer {
|
||||
*/
|
||||
public MetaInfoManager getMetaInfoManager();
|
||||
|
||||
|
||||
/**
|
||||
* Return the BeanState for a given entity bean.
|
||||
* <p>
|
||||
@@ -191,15 +191,15 @@ public interface EbeanServer {
|
||||
* moved to {@link #createNamedQuery(Class, String)}.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
* EbeanServer ebeanServer = ... ;
|
||||
* String q = "find order fetch details where status = :st";
|
||||
*
|
||||
* List<Order> newOrders
|
||||
* List<Order> newOrders
|
||||
* = ebeanServer.createQuery(Order.class, q)
|
||||
* .setParameter("st", Order.Status.NEW)
|
||||
* .findList();
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @param query
|
||||
* the object query
|
||||
@@ -207,16 +207,14 @@ public interface EbeanServer {
|
||||
public <T> Query<T> createQuery(Class<T> beanType, String query);
|
||||
|
||||
/**
|
||||
* Create a query for an entity bean (refer {@link Ebean#createQuery(Class)}
|
||||
* ).
|
||||
* Create a query for an entity bean (refer {@link Ebean#createQuery(Class)}).
|
||||
*
|
||||
* @see Ebean#createQuery(Class)
|
||||
*/
|
||||
public <T> Query<T> createQuery(Class<T> beanType);
|
||||
|
||||
/**
|
||||
* Create a query for a type of entity bean (the same as
|
||||
* {@link EbeanServer#createQuery(Class)}).
|
||||
* Create a query for a type of entity bean (the same as {@link EbeanServer#createQuery(Class)}).
|
||||
*/
|
||||
public <T> Query<T> find(Class<T> beanType);
|
||||
|
||||
@@ -272,8 +270,7 @@ public interface EbeanServer {
|
||||
public SqlQuery createSqlQuery(String sql);
|
||||
|
||||
/**
|
||||
* Create a named sql query (refer {@link Ebean#createNamedSqlQuery(String)}
|
||||
* ).
|
||||
* Create a named sql query (refer {@link Ebean#createNamedSqlQuery(String)}).
|
||||
* <p>
|
||||
* The query statement will be defined in a deployment orm xml file.
|
||||
* </p>
|
||||
@@ -283,8 +280,7 @@ public interface EbeanServer {
|
||||
public SqlQuery createNamedSqlQuery(String namedQuery);
|
||||
|
||||
/**
|
||||
* Create a sql update for executing native dml statements (refer
|
||||
* {@link Ebean#createSqlUpdate(String)}).
|
||||
* Create a sql update for executing native dml statements (refer {@link Ebean#createSqlUpdate(String)}).
|
||||
*
|
||||
* @see Ebean#createSqlUpdate(String)
|
||||
*/
|
||||
@@ -296,8 +292,7 @@ public interface EbeanServer {
|
||||
public CallableSql createCallableSql(String callableSql);
|
||||
|
||||
/**
|
||||
* Create a named sql update (refer {@link Ebean#createNamedSqlUpdate(String)}
|
||||
* ).
|
||||
* Create a named sql update (refer {@link Ebean#createNamedSqlUpdate(String)}).
|
||||
* <p>
|
||||
* The statement (an Insert Update or Delete statement) will be defined in a
|
||||
* deployment orm xml file.
|
||||
@@ -307,6 +302,17 @@ public interface EbeanServer {
|
||||
*/
|
||||
public SqlUpdate createNamedSqlUpdate(String namedQuery);
|
||||
|
||||
/**
|
||||
* Register a TransactionCallback on the currently active transaction.
|
||||
* <p/>
|
||||
* If there is no currently active transaction then a PersistenceException is thrown.
|
||||
*
|
||||
* @param transactionCallback The transaction callback to be registered with the current transaction.
|
||||
*
|
||||
* @throws PersistenceException If there is no currently active transaction
|
||||
*/
|
||||
public void register(TransactionCallback transactionCallback) throws PersistenceException;
|
||||
|
||||
/**
|
||||
* Create a new transaction that is not held in TransactionThreadLocal.
|
||||
* <p>
|
||||
@@ -338,8 +344,7 @@ public interface EbeanServer {
|
||||
public Transaction beginTransaction(TxIsolation isolation);
|
||||
|
||||
/**
|
||||
* Returns the current transaction or null if there is no current transaction
|
||||
* in scope.
|
||||
* Returns the current transaction or null if there is no current transaction in scope.
|
||||
*/
|
||||
public Transaction currentTransaction();
|
||||
|
||||
@@ -367,15 +372,19 @@ public interface EbeanServer {
|
||||
* <p>
|
||||
* Code example:
|
||||
*
|
||||
* <pre class="code">
|
||||
* Ebean.startTransaction(); try { // do some fetching
|
||||
* and or persisting
|
||||
* <pre>{@code
|
||||
* ebeanServer.startTransaction();
|
||||
* try {
|
||||
* // do some fetching and or persisting ...
|
||||
*
|
||||
* // commit at the end Ebean.commitTransaction();
|
||||
* // commit at the end
|
||||
* ebeanServer.commitTransaction();
|
||||
*
|
||||
* } finally { // if commit didn't occur then rollback the transaction
|
||||
* Ebean.endTransaction(); }
|
||||
* </pre>
|
||||
* } finally {
|
||||
* // if commit didn't occur then rollback the transaction
|
||||
* ebeanServer.endTransaction();
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
@@ -417,7 +426,7 @@ public interface EbeanServer {
|
||||
* <p>
|
||||
* This will not perform a query against the database.
|
||||
* </p>
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
* Product product = Ebean.getReference(Product.class, 1);
|
||||
*
|
||||
* // You can get the id without causing a fetch/lazy load
|
||||
@@ -426,14 +435,14 @@ public interface EbeanServer {
|
||||
* // If you try to get any other property a fetch/lazy loading will occur
|
||||
* // This will cause a query to execute...
|
||||
* String name = product.getName();
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @param beanType
|
||||
* the type of entity bean
|
||||
* @param id
|
||||
* the id value
|
||||
*/
|
||||
public <T> T getReference(Class<T> beanType, Object uid);
|
||||
public <T> T getReference(Class<T> beanType, Object id);
|
||||
|
||||
/**
|
||||
* Return the number of 'top level' or 'root' entities this query should
|
||||
@@ -457,6 +466,30 @@ public interface EbeanServer {
|
||||
* 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.
|
||||
*
|
||||
* @see Query#findEach(QueryEachConsumer)
|
||||
*/
|
||||
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction transaction);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @see Query#findEachWhile(QueryEachWhileConsumer)
|
||||
*/
|
||||
public <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
|
||||
*/
|
||||
public <T> void findVisit(Query<T> query, QueryResultVisitor<T> visitor, Transaction transaction);
|
||||
|
||||
@@ -489,7 +522,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @param query
|
||||
* the query to execute the row count on
|
||||
* @param t
|
||||
* @param transaction
|
||||
* the transaction (can be null).
|
||||
* @return a Future object for the row count query
|
||||
*/
|
||||
@@ -505,7 +538,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @param query
|
||||
* the query to execute the fetch Id's on
|
||||
* @param t
|
||||
* @param transaction
|
||||
* the transaction (can be null).
|
||||
* @return a Future object for the list of Id's
|
||||
*/
|
||||
@@ -521,7 +554,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @param query
|
||||
* the query to execute in the background
|
||||
* @param t
|
||||
* @param transaction
|
||||
* the transaction (can be null).
|
||||
* @return a Future object for the list result of the query
|
||||
* @deprecated
|
||||
@@ -538,7 +571,7 @@ public interface EbeanServer {
|
||||
*
|
||||
* @param query
|
||||
* the query to execute in the background
|
||||
* @param t
|
||||
* @param transaction
|
||||
* the transaction (can be null).
|
||||
* @return a Future object for the list result of the query
|
||||
* @deprecated
|
||||
@@ -837,6 +870,28 @@ public interface EbeanServer {
|
||||
*/
|
||||
public int save(Collection<?> beans, Transaction transaction) throws OptimisticLockException;
|
||||
|
||||
/**
|
||||
* Marks the entity bean as dirty.
|
||||
* <p>
|
||||
* This is used so that when a bean that is otherwise unmodified is updated the version
|
||||
* property is updated.
|
||||
* <p>
|
||||
* An unmodified bean that is saved or updated is normally skipped and this marks the bean as
|
||||
* dirty so that it is not skipped.
|
||||
*
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer = ebeanServer.find(Customer, id);
|
||||
*
|
||||
* // mark the bean as dirty so that a save() or update() will
|
||||
* // increment the version property
|
||||
* ebeanServer.markAsDirty(customer);
|
||||
* ebeanServer.save(customer);
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public void markAsDirty(Object bean);
|
||||
|
||||
/**
|
||||
* Saves the bean using an update. If you know you are updating a bean then it is preferrable to
|
||||
* use this update() method rather than save().
|
||||
@@ -860,15 +915,15 @@ public interface EbeanServer {
|
||||
* properties are included instead.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
*
|
||||
* // A 'stateless update' example
|
||||
* Customer customer = new Customer();
|
||||
* customer.setId(7);
|
||||
* customer.setName("ModifiedNameNoOCC");
|
||||
* customer.setName("ModifiedNameNoOCC");
|
||||
* ebeanServer.update(customer);
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @see ServerConfig#setUpdatesDeleteMissingChildren(boolean)
|
||||
* @see ServerConfig#setUpdateChangesOnly(boolean)
|
||||
@@ -1097,9 +1152,14 @@ public interface EbeanServer {
|
||||
public void runCacheWarming(Class<?> beanType);
|
||||
|
||||
/**
|
||||
* Create a JsonContext that will use the default configuration options.
|
||||
* Return the JsonContext for reading/writing JSON.
|
||||
* @deprecated Please use #json instead.
|
||||
*/
|
||||
public JsonContext createJsonContext();
|
||||
|
||||
/**
|
||||
* Return the JsonContext for reading/writing JSON.
|
||||
*/
|
||||
public JsonContext json();
|
||||
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ import com.avaje.ebean.common.BootupEbeanManager;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.util.ClassUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Creates EbeanServer instances.
|
||||
@@ -26,14 +24,9 @@ import org.slf4j.LoggerFactory;
|
||||
* methods on the Ebean singleton such as {@link Ebean#find(Class)} are just a
|
||||
* convenient way of using the 'default/primary' EbeanServer.
|
||||
* </p>
|
||||
*
|
||||
* @author Rob Bygrave
|
||||
*
|
||||
*/
|
||||
public class EbeanServerFactory {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(EbeanServerFactory.class);
|
||||
|
||||
private static BootupEbeanManager serverFactory = createServerFactory();
|
||||
|
||||
/**
|
||||
@@ -69,27 +62,10 @@ public class EbeanServerFactory {
|
||||
|
||||
private static BootupEbeanManager createServerFactory() {
|
||||
|
||||
// String d___ =
|
||||
// com.avaje.ebean.server.core.DefaultServerFactory.class.getName();
|
||||
String dflt = "com.avaje.ebeaninternal.server.core.DefaultServerFactory";
|
||||
String implClassName = GlobalProperties.get("ebean.serverfactory", dflt);
|
||||
String implClassName = System.getProperty("ebean.serverfactory", dflt);
|
||||
|
||||
int delaySecs = GlobalProperties.getInt("ebean.start.delay", 0);
|
||||
if (delaySecs > 0) {
|
||||
try {
|
||||
// perhaps useful to delay the startup to give time to
|
||||
// attach a debugger when running in a server like tomcat.
|
||||
String m = "Ebean sleeping " + delaySecs + " seconds due to ebean.start.delay";
|
||||
logger.info(m);
|
||||
Thread.sleep(delaySecs * 1000);
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
String m = "Interrupting debug.start.delay of " + delaySecs;
|
||||
logger.error(m, e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
// use a client side implementation?
|
||||
return (BootupEbeanManager) ClassUtil.newInstance(implClassName);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -87,6 +89,11 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
public Query<T> setOrderBy(String orderBy);
|
||||
|
||||
/**
|
||||
* Apply the path properties to the query replacing the select and fetch clauses.
|
||||
*/
|
||||
public Query<T> apply(PathProperties pathProperties);
|
||||
|
||||
/**
|
||||
* Execute the query iterating over the results.
|
||||
*
|
||||
@@ -95,9 +102,25 @@ public interface ExpressionList<T> extends Serializable {
|
||||
public QueryIterator<T> findIterate();
|
||||
|
||||
/**
|
||||
* Execute the query visiting the results.
|
||||
*
|
||||
* @see Query#findVisit(QueryResultVisitor)
|
||||
* Execute the query process the beans one at a time.
|
||||
*
|
||||
* @see Query#findEach(QueryEachConsumer)
|
||||
*/
|
||||
public void findEach(QueryEachConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query processing the beans one at a time with the ability to
|
||||
* stop processing before reading all the beans.
|
||||
*
|
||||
* @see Query#findEachWhile(QueryEachWhileConsumer)
|
||||
*/
|
||||
public void findEachWhile(QueryEachWhileConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Deprecated in favor of #findEachWhile which is functionally exactly the same
|
||||
* but has a much better name.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public void findVisit(QueryResultVisitor<T> visitor);
|
||||
|
||||
@@ -238,22 +261,6 @@ public interface ExpressionList<T> extends Serializable {
|
||||
*/
|
||||
public Query<T> select(String properties);
|
||||
|
||||
/**
|
||||
* Specify a property (associated bean) to join and <em>fetch</em> including
|
||||
* all its properties.
|
||||
*
|
||||
* @see Query#join(String)
|
||||
*/
|
||||
public Query<T> join(String assocProperties);
|
||||
|
||||
/**
|
||||
* Specify a property (associated bean) to join and <em>fetch</em> with its
|
||||
* specific properties to include (aka partial object).
|
||||
*
|
||||
* @see Query#join(String,String)
|
||||
*/
|
||||
public Query<T> join(String assocProperty, String assocProperties);
|
||||
|
||||
/**
|
||||
* Set the first row to fetch.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -29,7 +31,7 @@ import javax.persistence.MappedSuperclass;
|
||||
* relatively nice clean way to write queries.
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public class Model {
|
||||
public abstract class Model {
|
||||
|
||||
/**
|
||||
* Return the underlying 'default' EbeanServer.
|
||||
@@ -38,9 +40,36 @@ public class Model {
|
||||
* This provides full access to the API such as explicit transaction demarcation etc.
|
||||
*
|
||||
* <p>
|
||||
* TODO: Transaction example
|
||||
* Example:
|
||||
* <pre class="code">
|
||||
* Transaction transaction = Customer.db().beginTransaction();
|
||||
* try {
|
||||
*
|
||||
* // turn off cascade persist for this transaction
|
||||
* transaction.setPersistCascade(false);
|
||||
*
|
||||
* // extra control over jdbc batching for this transaction
|
||||
* transaction.setBatchGetGeneratedKeys(false);
|
||||
* transaction.setBatchMode(true);
|
||||
* transaction.setBatchSize(20);
|
||||
*
|
||||
* Customer customer = new Customer();
|
||||
* customer.setName("Roberto");
|
||||
* customer.save();
|
||||
*
|
||||
* Customer otherCustomer = new Customer();
|
||||
* otherCustomer.setName("Franko");
|
||||
* otherCustomer.save();
|
||||
*
|
||||
* transaction.commit();
|
||||
*
|
||||
* } finally {
|
||||
* transaction.end();
|
||||
* }
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public EbeanServer db() {
|
||||
public static EbeanServer db() {
|
||||
return Ebean.getServer(null);
|
||||
}
|
||||
|
||||
@@ -54,10 +83,34 @@ public class Model {
|
||||
* @param server
|
||||
* The name of the EbeanServer. If this is null then the default EbeanServer is returned.
|
||||
*/
|
||||
public EbeanServer db(String server) {
|
||||
public static EbeanServer db(String server) {
|
||||
return Ebean.getServer(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the entity bean as dirty.
|
||||
* <p>
|
||||
* This is used so that when a bean that is otherwise unmodified is updated the version
|
||||
* property is updated.
|
||||
* <p>
|
||||
* An unmodified bean that is saved or updated is normally skipped and this marks the bean as
|
||||
* dirty so that it is not skipped.
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Customer customer = Customer.find.byId(id);
|
||||
*
|
||||
* // mark the bean as dirty so that a save() or update() will
|
||||
* // increment the version property
|
||||
* customer.markAsDirty();
|
||||
* customer.save();
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
public void markAsDirty() {
|
||||
db().markAsDirty(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert or update this entity depending on its state.
|
||||
*
|
||||
@@ -125,11 +178,11 @@ public class Model {
|
||||
* Typically a Finder is defined as a public static field on an entity bean class to provide a
|
||||
* nice way to write queries.
|
||||
*
|
||||
* @param I
|
||||
* @param <I>
|
||||
* The Id type. This is most often a {@link Long} but is also often a {@link UUID} or
|
||||
* {@link String}.
|
||||
*
|
||||
* @param T
|
||||
*
|
||||
* @param <T>
|
||||
* The bean type
|
||||
*/
|
||||
public static class Finder<I, T> {
|
||||
@@ -214,7 +267,7 @@ public class Model {
|
||||
* Retrieves an entity by ID.
|
||||
*
|
||||
* <p>
|
||||
* Equivilent to {@link EbeanServer#find(Class, Object)}
|
||||
* Equivalent to {@link EbeanServer#find(Class, Object)}
|
||||
*/
|
||||
public T byId(I id) {
|
||||
return db().find(type, id);
|
||||
@@ -224,7 +277,7 @@ public class Model {
|
||||
* Creates an entity reference for this ID.
|
||||
*
|
||||
* <p>
|
||||
* Equivilent to {@link EbeanServer#getReference(Class, Object)}
|
||||
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
|
||||
*/
|
||||
public T ref(I id) {
|
||||
return db().getReference(type, id);
|
||||
@@ -234,7 +287,7 @@ public class Model {
|
||||
* Creates a filter for sorting and filtering lists of entities locally without going back to
|
||||
* the database.
|
||||
* <p>
|
||||
* Equivilent to {@link EbeanServer#filter(Class)}
|
||||
* Equivalent to {@link EbeanServer#filter(Class)}
|
||||
*/
|
||||
public Filter<T> filter() {
|
||||
return db().filter(type);
|
||||
@@ -243,12 +296,19 @@ public class Model {
|
||||
/**
|
||||
* Creates a query.
|
||||
* <p>
|
||||
* Equivilent to {@link EbeanServer#find(Class)}
|
||||
* Equivalent to {@link EbeanServer#find(Class)}
|
||||
*/
|
||||
public Query<T> query() {
|
||||
return db().find(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query applying the path properties to set the select and fetch clauses.
|
||||
*/
|
||||
public Query<T> apply(PathProperties pathProperties) {
|
||||
return db().find(type).apply(pathProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next identity value.
|
||||
*
|
||||
@@ -262,18 +322,49 @@ public class Model {
|
||||
/**
|
||||
* Executes a query and returns the results as a list of IDs.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#findIds()}
|
||||
* Equivalent to {@link Query#findIds()}
|
||||
*/
|
||||
public List<Object> findIds() {
|
||||
return query().findIds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query consuming each bean one at a time.
|
||||
* <p>
|
||||
* This is generally used to process large queries where unlike findList
|
||||
* you do not want to hold all the results in memory at once but instead
|
||||
* process them one at a time (requiring far less memory).
|
||||
* </p>
|
||||
* Equivalent to {@link Query#findEach(QueryEachConsumer)}
|
||||
*/
|
||||
public void findEach(QueryEachConsumer<T> consumer) {
|
||||
query().findEach(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the query consuming each bean one at a time.
|
||||
* <p>
|
||||
* This is similar to #findEach except that you return boolean
|
||||
* true to continue processing beans and return false to stop
|
||||
* processing early.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is generally used to process large queries where unlike findList
|
||||
* you do not want to hold all the results in memory at once but instead
|
||||
* process them one at a time (requiring far less memory).
|
||||
* </p>
|
||||
* Equivalent to {@link Query#findEachWhile(QueryEachWhileConsumer)}
|
||||
*/
|
||||
public void findEachWhile(QueryEachWhileConsumer<T> consumer) {
|
||||
query().findEachWhile(consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all entities of the given type.
|
||||
* <p>
|
||||
* The same as {@link #all()}
|
||||
* <p>
|
||||
* Equivilent to {@link Query#findList()}
|
||||
* Equivalent to {@link Query#findList()}
|
||||
*/
|
||||
public List<T> findList() {
|
||||
return query().findList();
|
||||
@@ -282,7 +373,7 @@ public class Model {
|
||||
/**
|
||||
* Returns all the entities of the given type as a set.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#findSet()}
|
||||
* Equivalent to {@link Query#findSet()}
|
||||
*/
|
||||
public Set<T> findSet() {
|
||||
return query().findSet();
|
||||
@@ -291,7 +382,7 @@ public class Model {
|
||||
/**
|
||||
* Retrieves all entities of the given type as a map of objects.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#findMap()}
|
||||
* Equivalent to {@link Query#findMap()}
|
||||
*/
|
||||
public Map<?, T> findMap() {
|
||||
return query().findMap();
|
||||
@@ -301,7 +392,7 @@ public class Model {
|
||||
* Executes the query and returns the results as a map of the objects specifying the map key
|
||||
* property.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#findMap(String, Class)}
|
||||
* Equivalent to {@link Query#findMap(String, Class)}
|
||||
*/
|
||||
public <K> Map<K, T> findMap(String keyProperty, Class<K> keyType) {
|
||||
return query().findMap(keyProperty, keyType);
|
||||
@@ -311,7 +402,7 @@ public class Model {
|
||||
* Return a PagedList of all entities of the given type (use where() to specify predicates as
|
||||
* needed).
|
||||
* <p>
|
||||
* Equivilent to {@link Query#findPagedList(int, int)}
|
||||
* Equivalent to {@link Query#findPagedList(int, int)}
|
||||
*/
|
||||
public PagedList<T> findPagedList(int pageIndex, int pageSize) {
|
||||
return query().findPagedList(pageIndex, pageSize);
|
||||
@@ -320,7 +411,7 @@ public class Model {
|
||||
/**
|
||||
* Executes a find row count query in a background thread.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#findFutureRowCount()}
|
||||
* Equivalent to {@link Query#findFutureRowCount()}
|
||||
*/
|
||||
public FutureRowCount<T> findFutureRowCount() {
|
||||
return query().findFutureRowCount();
|
||||
@@ -329,7 +420,7 @@ public class Model {
|
||||
/**
|
||||
* Returns the total number of entities for this type. *
|
||||
* <p>
|
||||
* Equivilent to {@link Query#findRowCount()}
|
||||
* Equivalent to {@link Query#findRowCount()}
|
||||
*/
|
||||
public int findRowCount() {
|
||||
return query().findRowCount();
|
||||
@@ -346,7 +437,7 @@ public class Model {
|
||||
* Explicitly sets a comma delimited list of the properties to fetch on the 'main' entity bean,
|
||||
* to load a partial object.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#select(String)}
|
||||
* Equivalent to {@link Query#select(String)}
|
||||
*/
|
||||
public Query<T> select(String fetchProperties) {
|
||||
return query().select(fetchProperties);
|
||||
@@ -355,7 +446,7 @@ public class Model {
|
||||
/**
|
||||
* Specifies a path to load including all its properties.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#fetch(String)}
|
||||
* Equivalent to {@link Query#fetch(String)}
|
||||
*/
|
||||
public Query<T> fetch(String path) {
|
||||
return query().fetch(path);
|
||||
@@ -365,7 +456,7 @@ public class Model {
|
||||
* Additionally specifies a <code>FetchConfig</code> to specify a 'query join' and/or define the
|
||||
* lazy loading query.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#fetch(String, FetchConfig)}
|
||||
* Equivalent to {@link Query#fetch(String, FetchConfig)}
|
||||
*/
|
||||
public Query<T> fetch(String path, FetchConfig joinConfig) {
|
||||
return query().fetch(path, joinConfig);
|
||||
@@ -375,7 +466,7 @@ public class Model {
|
||||
* Specifies a path to fetch with a specific list properties to include, to load a partial
|
||||
* object.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#fetch(String, String)}
|
||||
* Equivalent to {@link Query#fetch(String, String)}
|
||||
*/
|
||||
public Query<T> fetch(String path, String fetchProperties) {
|
||||
return query().fetch(path, fetchProperties);
|
||||
@@ -385,7 +476,7 @@ public class Model {
|
||||
* Additionally specifies a <code>FetchConfig</code> to use a separate query or lazy loading to
|
||||
* load this path.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#fetch(String, String, FetchConfig)}
|
||||
* Equivalent to {@link Query#fetch(String, String, FetchConfig)}
|
||||
*/
|
||||
public Query<T> fetch(String assocProperty, String fetchProperties, FetchConfig fetchConfig) {
|
||||
return query().fetch(assocProperty, fetchProperties, fetchConfig);
|
||||
@@ -395,7 +486,7 @@ public class Model {
|
||||
* Adds expressions to the <code>where</code> clause with the ability to chain on the
|
||||
* <code>ExpressionList</code>.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#where()}
|
||||
* Equivalent to {@link Query#where()}
|
||||
*/
|
||||
public ExpressionList<T> where() {
|
||||
return query().where();
|
||||
@@ -407,7 +498,7 @@ public class Model {
|
||||
* <p>
|
||||
* This is exactly the same as {@link #orderBy}.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#order()}
|
||||
* Equivalent to {@link Query#order()}
|
||||
*/
|
||||
public OrderBy<T> order() {
|
||||
return query().order();
|
||||
@@ -429,7 +520,7 @@ public class Model {
|
||||
* <p>
|
||||
* This is exactly the same as {@link #order}.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#orderBy()}
|
||||
* Equivalent to {@link Query#orderBy()}
|
||||
*/
|
||||
public OrderBy<T> orderBy() {
|
||||
return query().orderBy();
|
||||
@@ -448,7 +539,7 @@ public class Model {
|
||||
/**
|
||||
* Sets the first row to return for this query.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#setFirstRow(int)}
|
||||
* Equivalent to {@link Query#setFirstRow(int)}
|
||||
*/
|
||||
public Query<T> setFirstRow(int firstRow) {
|
||||
return query().setFirstRow(firstRow);
|
||||
@@ -457,7 +548,7 @@ public class Model {
|
||||
/**
|
||||
* Sets the maximum number of rows to return in the query.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#setMaxRows(int)}
|
||||
* Equivalent to {@link Query#setMaxRows(int)}
|
||||
*/
|
||||
public Query<T> setMaxRows(int maxRows) {
|
||||
return query().setMaxRows(maxRows);
|
||||
@@ -470,7 +561,7 @@ public class Model {
|
||||
* Use this to perform a find byId query but with additional control over the query such as
|
||||
* using select and fetch to control what parts of the object graph are returned.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#setId(Object)}
|
||||
* Equivalent to {@link Query#setId(Object)}
|
||||
*/
|
||||
public Query<T> setId(Object id) {
|
||||
return query().setId(id);
|
||||
@@ -479,7 +570,7 @@ public class Model {
|
||||
/**
|
||||
* Create and return a new query using the OQL.
|
||||
* <p>
|
||||
* Equivilent to {@link EbeanServer#createQuery(Class, String)}
|
||||
* Equivalent to {@link EbeanServer#createQuery(Class, String)}
|
||||
*/
|
||||
public Query<T> setQuery(String oql) {
|
||||
return db().createQuery(type, oql);
|
||||
@@ -488,7 +579,7 @@ public class Model {
|
||||
/**
|
||||
* Create and return a new query based on the <code>RawSql</code>.
|
||||
* <p>
|
||||
* Equivilent to {@link Query#setRawSql(RawSql)}
|
||||
* Equivalent to {@link Query#setRawSql(RawSql)}
|
||||
*/
|
||||
public Query<T> setRawSql(RawSql rawSql) {
|
||||
return query().setRawSql(rawSql);
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Defines the scope for PersistenceContext.
|
||||
* <p/>
|
||||
* Ebean has traditionally used Transaction scope for the PersistenceContext. This is used to change the scope to
|
||||
* use (by default) and explicitly set the scope to use for an individual query.
|
||||
*
|
||||
* @see com.avaje.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)
|
||||
* @see com.avaje.ebean.Query#setPersistenceContextScope(PersistenceContextScope)
|
||||
*/
|
||||
public enum PersistenceContextScope {
|
||||
|
||||
/**
|
||||
* PersistenceContext is scoped to the transaction.
|
||||
* <p/>
|
||||
* If a transaction spans 2 or more queries that fetch the same bean in terms of same type
|
||||
* and same Id value then they share the same bean instance.
|
||||
* <p/>
|
||||
* You may want to change to use QUERY scope when you want a query executing in a transaction to effectively
|
||||
* ignore beans that have already been loaded (by other queries in the same transaction) and instead get a
|
||||
* 'fresh copy' of the bean.
|
||||
*/
|
||||
TRANSACTION,
|
||||
|
||||
/**
|
||||
* PersistenceContext is scoped to the query.
|
||||
* <p/>
|
||||
* This means that for this query running in an existing transaction then it will effectively ignore any beans
|
||||
* that have already been queried/loaded by prior queries in the same transaction.
|
||||
* <p/>
|
||||
* You may use QUERY scope on a query that is executed in a transaction and you want to get a 'fresh copy' of the bean.
|
||||
*/
|
||||
QUERY
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -299,6 +301,21 @@ public interface Query<T> extends Serializable {
|
||||
*/
|
||||
public Query<T> copy();
|
||||
|
||||
/**
|
||||
* Specify the PersistenceContextScope to use for this query.
|
||||
* <p/>
|
||||
* When this is not set the 'default' configured on {@link com.avaje.ebean.config.ServerConfig#setPersistenceContextScope(PersistenceContextScope)}
|
||||
* is used - this value defaults to {@link com.avaje.ebean.PersistenceContextScope#TRANSACTION}.
|
||||
* <p/>
|
||||
* Note that the same persistence Context is used for subsequent lazy loading and query join queries.
|
||||
* <p/>
|
||||
* Note that #findEach uses a 'per object graph' PersistenceContext so this scope is ignored for
|
||||
* queries executed as #findIterate, #findEach, #findEachWhile.
|
||||
*
|
||||
* @param scope The scope to use for this query and subsequent lazy loading.
|
||||
*/
|
||||
public Query<T> setPersistenceContextScope(PersistenceContextScope scope);
|
||||
|
||||
/**
|
||||
* Return the ExpressionFactory used by this query.
|
||||
*/
|
||||
@@ -323,22 +340,32 @@ public interface Query<T> extends Serializable {
|
||||
*/
|
||||
public Query<T> setAutofetch(boolean autofetch);
|
||||
|
||||
/**
|
||||
* Set the default lazy loading batch size to use.
|
||||
* <p>
|
||||
* When lazy loading is invoked on beans loaded by this query then this sets the
|
||||
* batch size used to load those beans.
|
||||
*
|
||||
* @param lazyLoadBatchSize the number of beans to lazy load in a single batch
|
||||
*/
|
||||
public Query<T> setLazyLoadBatchSize(int lazyLoadBatchSize);
|
||||
|
||||
/**
|
||||
* Explicitly set a comma delimited list of the properties to fetch on the
|
||||
* 'main' entity bean (aka partial object). Note that '*' means all
|
||||
* properties.
|
||||
*
|
||||
*
|
||||
* <pre class="code">
|
||||
* Query<Customer> query = Ebean.createQuery(Customer.class);
|
||||
*
|
||||
*
|
||||
* // Only fetch the customer id, name and status.
|
||||
* // This is described as a "Partial Object"
|
||||
* query.select("name, status");
|
||||
* query.where("lower(name) like :custname").setParameter("custname", "rob%");
|
||||
*
|
||||
*
|
||||
* List<Customer> customerList = query.findList();
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @param fetchProperties
|
||||
* the properties to fetch for this bean (* = all properties).
|
||||
*/
|
||||
@@ -413,6 +440,14 @@ public interface Query<T> extends Serializable {
|
||||
*/
|
||||
public Query<T> fetch(String path, FetchConfig joinConfig);
|
||||
|
||||
/**
|
||||
* Apply the path properties replacing the select and fetch clauses.
|
||||
* <p>
|
||||
* This is typically used when the PathProperties is applied to both the query and the JSON output.
|
||||
* </p>
|
||||
*/
|
||||
public Query<T> apply(PathProperties pathProperties);
|
||||
|
||||
/**
|
||||
* Execute the query returning the list of Id's.
|
||||
* <p>
|
||||
@@ -436,37 +471,89 @@ public interface Query<T> extends Serializable {
|
||||
*/
|
||||
public 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
|
||||
*/
|
||||
public void findVisit(QueryResultVisitor<T> visitor);
|
||||
|
||||
/**
|
||||
* Execute the query processing the beans one at a time.
|
||||
* <p>
|
||||
* This method is appropriate to process very large query results as the
|
||||
* beans are consumed one at a time and do not need to be held in memory
|
||||
* (unlike #findList #findSet etc)
|
||||
* </p>
|
||||
* <p>
|
||||
* Compared with #findEachWhile this will always process all the beans where as
|
||||
* #findEachWhile provides a way to stop processing the query result early before
|
||||
* all the beans have been read.
|
||||
* </p>
|
||||
* <p>
|
||||
* This method is functionally equivalent to findIterate() but instead of using an
|
||||
* iterator uses the QueryEachConsumer (SAM) interface which is better suited to use
|
||||
* with Java8 closures.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* query.findVisit((Customer customer) -> {
|
||||
*
|
||||
* // do something with customer
|
||||
* System.out.println("-- visit " + customer);
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param consumer
|
||||
* the consumer used to process the queried beans.
|
||||
*/
|
||||
public void findEach(QueryEachConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query using callbacks to a visitor to process the resulting
|
||||
* beans one at a time.
|
||||
* <p>
|
||||
* Similar to findIterate() this query method does not require all the result
|
||||
* beans to be all held in memory at once and as such is useful for processing
|
||||
* large queries.
|
||||
* This method is functionally equivalent to findIterate() but instead of using an
|
||||
* iterator uses the QueryEachWhileConsumer (SAM) interface which is better suited to use
|
||||
* with Java8 closures.
|
||||
* </p>
|
||||
*
|
||||
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* query.findVisit(new QueryResultVisitor<Customer>() {
|
||||
*
|
||||
* public boolean accept(Customer customer) {
|
||||
*
|
||||
* query.findEachWhile((Customer customer) -> {
|
||||
*
|
||||
* // do something with customer
|
||||
* System.out.println("-- visit " + customer);
|
||||
* return true;
|
||||
* }
|
||||
*
|
||||
* // return true to continue processing or false to stop
|
||||
* return (customer.getId() < 40);
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param visitor
|
||||
* the visitor used to process the queried beans.
|
||||
*
|
||||
* @param consumer
|
||||
* the consumer used to process the queried beans.
|
||||
*/
|
||||
public void findVisit(QueryResultVisitor<T> visitor);
|
||||
public void findEachWhile(QueryEachWhileConsumer<T> consumer);
|
||||
|
||||
/**
|
||||
* Execute the query returning the list of objects.
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Used to process a query result one bean at a time via a callback to this
|
||||
* visitor.
|
||||
* <p>
|
||||
* If you wish to stop further processing return false from the accept method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Unlike findList() and findSet() using a QueryResultVisitor does not require
|
||||
* all the beans in the query result to be held in memory at once. This makes
|
||||
* QueryResultVisitor useful for processing large queries.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* query.findVisit((Customer customer) -> {
|
||||
*
|
||||
* // do something with customer
|
||||
* System.out.println("-- visit " + customer);
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean being queried.
|
||||
*/
|
||||
public interface QueryEachConsumer<T> {
|
||||
|
||||
/**
|
||||
* Process the bean.
|
||||
*
|
||||
* @param bean
|
||||
* the entity bean to process
|
||||
*/
|
||||
public void accept(T bean);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
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>
|
||||
* <p/>
|
||||
* <pre class="code">
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .fetch("contacts", new FetchConfig().query(2))
|
||||
* .where().gt("id", 0)
|
||||
* .orderBy("id")
|
||||
* .setMaxRows(2);
|
||||
*
|
||||
* query.findEachWhile((Customer customer) -> {
|
||||
*
|
||||
* // do something with customer
|
||||
* System.out.println("-- visit " + customer);
|
||||
*
|
||||
* // return true to continue processing or false to stop
|
||||
* return (customer.getId() < 40);
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param <T> the type of entity bean being queried.
|
||||
*/
|
||||
public interface QueryEachWhileConsumer<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 more beans or false to stop.
|
||||
*/
|
||||
public boolean accept(T bean);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.ResultSet;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
@@ -135,18 +136,33 @@ import com.avaje.ebean.util.CamelCaseHelper;
|
||||
* Note that lazy loading also works with object graphs built with RawSql.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public final class RawSql implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final ResultSet resultSet;
|
||||
|
||||
private final Sql sql;
|
||||
|
||||
private final ColumnMapping columnMapping;
|
||||
|
||||
protected RawSql(Sql sql, ColumnMapping columnMapping) {
|
||||
/**
|
||||
* Construct with a ResultSet and properties that the columns map to.
|
||||
* <p>
|
||||
* The properties listed in the propertyNames must be in the same order as the columns in the
|
||||
* resultSet.
|
||||
* <p>
|
||||
* When a query executes this RawSql object then it will close the resultSet.
|
||||
*/
|
||||
public RawSql(ResultSet resultSet, String... propertyNames) {
|
||||
this.resultSet = resultSet;
|
||||
this.sql = null;
|
||||
this.columnMapping = new ColumnMapping(propertyNames);
|
||||
}
|
||||
|
||||
protected RawSql(ResultSet resultSet, Sql sql, ColumnMapping columnMapping) {
|
||||
this.resultSet = resultSet;
|
||||
this.sql = sql;
|
||||
this.columnMapping = columnMapping;
|
||||
}
|
||||
@@ -158,6 +174,14 @@ public final class RawSql implements Serializable {
|
||||
return sql;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the resultSet if this is a ResultSet based RawSql.
|
||||
*/
|
||||
public ResultSet getResultSet() {
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column mapping for the SQL columns to bean properties.
|
||||
*/
|
||||
@@ -169,6 +193,9 @@ public final class RawSql implements Serializable {
|
||||
* Return the hash for this query.
|
||||
*/
|
||||
public int queryHash() {
|
||||
if (resultSet != null) {
|
||||
return 31 * columnMapping.queryHash();
|
||||
}
|
||||
return 31 * sql.queryHash() + columnMapping.queryHash();
|
||||
}
|
||||
|
||||
@@ -329,6 +356,7 @@ public final class RawSql implements Serializable {
|
||||
private final LinkedHashMap<String, Column> dbColumnMap;
|
||||
|
||||
private final Map<String, String> propertyMap;
|
||||
|
||||
private final Map<String, Column> propertyColumnMap;
|
||||
|
||||
private final boolean parsed;
|
||||
@@ -364,6 +392,26 @@ public final class RawSql implements Serializable {
|
||||
this.propertyColumnMap = null;
|
||||
this.dbColumnMap = new LinkedHashMap<String, Column>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct for ResultSet use.
|
||||
*/
|
||||
protected ColumnMapping(String... propertyNames) {
|
||||
this.immutable = false;
|
||||
this.parsed = false;
|
||||
this.propertyMap = null;
|
||||
//this.propertyColumnMap = null;
|
||||
this.dbColumnMap = new LinkedHashMap<String, Column>();
|
||||
|
||||
int hc = 31;
|
||||
int pos = 0;
|
||||
for (String prop : propertyNames) {
|
||||
hc = 31 * hc + prop.hashCode();
|
||||
dbColumnMap.put(prop, new Column(pos++, prop, null, prop));
|
||||
}
|
||||
propertyColumnMap = dbColumnMap;
|
||||
this.queryHashCode = hc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an immutable ColumnMapping based on collected information.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import com.avaje.ebean.RawSql.ColumnMapping;
|
||||
import com.avaje.ebean.RawSql.Sql;
|
||||
|
||||
@@ -10,8 +12,6 @@ import com.avaje.ebean.RawSql.Sql;
|
||||
* named query.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @see RawSql
|
||||
*/
|
||||
public class RawSqlBuilder {
|
||||
@@ -21,10 +21,23 @@ public class RawSqlBuilder {
|
||||
*/
|
||||
public static final String IGNORE_COLUMN = "$$_IGNORE_COLUMN_$$";
|
||||
|
||||
private final ResultSet resultSet;
|
||||
|
||||
private final Sql sql;
|
||||
|
||||
private final ColumnMapping columnMapping;
|
||||
|
||||
/**
|
||||
* Create and return a RawSql object based on the resultSet and list of properties the columns in
|
||||
* the resultSet map to.
|
||||
* <p>
|
||||
* The properties listed in the propertyNames must be in the same order as the columns in the
|
||||
* resultSet.
|
||||
*/
|
||||
public static RawSql resultSet(ResultSet resultSet, String... propertyNames) {
|
||||
return new RawSql(resultSet, propertyNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an unparsed RawSqlBuilder. Unlike a parsed one this query can not be
|
||||
* modified - so no additional WHERE or HAVING expressions can be added to
|
||||
@@ -58,9 +71,17 @@ public class RawSqlBuilder {
|
||||
return new RawSqlBuilder(sql2, mapping);
|
||||
}
|
||||
|
||||
|
||||
private RawSqlBuilder(ResultSet resultSet, ColumnMapping columnMapping) {
|
||||
this.resultSet = resultSet;
|
||||
this.columnMapping = columnMapping;
|
||||
this.sql = null;
|
||||
}
|
||||
|
||||
private RawSqlBuilder(Sql sql, ColumnMapping columnMapping) {
|
||||
this.sql = sql;
|
||||
this.columnMapping = columnMapping;
|
||||
this.resultSet = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +113,7 @@ public class RawSqlBuilder {
|
||||
* has been defined.
|
||||
*/
|
||||
public RawSql create() {
|
||||
return new RawSql(sql, columnMapping.createImmutableCopy());
|
||||
return new RawSql(resultSet, sql, columnMapping.createImmutableCopy());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,4 +122,6 @@ public class RawSqlBuilder {
|
||||
protected Sql getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
public class SimpleTextParser {
|
||||
class SimpleTextParser {
|
||||
|
||||
private final String oql;
|
||||
private final char[] chars;
|
||||
@@ -10,9 +10,7 @@ public class SimpleTextParser {
|
||||
private String word;
|
||||
private String lowerWord;
|
||||
|
||||
private int openParenthesisCount;
|
||||
|
||||
public SimpleTextParser(String oql) {
|
||||
SimpleTextParser(String oql) {
|
||||
this.oql = oql;
|
||||
this.chars = oql.toCharArray();
|
||||
this.eof = oql.length();
|
||||
@@ -22,10 +20,6 @@ public class SimpleTextParser {
|
||||
return pos;
|
||||
}
|
||||
|
||||
public String getOql() {
|
||||
return oql;
|
||||
}
|
||||
|
||||
public String getWord() {
|
||||
return word;
|
||||
}
|
||||
@@ -104,7 +98,7 @@ public class SimpleTextParser {
|
||||
private void moveToClose() {
|
||||
|
||||
pos++;
|
||||
openParenthesisCount = 0;
|
||||
int openParenthesisCount = 0;
|
||||
|
||||
for (; pos < eof; pos++) {
|
||||
char c = chars[pos];
|
||||
@@ -143,11 +137,7 @@ public class SimpleTextParser {
|
||||
if (isOperator(c)) {
|
||||
return !isOperator;
|
||||
}
|
||||
if (c == '(') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isOperator;
|
||||
return c == '(' || isOperator;
|
||||
}
|
||||
|
||||
private boolean isOperator(char c) {
|
||||
|
||||
@@ -91,6 +91,11 @@ public interface SqlUpdate {
|
||||
*/
|
||||
public String getSql();
|
||||
|
||||
/**
|
||||
* Return the generated sql that has named parameters converted to positioned parameters.
|
||||
*/
|
||||
public String getGeneratedSql();
|
||||
|
||||
/**
|
||||
* Return the timeout used to execute this statement.
|
||||
*/
|
||||
|
||||
@@ -35,6 +35,11 @@ public interface Transaction extends Closeable {
|
||||
*/
|
||||
public static final int SERIALIZABLE = java.sql.Connection.TRANSACTION_SERIALIZABLE;
|
||||
|
||||
/**
|
||||
* Register a TransactionCallback with this transaction.
|
||||
*/
|
||||
public void register(TransactionCallback callback);
|
||||
|
||||
/**
|
||||
* Return true if this transaction is read only.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Provides a callback that can be registered with a Transaction.
|
||||
* <p/>
|
||||
* The callback methods are called just prior to and after the transaction performs a commit or rollback.
|
||||
* <p/>
|
||||
* A typical use of TransactionCallback would be to clean up non-transactional resources like files. For example,
|
||||
* when processing files on postCommit/postRollback clean up the associated files. As another example when
|
||||
* on postCommit of a delete remove associated resources from the file system or remote service.
|
||||
*/
|
||||
public interface TransactionCallback {
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction commit.
|
||||
*/
|
||||
void preCommit();
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction commit.
|
||||
*/
|
||||
void postCommit();
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction rollback.
|
||||
*/
|
||||
void preRollback();
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction rollback.
|
||||
*/
|
||||
void postRollback();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Adapter that can be extended for easier implementation of TransactionCallback.
|
||||
* <p/>
|
||||
* Provides 'no operation' implementation for each of the TransactionCallback methods. It is expected that this
|
||||
* class is extended and override the methods you need to.
|
||||
*/
|
||||
public abstract class TransactionCallbackAdapter implements TransactionCallback {
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction commit.
|
||||
*/
|
||||
@Override
|
||||
public void preCommit() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction commit.
|
||||
*/
|
||||
@Override
|
||||
public void postCommit() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform processing just prior to the transaction rollback.
|
||||
*/
|
||||
@Override
|
||||
public void preRollback() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform processing just after the transaction rollback.
|
||||
*/
|
||||
@Override
|
||||
public void postRollback() {
|
||||
// do nothing - override as necessary
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface ColumnHstore {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* An annotation for declaring an index on a single column.
|
||||
*
|
||||
* @author rvbiljouw
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Index {
|
||||
|
||||
/**
|
||||
* Name of the index
|
||||
*
|
||||
* @return index name
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
}
|
||||
@@ -55,21 +55,6 @@ import com.avaje.ebean.TxType;
|
||||
* Ebean.save(order);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* During development and testing you can set a debug level which will log the
|
||||
* transaction begin, commit and rollback events so that you can easily confirm
|
||||
* it is behaving as you would expect.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* ## in ebean.properties file
|
||||
*
|
||||
* ## Log transaction begins and ends etc
|
||||
* ## (0=NoLogging 1=minimal ... 9=logAll)
|
||||
* ebean.debug.transaction=3
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
||||
@@ -31,6 +31,13 @@ public interface BeanCollection<E> extends Serializable {
|
||||
ALL
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the collection back to an empty state ready for reloading.
|
||||
* <p>
|
||||
* This is done as part of bean refresh.
|
||||
*/
|
||||
public void reset(EntityBean ownerBean, String propertyName);
|
||||
|
||||
/**
|
||||
* Return true if the collection is empty and untouched. Used to detect if a
|
||||
* collection was 'cleared' deliberately or just un-initialised.
|
||||
@@ -47,14 +54,6 @@ public interface BeanCollection<E> extends Serializable {
|
||||
*/
|
||||
public String getPropertyName();
|
||||
|
||||
/**
|
||||
* Return the index position of this collection in the lazy/query loader.
|
||||
* <p>
|
||||
* Used for batch loading of collections.
|
||||
* </p>
|
||||
*/
|
||||
public int getLoaderIndex();
|
||||
|
||||
/**
|
||||
* Check after the lazy load that the underlying collection is not null
|
||||
* (handle case where join to many not outer).
|
||||
@@ -108,11 +107,6 @@ public interface BeanCollection<E> extends Serializable {
|
||||
*/
|
||||
public void internalAdd(Object bean);
|
||||
|
||||
/**
|
||||
* Returns the underlying List Set or Map object.
|
||||
*/
|
||||
public Object getActualCollection();
|
||||
|
||||
/**
|
||||
* Return the number of elements in the List Set or Map.
|
||||
*/
|
||||
@@ -137,22 +131,6 @@ public interface BeanCollection<E> extends Serializable {
|
||||
*/
|
||||
public Collection<?> getActualEntries();
|
||||
|
||||
/**
|
||||
* Set to true if maxRows was hit and there are actually more rows available.
|
||||
* <p>
|
||||
* Can be used by client code that is paging through results using
|
||||
* setFirstRow() setMaxRows(). If this returns true then the client can
|
||||
* display a 'next' button etc.
|
||||
* </p>
|
||||
*/
|
||||
public boolean hasMoreRows();
|
||||
|
||||
/**
|
||||
* Set to true when maxRows is hit but there are actually more rows available.
|
||||
* This is set so that client code knows that there is more data available.
|
||||
*/
|
||||
public void setHasMoreRows(boolean hasMoreRows);
|
||||
|
||||
/**
|
||||
* return true if there are real rows held. Return false is this is using
|
||||
* Deferred fetch to lazy load the rows and the rows have not yet been
|
||||
|
||||
@@ -39,8 +39,6 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
private transient PersistenceContext persistenceContext;
|
||||
|
||||
private transient BeanLoader beanLoader;
|
||||
|
||||
private int beanLoaderIndex;
|
||||
|
||||
private String ebeanServerName;
|
||||
|
||||
@@ -200,34 +198,22 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index position for batch loading via BeanLoader.
|
||||
* Set the BeanLoader with PersistenceContext.
|
||||
*/
|
||||
public int getBeanLoaderIndex() {
|
||||
return beanLoaderIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Lazy Loading by ebeanServerName.
|
||||
* <p>
|
||||
* This is for reference beans created by themselves.
|
||||
* </p>
|
||||
*/
|
||||
public void setBeanLoaderByServerName(String ebeanServerName) {
|
||||
this.beanLoaderIndex = 0;
|
||||
this.beanLoader = null;
|
||||
this.ebeanServerName = ebeanServerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the BeanLoader for general lazy loading.
|
||||
*/
|
||||
public void setBeanLoader(int index, BeanLoader beanLoader, PersistenceContext ctx) {
|
||||
this.beanLoaderIndex = index;
|
||||
public void setBeanLoader(BeanLoader beanLoader, PersistenceContext ctx) {
|
||||
this.beanLoader = beanLoader;
|
||||
this.persistenceContext = ctx;
|
||||
this.ebeanServerName = beanLoader.getName();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the BeanLoader.
|
||||
*/
|
||||
public void setBeanLoader(BeanLoader beanLoader) {
|
||||
this.beanLoader = beanLoader;
|
||||
this.ebeanServerName = beanLoader.getName();
|
||||
}
|
||||
|
||||
public boolean isFullyLoadedBean() {
|
||||
return fullyLoadedBean;
|
||||
}
|
||||
|
||||
@@ -38,18 +38,12 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
/**
|
||||
* The owning bean (used for lazy fetch).
|
||||
*/
|
||||
protected final EntityBean ownerBean;
|
||||
protected EntityBean ownerBean;
|
||||
|
||||
/**
|
||||
* The name of this property in the owning bean (used for lazy fetch).
|
||||
*/
|
||||
protected final String propertyName;
|
||||
|
||||
/**
|
||||
* Flag set to true if rows are limited by firstRow maxRows and more rows
|
||||
* exist. For use by client to enable 'next' for paging.
|
||||
*/
|
||||
protected boolean hasMoreRows;
|
||||
protected String propertyName;
|
||||
|
||||
protected ModifyHolder<E> modifyHolder;
|
||||
|
||||
@@ -68,8 +62,6 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
* Constructor not non-lazy loading collection.
|
||||
*/
|
||||
public AbstractBeanCollection() {
|
||||
this.ownerBean = null;
|
||||
this.propertyName = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,10 +83,6 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
return propertyName;
|
||||
}
|
||||
|
||||
public int getLoaderIndex() {
|
||||
return loaderIndex;
|
||||
}
|
||||
|
||||
public ExpressionList<?> getFilterMany() {
|
||||
return filterMany;
|
||||
}
|
||||
@@ -151,26 +139,6 @@ public abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if maxRows was hit and there are actually more rows available.
|
||||
* <p>
|
||||
* Can be used by client code that is paging through results using
|
||||
* setFirstRow() setMaxRows(). If this returns true then the client can
|
||||
* display a 'next' button etc.
|
||||
* </p>
|
||||
*/
|
||||
public boolean hasMoreRows() {
|
||||
return hasMoreRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true when maxRows is hit but there are actually more rows available.
|
||||
* This is set so that client code knows that there is more data available.
|
||||
*/
|
||||
public void setHasMoreRows(boolean hasMoreRows) {
|
||||
this.hasMoreRows = hasMoreRows;
|
||||
}
|
||||
|
||||
protected void checkReadOnly() {
|
||||
if (readOnly) {
|
||||
String msg = "This collection is in ReadOnly mode";
|
||||
|
||||
@@ -46,6 +46,14 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
super(loader, ownerBean, propertyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(EntityBean ownerBean, String propertyName) {
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.list = null;
|
||||
this.touched = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmptyAndUntouched() {
|
||||
return !touched && (list == null || list.isEmpty());
|
||||
@@ -130,13 +138,6 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying list.
|
||||
*/
|
||||
public Object getActualCollection() {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the underlying list is populated.
|
||||
*/
|
||||
@@ -153,7 +154,7 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuffer sb = new StringBuffer(50);
|
||||
sb.append("BeanList ");
|
||||
if (isReadOnly()) {
|
||||
sb.append("readOnly ");
|
||||
@@ -163,7 +164,6 @@ public final class BeanList<E> extends AbstractBeanCollection<E> implements List
|
||||
|
||||
} else {
|
||||
sb.append("size[").append(list.size()).append("] ");
|
||||
sb.append("hasMoreRows[").append(hasMoreRows).append("] ");
|
||||
sb.append("list").append(list).append("");
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
@@ -39,7 +39,15 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
public BeanMap(BeanCollectionLoader ebeanServer, EntityBean ownerBean, String propertyName) {
|
||||
super(ebeanServer, ownerBean, propertyName);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void reset(EntityBean ownerBean, String propertyName) {
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.map = null;
|
||||
this.touched = false;
|
||||
}
|
||||
|
||||
public boolean isEmptyAndUntouched() {
|
||||
return !touched && (map == null || map.isEmpty());
|
||||
}
|
||||
@@ -146,15 +154,8 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying map.
|
||||
*/
|
||||
public Object getActualCollection() {
|
||||
return map;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder(50);
|
||||
sb.append("BeanMap ");
|
||||
if (isReadOnly()) {
|
||||
sb.append("readOnly ");
|
||||
@@ -164,7 +165,6 @@ public final class BeanMap<K, E> extends AbstractBeanCollection<E> implements Ma
|
||||
|
||||
} else {
|
||||
sb.append("size[").append(map.size()).append("]");
|
||||
sb.append(" hasMoreRows[").append(hasMoreRows).append("]");
|
||||
sb.append(" map").append(map);
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
@@ -40,6 +40,14 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
super(loader, ownerBean, propertyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(EntityBean ownerBean, String propertyName) {
|
||||
this.ownerBean = ownerBean;
|
||||
this.propertyName = propertyName;
|
||||
this.set = null;
|
||||
this.touched = false;
|
||||
}
|
||||
|
||||
public boolean isEmptyAndUntouched() {
|
||||
return !touched && (set == null || set.isEmpty());
|
||||
}
|
||||
@@ -143,7 +151,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuffer sb = new StringBuffer(50);
|
||||
sb.append("BeanSet ");
|
||||
if (isReadOnly()) {
|
||||
sb.append("readOnly ");
|
||||
@@ -153,7 +161,6 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
|
||||
} else {
|
||||
sb.append("size[").append(set.size()).append("]");
|
||||
sb.append(" hasMoreRows[").append(hasMoreRows).append("]");
|
||||
sb.append(" set").append(set);
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
@@ -32,6 +32,8 @@ public class DataSourceConfig {
|
||||
|
||||
private int isolationLevel = Transaction.READ_COMMITTED;
|
||||
|
||||
private boolean autoCommit;
|
||||
|
||||
private String heartbeatSql;
|
||||
|
||||
private int heartbeatFreqSecs = 30;
|
||||
@@ -131,6 +133,20 @@ public class DataSourceConfig {
|
||||
public void setIsolationLevel(int isolationLevel) {
|
||||
this.isolationLevel = isolationLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return autoCommit setting.
|
||||
*/
|
||||
public boolean isAutoCommit() {
|
||||
return autoCommit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to turn on autoCommit.
|
||||
*/
|
||||
public void setAutoCommit(boolean autoCommit) {
|
||||
this.autoCommit = autoCommit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum number of connections the pool should maintain.
|
||||
@@ -450,6 +466,7 @@ public class DataSourceConfig {
|
||||
String dbUrl = properties.get(prefix + "databaseUrl", null);
|
||||
this.url = properties.get(prefix + "url", dbUrl);
|
||||
|
||||
this.autoCommit = properties.getBoolean(prefix + "autoCommit", false);
|
||||
this.captureStackTrace = properties.getBoolean(prefix + "captureStackTrace", false);
|
||||
this.maxStackTraceSize = properties.getInt(prefix + "maxStackTraceSize", 5);
|
||||
this.leakTimeMinutes = properties.getInt(prefix + "leakTimeMinutes", 30);
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Configuration for JSON features.
|
||||
*/
|
||||
public abstract class JsonConfig {
|
||||
|
||||
/**
|
||||
* Defined the format used for DateTime types.
|
||||
*/
|
||||
public enum DateTime {
|
||||
|
||||
/**
|
||||
* Format as epoch millis.
|
||||
*/
|
||||
MILLIS,
|
||||
|
||||
/**
|
||||
* Format as epoch with nanos.
|
||||
*/
|
||||
NANOS,
|
||||
|
||||
/**
|
||||
* Format as ISO-8601 date format.
|
||||
*/
|
||||
ISO8601
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A map like structure of properties.
|
||||
@@ -68,9 +67,8 @@ final class PropertyMap implements Serializable {
|
||||
}
|
||||
|
||||
synchronized void putAll(Map<String, String> keyValueMap) {
|
||||
Iterator<Entry<String, String>> it = keyValueMap.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<String, String> entry = it.next();
|
||||
|
||||
for (Map.Entry<String, String> entry : keyValueMap.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Helper used to load the PropertyMap.
|
||||
*/
|
||||
@@ -81,9 +79,7 @@ final class PropertyMapLoader {
|
||||
}
|
||||
|
||||
// put values in initially without any evaluation
|
||||
Iterator<Entry<Object, Object>> it = props.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry<Object, Object> entry = it.next();
|
||||
for (Map.Entry<Object, Object> entry : props.entrySet()) {
|
||||
String key = ((String) entry.getKey()).toLowerCase();
|
||||
String val = ((String) entry.getValue());
|
||||
if (val != null) {
|
||||
|
||||
@@ -1,25 +1,21 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.EbeanServerFactory;
|
||||
import com.avaje.ebean.PersistenceContextScope;
|
||||
import com.avaje.ebean.annotation.Encrypted;
|
||||
import com.avaje.ebean.cache.ServerCacheFactory;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.GlobalProperties.PropertySource;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncrypt;
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
import com.avaje.ebean.event.BeanPersistListener;
|
||||
import com.avaje.ebean.event.BeanQueryAdapter;
|
||||
import com.avaje.ebean.event.BulkTableEventListener;
|
||||
import com.avaje.ebean.event.ServerConfigStartup;
|
||||
import com.avaje.ebean.event.TransactionEventListener;
|
||||
import com.avaje.ebean.event.*;
|
||||
import com.avaje.ebean.meta.MetaInfoManager;
|
||||
import com.avaje.ebean.util.ClassUtil;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The configuration used for creating a EbeanServer.
|
||||
@@ -120,6 +116,11 @@ public class ServerConfig {
|
||||
*/
|
||||
private AutofetchConfig autofetchConfig = new AutofetchConfig();
|
||||
|
||||
/**
|
||||
* The JSON format used for DateTime types. Default to millis.
|
||||
*/
|
||||
private JsonConfig.DateTime jsonDateTime = JsonConfig.DateTime.MILLIS;
|
||||
|
||||
/**
|
||||
* The database platform name. Used to imply a DatabasePlatform to use.
|
||||
*/
|
||||
@@ -175,6 +176,13 @@ public class ServerConfig {
|
||||
*/
|
||||
private DataSourceConfig dataSourceConfig = new DataSourceConfig();
|
||||
|
||||
/**
|
||||
* Set to true if the DataSource uses autoCommit.
|
||||
* <p>
|
||||
* Indicates that Ebean should use autoCommit friendly Transactions and TransactionManager.
|
||||
*/
|
||||
private boolean autoCommitMode;
|
||||
|
||||
/**
|
||||
* The data source JNDI name if using a JNDI DataSource.
|
||||
*/
|
||||
@@ -209,10 +217,10 @@ public class ServerConfig {
|
||||
* Setting to indicate if UUID should be stored as binary(16) or varchar(40).
|
||||
*/
|
||||
private boolean uuidStoreAsBinary;
|
||||
|
||||
|
||||
|
||||
private List<BeanPersistController> persistControllers = new ArrayList<BeanPersistController>();
|
||||
private List<BeanPersistListener<?>> persistListeners = new ArrayList<BeanPersistListener<?>>();
|
||||
private List<BeanPersistListener> persistListeners = new ArrayList<BeanPersistListener>();
|
||||
private List<BeanQueryAdapter> queryAdapters = new ArrayList<BeanQueryAdapter>();
|
||||
private List<BulkTableEventListener> bulkTableEventListeners = new ArrayList<BulkTableEventListener>();
|
||||
private List<ServerConfigStartup> configStartupListeners = new ArrayList<ServerConfigStartup>();
|
||||
@@ -233,14 +241,56 @@ public class ServerConfig {
|
||||
private boolean collectQueryStatsByNode;
|
||||
|
||||
private boolean collectQueryOrigins;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a Server Configuration for programmatically creating an
|
||||
* EbeanServer.
|
||||
* The default PersistenceContextScope used if one is not explicitly set on a query.
|
||||
*/
|
||||
private PersistenceContextScope persistenceContextScope = PersistenceContextScope.TRANSACTION;
|
||||
|
||||
private JsonFactory jsonFactory;
|
||||
|
||||
private boolean localTimeWithNanos;
|
||||
|
||||
private boolean durationWithNanos;
|
||||
|
||||
/**
|
||||
* Construct a Server Configuration for programmatically creating an EbeanServer.
|
||||
*/
|
||||
public ServerConfig() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Jackson JsonFactory to use.
|
||||
* <p>
|
||||
* If not set a default implmentation will be used.
|
||||
*/
|
||||
public JsonFactory getJsonFactory() {
|
||||
return jsonFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Jackson JsonFactory to use.
|
||||
* <p>
|
||||
* If not set a default implmentation will be used.
|
||||
*/
|
||||
public void setJsonFactory(JsonFactory jsonFactory) {
|
||||
this.jsonFactory = jsonFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JSON format used for DateTime types.
|
||||
*/
|
||||
public JsonConfig.DateTime getJsonDateTime() {
|
||||
return jsonDateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JSON format to use for DateTime types.
|
||||
*/
|
||||
public void setJsonDateTime(JsonConfig.DateTime jsonDateTime) {
|
||||
this.jsonDateTime = jsonDateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the EbeanServer.
|
||||
@@ -582,6 +632,20 @@ public class ServerConfig {
|
||||
public void setDataSourceJndiName(String dataSourceJndiName) {
|
||||
this.dataSourceJndiName = dataSourceJndiName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if autoCommit mode is on. This indicates to Ebean to use autoCommit friendly Transactions and TransactionManager.
|
||||
*/
|
||||
public boolean isAutoCommitMode() {
|
||||
return autoCommitMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if autoCommit mode is on and Ebean should use autoCommit friendly Transactions and TransactionManager.
|
||||
*/
|
||||
public void setAutoCommitMode(boolean autoCommitMode) {
|
||||
this.autoCommitMode = autoCommitMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a value used to represent TRUE in the database.
|
||||
@@ -817,6 +881,43 @@ public class ServerConfig {
|
||||
this.uuidStoreAsBinary = uuidStoreAsBinary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if LocalTime should be persisted with nanos precision.
|
||||
*/
|
||||
public boolean isLocalTimeWithNanos() {
|
||||
return localTimeWithNanos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if LocalTime should be persisted with nanos precision.
|
||||
* <p>
|
||||
* Otherwise it is persisted using java.sql.Time which is seconds precision.
|
||||
* </p>
|
||||
*/
|
||||
public void setLocalTimeWithNanos(boolean localTimeWithNanos) {
|
||||
this.localTimeWithNanos = localTimeWithNanos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if Duration should be persisted with nanos precision (SQL DECIMAL).
|
||||
* <p>
|
||||
* Otherwise it is persisted with second precision (SQL INTEGER).
|
||||
* </p>
|
||||
*/
|
||||
public boolean isDurationWithNanos() {
|
||||
return durationWithNanos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if Duration should be persisted with nanos precision (SQL DECIMAL).
|
||||
* <p>
|
||||
* Otherwise it is persisted with second precision (SQL INTEGER).
|
||||
* </p>
|
||||
*/
|
||||
public void setDurationWithNanos(boolean durationWithNanos) {
|
||||
this.durationWithNanos = durationWithNanos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to run the DDL generation on startup.
|
||||
*/
|
||||
@@ -1153,14 +1254,14 @@ public class ServerConfig {
|
||||
* all the BeanPersistListener instances.
|
||||
* </p>
|
||||
*/
|
||||
public void add(BeanPersistListener<?> beanPersistListener) {
|
||||
public void add(BeanPersistListener beanPersistListener) {
|
||||
persistListeners.add(beanPersistListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanPersistListener instances.
|
||||
*/
|
||||
public List<BeanPersistListener<?>> getPersistListeners() {
|
||||
public List<BeanPersistListener> getPersistListeners() {
|
||||
return persistListeners;
|
||||
}
|
||||
|
||||
@@ -1199,10 +1300,39 @@ public class ServerConfig {
|
||||
* BeanPersistListener instances one at a time.
|
||||
* </p>
|
||||
*/
|
||||
public void setPersistListeners(List<BeanPersistListener<?>> persistListeners) {
|
||||
public void setPersistListeners(List<BeanPersistListener> persistListeners) {
|
||||
this.persistListeners = persistListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default PersistenceContextScope to be used if one is not explicitly set on a query.
|
||||
* <p/>
|
||||
* The PersistenceContextScope can specified on each query via {@link com.avaje.ebean
|
||||
* .Query#setPersistenceContextScope(com.avaje.ebean.PersistenceContextScope)}. If it
|
||||
* is not set on the query this default scope is used.
|
||||
*
|
||||
* @see com.avaje.ebean.Query#setPersistenceContextScope(com.avaje.ebean.PersistenceContextScope)
|
||||
*/
|
||||
public PersistenceContextScope getPersistenceContextScope() {
|
||||
// if somehow null return TRANSACTION scope
|
||||
return persistenceContextScope == null ? PersistenceContextScope.TRANSACTION : persistenceContextScope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PersistenceContext scope to be used if one is not explicitly set on a query.
|
||||
* <p/>
|
||||
* This defaults to {@link PersistenceContextScope#TRANSACTION}.
|
||||
* <p/>
|
||||
* The PersistenceContextScope can specified on each query via {@link com.avaje.ebean
|
||||
* .Query#setPersistenceContextScope(com.avaje.ebean.PersistenceContextScope)}. If it
|
||||
* is not set on the query this scope is used.
|
||||
*
|
||||
* @see com.avaje.ebean.Query#setPersistenceContextScope(com.avaje.ebean.PersistenceContextScope)
|
||||
*/
|
||||
public void setPersistenceContextScope(PersistenceContextScope persistenceContextScope) {
|
||||
this.persistenceContextScope = persistenceContextScope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from the ebean.properties file.
|
||||
*/
|
||||
@@ -1257,8 +1387,6 @@ public class ServerConfig {
|
||||
|
||||
/**
|
||||
* This is broken out for the same reason as above - preserve existing behaviour but let it be overridden.
|
||||
*
|
||||
* @param p
|
||||
*/
|
||||
protected void loadAutofetchConfig(PropertySource p) {
|
||||
autofetchConfig.loadSettings(p);
|
||||
@@ -1281,6 +1409,7 @@ public class ServerConfig {
|
||||
|
||||
loadDataSourceSettings(p);
|
||||
|
||||
autoCommitMode = p.getBoolean("autoCommitMode", false);
|
||||
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", false);
|
||||
namingConvention = createNamingConvention(p);
|
||||
databasePlatform = createInstance(p, DatabasePlatform.class, "databasePlatform");
|
||||
@@ -1315,16 +1444,26 @@ public class ServerConfig {
|
||||
int batchSize = p.getInt("batch.size", 20);
|
||||
persistBatchSize = p.getInt("persistBatchSize", batchSize);
|
||||
|
||||
persistenceContextScope = PersistenceContextScope.valueOf(p.get("persistenceContextScope","TRANSACTION"));
|
||||
|
||||
dataSourceJndiName = p.get("dataSourceJndiName", null);
|
||||
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", 20);
|
||||
databaseBooleanTrue = p.get("databaseBooleanTrue", null);
|
||||
databaseBooleanFalse = p.get("databaseBooleanFalse", null);
|
||||
databasePlatformName = p.get("databasePlatformName", null);
|
||||
uuidStoreAsBinary = p.getBoolean("uuidStoreAsBinary", false);
|
||||
localTimeWithNanos = p.getBoolean("localTimeWithNanos", false);
|
||||
|
||||
lazyLoadBatchSize = p.getInt("lazyLoadBatchSize", 1);
|
||||
queryBatchSize = p.getInt("queryBatchSize", DEFAULT_QUERY_BATCH_SIZE);
|
||||
|
||||
String jsonDateTimeFormat = p.get("jsonDateTime", null);
|
||||
if (jsonDateTimeFormat != null) {
|
||||
jsonDateTime = JsonConfig.DateTime.valueOf(jsonDateTimeFormat);
|
||||
} else {
|
||||
jsonDateTime = JsonConfig.DateTime.MILLIS;
|
||||
}
|
||||
|
||||
ddlGenerate = p.getBoolean("ddl.generate", false);
|
||||
ddlRun = p.getBoolean("ddl.run", false);
|
||||
|
||||
|
||||
@@ -57,6 +57,13 @@ public final class TableName {
|
||||
this.name = split[len - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a qualifiedTableName that might include a catalog and schema and just return the table name.
|
||||
*/
|
||||
public static String parse(String qualifiedTableName) {
|
||||
return new TableName(qualifiedTableName).getName();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getQualifiedName();
|
||||
}
|
||||
@@ -121,6 +128,18 @@ public final class TableName {
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a catalog and schema prefix if they exist to the string builder.
|
||||
*/
|
||||
public void appendCatalogAndSchema(StringBuilder buffer) {
|
||||
if (catalog != null) {
|
||||
buffer.append(catalog).append(".");
|
||||
}
|
||||
if (schema != null) {
|
||||
buffer.append(schema).append(".");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is table name is valid i.e. it has at least a name.
|
||||
*
|
||||
|
||||
@@ -6,6 +6,7 @@ import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -14,40 +15,61 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class DatabasePlatform {
|
||||
|
||||
/** The Constant logger. */
|
||||
private static final Logger logger = LoggerFactory.getLogger(DatabasePlatform.class);
|
||||
|
||||
/** The open quote used by quoted identifiers. */
|
||||
/**
|
||||
* The open quote used by quoted identifiers.
|
||||
*/
|
||||
protected String openQuote = "\"";
|
||||
|
||||
/** The close quote used by quoted identifiers. */
|
||||
/**
|
||||
* The close quote used by quoted identifiers.
|
||||
*/
|
||||
protected String closeQuote = "\"";
|
||||
|
||||
/** For limit/offset, row_number etc limiting of SQL queries. */
|
||||
/**
|
||||
* For limit/offset, row_number etc limiting of SQL queries.
|
||||
*/
|
||||
protected SqlLimiter sqlLimiter = new LimitOffsetSqlLimiter();
|
||||
|
||||
/** Mapping of JDBC to Database types. */
|
||||
/**
|
||||
* Mapping of JDBC to Database types.
|
||||
*/
|
||||
protected DbTypeMap dbTypeMap = new DbTypeMap();
|
||||
|
||||
/** DB specific DDL syntax. */
|
||||
/**
|
||||
* DB specific DDL syntax.
|
||||
*/
|
||||
protected DbDdlSyntax dbDdlSyntax = new DbDdlSyntax();
|
||||
|
||||
/** Defines DB identity/sequence features. */
|
||||
/**
|
||||
* Defines DB identity/sequence features.
|
||||
*/
|
||||
protected DbIdentity dbIdentity = new DbIdentity();
|
||||
|
||||
/** The JDBC type to map booleans to (by default). */
|
||||
/**
|
||||
* The JDBC type to map booleans to (by default).
|
||||
*/
|
||||
protected int booleanDbType = Types.BOOLEAN;
|
||||
|
||||
/** The JDBC type to map Blob to. */
|
||||
/**
|
||||
* The JDBC type to map Blob to.
|
||||
*/
|
||||
protected int blobDbType = Types.BLOB;
|
||||
|
||||
/** The JDBC type to map Clob to. */
|
||||
/**
|
||||
* The JDBC type to map Clob to.
|
||||
*/
|
||||
protected int clobDbType = Types.CLOB;
|
||||
|
||||
/** For Oracle treat empty strings as null. */
|
||||
/**
|
||||
* For Oracle treat empty strings as null.
|
||||
*/
|
||||
protected boolean treatEmptyStringsAsNull;
|
||||
|
||||
/** The name. */
|
||||
/**
|
||||
* The database platform name.
|
||||
*/
|
||||
protected String name = "generic";
|
||||
|
||||
/**
|
||||
@@ -57,6 +79,11 @@ public class DatabasePlatform {
|
||||
*/
|
||||
private static final char BACK_TICK = '`';
|
||||
|
||||
/**
|
||||
* The like clause. Can be overridden to disable default escape character.
|
||||
*/
|
||||
protected String likeClause = "like ?";
|
||||
|
||||
protected DbEncrypt dbEncrypt;
|
||||
|
||||
protected boolean idInExpandedForm;
|
||||
@@ -299,4 +326,13 @@ public class DatabasePlatform {
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the like clause used by this database platform.
|
||||
* <p>
|
||||
* This may include an escape clause to disable a default escape character.
|
||||
*/
|
||||
public String getLikeClause() {
|
||||
return likeClause;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.config.TableName;
|
||||
|
||||
/**
|
||||
* Used to support DB specific syntax for DDL generation.
|
||||
*/
|
||||
@@ -9,7 +11,7 @@ public class DbDdlSyntax {
|
||||
|
||||
private boolean inlinePrimaryKeyConstraint = false;
|
||||
|
||||
private boolean addOneToOneUniqueContraint = false;
|
||||
private boolean addOneToOneUniqueContraint = true;
|
||||
|
||||
private int maxConstraintNameLength = 32;
|
||||
|
||||
@@ -43,6 +45,17 @@ public class DbDdlSyntax {
|
||||
return pk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column definition for an identity column.
|
||||
*/
|
||||
public String getIdentityColumnDefn(String columnDefn) {
|
||||
String identity = getIdentity();
|
||||
if (identity != null && identity.length() > 0) {
|
||||
return columnDefn+" "+identity;
|
||||
}
|
||||
return columnDefn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the identity clause for DB's that have identities.
|
||||
*/
|
||||
@@ -248,26 +261,29 @@ public class DbDdlSyntax {
|
||||
this.inlinePrimaryKeyConstraint = inlinePrimaryKeyConstraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns a fully index name.
|
||||
*/
|
||||
public String getIndexName(String table, String propName, int ixCount) {
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append("ix_");
|
||||
buffer.append(table);
|
||||
buffer.append("_");
|
||||
buffer.append(propName);
|
||||
|
||||
StringBuilder buffer = new StringBuilder(30);
|
||||
buffer.append("ix_").append(TableName.parse(table));
|
||||
buffer.append("_").append(propName);
|
||||
|
||||
addSuffix(buffer, ixCount);
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns a fully qualified foreign key constraint name.
|
||||
*/
|
||||
public String getForeignKeyName(String table, String propName, int fkCount) {
|
||||
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.append("fk_");
|
||||
buffer.append(table);
|
||||
buffer.append("_");
|
||||
buffer.append(propName);
|
||||
StringBuilder buffer = new StringBuilder(30);
|
||||
buffer.append("fk_").append(TableName.parse(table));
|
||||
buffer.append("_").append(propName);
|
||||
|
||||
addSuffix(buffer, fkCount);
|
||||
|
||||
@@ -276,15 +292,10 @@ public class DbDdlSyntax {
|
||||
|
||||
/**
|
||||
* Adds the suffix.
|
||||
*
|
||||
* @param buffer
|
||||
* the buffer
|
||||
* @param count
|
||||
* the count
|
||||
*/
|
||||
protected void addSuffix(StringBuilder buffer, int count) {
|
||||
final String suffixNr = Integer.toString(count);
|
||||
final int suffixLen = suffixNr.length() + 1;
|
||||
String suffixNr = Integer.toString(count);
|
||||
int suffixLen = suffixNr.length() + 1;
|
||||
|
||||
if (buffer.length() + suffixLen > maxConstraintNameLength) {
|
||||
buffer.setLength(maxConstraintNameLength - suffixLen);
|
||||
|
||||
@@ -14,6 +14,7 @@ public class H2Platform extends DatabasePlatform {
|
||||
super();
|
||||
this.name = "h2";
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
this.likeClause = "like ? escape''";
|
||||
|
||||
// only support getGeneratedKeys with non-batch JDBC
|
||||
// so generally use SEQUENCE instead of IDENTITY for H2
|
||||
|
||||
@@ -17,22 +17,21 @@ public class LimitOffsetSqlLimiter implements SqlLimiter {
|
||||
|
||||
public SqlLimitResponse limit(SqlLimitRequest request) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(512);
|
||||
String dbSql = request.getDbSql();
|
||||
|
||||
StringBuilder sb = new StringBuilder(50 + dbSql.length());
|
||||
sb.append("select ");
|
||||
if (request.isDistinct()) {
|
||||
sb.append("distinct ");
|
||||
}
|
||||
|
||||
sb.append(request.getDbSql());
|
||||
sb.append(dbSql);
|
||||
|
||||
int firstRow = request.getFirstRow();
|
||||
int maxRows = request.getMaxRows();
|
||||
if (maxRows > 0) {
|
||||
maxRows = maxRows + 1;
|
||||
}
|
||||
|
||||
if (maxRows > 0 || firstRow > 0) {
|
||||
sb.append(" ").append(NEW_LINE).append(LIMIT).append(" ").append(maxRows);
|
||||
sb.append(" ").append(LIMIT).append(" ").append(maxRows);
|
||||
if (firstRow > 0) {
|
||||
sb.append(" ").append(OFFSET).append(" ");
|
||||
sb.append(firstRow);
|
||||
|
||||
@@ -26,9 +26,7 @@ public class MsSqlServer2005SqlLimiter implements SqlLimiter {
|
||||
|
||||
int lastRow = request.getMaxRows();
|
||||
if (lastRow > 0) {
|
||||
// fetch 1 more than we return so that
|
||||
// we know if more rows are available
|
||||
lastRow = lastRow + firstRow + 1;
|
||||
lastRow = lastRow + firstRow;
|
||||
}
|
||||
|
||||
if (firstRow < 1) {
|
||||
|
||||
@@ -20,6 +20,7 @@ public class MySqlPlatform extends DatabasePlatform {
|
||||
public MySqlPlatform() {
|
||||
super();
|
||||
this.name = "mysql";
|
||||
this.likeClause = "like ? escape''";
|
||||
this.selectCountWithAlias = true;
|
||||
this.dbEncrypt = new MySqlDbEncrypt();
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Postgres v8.3 specific platform.
|
||||
* <p>
|
||||
* No support for getGeneratedKeys.
|
||||
* </p>
|
||||
*/
|
||||
public class Postgres8Platform extends DatabasePlatform {
|
||||
|
||||
public Postgres8Platform() {
|
||||
super();
|
||||
this.name = "postgres";
|
||||
this.selectCountWithAlias = true;
|
||||
this.blobDbType = Types.LONGVARBINARY;
|
||||
this.clobDbType = Types.VARCHAR;
|
||||
|
||||
this.dbEncrypt = new PostgresDbEncrypt();
|
||||
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
this.dbIdentity.setIdType(IdType.SEQUENCE);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
String colAlias = GlobalProperties.get("ebean.columnAliasPrefix", null);
|
||||
if (colAlias == null) {
|
||||
// Postgres requires the "as" keyword for column alias
|
||||
GlobalProperties.put("ebean.columnAliasPrefix", "as c");
|
||||
}
|
||||
|
||||
this.openQuote = "\"";
|
||||
this.closeQuote = "\"";
|
||||
|
||||
// dbTypeMap.put(Types.BOOLEAN, new DbType("bit default 0"));
|
||||
|
||||
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
|
||||
dbTypeMap.put(Types.DOUBLE, new DbType("float"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 38));
|
||||
|
||||
dbTypeMap.put(Types.BINARY, new DbType("bytea", false));
|
||||
dbTypeMap.put(Types.VARBINARY, new DbType("bytea", false));
|
||||
|
||||
dbTypeMap.put(Types.BLOB, new DbType("bytea", false));
|
||||
dbTypeMap.put(Types.CLOB, new DbType("text"));
|
||||
dbTypeMap.put(Types.LONGVARBINARY, new DbType("bytea", false));
|
||||
dbTypeMap.put(Types.LONGVARCHAR, new DbType("text"));
|
||||
|
||||
dbDdlSyntax.setDropTableCascade("cascade");
|
||||
dbDdlSyntax.setDropIfExists("if exists");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Postgres specific sequence IdGenerator.
|
||||
*/
|
||||
@Override
|
||||
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds,
|
||||
String seqName, int batchSize) {
|
||||
|
||||
return new PostgresSequenceIdGenerator(be, ds, seqName, batchSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String withForUpdate(String sql) {
|
||||
return sql + " for update";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
public class PostgresDdlSyntax extends DbDdlSyntax {
|
||||
|
||||
/**
|
||||
* Map bigint, integer and smallint into their equivilent serial types.
|
||||
*/
|
||||
@Override
|
||||
public String getIdentityColumnDefn(String columnDefn) {
|
||||
|
||||
//smallserial, serial and bigserial
|
||||
if ("bigint".equalsIgnoreCase(columnDefn)) {
|
||||
return "bigserial";
|
||||
}
|
||||
if ("integer".equalsIgnoreCase(columnDefn)) {
|
||||
return "serial";
|
||||
}
|
||||
if ("smallint".equalsIgnoreCase(columnDefn)) {
|
||||
return "smallserial";
|
||||
}
|
||||
|
||||
return columnDefn;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,27 +4,38 @@ import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* Postgres v8.3 specific platform.
|
||||
* Postgres v9 specific platform.
|
||||
* <p>
|
||||
* No support for getGeneratedKeys.
|
||||
* Uses serial types and getGeneratedKeys.
|
||||
* </p>
|
||||
*/
|
||||
public class PostgresPlatform extends DatabasePlatform {
|
||||
|
||||
/**
|
||||
* Unique jdbc type id defined for hstore type.
|
||||
*/
|
||||
public static final int TYPE_HSTORE = 4001;
|
||||
|
||||
public PostgresPlatform() {
|
||||
super();
|
||||
this.name = "postgres";
|
||||
this.likeClause = "like ? escape''";
|
||||
|
||||
this.dbDdlSyntax = new PostgresDdlSyntax();
|
||||
|
||||
this.selectCountWithAlias = true;
|
||||
this.blobDbType = Types.LONGVARBINARY;
|
||||
this.clobDbType = Types.VARCHAR;
|
||||
|
||||
this.dbEncrypt = new PostgresDbEncrypt();
|
||||
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
this.dbIdentity.setIdType(IdType.SEQUENCE);
|
||||
// Use Identity and getGeneratedKeys
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
String colAlias = GlobalProperties.get("ebean.columnAliasPrefix", null);
|
||||
@@ -36,8 +47,8 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
this.openQuote = "\"";
|
||||
this.closeQuote = "\"";
|
||||
|
||||
// dbTypeMap.put(Types.BOOLEAN, new DbType("bit default 0"));
|
||||
|
||||
dbTypeMap.put(TYPE_HSTORE, new DbType("hstore"));
|
||||
|
||||
dbTypeMap.put(Types.INTEGER, new DbType("integer", false));
|
||||
dbTypeMap.put(Types.DOUBLE, new DbType("float"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
|
||||
@@ -15,7 +15,7 @@ public class RowNumberSqlLimiter implements SqlLimiter {
|
||||
*/
|
||||
private static final String ROW_NUMBER_AS = ") as rn, ";
|
||||
|
||||
final String rowNumberWindowAlias;
|
||||
private final String rowNumberWindowAlias;
|
||||
|
||||
/**
|
||||
* Specify the name of the rowNumberWindowAlias.
|
||||
@@ -30,16 +30,18 @@ public class RowNumberSqlLimiter implements SqlLimiter {
|
||||
|
||||
public SqlLimitResponse limit(SqlLimitRequest request) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(500);
|
||||
String dbSql = request.getDbSql();
|
||||
|
||||
StringBuilder sb = new StringBuilder(60 + dbSql.length());
|
||||
|
||||
int firstRow = request.getFirstRow();
|
||||
|
||||
int lastRow = request.getMaxRows();
|
||||
if (lastRow > 0) {
|
||||
lastRow = lastRow + firstRow + 1;
|
||||
lastRow = lastRow + firstRow;
|
||||
}
|
||||
|
||||
sb.append("select * from (").append(NEW_LINE);
|
||||
sb.append("select * from ( ");
|
||||
|
||||
sb.append("select ");
|
||||
if (request.isDistinct()) {
|
||||
@@ -50,9 +52,9 @@ public class RowNumberSqlLimiter implements SqlLimiter {
|
||||
sb.append(request.getDbOrderBy());
|
||||
sb.append(ROW_NUMBER_AS);
|
||||
|
||||
sb.append(request.getDbSql());
|
||||
sb.append(dbSql);
|
||||
|
||||
sb.append(NEW_LINE).append(") ");
|
||||
sb.append(" ) ");
|
||||
sb.append(rowNumberWindowAlias);
|
||||
sb.append(" where ");
|
||||
if (firstRow > 0) {
|
||||
|
||||
@@ -35,38 +35,40 @@ public class RownumSqlLimiter implements SqlLimiter {
|
||||
// :MAX_ROW_TO_FETCH )
|
||||
// where rnum >= :MIN_ROW_TO_FETCH;
|
||||
|
||||
StringBuilder sb = new StringBuilder(500);
|
||||
String dbSql = request.getDbSql();
|
||||
|
||||
StringBuilder sb = new StringBuilder(60 + dbSql.length());
|
||||
|
||||
int firstRow = request.getFirstRow();
|
||||
|
||||
int lastRow = request.getMaxRows();
|
||||
if (lastRow > 0) {
|
||||
lastRow = lastRow + firstRow + 1;
|
||||
lastRow = lastRow + firstRow;
|
||||
}
|
||||
|
||||
sb.append("select * ").append(NEW_LINE).append("from ( ");
|
||||
sb.append("select * from ( ");
|
||||
|
||||
sb.append("select ");
|
||||
if (useFirstRowsHint && request.getMaxRows() > 0) {
|
||||
sb.append("/*+ FIRST_ROWS(").append(request.getMaxRows() + 1).append(") */ ");
|
||||
sb.append("/*+ FIRST_ROWS(").append(request.getMaxRows()).append(") */ ");
|
||||
}
|
||||
|
||||
sb.append("rownum ").append(rnum).append(", a.* ").append(NEW_LINE);
|
||||
sb.append(" from (");//
|
||||
sb.append("rownum ").append(rnum).append(", a.* ");
|
||||
sb.append(" from (");
|
||||
|
||||
sb.append(" select ");
|
||||
if (request.isDistinct()) {
|
||||
sb.append("distinct ");
|
||||
}
|
||||
sb.append(request.getDbSql());
|
||||
sb.append(dbSql);
|
||||
|
||||
sb.append(NEW_LINE).append(" ) a ");
|
||||
sb.append(NEW_LINE).append(" ) a ");
|
||||
if (lastRow > 0) {
|
||||
sb.append(NEW_LINE).append(" where rownum <= ").append(lastRow);
|
||||
sb.append(" where rownum <= ").append(lastRow);
|
||||
}
|
||||
sb.append(NEW_LINE).append(" ) ");
|
||||
sb.append(" ) ");
|
||||
if (firstRow > 0) {
|
||||
sb.append(NEW_LINE).append("where ");
|
||||
sb.append(" where ");
|
||||
sb.append(rnum).append(" > ").append(firstRow);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,15 +8,12 @@ public class SqlAnywhereLimiter implements SqlLimiter {
|
||||
|
||||
public SqlLimitResponse limit(SqlLimitRequest request) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(500);
|
||||
String dbSql = request.getDbSql();
|
||||
|
||||
StringBuilder sb = new StringBuilder(60 + dbSql.length());
|
||||
|
||||
int firstRow = request.getFirstRow();
|
||||
int maxRows = request.getMaxRows();
|
||||
if (maxRows > 0) {
|
||||
// fetch 1 more than we return so that
|
||||
// we know if more rows are available
|
||||
maxRows = maxRows + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SELECT TOP xx START AT xx ... FROM ...
|
||||
@@ -31,7 +28,7 @@ public class SqlAnywhereLimiter implements SqlLimiter {
|
||||
if (firstRow > 0) {
|
||||
sb.append("start at ").append(firstRow + 1).append(" ");
|
||||
}
|
||||
sb.append(request.getDbSql());
|
||||
sb.append(dbSql);
|
||||
|
||||
String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery());
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@ import com.avaje.ebean.Query;
|
||||
/**
|
||||
* The request object for the query that can have sql limiting applied to it
|
||||
* (such as a LIMIT OFFSET clause).
|
||||
*
|
||||
* @author rob
|
||||
*/
|
||||
public interface SqlLimitRequest {
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.avaje.ebean.event;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides a base implementation of BeanPersistListener.
|
||||
* <p>
|
||||
* Objects extending this should override the methods then are interested in.
|
||||
* The default inserted() updated() and deleted() methods return false and as such
|
||||
* means other servers in the cluster are not notified.
|
||||
* </p>
|
||||
*/
|
||||
public abstract class AbstractBeanPersistListener implements BeanPersistListener {
|
||||
|
||||
/**
|
||||
* Notified that a bean has been inserted locally. Return true if you want the
|
||||
* cluster to be notified of the event.
|
||||
*
|
||||
* @param bean The bean that was inserted.
|
||||
*/
|
||||
@Override
|
||||
public boolean inserted(Object bean) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notified that a bean has been updated locally. Return true if you want the
|
||||
* cluster to be notified of the event.
|
||||
*
|
||||
* @param bean The bean that was updated.
|
||||
* @param updatedProperties The properties that were modified by this update.
|
||||
*/
|
||||
@Override
|
||||
public boolean updated(Object bean, Set<String> updatedProperties) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notified that a bean has been deleted locally. Return true if you want the
|
||||
* cluster to be notified of the event.
|
||||
*
|
||||
* @param bean The bean that was deleted.
|
||||
*/
|
||||
@Override
|
||||
public boolean deleted(Object bean) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that a bean was inserted on another node of the cluster.
|
||||
*
|
||||
* @param id the id value of the inserted bean
|
||||
*/
|
||||
@Override
|
||||
public void remoteInsert(Object id) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that a bean was updated on another node of the cluster.
|
||||
*
|
||||
* @param id the id value of the updated bean.
|
||||
*/
|
||||
@Override
|
||||
public void remoteUpdate(Object id) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify that a bean was deleted on another node of the cluster.
|
||||
*
|
||||
* @param id the id value of the deleted bean.
|
||||
*/
|
||||
@Override
|
||||
public void remoteDelete(Object id) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
@@ -33,11 +33,17 @@ import com.avaje.ebean.config.ServerConfig;
|
||||
* </p>
|
||||
* <p>
|
||||
* A BeanPersistListener is either found automatically via class path search or
|
||||
* can be added programmatically via {@link ServerConfig#add(BeanPersistListener)}.
|
||||
* can be added programmatically via {@link ServerConfig#add(BeanPersistListener<?>)}}.
|
||||
* </p>
|
||||
* @see ServerConfig#add(BeanPersistListener)
|
||||
*/
|
||||
public interface BeanPersistListener<T> {
|
||||
public interface BeanPersistListener {
|
||||
|
||||
/**
|
||||
* Return true if this BeanPersistListener should be registered for events
|
||||
* on this entity type.
|
||||
*/
|
||||
public boolean isRegisterFor(Class<?> cls);
|
||||
|
||||
/**
|
||||
* Notified that a bean has been inserted locally. Return true if you want the
|
||||
@@ -46,7 +52,7 @@ public interface BeanPersistListener<T> {
|
||||
* @param bean
|
||||
* The bean that was inserted.
|
||||
*/
|
||||
public boolean inserted(T bean);
|
||||
public boolean inserted(Object bean);
|
||||
|
||||
/**
|
||||
* Notified that a bean has been updated locally. Return true if you want the
|
||||
@@ -57,7 +63,7 @@ public interface BeanPersistListener<T> {
|
||||
* @param updatedProperties
|
||||
* The properties that were modified by this update.
|
||||
*/
|
||||
public boolean updated(T bean, Set<String> updatedProperties);
|
||||
public boolean updated(Object bean, Set<String> updatedProperties);
|
||||
|
||||
/**
|
||||
* Notified that a bean has been deleted locally. Return true if you want the
|
||||
@@ -66,7 +72,7 @@ public interface BeanPersistListener<T> {
|
||||
* @param bean
|
||||
* The bean that was deleted.
|
||||
*/
|
||||
public boolean deleted(T bean);
|
||||
public boolean deleted(Object bean);
|
||||
|
||||
/**
|
||||
* Notify that a bean was inserted on another node of the cluster.
|
||||
|
||||
@@ -53,6 +53,9 @@ class PathPropertiesParser {
|
||||
case '(':
|
||||
return currentWord();
|
||||
default:
|
||||
if (pos == 1) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
} while (pos < eof);
|
||||
throw new RuntimeException("Hit EOF while reading sectionTitle from " + startPos);
|
||||
@@ -91,6 +94,10 @@ class PathPropertiesParser {
|
||||
}
|
||||
|
||||
} while (pos < eof);
|
||||
if (startPos < pos) {
|
||||
String currentWord = source.substring(startPos, pos);
|
||||
currentPathProps.addProperty(currentWord);
|
||||
}
|
||||
}
|
||||
|
||||
private void addSubpath() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.avaje.ebean.text;
|
||||
|
||||
/**
|
||||
* An exception occured typically in processing CSV, JSON or XML.
|
||||
* An exception occurred typically in processing CSV, JSON or XML.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
/**
|
||||
* Utility that converts between JSON content and simple java Maps/Lists.
|
||||
*/
|
||||
public class EJson {
|
||||
|
||||
/**
|
||||
* Write the nested Map/List as json.
|
||||
*/
|
||||
public static String write(Object object) throws IOException {
|
||||
return EJsonWriter.write(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the nested Map/List as json to the writer.
|
||||
*/
|
||||
public static void write(Object object, Writer writer) throws IOException {
|
||||
EJsonWriter.write(object, writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the nested Map/List as json to the jsonGenerator.
|
||||
*/
|
||||
public static void write(Object object, JsonGenerator jsonGenerator) throws IOException {
|
||||
EJsonWriter.write(object, jsonGenerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the json and return as a Map.
|
||||
*/
|
||||
public static Map<String,Object> parseObject(String json) throws IOException {
|
||||
return EJsonReader.parseObject(json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the json and return as a Map taking a reader.
|
||||
*/
|
||||
public static Map<String,Object> parseObject(Reader reader) throws IOException {
|
||||
return EJsonReader.parseObject(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the json and return as a Map taking a JsonParser.
|
||||
*/
|
||||
public static Map<String,Object> parseObject(JsonParser parser) throws IOException {
|
||||
return EJsonReader.parseObject(parser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the json and return as a Map taking a JsonParser and a starting token.
|
||||
* <p>
|
||||
* Used when the first token is checked to see if the value is null prior to calling this.
|
||||
* </p>
|
||||
*/
|
||||
public static Map<String,Object> parseObject(JsonParser parser, JsonToken token) throws IOException {
|
||||
return EJsonReader.parseObject(parser, token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the json and return as a List.
|
||||
* @throws IOException
|
||||
*/
|
||||
public static List<Object> parseList(String json) throws IOException {
|
||||
return EJsonReader.parseList(json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the json and return as a List taking a Reader.
|
||||
* @throws IOException
|
||||
*/
|
||||
public static List<Object> parseList(Reader reader) throws IOException {
|
||||
return EJsonReader.parseList(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the json and return as a List taking a JsonParser.
|
||||
*/
|
||||
public static List<Object> parseList(JsonParser parser) throws IOException {
|
||||
return EJsonReader.parseList(parser);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse the json and return as a List or Map.
|
||||
*/
|
||||
public static Object parse(String json) throws IOException {
|
||||
return EJsonReader.parse(json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the json and return as a List or Map.
|
||||
*/
|
||||
public static Object parse(Reader reader) throws IOException {
|
||||
return EJsonReader.parse(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the json and return as a List or Map.
|
||||
*/
|
||||
public static Object parse(JsonParser parser) throws IOException {
|
||||
return EJsonReader.parse(parser);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
|
||||
class EJsonReader {
|
||||
|
||||
static JsonFactory json = new JsonFactory();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static Map<String, Object> parseObject(String json) throws IOException {
|
||||
return (Map<String, Object>) parse(json);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static Map<String, Object> parseObject(Reader reader) throws IOException {
|
||||
return (Map<String, Object>) parse(reader);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static Map<String, Object> parseObject(JsonParser parser) throws IOException {
|
||||
return (Map<String, Object>) parse(parser);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static Map<String, Object> parseObject(JsonParser parser, JsonToken token) throws IOException {
|
||||
return (Map<String, Object>)parse(parser, token);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static List<Object> parseList(String json) throws IOException {
|
||||
return (List<Object>) parse(json);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static List<Object> parseList(Reader reader) throws IOException {
|
||||
return (List<Object>) parse(reader);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static List<Object> parseList(JsonParser parser) throws IOException {
|
||||
return (List<Object>) parse(parser);
|
||||
}
|
||||
|
||||
static Object parse(String json) throws IOException {
|
||||
return parse(new StringReader(json));
|
||||
}
|
||||
|
||||
static Object parse(Reader reader) throws IOException {
|
||||
return parse(json.createParser(reader));
|
||||
}
|
||||
|
||||
static Object parse(JsonParser parser) throws IOException {
|
||||
return parse(parser, null);
|
||||
}
|
||||
|
||||
static Object parse(JsonParser parser, JsonToken token) throws IOException {
|
||||
return new EJsonReader(parser).parseJson(token);
|
||||
}
|
||||
|
||||
private final JsonParser parser;
|
||||
|
||||
private int depth;
|
||||
|
||||
private Stack stack;
|
||||
|
||||
private Context currentContext;
|
||||
|
||||
EJsonReader(JsonParser parser) {
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
private void startArray() {
|
||||
depth++;
|
||||
stack.push(currentContext);
|
||||
currentContext = new ArrayContext();
|
||||
}
|
||||
|
||||
private void startObject() {
|
||||
depth++;
|
||||
stack.push(currentContext);
|
||||
currentContext = new ObjectContext();
|
||||
}
|
||||
|
||||
private void endArray() {
|
||||
end();
|
||||
}
|
||||
|
||||
private void endObject() {
|
||||
end();
|
||||
}
|
||||
|
||||
private void end() {
|
||||
depth--;
|
||||
if (!stack.isEmpty()) {
|
||||
currentContext = stack.pop(currentContext);
|
||||
}
|
||||
}
|
||||
|
||||
private void setValue(Object value) {
|
||||
currentContext.setValue(value);
|
||||
}
|
||||
|
||||
private void setValueNull() {
|
||||
currentContext.setValueNull();
|
||||
}
|
||||
|
||||
private Object parseJson(JsonToken token) throws IOException {
|
||||
|
||||
if (token == null) {
|
||||
// no initial token so expect to read START_OBJECT or similar
|
||||
token = parser.nextToken();
|
||||
if (JsonToken.VALUE_NULL == token) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
stack = new Stack();
|
||||
// it is a object or array, process the first JsonToken
|
||||
processJsonToken(token);
|
||||
|
||||
// process the rest of the object or array
|
||||
while (depth > 0) {
|
||||
token = parser.nextToken();
|
||||
processJsonToken(token);
|
||||
}
|
||||
|
||||
return currentContext.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the JsonToken for objects and arrays.
|
||||
*/
|
||||
private void processJsonToken(JsonToken token) throws IOException {
|
||||
switch (token) {
|
||||
|
||||
case START_ARRAY:
|
||||
startArray();
|
||||
break;
|
||||
|
||||
case START_OBJECT:
|
||||
startObject();
|
||||
break;
|
||||
|
||||
case FIELD_NAME:
|
||||
currentContext.setKey(parser.getCurrentName());
|
||||
break;
|
||||
|
||||
case VALUE_STRING:
|
||||
setValue(parser.getValueAsString());
|
||||
break;
|
||||
|
||||
case VALUE_NUMBER_INT:
|
||||
setValue(parser.getLongValue());
|
||||
break;
|
||||
|
||||
case VALUE_NUMBER_FLOAT:
|
||||
setValue(parser.getDecimalValue());
|
||||
break;
|
||||
|
||||
case VALUE_TRUE:
|
||||
setValue(Boolean.TRUE);
|
||||
break;
|
||||
|
||||
case VALUE_FALSE:
|
||||
setValue(Boolean.FALSE);
|
||||
break;
|
||||
|
||||
case VALUE_NULL:
|
||||
setValueNull();
|
||||
break;
|
||||
|
||||
case END_OBJECT:
|
||||
endObject();
|
||||
break;
|
||||
|
||||
case END_ARRAY:
|
||||
endArray();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Stack {
|
||||
|
||||
private Context head;
|
||||
|
||||
private void push(Context context) {
|
||||
if (context != null) {
|
||||
context.next = head;
|
||||
head = context;
|
||||
}
|
||||
}
|
||||
|
||||
private Context pop(Context endingContext) {
|
||||
if (head == null) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
Context temp = head;
|
||||
head = head.next;
|
||||
temp.popContext(endingContext);
|
||||
return temp;
|
||||
}
|
||||
|
||||
private boolean isEmpty() {
|
||||
return head == null;
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class Context {
|
||||
Context next;
|
||||
abstract void popContext(Context temp);
|
||||
abstract Object getValue();
|
||||
abstract void setKey(String key);
|
||||
abstract void setValue(Object value);
|
||||
abstract void setValueNull();
|
||||
}
|
||||
|
||||
private static class ObjectContext extends Context {
|
||||
|
||||
private final Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
|
||||
private String key;
|
||||
|
||||
public void popContext(Context temp) {
|
||||
setValue(temp.getValue());
|
||||
}
|
||||
|
||||
Object getValue() {
|
||||
return map;
|
||||
}
|
||||
|
||||
void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
void setValue(Object value) {
|
||||
map.put(key, value);
|
||||
}
|
||||
|
||||
void setValueNull() {
|
||||
map.put(key, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ArrayContext extends Context {
|
||||
|
||||
private final List<Object> values = new ArrayList<Object>();
|
||||
|
||||
public void popContext(Context temp) {
|
||||
values.add(temp.getValue());
|
||||
}
|
||||
|
||||
Object getValue() {
|
||||
return values;
|
||||
}
|
||||
|
||||
void setValue(Object value) {
|
||||
values.add(value);
|
||||
}
|
||||
|
||||
void setValueNull() {
|
||||
// ignore
|
||||
}
|
||||
void setKey(String key) {
|
||||
// not expected
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
|
||||
class EJsonWriter {
|
||||
|
||||
/**
|
||||
* Base jsonFactory implementation used when it is not passed in.
|
||||
*/
|
||||
static JsonFactory jsonFactory = new JsonFactory();
|
||||
|
||||
static String write(Object object) throws IOException {
|
||||
StringWriter writer = new StringWriter(200);
|
||||
write(object, writer);
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
static void write(Object object, Writer writer) throws IOException {
|
||||
JsonGenerator generator = jsonFactory.createGenerator(writer);
|
||||
write(object, generator);
|
||||
generator.close();
|
||||
}
|
||||
|
||||
static void write(Object object, JsonGenerator jsonGenerator) {
|
||||
new EJsonWriter(jsonGenerator).writeJson(object);
|
||||
}
|
||||
|
||||
private final JsonGenerator jsonGenerator;
|
||||
|
||||
private EJsonWriter(JsonGenerator jsonGenerator) {
|
||||
this.jsonGenerator = jsonGenerator;
|
||||
}
|
||||
|
||||
private void writeJson(Object object) {
|
||||
writeJson(null, object);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void writeJson(String name, Object object) {
|
||||
try {
|
||||
if (object == null) {
|
||||
writeNull(name);
|
||||
|
||||
} else if (object instanceof Map) {
|
||||
writeMap(name, (Map<Object, Object>) object);
|
||||
|
||||
} else if (object instanceof Collection) {
|
||||
writeCollection(name, (Collection<Object>) object);
|
||||
|
||||
} else if (object instanceof Boolean) {
|
||||
writeBoolean(name, (Boolean) object);
|
||||
|
||||
} else if (object instanceof Number) {
|
||||
writeNumber(name, (Number) object);
|
||||
|
||||
} else if (object instanceof Date) {
|
||||
writeDate(name, (Date) object);
|
||||
|
||||
} else if (object instanceof String) {
|
||||
writeString(name, (String) object);
|
||||
|
||||
} else if (object instanceof Map.Entry<?, ?>) {
|
||||
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object;
|
||||
writeJson(entry.getKey().toString(), entry.getValue());
|
||||
|
||||
} else {
|
||||
writeString(name, object.toString());
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeBoolean(String name, Boolean object) throws IOException {
|
||||
if (name == null) {
|
||||
jsonGenerator.writeBoolean(object);
|
||||
} else {
|
||||
jsonGenerator.writeBooleanField(name, object);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeDate(String name, Date object) throws IOException {
|
||||
if (name == null) {
|
||||
jsonGenerator.writeNumber(object.getTime());
|
||||
} else {
|
||||
jsonGenerator.writeNumberField(name, object.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
private void writeNumber(String name, Number object) throws IOException {
|
||||
|
||||
if (object instanceof Long) {
|
||||
writeLong(name, object);
|
||||
|
||||
} else if (object instanceof Integer) {
|
||||
writeInteger(name, object);
|
||||
|
||||
} else if (object instanceof Double) {
|
||||
writeDouble(name, object);
|
||||
|
||||
} else if (object instanceof BigDecimal) {
|
||||
writeBigDecimal(name, object);
|
||||
|
||||
} else if (object instanceof BigInteger) {
|
||||
writeBigInteger(name, object);
|
||||
|
||||
} else {
|
||||
writeGeneralNumber(name, object);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeGeneralNumber(String name, Number object) throws IOException {
|
||||
writeBigDecimal(name, new BigDecimal(object.toString()));
|
||||
}
|
||||
|
||||
private void writeBigDecimal(String name, Number object) throws IOException {
|
||||
if (name == null) {
|
||||
jsonGenerator.writeNumber((BigDecimal) object);
|
||||
} else {
|
||||
jsonGenerator.writeNumberField(name, (BigDecimal) object);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeBigInteger(String name, Number object) throws IOException {
|
||||
if (name == null) {
|
||||
jsonGenerator.writeNumber((BigInteger) object);
|
||||
} else {
|
||||
jsonGenerator.writeNumberField(name, object.longValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void writeDouble(String name, Number object) throws IOException {
|
||||
if (name == null) {
|
||||
jsonGenerator.writeNumber((Double) object);
|
||||
} else {
|
||||
jsonGenerator.writeNumberField(name, (Double) object);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeLong(String name, Number object) throws IOException {
|
||||
if (name == null) {
|
||||
jsonGenerator.writeNumber((Long) object);
|
||||
} else {
|
||||
jsonGenerator.writeNumberField(name, (Long) object);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeInteger(String name, Number object) throws IOException {
|
||||
if (name == null) {
|
||||
jsonGenerator.writeNumber((Integer) object);
|
||||
} else {
|
||||
jsonGenerator.writeNumberField(name, (Integer) object);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeNull(String name) throws IOException {
|
||||
if (name == null) {
|
||||
jsonGenerator.writeNull();
|
||||
} else {
|
||||
jsonGenerator.writeNullField(name);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeString(String name, String object) throws IOException {
|
||||
if (name == null) {
|
||||
jsonGenerator.writeString(object);
|
||||
} else {
|
||||
jsonGenerator.writeStringField(name, object);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeCollection(String name, Collection<Object> collection) throws IOException {
|
||||
if (name != null) {
|
||||
jsonGenerator.writeFieldName(name);
|
||||
}
|
||||
jsonGenerator.writeStartArray();
|
||||
for (Object object : collection) {
|
||||
writeJson(null, object);
|
||||
}
|
||||
jsonGenerator.writeEndArray();
|
||||
}
|
||||
|
||||
private void writeMap(String name, Map<Object, Object> map) throws IOException {
|
||||
|
||||
if (name != null) {
|
||||
jsonGenerator.writeFieldName(name);
|
||||
}
|
||||
jsonGenerator.writeStartObject();
|
||||
Set<Entry<Object, Object>> entrySet = map.entrySet();
|
||||
for (Entry<Object, Object> entry : entrySet) {
|
||||
writeJson(entry.getKey().toString(), entry.getValue());
|
||||
}
|
||||
jsonGenerator.writeEndObject();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Type;
|
||||
@@ -7,125 +10,105 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* Converts objects to and from JSON format.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface JsonContext {
|
||||
|
||||
/**
|
||||
* Convert json string input into a Bean of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public <T> T toBean(Class<T> rootType, String json);
|
||||
public <T> T toBean(Class<T> rootType, String json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json reader input into a Bean of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public <T> T toBean(Class<T> rootType, Reader json);
|
||||
|
||||
/**
|
||||
* Convert json string input into a Bean of a specific type with options.
|
||||
*/
|
||||
public <T> T toBean(Class<T> rootType, String json, JsonReadOptions options);
|
||||
|
||||
/**
|
||||
* Convert json reader input into a Bean of a specific type with options.
|
||||
*/
|
||||
public <T> T toBean(Class<T> rootType, Reader json, JsonReadOptions options);
|
||||
public <T> T toBean(Class<T> rootType, Reader json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json string input into a list of beans of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public <T> List<T> toList(Class<T> rootType, String json);
|
||||
|
||||
/**
|
||||
* Convert json string input into a list of beans of a specific type with
|
||||
* options.
|
||||
*/
|
||||
public <T> List<T> toList(Class<T> rootType, String json, JsonReadOptions options);
|
||||
public <T> List<T> toList(Class<T> rootType, String json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert json reader input into a list of beans of a specific type.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public <T> List<T> toList(Class<T> rootType, Reader json);
|
||||
|
||||
/**
|
||||
* Convert json reader input into a list of beans of a specific type with
|
||||
* options.
|
||||
*/
|
||||
public <T> List<T> toList(Class<T> rootType, Reader json, JsonReadOptions options);
|
||||
public <T> List<T> toList(Class<T> rootType, Reader json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Use the genericType to determine if this should be converted into a List or
|
||||
* bean.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public Object toObject(Type genericType, Reader json, JsonReadOptions options);
|
||||
public Object toObject(Type genericType, Reader json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Use the genericType to determine if this should be converted into a List or
|
||||
* bean.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public Object toObject(Type genericType, String json, JsonReadOptions options);
|
||||
public Object toObject(Type genericType, String json) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Write the bean or collection in JSON format to the writer with default
|
||||
* options.
|
||||
*
|
||||
* @param o
|
||||
* the bean or collection of beans to write
|
||||
* @param writer
|
||||
* used to write the json output to
|
||||
*
|
||||
* @param value the bean or collection of beans to write
|
||||
* @param writer used to write the json output to
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public void toJsonWriter(Object o, Writer writer);
|
||||
|
||||
/**
|
||||
* With additional pretty output option.
|
||||
*/
|
||||
public void toJsonWriter(Object o, Writer writer, boolean pretty);
|
||||
public void toJson(Object value, Writer writer) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* With additional options to specify JsonValueAdapter and
|
||||
* JsonWriteBeanVisitor's.
|
||||
*
|
||||
* @param o
|
||||
* the bean or collection of beans to write
|
||||
* @param writer
|
||||
* used to write the json output to
|
||||
* @param options
|
||||
* additional options to control the JSON output
|
||||
*
|
||||
* @param value the bean or collection of beans to write
|
||||
* @param writer used to write the json output to
|
||||
* @param options additional options to control the JSON output
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public void toJsonWriter(Object o, Writer writer, boolean pretty, JsonWriteOptions options);
|
||||
|
||||
/**
|
||||
* With additional JSONP callback function.
|
||||
*/
|
||||
public void toJsonWriter(Object o, Writer writer, boolean pretty, JsonWriteOptions options,
|
||||
String callback);
|
||||
public void toJson(Object value, Writer writer, JsonWriteOptions options) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert a bean or collection to json string using default options.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public String toJsonString(Object o);
|
||||
public String toJson(Object value) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert a bean or collection to json string with pretty format using
|
||||
* default options.
|
||||
* Convert a bean or collection to json string.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public String toJsonString(Object o, boolean pretty);
|
||||
public String toJson(Object value, JsonWriteOptions options) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Convert a bean or collection to json string using options.
|
||||
*/
|
||||
public String toJsonString(Object o, boolean pretty, JsonWriteOptions options);
|
||||
|
||||
/**
|
||||
* Convert a bean or collection to json string using a JSONP callback.
|
||||
*/
|
||||
public String toJsonString(Object o, boolean pretty, JsonWriteOptions options, String callback);
|
||||
|
||||
/**
|
||||
* Return true if the type is known as an Entity or Xml type or a List Set or
|
||||
* Map of known bean types.
|
||||
* Return true if the type is known as an Entity bean or a List Set or
|
||||
* Map of entity beans.
|
||||
*/
|
||||
public boolean isSupportedType(Type genericType);
|
||||
|
||||
/**
|
||||
* Create and return a new JsonGenerator for the given writer.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public JsonGenerator createGenerator(Writer writer) throws JsonIOException;
|
||||
|
||||
/**
|
||||
* Create and return a new JsonParser for the given reader.
|
||||
*
|
||||
* @throws JsonIOException When IOException occurs
|
||||
*/
|
||||
public JsonParser createParser(Reader reader) throws JsonIOException;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
/**
|
||||
* Marker interface for all the Raw JSON types.
|
||||
* <p>
|
||||
* You will only use the JsonElements when you register a JsonReadBeanVisitor.
|
||||
* The JSON elements that are not mapped to a bean property are made available
|
||||
* to the JsonReadBeanVisitor.
|
||||
* </p>
|
||||
*
|
||||
* @see JsonReadBeanVisitor
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface JsonElement {
|
||||
|
||||
/**
|
||||
* Return true if this is a JSON primitive type (null, boolean, number or
|
||||
* string).
|
||||
*/
|
||||
public boolean isPrimitive();
|
||||
|
||||
/**
|
||||
* Return the string value of this primitive JSON element.
|
||||
* <p>
|
||||
* This can not be used for JsonElementObject or JsonElementArray.
|
||||
* </p>
|
||||
*/
|
||||
public String toPrimitiveString();
|
||||
|
||||
public Object eval(String exp);
|
||||
|
||||
public int evalInt(String exp);
|
||||
|
||||
public String evalString(String exp);
|
||||
|
||||
public boolean evalBoolean(String exp);
|
||||
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* JSON Array element.
|
||||
* <p>
|
||||
* You will only use the JsonElements when you register a JsonReadBeanVisitor.
|
||||
* The JSON elements that are not mapped to a bean property are made available
|
||||
* to the JsonReadBeanVisitor.
|
||||
* </p>
|
||||
*
|
||||
* @see JsonReadBeanVisitor
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class JsonElementArray implements JsonElement {
|
||||
|
||||
private final List<JsonElement> values = new ArrayList<JsonElement>();
|
||||
|
||||
public List<JsonElement> getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
public void add(JsonElement value) {
|
||||
values.add(value);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return values.toString();
|
||||
}
|
||||
|
||||
public boolean isPrimitive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toPrimitiveString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String[] split(String exp) {
|
||||
int pos = exp.indexOf('.');
|
||||
if (pos == -1) {
|
||||
return new String[] { exp, null };
|
||||
}
|
||||
String exp0 = exp.substring(0, pos);
|
||||
String exp1 = exp.substring(pos + 1);
|
||||
return new String[] { exp0, exp1 };
|
||||
}
|
||||
|
||||
public Object eval(String exp) {
|
||||
String[] e = split(exp);
|
||||
return eval(e[0], e[1]);
|
||||
}
|
||||
|
||||
public int evalInt(String exp) {
|
||||
String[] e = split(exp);
|
||||
return evalInt(e[0], e[1]);
|
||||
}
|
||||
|
||||
public String evalString(String exp) {
|
||||
String[] e = split(exp);
|
||||
return evalString(e[0], e[1]);
|
||||
}
|
||||
|
||||
public boolean evalBoolean(String exp) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
private Object eval(String exp0, String exp1) {
|
||||
if ("size".equals(exp0)) {
|
||||
return values.size();
|
||||
}
|
||||
if ("isEmpty".equals(exp0)) {
|
||||
return values.isEmpty();
|
||||
}
|
||||
int idx = Integer.parseInt(exp0);
|
||||
JsonElement element = values.get(idx);
|
||||
return element.eval(exp1);
|
||||
}
|
||||
|
||||
private int evalInt(String exp0, String exp1) {
|
||||
if ("size".equals(exp0)) {
|
||||
return values.size();
|
||||
}
|
||||
if ("isEmpty".equals(exp0)) {
|
||||
return values.isEmpty() ? 1 : 0;
|
||||
}
|
||||
int idx = Integer.parseInt(exp0);
|
||||
JsonElement element = values.get(idx);
|
||||
return element.evalInt(exp1);
|
||||
}
|
||||
|
||||
private String evalString(String exp0, String exp1) {
|
||||
if ("size".equals(exp0)) {
|
||||
return String.valueOf(values.size());
|
||||
}
|
||||
if ("isEmpty".equals(exp0)) {
|
||||
return String.valueOf(values.isEmpty());
|
||||
}
|
||||
int idx = Integer.parseInt(exp0);
|
||||
JsonElement element = values.get(idx);
|
||||
return element.evalString(exp1);
|
||||
}
|
||||
|
||||
public String getString() {
|
||||
return toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
/**
|
||||
* JSON boolean element.
|
||||
* <p>
|
||||
* You will only use the JsonElements when you register a JsonReadBeanVisitor.
|
||||
* The JSON elements that are not mapped to a bean property are made available
|
||||
* to the JsonReadBeanVisitor.
|
||||
* </p>
|
||||
*
|
||||
* @see JsonReadBeanVisitor
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
|
||||
public class JsonElementBoolean implements JsonElement {
|
||||
|
||||
public static final JsonElementBoolean TRUE = new JsonElementBoolean(true);
|
||||
|
||||
public static final JsonElementBoolean FALSE = new JsonElementBoolean(false);
|
||||
|
||||
private final Boolean value;
|
||||
|
||||
private JsonElementBoolean(Boolean value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Boolean getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return Boolean.toString(value);
|
||||
}
|
||||
|
||||
public boolean isPrimitive() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toPrimitiveString() {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
public Object eval(String exp) {
|
||||
if (exp != null) {
|
||||
throw new IllegalArgumentException("expression [" + exp + "] not allowed on boolean");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public int evalInt(String exp) {
|
||||
return value ? 1 : 0;
|
||||
}
|
||||
|
||||
public String evalString(String exp) {
|
||||
return toString();
|
||||
}
|
||||
|
||||
public boolean evalBoolean(String exp) {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
/**
|
||||
* JSON null element.
|
||||
* <p>
|
||||
* You will only use the JsonElements when you register a JsonReadBeanVisitor.
|
||||
* The JSON elements that are not mapped to a bean property are made available
|
||||
* to the JsonReadBeanVisitor.
|
||||
* </p>
|
||||
*
|
||||
* @see JsonReadBeanVisitor
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class JsonElementNull implements JsonElement {
|
||||
|
||||
public static final JsonElementNull NULL = new JsonElementNull();
|
||||
|
||||
private JsonElementNull() {
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return "null";
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "json null";
|
||||
}
|
||||
|
||||
public boolean isPrimitive() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toPrimitiveString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object eval(String exp) {
|
||||
if (exp != null) {
|
||||
throw new IllegalArgumentException("expression [" + exp + "] not allowed on null");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int evalInt(String exp) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String evalString(String exp) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean evalBoolean(String exp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
/**
|
||||
* JSON number element.
|
||||
* <p>
|
||||
* You will only use the JsonElements when you register a JsonReadBeanVisitor.
|
||||
* The JSON elements that are not mapped to a bean property are made available
|
||||
* to the JsonReadBeanVisitor.
|
||||
* </p>
|
||||
*
|
||||
* @see JsonReadBeanVisitor
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class JsonElementNumber implements JsonElement {
|
||||
|
||||
private final String value;
|
||||
|
||||
public JsonElementNumber(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean isPrimitive() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toPrimitiveString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Object eval(String exp) {
|
||||
if (exp != null) {
|
||||
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
|
||||
}
|
||||
return Double.parseDouble(value);
|
||||
}
|
||||
|
||||
public int evalInt(String exp) {
|
||||
if (exp != null) {
|
||||
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
|
||||
}
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
|
||||
public String evalString(String exp) {
|
||||
if (exp != null) {
|
||||
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean evalBoolean(String exp) {
|
||||
if (exp != null) {
|
||||
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
|
||||
}
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* JSON Object element.
|
||||
* <p>
|
||||
* You will only use the JsonElements when you register a JsonReadBeanVisitor.
|
||||
* The JSON elements that are not mapped to a bean property are made available
|
||||
* to the JsonReadBeanVisitor.
|
||||
* </p>
|
||||
*
|
||||
* @see JsonReadBeanVisitor
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class JsonElementObject implements JsonElement {
|
||||
|
||||
private final Map<String, JsonElement> map = new LinkedHashMap<String, JsonElement>();
|
||||
|
||||
public void put(String key, JsonElement value) {
|
||||
map.put(key, value);
|
||||
}
|
||||
|
||||
private String[] split(String exp) {
|
||||
int pos = exp.indexOf('.');
|
||||
if (pos == -1) {
|
||||
return new String[] { exp, null };
|
||||
}
|
||||
String exp0 = exp.substring(0, pos);
|
||||
String exp1 = exp.substring(pos + 1);
|
||||
return new String[] { exp0, exp1 };
|
||||
}
|
||||
|
||||
public Object eval(String exp) {
|
||||
String[] e = split(exp);
|
||||
return eval(e[0], e[1]);
|
||||
}
|
||||
|
||||
public int evalInt(String exp) {
|
||||
String[] e = split(exp);
|
||||
return evalInt(e[0], e[1]);
|
||||
}
|
||||
|
||||
public String evalString(String exp) {
|
||||
if (exp == null) {
|
||||
return map.toString();
|
||||
}
|
||||
String[] e = split(exp);
|
||||
return evalString(e[0], e[1]);
|
||||
}
|
||||
|
||||
public boolean evalBoolean(String exp) {
|
||||
String[] e = split(exp);
|
||||
return evalBoolean(e[0], e[1]);
|
||||
}
|
||||
|
||||
private Object eval(String exp0, String exp1) {
|
||||
JsonElement e = map.get(exp0);
|
||||
return e == null ? null : e.eval(exp1);
|
||||
}
|
||||
|
||||
private int evalInt(String exp0, String exp1) {
|
||||
JsonElement e = map.get(exp0);
|
||||
return e == null ? 0 : e.evalInt(exp1);
|
||||
}
|
||||
|
||||
private String evalString(String exp0, String exp1) {
|
||||
JsonElement e = map.get(exp0);
|
||||
return e == null ? "" : e.evalString(exp1);
|
||||
}
|
||||
|
||||
private boolean evalBoolean(String exp0, String exp1) {
|
||||
JsonElement e = map.get(exp0);
|
||||
return e == null ? false : e.evalBoolean(exp1);
|
||||
}
|
||||
|
||||
public JsonElement get(String key) {
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
public JsonElement getValue(String key) {
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
public Set<String> keySet() {
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
public Set<Map.Entry<String, JsonElement>> entrySet() {
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return map.toString();
|
||||
}
|
||||
|
||||
public boolean isPrimitive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toPrimitiveString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
/**
|
||||
* JSON string element.
|
||||
* <p>
|
||||
* You will only use the JsonElements when you register a JsonReadBeanVisitor.
|
||||
* The JSON elements that are not mapped to a bean property are made available
|
||||
* to the JsonReadBeanVisitor.
|
||||
* </p>
|
||||
*
|
||||
* @see JsonReadBeanVisitor
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class JsonElementString implements JsonElement {
|
||||
|
||||
private final String value;
|
||||
|
||||
public JsonElementString(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean isPrimitive() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toPrimitiveString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Object eval(String exp) {
|
||||
if (exp != null) {
|
||||
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public int evalInt(String exp) {
|
||||
if (exp != null) {
|
||||
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public String evalString(String exp) {
|
||||
if (exp != null) {
|
||||
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean evalBoolean(String exp) {
|
||||
if (exp != null) {
|
||||
throw new IllegalArgumentException("expression [" + exp + "] not allowed on number");
|
||||
}
|
||||
return Boolean.parseBoolean(exp);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
/**
|
||||
* Unchecked exception thrown when an IOException occurs in json processing.
|
||||
* <p>
|
||||
* Typically wraps the checked IOException.
|
||||
* </p>
|
||||
*/
|
||||
public class JsonIOException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Construct with an underlying cause.
|
||||
*/
|
||||
public JsonIOException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a message.
|
||||
*/
|
||||
public JsonIOException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Provides for some custom handling of json content as it is read.
|
||||
* <p>
|
||||
* This visit method is called after all the known properties of the bean have
|
||||
* been processed. Any JSON elements that could not be mapped to known bean
|
||||
* properties are available in the unmapped Map.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <T>
|
||||
* The type of entity bean
|
||||
*/
|
||||
public interface JsonReadBeanVisitor<T> {
|
||||
|
||||
/**
|
||||
* Visit the bean that has just been processed.
|
||||
* <p>
|
||||
* This provides a method of customising the bean and processing any custom
|
||||
* JSON content.
|
||||
* </p>
|
||||
*
|
||||
* @param bean
|
||||
* the bean being processed
|
||||
* @param unmapped
|
||||
* Map of any JSON elements that didn't map to known bean properties
|
||||
*/
|
||||
public void visit(T bean, Map<String, JsonElement> unmapped);
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Provides the ability to customise the reading of JSON content.
|
||||
* <p>
|
||||
* You can optionally provide a custom JsonValueAdapter to handle specific
|
||||
* formatting for Date and DateTime types.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can optionally register JsonReadBeanVisitors to customise the processing
|
||||
* of the beans as they are processed and handle any custom JSON elements that
|
||||
* could not be mapped to bean properties.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public class JsonReadOptions {
|
||||
|
||||
protected JsonValueAdapter valueAdapter;
|
||||
|
||||
protected Map<String, JsonReadBeanVisitor<?>> visitorMap;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public JsonReadOptions() {
|
||||
this.visitorMap = new LinkedHashMap<String, JsonReadBeanVisitor<?>>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JsonValueAdapter.
|
||||
*/
|
||||
public JsonValueAdapter getValueAdapter() {
|
||||
return valueAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the map of JsonReadBeanVisitor's.
|
||||
*/
|
||||
public Map<String, JsonReadBeanVisitor<?>> getVisitorMap() {
|
||||
return visitorMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a JsonValueAdapter for custom DateTime and Date formatting.
|
||||
*/
|
||||
public JsonReadOptions setValueAdapter(JsonValueAdapter valueAdapter) {
|
||||
this.valueAdapter = valueAdapter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a JsonReadBeanVisitor for the root level.
|
||||
*/
|
||||
public JsonReadOptions addRootVisitor(JsonReadBeanVisitor<?> visitor) {
|
||||
return addVisitor(null, visitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a JsonReadBeanVisitor for a given path.
|
||||
*/
|
||||
public JsonReadOptions addVisitor(String path, JsonReadBeanVisitor<?> visitor) {
|
||||
visitorMap.put(path, visitor);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2009 Authors
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Ebean is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* Allows you to customise the Date and Timestamp formats.
|
||||
* <p>
|
||||
* There is not a standard JSON format for Date or Timestamp types. By default
|
||||
* Ebean uses ISO8601 "yyyy-MM-dd'T'HH:mm:ss.SSSZ" and "yyyy-MM-dd".
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that Ebean will convert Joda types to either of the Date or Timestamp
|
||||
* types and back for you.
|
||||
* </p>
|
||||
*
|
||||
* @see JsonReadOptions
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface JsonValueAdapter {
|
||||
|
||||
/**
|
||||
* Convert the Date to json string.
|
||||
*/
|
||||
public String jsonFromDate(java.sql.Date date);
|
||||
|
||||
/**
|
||||
* Convert the DateTime to json string.
|
||||
*/
|
||||
public String jsonFromTimestamp(java.sql.Timestamp date);
|
||||
|
||||
/**
|
||||
* Parse the JSON string into a Date.
|
||||
*/
|
||||
public java.sql.Date jsonToDate(String jsonDate);
|
||||
|
||||
/**
|
||||
* Parse the JSON DateTime into a Timestamp.
|
||||
*/
|
||||
public Timestamp jsonToTimestamp(String jsonDateTime);
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
/**
|
||||
* Allows for customising the JSON write processing.
|
||||
* <p>
|
||||
* You can use this to add raw JSON content via {@link JsonWriter}.
|
||||
* </p>
|
||||
* <p>
|
||||
* You register a JsonWriteBeanVisitor with {@link JsonWriteOptions}.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
* @param <T>
|
||||
* the type of entity bean
|
||||
*
|
||||
* @see JsonWriteOptions
|
||||
*/
|
||||
public interface JsonWriteBeanVisitor<T> {
|
||||
|
||||
/**
|
||||
* Visit the bean that has just been writing it's content to JSON. You can
|
||||
* write your own additional JSON content to the JsonWriter if you wish.
|
||||
*
|
||||
* @param bean
|
||||
* the bean that has been writing it's content
|
||||
* @param jsonWriter
|
||||
* the JsonWriter which you can append custom json content to if you
|
||||
* wish.
|
||||
*/
|
||||
public void visit(T bean, JsonWriter jsonWriter);
|
||||
|
||||
}
|
||||
@@ -1,78 +1,23 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebean.text.PathProperties;
|
||||
|
||||
/**
|
||||
* Provides options for customising the JSON write process.
|
||||
* <p>
|
||||
* You can optionally provide a custom JsonValueAdapter to handle specific
|
||||
* formatting for Date and DateTime types.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can optionally register JsonWriteBeanVisitors to customise the processing
|
||||
* of the beans as they are processed and <strong>add raw JSON
|
||||
* elements</strong>.
|
||||
* </p>
|
||||
* <p>
|
||||
* You can explicitly state which properties to include in the JSON output for
|
||||
* the root level and each path.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* // find some customers ...
|
||||
*
|
||||
* List<Customer> list = Ebean.find(Customer.class).select("id, name, status, shippingAddress")
|
||||
* .fetch("billingAddress",
|
||||
* "line1, city").fetch("billingAddress.country", "*").fetch("contacts", "firstName,email")
|
||||
* .order().desc("id")
|
||||
* .findList();
|
||||
*
|
||||
* JsonContext json = Ebean.createJsonContext();
|
||||
*
|
||||
* JsonWriteOptions writeOptions = new JsonWriteOptions();
|
||||
* writeOptions.setRootPathVisitor(new JsonWriteBeanVisitor<Customer>() {
|
||||
*
|
||||
* public void visit(Customer bean, JsonWriter ctx) {
|
||||
* System.out.println("write visit customer: " + bean);
|
||||
* ctx.appendKeyValue("dummyCust", "34");
|
||||
* ctx.appendKeyValue("smallCustObject", "{\"a\":34,\"b\":\"asdasdasd\"}");
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* writeOptions.setPathProperties("contacts", "firstName,id");
|
||||
* writeOptions.setPathVisitor("contacts", new JsonWriteBeanVisitor<Contact>() {
|
||||
*
|
||||
* public void visit(Contact bean, JsonWriter ctx) {
|
||||
* System.out.println("write additional custom json on customer: " + bean);
|
||||
* ctx.appendKeyValue("dummy", " 3400" + bean.getId() + "");
|
||||
* ctx.appendKeyValue("smallObject", "{\"contactA\":34,\"contactB\":\"banana\"}");
|
||||
* }
|
||||
*
|
||||
* });
|
||||
*
|
||||
|
||||
* // output as a JSON string with pretty formatting
|
||||
* String s = json.toJsonString(list, true, writeOptions);
|
||||
* String s = json.toJson(list, true, writeOptions);
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @see JsonContext#toList(Class, String, JsonReadOptions)
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public class JsonWriteOptions {
|
||||
|
||||
protected String callback;
|
||||
|
||||
protected JsonValueAdapter valueAdapter;
|
||||
|
||||
protected Map<String, JsonWriteBeanVisitor<?>> visitorMap;
|
||||
|
||||
protected PathProperties pathProperties;
|
||||
|
||||
/**
|
||||
@@ -88,138 +33,6 @@ public class JsonWriteOptions {
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* This creates and returns a copy of these options.
|
||||
* <p>
|
||||
* Note that it assumes that the JsonWriteBeanVisitor (if defined) are
|
||||
* immutable and any JsonWriteBeanVisitor instances are shared between the
|
||||
* original and the copy.
|
||||
* </p>
|
||||
*/
|
||||
public JsonWriteOptions copy() {
|
||||
JsonWriteOptions copy = new JsonWriteOptions();
|
||||
copy.callback = callback;
|
||||
copy.valueAdapter = valueAdapter;
|
||||
copy.pathProperties = pathProperties;
|
||||
if (visitorMap != null) {
|
||||
copy.visitorMap = new HashMap<String, JsonWriteBeanVisitor<?>>(visitorMap);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a JSONP callback function.
|
||||
*/
|
||||
public String getCallback() {
|
||||
return callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a JSONP callback function.
|
||||
*/
|
||||
public JsonWriteOptions setCallback(String callback) {
|
||||
this.callback = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JsonValueAdapter.
|
||||
*/
|
||||
public JsonValueAdapter getValueAdapter() {
|
||||
return valueAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a JsonValueAdapter for custom DateTime and Date formatting.
|
||||
*/
|
||||
public JsonWriteOptions setValueAdapter(JsonValueAdapter valueAdapter) {
|
||||
this.valueAdapter = valueAdapter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a JsonWriteBeanVisitor for the root level.
|
||||
*/
|
||||
public JsonWriteOptions setRootPathVisitor(JsonWriteBeanVisitor<?> visitor) {
|
||||
return setPathVisitor(null, visitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a JsonWriteBeanVisitor for the given path.
|
||||
*/
|
||||
public JsonWriteOptions setPathVisitor(String path, JsonWriteBeanVisitor<?> visitor) {
|
||||
if (visitorMap == null) {
|
||||
visitorMap = new HashMap<String, JsonWriteBeanVisitor<?>>();
|
||||
}
|
||||
visitorMap.put(path, visitor);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the properties to include in the JSON output for the given path.
|
||||
*
|
||||
* @param propertiesToInclude
|
||||
* The set of properties to output
|
||||
*/
|
||||
public JsonWriteOptions setPathProperties(String path, Set<String> propertiesToInclude) {
|
||||
if (pathProperties == null) {
|
||||
pathProperties = new PathProperties();
|
||||
}
|
||||
pathProperties.put(path, propertiesToInclude);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the properties to include in the JSON output for the given path.
|
||||
*
|
||||
* @param propertiesToInclude
|
||||
* Comma delimited list of properties to output
|
||||
*/
|
||||
public JsonWriteOptions setPathProperties(String path, String propertiesToInclude) {
|
||||
return setPathProperties(path, parseProps(propertiesToInclude));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the properties to include in the JSON output for the root level.
|
||||
*
|
||||
* @param propertiesToInclude
|
||||
* Comma delimited list of properties to output
|
||||
*/
|
||||
public JsonWriteOptions setRootPathProperties(String propertiesToInclude) {
|
||||
return setPathProperties(null, parseProps(propertiesToInclude));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the properties to include in the JSON output for the root level.
|
||||
*
|
||||
* @param propertiesToInclude
|
||||
* The set of properties to output
|
||||
*/
|
||||
public JsonWriteOptions setRootPathProperties(Set<String> propertiesToInclude) {
|
||||
return setPathProperties(null, propertiesToInclude);
|
||||
}
|
||||
|
||||
private Set<String> parseProps(String propertiesToInclude) {
|
||||
|
||||
LinkedHashSet<String> props = new LinkedHashSet<String>();
|
||||
|
||||
String[] split = propertiesToInclude.split(",");
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
String s = split[i].trim();
|
||||
if (s.length() > 0) {
|
||||
props.add(s);
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Map of registered JsonWriteBeanVisitor's by path.
|
||||
*/
|
||||
public Map<String, JsonWriteBeanVisitor<?>> getVisitorMap() {
|
||||
return visitorMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Map of properties to include by path.
|
||||
*/
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.avaje.ebean.text.json;
|
||||
|
||||
/**
|
||||
* The JSON Writer made available to JsonWriteBeanVisitor's so that you can
|
||||
* append your own JSON content into the output.
|
||||
*
|
||||
* @see JsonWriteBeanVisitor
|
||||
* @see JsonWriteOptions#setRootPathVisitor(JsonWriteBeanVisitor)
|
||||
* @see JsonWriteOptions#setPathVisitor(String, JsonWriteBeanVisitor)
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public interface JsonWriter {
|
||||
|
||||
/**
|
||||
* Use this to append some custom content into the JSON output.
|
||||
*
|
||||
* @param key
|
||||
* the json key
|
||||
*
|
||||
* @param rawJsonValue
|
||||
* raw json value
|
||||
*/
|
||||
public void appendRawValue(String key, String rawJsonValue);
|
||||
|
||||
public void appendQuoteEscapeValue(String key, String rawJsonValue);
|
||||
|
||||
}
|
||||
@@ -19,31 +19,10 @@
|
||||
* .order().desc("id")
|
||||
* .findList();
|
||||
*
|
||||
* JsonContext json = Ebean.createJsonContext();
|
||||
*
|
||||
* JsonWriteOptions writeOptions = new JsonWriteOptions();
|
||||
* writeOptions.setRootPathVisitor(new JsonWriteBeanVisitor<Customer>() {
|
||||
*
|
||||
* public void visit(Customer bean, JsonWriter ctx) {
|
||||
* System.out.println("write visit customer: " + bean);
|
||||
* ctx.appendKeyValue("dummyCust", "34");
|
||||
* ctx.appendKeyValue("smallCustObject", "{\"a\":34,\"b\":\"asdasdasd\"}");
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* writeOptions.setPathProperties("contacts", "firstName,id");
|
||||
* writeOptions.setPathVisitor("contacts", new JsonWriteBeanVisitor<Contact>() {
|
||||
*
|
||||
* public void visit(Contact bean, JsonWriter ctx) {
|
||||
* System.out.println("write additional custom json on customer: " + bean);
|
||||
* ctx.appendKeyValue("dummy", " 3400" + bean.getId() + "");
|
||||
* ctx.appendKeyValue("smallObject", "{\"contactA\":34,\"contactB\":\"banana\"}");
|
||||
* }
|
||||
*
|
||||
* });
|
||||
*
|
||||
* // output as a JSON string with pretty formatting
|
||||
* String s = json.toJsonString(list, true, writeOptions);
|
||||
* JsonContext json = Ebean.json();
|
||||
*
|
||||
* // output as a JSON string
|
||||
* String jsonOutput = json.toJson(list);
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@@ -31,6 +31,12 @@ public class BindParams implements Serializable {
|
||||
*/
|
||||
private String preparedSql;
|
||||
|
||||
/**
|
||||
* Bind hash and count used to detect when the bind values have changed such
|
||||
* that the generated SQL (with named parameters) needs to be recalculated.
|
||||
*/
|
||||
private int[] bindHash;
|
||||
|
||||
public BindParams() {
|
||||
}
|
||||
|
||||
@@ -51,20 +57,33 @@ public class BindParams implements Serializable {
|
||||
* </p>
|
||||
*/
|
||||
public void buildQueryPlanHash(HashQueryPlanBuilder builder) {
|
||||
int[] vals = calcQueryPlanHash();
|
||||
builder.add(vals[0]).bind(vals[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate and return a query plan bind hash with total bind count.
|
||||
*/
|
||||
public int[] calcQueryPlanHash() {
|
||||
int tempBindCount;
|
||||
int bc = 0;
|
||||
int hc = 31;
|
||||
for (Param param : positionedParameters) {
|
||||
hc = hc * 31 + param.queryBindCount();
|
||||
tempBindCount = param.queryBindCount();
|
||||
bc += tempBindCount;
|
||||
hc = hc * 31 + tempBindCount;
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Param> entry : namedParameters.entrySet()) {
|
||||
tempBindCount = entry.getValue().queryBindCount();
|
||||
bc += tempBindCount;
|
||||
hc = hc * 31 + entry.getKey().hashCode();
|
||||
hc = hc * 31 + entry.getValue().queryBindCount();
|
||||
hc = hc * 31 + tempBindCount;
|
||||
}
|
||||
|
||||
int bindCount = positionedParameters.size() + namedParameters.size();
|
||||
builder.add(hc).bind(bindCount);
|
||||
return new int[]{hc, bc};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a deep copy of the BindParams.
|
||||
*/
|
||||
@@ -110,7 +129,7 @@ public class BindParams implements Serializable {
|
||||
* parameters ordered.
|
||||
*/
|
||||
public boolean requiresNamedParamsPrepare() {
|
||||
return !namedParameters.isEmpty() && positionedParameters.isEmpty();
|
||||
return !namedParameters.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,7 +169,7 @@ public class BindParams implements Serializable {
|
||||
}
|
||||
|
||||
private Param getParam(String name) {
|
||||
Param p = (Param) namedParameters.get(name);
|
||||
Param p = namedParameters.get(name);
|
||||
if (p == null) {
|
||||
p = new Param();
|
||||
namedParameters.put(name, p);
|
||||
@@ -165,7 +184,7 @@ public class BindParams implements Serializable {
|
||||
positionedParameters.add(new Param());
|
||||
}
|
||||
}
|
||||
return (Param) positionedParameters.get(position - 1);
|
||||
return positionedParameters.get(position - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,7 +272,29 @@ public class BindParams implements Serializable {
|
||||
return preparedSql;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Return true if the bind hash and count has not changed.
|
||||
*/
|
||||
public boolean isSameBindHash() {
|
||||
|
||||
if (bindHash == null) {
|
||||
bindHash = calcQueryPlanHash();
|
||||
return false;
|
||||
}
|
||||
int[] oldPlan = bindHash;
|
||||
bindHash = calcQueryPlanHash();
|
||||
return bindHash[0] == oldPlan[0] && bindHash[1] == oldPlan[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new positioned parameters orderedList.
|
||||
*/
|
||||
public OrderedList createOrderedList() {
|
||||
positionedParameters.clear();
|
||||
return new OrderedList(positionedParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* The bind parameters in the correct binding order.
|
||||
* <p>
|
||||
* This is the result of converting sql with named parameters
|
||||
@@ -327,8 +368,6 @@ public class BindParams implements Serializable {
|
||||
|
||||
private Object outValue;
|
||||
|
||||
private int textLocation;
|
||||
|
||||
/**
|
||||
* Construct a Parameter.
|
||||
*/
|
||||
@@ -368,17 +407,8 @@ public class BindParams implements Serializable {
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == null) {
|
||||
return false;
|
||||
}
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (o instanceof Param) {
|
||||
return hashCode() == o.hashCode();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return o != null && (o == this || (o instanceof Param) && hashCode() == o.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is an In parameter that needs to be bound before
|
||||
@@ -463,21 +493,6 @@ public class BindParams implements Serializable {
|
||||
this.outValue = out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location this parameter was found in the sql text.
|
||||
*/
|
||||
public int getTextLocation() {
|
||||
return textLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the location in the sql text this parameter was located. This is
|
||||
* used to control order for named parameters.
|
||||
*/
|
||||
public void setTextLocation(int textLocation) {
|
||||
this.textLocation = textLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true do not include this value in a transaction log.
|
||||
*/
|
||||
|
||||
@@ -11,6 +11,8 @@ import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
*/
|
||||
public interface LoadBeanBuffer {
|
||||
|
||||
public int getBatchSize();
|
||||
|
||||
public List<EntityBeanIntercept> getBatch();
|
||||
|
||||
public BeanDescriptor<?> getBeanDescriptor();
|
||||
|
||||
@@ -59,4 +59,7 @@ public class LoadBeanRequest extends LoadRequest {
|
||||
return lazyLoadProperty;
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return getLoadContext().getBatchSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,16 +11,16 @@ import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
*/
|
||||
public interface LoadContext {
|
||||
|
||||
/**
|
||||
* Return the minimum batch size when using QueryIterator with query joins.
|
||||
*/
|
||||
public int getSecondaryQueriesMinBatchSize(OrmQueryRequest<?> parentRequest, int defaultQueryBatch);
|
||||
/**
|
||||
* Return the minimum batch size when using QueryIterator with query joins.
|
||||
*/
|
||||
public int getSecondaryQueriesMinBatchSize(OrmQueryRequest<?> parentRequest, int defaultQueryBatch);
|
||||
|
||||
/**
|
||||
* Execute any secondary (+query) queries if there are any defined.
|
||||
* @param parentRequest the originating query request
|
||||
*/
|
||||
public void executeSecondaryQueries(OrmQueryRequest<?> parentRequest, int defaultQueryBatch);
|
||||
public void executeSecondaryQueries(OrmQueryRequest<?> parentRequest);
|
||||
|
||||
/**
|
||||
* Register any secondary queries (+query or +lazy) with their
|
||||
|
||||
@@ -13,6 +13,8 @@ import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
*/
|
||||
public interface LoadManyBuffer {
|
||||
|
||||
public int getBatchSize();
|
||||
|
||||
public List<BeanCollection<?>> getBatch();
|
||||
|
||||
public BeanPropertyAssocMany<?> getBeanProperty();
|
||||
|
||||
@@ -18,12 +18,11 @@ public class LoadManyRequest extends LoadRequest {
|
||||
|
||||
private final boolean loadCache;
|
||||
|
||||
public LoadManyRequest(LoadManyBuffer loadContext, int batchSize, boolean lazy,boolean onlyIds, boolean loadCache) {
|
||||
this(loadContext, null, batchSize, lazy, onlyIds, loadCache);
|
||||
public LoadManyRequest(LoadManyBuffer loadContext, boolean lazy, boolean onlyIds, boolean loadCache) {
|
||||
this(loadContext, null, lazy, onlyIds, loadCache);
|
||||
}
|
||||
|
||||
public LoadManyRequest(LoadManyBuffer loadContext, OrmQueryRequest<?> parentRequest, int batchSize, boolean lazy,
|
||||
boolean onlyIds, boolean loadCache) {
|
||||
public LoadManyRequest(LoadManyBuffer loadContext, OrmQueryRequest<?> parentRequest, boolean lazy, boolean onlyIds, boolean loadCache) {
|
||||
|
||||
super(parentRequest, lazy);
|
||||
this.loadContext = loadContext;
|
||||
@@ -69,4 +68,10 @@ public class LoadManyRequest extends LoadRequest {
|
||||
return loadCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size used for this load context.
|
||||
*/
|
||||
public int getBatchSize() {
|
||||
return loadContext.getBatchSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,6 @@ public interface LoadSecondaryQuery {
|
||||
|
||||
/**
|
||||
* Execute the secondary query with a given batch size.
|
||||
*
|
||||
* @param parentRequest
|
||||
* the originating query request
|
||||
*/
|
||||
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, int requestedBatchSize, boolean all);
|
||||
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest);
|
||||
}
|
||||
|
||||
@@ -53,13 +53,15 @@ public class ManyWhereJoins implements Serializable {
|
||||
String join = elProp.getElPrefix();
|
||||
BeanProperty p = elProp.getBeanProperty();
|
||||
if (p instanceof BeanPropertyAssocMany<?>){
|
||||
join = addManyToJoin(join, p.getName());
|
||||
join = addManyToJoin(join, p.getName());
|
||||
}
|
||||
if (join != null){
|
||||
addJoin(join);
|
||||
String secondaryTableJoinPrefix = p.getSecondaryTableJoinPrefix();
|
||||
if (secondaryTableJoinPrefix != null) {
|
||||
addJoin(join+"."+secondaryTableJoinPrefix);
|
||||
if (p != null) {
|
||||
String secondaryTableJoinPrefix = p.getSecondaryTableJoinPrefix();
|
||||
if (secondaryTableJoinPrefix != null) {
|
||||
addJoin(join+"."+secondaryTableJoinPrefix);
|
||||
}
|
||||
}
|
||||
addParentJoins(join);
|
||||
}
|
||||
|
||||
@@ -2,10 +2,7 @@ package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.TxScope;
|
||||
import com.avaje.ebean.*;
|
||||
import com.avaje.ebean.bean.BeanCollectionLoader;
|
||||
import com.avaje.ebean.bean.BeanLoader;
|
||||
import com.avaje.ebean.bean.CallStack;
|
||||
@@ -63,6 +60,11 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL
|
||||
*/
|
||||
public CallStack createCallStack();
|
||||
|
||||
/**
|
||||
* Return the PersistenceContextScope to use defined at query or server level.
|
||||
*/
|
||||
public PersistenceContextScope getPersistenceContextScope(SpiQuery<?> query);
|
||||
|
||||
/**
|
||||
* Return the DDL generator.
|
||||
*/
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import com.avaje.ebean.ExpressionFactory;
|
||||
import com.avaje.ebeaninternal.server.expression.FilterExprPath;
|
||||
|
||||
public interface SpiExpressionFactory extends ExpressionFactory {
|
||||
|
||||
/**
|
||||
* Create another expression factory with a given sub path.
|
||||
*/
|
||||
public ExpressionFactory createExpressionFactory();//FilterExprPath prefix);
|
||||
|
||||
/**
|
||||
* Create another expression factory with a given sub path.
|
||||
*/
|
||||
public ExpressionFactory createExpressionFactory();
|
||||
|
||||
}
|
||||
|
||||
@@ -44,9 +44,14 @@ public interface SpiExpressionRequest {
|
||||
* Return the ordered list of bind values for all expressions in this request.
|
||||
*/
|
||||
public ArrayList<Object> getBindValues();
|
||||
|
||||
/**
|
||||
* Increments the parameter index and returns that value.
|
||||
*/
|
||||
public int nextParameter();
|
||||
|
||||
/**
|
||||
* Increments the parameter index and returns that value.
|
||||
*/
|
||||
public int nextParameter();
|
||||
|
||||
/**
|
||||
* Append a DB Like clause.
|
||||
*/
|
||||
public void appendLike();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.List;
|
||||
|
||||
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;
|
||||
@@ -26,7 +27,7 @@ import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
*/
|
||||
public interface SpiQuery<T> extends Query<T> {
|
||||
|
||||
public enum Mode {
|
||||
public enum Mode {
|
||||
NORMAL(false), LAZYLOAD_MANY(false), LAZYLOAD_BEAN(true), REFRESH_BEAN(true);
|
||||
Mode(boolean loadContextBean) {
|
||||
this.loadContextBean = loadContextBean;
|
||||
@@ -79,7 +80,20 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
*/
|
||||
SUBQUERY
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the PersistenceContextScope that this query should use.
|
||||
* <p>
|
||||
* This can be null and in that case use the default scope.
|
||||
* </p>
|
||||
*/
|
||||
public PersistenceContextScope getPersistenceContextScope();
|
||||
|
||||
/**
|
||||
* Return the default lazy load batch size.
|
||||
*/
|
||||
public int getLazyLoadBatchSize();
|
||||
|
||||
/**
|
||||
* Return true if select all properties was used to ensure the property
|
||||
* invoking a lazy load was included in the query.
|
||||
@@ -532,12 +546,24 @@ public interface SpiQuery<T> extends Query<T> {
|
||||
* Return the index of the first row to return in the query.
|
||||
*/
|
||||
public int getFirstRow();
|
||||
|
||||
/**
|
||||
* Internally set by Ebean when this query must use the DISTINCT keyword.
|
||||
* <p>
|
||||
* This does not exclude/remove the use of the id property.
|
||||
*/
|
||||
public Query<T> setSqlDistinct(boolean sqlDistinct);
|
||||
|
||||
/**
|
||||
* return true if this query uses DISTINCT.
|
||||
* Return true if this query has been specified by a user or internally by Ebean to use DISTINCT.
|
||||
*/
|
||||
public boolean isDistinctQuery();
|
||||
|
||||
/**
|
||||
* Return true if this query has been specified by a user to use DISTINCT.
|
||||
*/
|
||||
public boolean isDistinct();
|
||||
|
||||
|
||||
/**
|
||||
* Set default select clauses where none have been explicitly defined.
|
||||
*/
|
||||
|
||||
@@ -5,4 +5,6 @@ import com.avaje.ebean.SqlUpdate;
|
||||
public interface SpiSqlUpdate extends SqlUpdate {
|
||||
|
||||
public BindParams getBindParams();
|
||||
|
||||
public void setGeneratedSql(String sql);
|
||||
}
|
||||
|
||||
@@ -15,178 +15,183 @@ import com.avaje.ebeaninternal.server.persist.BatchControl;
|
||||
*/
|
||||
public interface SpiTransaction extends Transaction {
|
||||
|
||||
/**
|
||||
* End the transaction when had query only use.
|
||||
*/
|
||||
public void endQueryOnly();
|
||||
|
||||
/**
|
||||
* Return the string prefix with the transactin id and label used in logging.
|
||||
*/
|
||||
public String getLogPrefix();
|
||||
|
||||
/**
|
||||
* Return true if generated SQL and Bind values should be logged to the
|
||||
* transaction log.
|
||||
*/
|
||||
public boolean isLogSql();
|
||||
|
||||
/**
|
||||
* Return true if summary level events should be logged to the transaction
|
||||
* log.
|
||||
*/
|
||||
public boolean isLogSummary();
|
||||
/**
|
||||
* Return true if generated SQL and Bind values should be logged to the
|
||||
* transaction log.
|
||||
*/
|
||||
public boolean isLogSql();
|
||||
|
||||
/**
|
||||
* Log a message to the SQL logger.
|
||||
*/
|
||||
public void logSql(String msg);
|
||||
/**
|
||||
* Return true if summary level events should be logged to the transaction
|
||||
* log.
|
||||
*/
|
||||
public boolean isLogSummary();
|
||||
|
||||
/**
|
||||
* Log a message to the SUMMARY logger.
|
||||
*/
|
||||
public void logSummary(String msg);
|
||||
/**
|
||||
* Log a message to the SQL logger.
|
||||
*/
|
||||
public void logSql(String msg);
|
||||
|
||||
/**
|
||||
* Register a "Derived Relationship" (that requires an additional update).
|
||||
*/
|
||||
public void registerDerivedRelationship(DerivedRelationshipData assocBean);
|
||||
/**
|
||||
* Log a message to the SUMMARY logger.
|
||||
*/
|
||||
public void logSummary(String msg);
|
||||
|
||||
/**
|
||||
* Return the list of "Derived Relationships" that must be maintained after
|
||||
* insert.
|
||||
*/
|
||||
public List<DerivedRelationshipData> getDerivedRelationship(Object bean);
|
||||
/**
|
||||
* Register a "Derived Relationship" (that requires an additional update).
|
||||
*/
|
||||
public void registerDerivedRelationship(DerivedRelationshipData assocBean);
|
||||
|
||||
/**
|
||||
* Add a deleting bean to the registered list.
|
||||
* <p>
|
||||
* This is to handle bi-directional relationships where both sides Cascade.
|
||||
* </p>
|
||||
*/
|
||||
public void registerDeleteBean(Integer hash);
|
||||
/**
|
||||
* Return the list of "Derived Relationships" that must be maintained after
|
||||
* insert.
|
||||
*/
|
||||
public List<DerivedRelationshipData> getDerivedRelationship(Object bean);
|
||||
|
||||
/**
|
||||
* Unregister the hash of the bean.
|
||||
*/
|
||||
public void unregisterDeleteBean(Integer hash);
|
||||
/**
|
||||
* Add a deleting bean to the registered list.
|
||||
* <p>
|
||||
* This is to handle bi-directional relationships where both sides Cascade.
|
||||
* </p>
|
||||
*/
|
||||
public void registerDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Return true if this is a bean that has already been saved/deleted.
|
||||
*/
|
||||
public boolean isRegisteredDeleteBean(Integer hash);
|
||||
/**
|
||||
* Unregister the hash of the bean.
|
||||
*/
|
||||
public void unregisterDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Unregister the persisted bean.
|
||||
*/
|
||||
public void unregisterBean(Object bean);
|
||||
/**
|
||||
* Return true if this is a bean that has already been saved/deleted.
|
||||
*/
|
||||
public boolean isRegisteredDeleteBean(Integer hash);
|
||||
|
||||
/**
|
||||
* Return true if this is a bean that has already been persisted in the
|
||||
* current recursive save request. The goal is to stop recursively saving
|
||||
* the bean when cascade persist is on both sides of a relationship).
|
||||
* <p>
|
||||
* This will register the bean if it is not already.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isRegisteredBean(Object bean);
|
||||
/**
|
||||
* Unregister the persisted bean.
|
||||
*/
|
||||
public void unregisterBean(Object bean);
|
||||
|
||||
/**
|
||||
* Returns a String used to identify the transaction. This id is used for
|
||||
* Transaction logging.
|
||||
*/
|
||||
public String getId();
|
||||
/**
|
||||
* Return true if this is a bean that has already been persisted in the
|
||||
* current recursive save request. The goal is to stop recursively saving
|
||||
* the bean when cascade persist is on both sides of a relationship).
|
||||
* <p>
|
||||
* This will register the bean if it is not already.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isRegisteredBean(Object bean);
|
||||
|
||||
/**
|
||||
* Return the batchSize specifically set for this transaction or 0.
|
||||
* <p>
|
||||
* Returning 0 implies to use the system wide default batch size.
|
||||
* </p>
|
||||
*/
|
||||
public int getBatchSize();
|
||||
/**
|
||||
* Returns a String used to identify the transaction. This id is used for
|
||||
* Transaction logging.
|
||||
*/
|
||||
public String getId();
|
||||
|
||||
/**
|
||||
* Modify and return the current 'depth' of the transaction.
|
||||
* <p>
|
||||
* As we cascade save or delete we traverse the object graph tree. Going up
|
||||
* to Assoc Ones the depth decreases and going down to Assoc Manys the depth
|
||||
* increases.
|
||||
* </p>
|
||||
* <p>
|
||||
* The depth is used for ordering batching statements. The lowest depth get
|
||||
* executed first during save.
|
||||
* </p>
|
||||
*/
|
||||
public int depth(int diff);
|
||||
/**
|
||||
* Return the batchSize specifically set for this transaction or 0.
|
||||
* <p>
|
||||
* Returning 0 implies to use the system wide default batch size.
|
||||
* </p>
|
||||
*/
|
||||
public int getBatchSize();
|
||||
|
||||
/**
|
||||
* Return true if this transaction was created explicitly via
|
||||
* <code>Ebean.beginTransaction()</code>.
|
||||
*/
|
||||
public boolean isExplicit();
|
||||
/**
|
||||
* Modify and return the current 'depth' of the transaction.
|
||||
* <p>
|
||||
* As we cascade save or delete we traverse the object graph tree. Going up
|
||||
* to Assoc Ones the depth decreases and going down to Assoc Manys the depth
|
||||
* increases.
|
||||
* </p>
|
||||
* <p>
|
||||
* The depth is used for ordering batching statements. The lowest depth get
|
||||
* executed first during save.
|
||||
* </p>
|
||||
*/
|
||||
public int depth(int diff);
|
||||
|
||||
/**
|
||||
* Get the object that holds the event details.
|
||||
* <p>
|
||||
* This information is used maintain the table state, cache and text
|
||||
* indexes. On commit the Table modifications this generates is broadcast
|
||||
* around the cluster (if you have a cluster).
|
||||
* </p>
|
||||
*/
|
||||
public TransactionEvent getEvent();
|
||||
/**
|
||||
* Return true if this transaction was created explicitly via
|
||||
* <code>Ebean.beginTransaction()</code>.
|
||||
*/
|
||||
public boolean isExplicit();
|
||||
|
||||
/**
|
||||
* Whether persistCascade is on for save and delete.
|
||||
*/
|
||||
public boolean isPersistCascade();
|
||||
/**
|
||||
* Get the object that holds the event details.
|
||||
* <p>
|
||||
* This information is used maintain the table state, cache and text
|
||||
* indexes. On commit the Table modifications this generates is broadcast
|
||||
* around the cluster (if you have a cluster).
|
||||
* </p>
|
||||
*/
|
||||
public TransactionEvent getEvent();
|
||||
|
||||
/**
|
||||
* Return true if this request should be batched. Conversely returns false
|
||||
* if this request should be executed immediately.
|
||||
*/
|
||||
public boolean isBatchThisRequest();
|
||||
/**
|
||||
* Whether persistCascade is on for save and delete.
|
||||
*/
|
||||
public boolean isPersistCascade();
|
||||
|
||||
/**
|
||||
* Return the queue used to batch up persist requests.
|
||||
*/
|
||||
public BatchControl getBatchControl();
|
||||
/**
|
||||
* Return true if this request should be batched. Conversely returns false
|
||||
* if this request should be executed immediately.
|
||||
*/
|
||||
public boolean isBatchThisRequest();
|
||||
|
||||
/**
|
||||
* Set the queue used to batch up persist requests. There should only be one
|
||||
* PersistQueue set per transaction.
|
||||
*/
|
||||
public void setBatchControl(BatchControl control);
|
||||
/**
|
||||
* Return the queue used to batch up persist requests.
|
||||
*/
|
||||
public BatchControl getBatchControl();
|
||||
|
||||
/**
|
||||
* Return the persistence context associated with this transaction.
|
||||
* <p>
|
||||
* You may wish to hold onto this and set it against another transaction
|
||||
* later. This is along the lines of 'extended persistence context'
|
||||
* behaviour.
|
||||
* </p>
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
/**
|
||||
* Set the queue used to batch up persist requests. There should only be one
|
||||
* PersistQueue set per transaction.
|
||||
*/
|
||||
public void setBatchControl(BatchControl control);
|
||||
|
||||
/**
|
||||
* Set the persistence context to this transaction.
|
||||
* <p>
|
||||
* This could be considered similar to 'EJB3 Extended Persistence Context'.
|
||||
* In that you can get the PersistenceContext from a transaction, hold onto
|
||||
* it, and then set it back later to a second transaction. In general there
|
||||
* is one PersistenceContext per Transaction. The getPersistenceContext()
|
||||
* and setPersistenceContext() enable a developer to reuse a single
|
||||
* PersistenceContext with multiple transactions.
|
||||
* </p>
|
||||
*/
|
||||
public void setPersistenceContext(PersistenceContext context);
|
||||
/**
|
||||
* Return the persistence context associated with this transaction.
|
||||
* <p>
|
||||
* You may wish to hold onto this and set it against another transaction
|
||||
* later. This is along the lines of 'extended persistence context'
|
||||
* behaviour.
|
||||
* </p>
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext();
|
||||
|
||||
/**
|
||||
* Return the underlying Connection for internal use.
|
||||
* <p>
|
||||
* If the connection is made public from Transaction and the user code calls
|
||||
* that method we can no longer trust the query only status of a
|
||||
* Transaction.
|
||||
* </p>
|
||||
*/
|
||||
public Connection getInternalConnection();
|
||||
/**
|
||||
* Set the persistence context to this transaction.
|
||||
* <p>
|
||||
* This could be considered similar to 'EJB3 Extended Persistence Context'.
|
||||
* In that you can get the PersistenceContext from a transaction, hold onto
|
||||
* it, and then set it back later to a second transaction. In general there
|
||||
* is one PersistenceContext per Transaction. The getPersistenceContext()
|
||||
* and setPersistenceContext() enable a developer to reuse a single
|
||||
* PersistenceContext with multiple transactions.
|
||||
* </p>
|
||||
*/
|
||||
public void setPersistenceContext(PersistenceContext context);
|
||||
|
||||
/**
|
||||
* Return true if the manyToMany intersection should be persisted for this particular relationship direction.
|
||||
*/
|
||||
/**
|
||||
* Return the underlying Connection for internal use.
|
||||
* <p>
|
||||
* If the connection is made public from Transaction and the user code calls
|
||||
* that method we can no longer trust the query only status of a
|
||||
* Transaction.
|
||||
* </p>
|
||||
*/
|
||||
public Connection getInternalConnection();
|
||||
|
||||
/**
|
||||
* Return true if the manyToMany intersection should be persisted for this particular relationship direction.
|
||||
*/
|
||||
public boolean isSaveAssocManyIntersection(String intersectionTable, String beanName);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.cache;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheTuning;
|
||||
@@ -89,9 +88,7 @@ public class DefaultCacheHolder {
|
||||
}
|
||||
|
||||
public void clearAll() {
|
||||
Iterator<ServerCache> it = concMap.values().iterator();
|
||||
while (it.hasNext()) {
|
||||
ServerCache serverCache = it.next();
|
||||
for (ServerCache serverCache : concMap.values()) {
|
||||
serverCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,9 +111,7 @@ public class DefaultServerCache implements ServerCache {
|
||||
|
||||
int hc = reset ? removedHitCount.getAndSet(0) : removedHitCount.get();
|
||||
|
||||
Iterator<CacheEntry> it = map.values().iterator();
|
||||
while (it.hasNext()) {
|
||||
CacheEntry cacheEntry = it.next();
|
||||
for (CacheEntry cacheEntry : map.values()) {
|
||||
hc += cacheEntry.getHitCount(reset);
|
||||
}
|
||||
|
||||
@@ -268,10 +266,6 @@ public class DefaultServerCache implements ServerCache {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
private Iterator<CacheEntry> cacheEntries() {
|
||||
return map.values().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* The task used to periodically trim the cache.
|
||||
*/
|
||||
@@ -296,7 +290,7 @@ public class DefaultServerCache implements ServerCache {
|
||||
long idleExpire = System.currentTimeMillis() - (maxIdleSecs*1000);
|
||||
long ttlExpire = System.currentTimeMillis() - (maxSecsToLive*1000);
|
||||
|
||||
Iterator<CacheEntry> it = cacheEntries();
|
||||
Iterator<CacheEntry> it = map.values().iterator();
|
||||
while (it.hasNext()) {
|
||||
CacheEntry cacheEntry = it.next();
|
||||
if (maxIdleSecs > 0 && idleExpire > cacheEntry.getLastAccessTime()) {
|
||||
|
||||
+7
-4
@@ -40,10 +40,13 @@ public class DefaultServerCacheManager implements ServerCacheManager {
|
||||
cacheFactory.init(server);
|
||||
this.ebeanServer = (SpiEbeanServer)server;
|
||||
}
|
||||
|
||||
public void setCaching(Class<?> beanType, boolean useCache) {
|
||||
ebeanServer.getBeanDescriptor(beanType).getCacheOptions().setUseCache(useCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set bean caching on or off for a given bean type.
|
||||
*/
|
||||
public void setCaching(Class<?> beanType, boolean useCache) {
|
||||
ebeanServer.getBeanDescriptor(beanType).setUseCache(useCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear both the bean cache and the query cache for a
|
||||
|
||||
@@ -32,8 +32,6 @@ public abstract class BeanRequest {
|
||||
|
||||
protected boolean createdTransaction;
|
||||
|
||||
protected boolean readOnly;
|
||||
|
||||
public BeanRequest(SpiEbeanServer ebeanServer, SpiTransaction t) {
|
||||
this.ebeanServer = ebeanServer;
|
||||
this.serverName = ebeanServer.getName();
|
||||
@@ -62,29 +60,19 @@ public abstract class BeanRequest {
|
||||
if (transaction == null || !transaction.isActive()) {
|
||||
// create an implicit transaction to execute this query
|
||||
transaction = ebeanServer.createServerTransaction(false, -1);
|
||||
// commented out for performance reasons...
|
||||
// TODO: review performance of trans.setReadOnly(true)
|
||||
//if (readOnlyTransaction) {
|
||||
// readOnly = true;
|
||||
// transaction.setReadOnly(true);
|
||||
//}
|
||||
createdTransaction = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit this transaction if it was created for this request.
|
||||
*/
|
||||
public void commitTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
if (readOnly) {
|
||||
transaction.rollback();
|
||||
} else {
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Commit this transaction if it was created for this request.
|
||||
*/
|
||||
public void commitTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the transaction if it was created for this request.
|
||||
@@ -128,17 +116,17 @@ public abstract class BeanRequest {
|
||||
return transaction.getInternalConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if SQL should be logged for this transaction.
|
||||
*/
|
||||
public boolean isLogSql() {
|
||||
return transaction.isLogSql();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if SUMMARY information should be logged for this transaction.
|
||||
*/
|
||||
public boolean isLogSummary() {
|
||||
return transaction.isLogSummary();
|
||||
}
|
||||
/**
|
||||
* Return true if SQL should be logged for this transaction.
|
||||
*/
|
||||
public boolean isLogSql() {
|
||||
return transaction.isLogSql();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if SUMMARY information should be logged for this transaction.
|
||||
*/
|
||||
public boolean isLogSummary() {
|
||||
return transaction.isLogSummary();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
@@ -11,6 +10,7 @@ import javax.persistence.Table;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.config.CompoundType;
|
||||
import com.avaje.ebean.config.ScalarTypeConverter;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
@@ -56,7 +56,7 @@ public class BootupClasses implements ClassPathSearchMatcher {
|
||||
private ArrayList<ServerConfigStartup> serverConfigStartupInstances = new ArrayList<ServerConfigStartup>();
|
||||
|
||||
private List<BeanPersistController> persistControllerInstances = new ArrayList<BeanPersistController>();
|
||||
private List<BeanPersistListener<?>> persistListenerInstances = new ArrayList<BeanPersistListener<?>>();
|
||||
private List<BeanPersistListener> persistListenerInstances = new ArrayList<BeanPersistListener>();
|
||||
private List<BeanQueryAdapter> queryAdapterInstances = new ArrayList<BeanQueryAdapter>();
|
||||
private List<TransactionEventListener> transactionEventListenerInstances = new ArrayList<TransactionEventListener>();
|
||||
|
||||
@@ -65,7 +65,9 @@ public class BootupClasses implements ClassPathSearchMatcher {
|
||||
|
||||
public BootupClasses(List<Class<?>> list) {
|
||||
if (list != null) {
|
||||
process(list.iterator());
|
||||
for (Class<?> cls : list) {
|
||||
isMatch(cls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,13 +85,6 @@ public class BootupClasses implements ClassPathSearchMatcher {
|
||||
this.serverConfigStartupList.addAll(parent.serverConfigStartupList);
|
||||
}
|
||||
|
||||
private void process(Iterator<Class<?>> it) {
|
||||
while (it.hasNext()) {
|
||||
Class<?> cls = it.next();
|
||||
isMatch(cls);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this object so that classes can be added to it.
|
||||
*/
|
||||
@@ -150,9 +145,9 @@ public class BootupClasses implements ClassPathSearchMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
public void addPersistListeners(List<BeanPersistListener<?>> listenerInstances) {
|
||||
public void addPersistListeners(List<BeanPersistListener> listenerInstances) {
|
||||
if (listenerInstances != null) {
|
||||
for (BeanPersistListener<?> l : listenerInstances) {
|
||||
for (BeanPersistListener l : listenerInstances) {
|
||||
this.persistListenerInstances.add(l);
|
||||
// don't automatically instantiate
|
||||
this.beanListenerList.remove(l.getClass());
|
||||
@@ -186,12 +181,12 @@ public class BootupClasses implements ClassPathSearchMatcher {
|
||||
return queryAdapterInstances;
|
||||
}
|
||||
|
||||
public List<BeanPersistListener<?>> getBeanPersistListeners() {
|
||||
public List<BeanPersistListener> getBeanPersistListeners() {
|
||||
// add class registered BeanPersistController to the
|
||||
// already created instances
|
||||
for (Class<?> cls : beanListenerList) {
|
||||
try {
|
||||
BeanPersistListener<?> newInstance = (BeanPersistListener<?>) cls.newInstance();
|
||||
BeanPersistListener newInstance = (BeanPersistListener) cls.newInstance();
|
||||
persistListenerInstances.add(newInstance);
|
||||
} catch (Exception e) {
|
||||
String msg = "Error creating BeanPersistController " + cls;
|
||||
@@ -297,13 +292,6 @@ public class BootupClasses implements ClassPathSearchMatcher {
|
||||
return beanListenerList;
|
||||
}
|
||||
|
||||
public void add(Iterator<Class<?>> it) {
|
||||
while (it.hasNext()) {
|
||||
Class<?> clazz = it.next();
|
||||
isMatch(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMatch(Class<?> cls) {
|
||||
|
||||
if (isEmbeddable(cls)) {
|
||||
|
||||
@@ -53,16 +53,16 @@ public class DatabasePlatformFactory {
|
||||
private DatabasePlatform byDatabaseName(String dbName) throws SQLException {
|
||||
|
||||
dbName = dbName.toLowerCase();
|
||||
if (dbName.equals("postgres83")) {
|
||||
if (dbName.equals("postgres") || dbName.equals("postgres9")) {
|
||||
return new PostgresPlatform();
|
||||
}
|
||||
if (dbName.equals("postgres8") || dbName.equals("postgres83")) {
|
||||
return new Postgres8Platform();
|
||||
}
|
||||
if (dbName.equals("oracle9")) {
|
||||
return new Oracle9Platform();
|
||||
}
|
||||
if (dbName.equals("oracle10")) {
|
||||
return new Oracle10Platform();
|
||||
}
|
||||
if (dbName.equals("oracle")) {
|
||||
if (dbName.equals("oracle") || dbName.equals("oracle10")) {
|
||||
return new Oracle10Platform();
|
||||
}
|
||||
if (dbName.equals("sqlserver2005")) {
|
||||
|
||||
@@ -8,8 +8,6 @@ import com.avaje.ebeaninternal.server.lib.DaemonThreadPool;
|
||||
|
||||
/**
|
||||
* The default implementation of the BackgroundExecutor.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
@@ -20,7 +18,7 @@ public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*
|
||||
* @param mainPoolSize
|
||||
* @param corePoolSize
|
||||
* the core size of the thread pool.
|
||||
* @param keepAliveSecs
|
||||
* the time in seconds idle threads are keep alive
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.avaje.ebeaninternal.api.SpiQuery.Mode;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
|
||||
|
||||
/**
|
||||
@@ -39,7 +40,7 @@ public class DefaultBeanLoader {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Return a batch size that might be less than the requestedBatchSize.
|
||||
* <p>
|
||||
* This means we can have large and variable requestedBatchSizes.
|
||||
@@ -50,7 +51,7 @@ public class DefaultBeanLoader {
|
||||
* </p>
|
||||
*/
|
||||
private int getBatchSize(int batchSize) {
|
||||
|
||||
|
||||
if (batchSize == 1) {
|
||||
// there is only one bean/collection to load
|
||||
return 1;
|
||||
@@ -73,10 +74,10 @@ public class DefaultBeanLoader {
|
||||
}
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
public void refreshMany(EntityBean parentBean, String propertyName) {
|
||||
refreshMany(parentBean, propertyName, null);
|
||||
}
|
||||
|
||||
public void refreshMany(EntityBean parentBean, String propertyName) {
|
||||
refreshMany(parentBean, propertyName, null);
|
||||
}
|
||||
|
||||
public void loadMany(LoadManyRequest loadRequest) {
|
||||
|
||||
@@ -108,6 +109,18 @@ public class DefaultBeanLoader {
|
||||
BeanDescriptor<?> desc = ctx.getBeanDescriptor();
|
||||
|
||||
SpiQuery<?> query = (SpiQuery<?>) server.createQuery(many.getTargetType());
|
||||
String orderBy = many.getLazyFetchOrderBy();
|
||||
if (orderBy != null) {
|
||||
query.orderBy(orderBy);
|
||||
}
|
||||
|
||||
String extraWhere = many.getExtraWhere();
|
||||
if (extraWhere != null) {
|
||||
// replace special ${ta} placeholder with the base table alias
|
||||
// which is always t0 and add the extra where clause
|
||||
String ew = StringHelper.replaceString(extraWhere, "${ta}", "t0");
|
||||
query.where().raw(ew);
|
||||
}
|
||||
|
||||
query.setLazyLoadForParents(idList, many);
|
||||
many.addWhereParentIdIn(query, idList);
|
||||
@@ -117,6 +130,11 @@ public class DefaultBeanLoader {
|
||||
String mode = loadRequest.isLazy() ? "+lazy" : "+query";
|
||||
query.setLoadDescription(mode, loadRequest.getDescription());
|
||||
|
||||
if (loadRequest.isLazy()) {
|
||||
// cascade the batch size (if set) for further lazy loading
|
||||
query.setLazyLoadBatchSize(loadRequest.getBatchSize());
|
||||
}
|
||||
|
||||
// potentially changes the joins and selected properties
|
||||
ctx.configureQuery(query);
|
||||
|
||||
@@ -140,7 +158,7 @@ public class DefaultBeanLoader {
|
||||
desc.cacheManyPropPut(many, bc, parentId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// log the query (for testing secondary queries)
|
||||
loadRequest.logSecondaryQuery(query);
|
||||
}
|
||||
@@ -150,18 +168,17 @@ public class DefaultBeanLoader {
|
||||
EntityBean parentBean = bc.getOwnerBean();
|
||||
String propertyName = bc.getPropertyName();
|
||||
|
||||
//ObjectGraphNode node = ctx == null ? null : ctx.getObjectGraphNode();
|
||||
|
||||
loadManyInternal(parentBean, propertyName, null, false, null, onlyIds);
|
||||
}
|
||||
|
||||
public void refreshMany(EntityBean parentBean, String propertyName, Transaction t) {
|
||||
loadManyInternal(parentBean, propertyName, t, true, null, false);
|
||||
}
|
||||
public void refreshMany(EntityBean parentBean, String propertyName, Transaction t) {
|
||||
loadManyInternal(parentBean, propertyName, t, true, null, false);
|
||||
}
|
||||
|
||||
private void loadManyInternal(EntityBean parentBean, String propertyName, Transaction t, boolean refresh, ObjectGraphNode node, boolean onlyIds) {
|
||||
private void loadManyInternal(EntityBean parentBean, String propertyName, Transaction t, boolean refresh,
|
||||
ObjectGraphNode node, boolean onlyIds) {
|
||||
|
||||
EntityBeanIntercept ebi = ((EntityBean) parentBean)._ebean_getIntercept();
|
||||
EntityBeanIntercept ebi = parentBean._ebean_getIntercept();
|
||||
PersistenceContext pc = ebi.getPersistenceContext();
|
||||
|
||||
BeanDescriptor<?> parentDesc = server.getBeanDescriptor(parentBean.getClass());
|
||||
@@ -169,7 +186,7 @@ public class DefaultBeanLoader {
|
||||
|
||||
BeanCollection<?> beanCollection = null;
|
||||
ExpressionList<?> filterMany = null;
|
||||
|
||||
|
||||
Object currentValue = many.getValue(parentBean);
|
||||
if (currentValue instanceof BeanCollection<?>) {
|
||||
beanCollection = (BeanCollection<?>) currentValue;
|
||||
@@ -186,7 +203,7 @@ public class DefaultBeanLoader {
|
||||
boolean useManyIdCache = beanCollection != null && parentDesc.isManyPropCaching();
|
||||
if (useManyIdCache) {
|
||||
Boolean readOnly = null;
|
||||
if (ebi != null && ebi.isReadOnly()) {
|
||||
if (ebi.isReadOnly()) {
|
||||
readOnly = Boolean.TRUE;
|
||||
}
|
||||
if (parentDesc.cacheManyPropLoad(many, beanCollection, parentId, readOnly)) {
|
||||
@@ -198,7 +215,7 @@ public class DefaultBeanLoader {
|
||||
|
||||
if (refresh) {
|
||||
// populate a new collection
|
||||
Object emptyCollection = many.createEmpty(false);
|
||||
BeanCollection<?> emptyCollection = many.createEmpty(parentBean);
|
||||
many.setValue(parentBean, emptyCollection);
|
||||
query.setLoadDescription("+refresh", null);
|
||||
} else {
|
||||
@@ -228,10 +245,8 @@ public class DefaultBeanLoader {
|
||||
query.setLazyLoadManyPath(many.getName());
|
||||
query.setPersistenceContext(pc);
|
||||
|
||||
if (ebi != null) {
|
||||
if (ebi.isReadOnly()) {
|
||||
query.setReadOnly(true);
|
||||
}
|
||||
if (ebi.isReadOnly()) {
|
||||
query.setReadOnly(true);
|
||||
}
|
||||
|
||||
server.findUnique(query, t);
|
||||
@@ -302,6 +317,11 @@ public class DefaultBeanLoader {
|
||||
String mode = loadRequest.isLazy() ? "+lazy" : "+query";
|
||||
query.setLoadDescription(mode, loadRequest.getDescription());
|
||||
|
||||
if (loadRequest.isLazy()) {
|
||||
// cascade the batch size (if set) for further lazy loading
|
||||
query.setLazyLoadBatchSize(loadRequest.getBatchSize());
|
||||
}
|
||||
|
||||
ctx.configureQuery(query, loadRequest.getLazyLoadProperty());
|
||||
|
||||
// make sure the query doesn't use the cache
|
||||
@@ -316,7 +336,7 @@ public class DefaultBeanLoader {
|
||||
|
||||
if (loadRequest.isLoadCache()) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
desc.cacheBeanPutData((EntityBean)list.get(i));
|
||||
desc.cacheBeanPutData((EntityBean) list.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,48 +345,50 @@ public class DefaultBeanLoader {
|
||||
// necessary but allow processing to continue until it is accessed by client code
|
||||
ebis[i].checkLazyLoadFailure();
|
||||
}
|
||||
|
||||
|
||||
// log the query (for testing secondary queries)
|
||||
loadRequest.logSecondaryQuery(query);
|
||||
}
|
||||
|
||||
public void refresh(EntityBean bean) {
|
||||
refreshBeanInternal(bean, SpiQuery.Mode.REFRESH_BEAN, -1);
|
||||
}
|
||||
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
refreshBeanInternal(ebi.getOwner(), SpiQuery.Mode.LAZYLOAD_BEAN, -1);
|
||||
}
|
||||
public void refresh(EntityBean bean) {
|
||||
refreshBeanInternal(bean, SpiQuery.Mode.REFRESH_BEAN, -1);
|
||||
}
|
||||
|
||||
public void loadBean(EntityBeanIntercept ebi) {
|
||||
refreshBeanInternal(ebi.getOwner(), SpiQuery.Mode.LAZYLOAD_BEAN, -1);
|
||||
}
|
||||
|
||||
private void refreshBeanInternal(EntityBean bean, SpiQuery.Mode mode, int embeddedOwnerIndex) {
|
||||
|
||||
EntityBeanIntercept ebi = ((EntityBean) bean)._ebean_getIntercept();;
|
||||
EntityBeanIntercept ebi = bean._ebean_getIntercept();
|
||||
PersistenceContext pc = ebi.getPersistenceContext();
|
||||
if (Mode.REFRESH_BEAN == mode) {
|
||||
// need a new PersistenceContext for REFRESH
|
||||
pc = null;
|
||||
}
|
||||
|
||||
BeanDescriptor<?> desc = server.getBeanDescriptor(bean.getClass());
|
||||
if (EntityType.EMBEDDED == desc.getEntityType()) {
|
||||
// lazy loading on an embedded bean property
|
||||
EntityBean embeddedOwner = (EntityBean)ebi.getEmbeddedOwner();
|
||||
EntityBean embeddedOwner = (EntityBean) ebi.getEmbeddedOwner();
|
||||
int ownerIndex = ebi.getEmbeddedOwnerIndex();
|
||||
|
||||
refreshBeanInternal(embeddedOwner, mode, ownerIndex);
|
||||
}
|
||||
|
||||
|
||||
Object id = desc.getId(bean);
|
||||
|
||||
if (pc == null) {
|
||||
// a reference with no existing persistenceContext
|
||||
pc = new DefaultPersistenceContext();
|
||||
pc.put(id, bean);
|
||||
if (ebi != null) {
|
||||
ebi.setPersistenceContext(pc);
|
||||
}
|
||||
ebi.setPersistenceContext(pc);
|
||||
}
|
||||
|
||||
if (embeddedOwnerIndex == -1) {
|
||||
if (SpiQuery.Mode.LAZYLOAD_BEAN.equals(mode) && desc.isBeanCaching()) {
|
||||
// lazy loading and the bean cache is active
|
||||
if (desc.cacheBeanLoad((EntityBean)bean, ebi, id)) {
|
||||
if (desc.cacheBeanLoad(bean, ebi, id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -376,15 +398,13 @@ public class DefaultBeanLoader {
|
||||
}
|
||||
|
||||
SpiQuery<?> query = (SpiQuery<?>) server.createQuery(desc.getBeanType());
|
||||
if (ebi != null) {
|
||||
query.setLazyLoadProperty(ebi.getLazyLoadProperty());
|
||||
}
|
||||
query.setLazyLoadProperty(ebi.getLazyLoadProperty());
|
||||
|
||||
if (embeddedOwnerIndex > -1) {
|
||||
String embeddedBeanPropertyName = ebi.getProperty(embeddedOwnerIndex);
|
||||
query.select("id,"+embeddedBeanPropertyName);
|
||||
query.select("id," + embeddedBeanPropertyName);
|
||||
}
|
||||
|
||||
|
||||
// don't collect autoFetch usage profiling information
|
||||
// as we just copy the data out of these fetched beans
|
||||
// and put the data into the original bean
|
||||
@@ -403,11 +423,20 @@ public class DefaultBeanLoader {
|
||||
query.setReadOnly(true);
|
||||
}
|
||||
|
||||
if (SpiQuery.Mode.REFRESH_BEAN.equals(mode)) {
|
||||
// explicitly state to load all properties on REFRESH.
|
||||
// Lobs default to fetch lazy so this forces lobs to be
|
||||
// included in a 'refresh' query
|
||||
query.select("*");
|
||||
}
|
||||
|
||||
Object dbBean = query.findUnique();
|
||||
if (dbBean == null) {
|
||||
String msg = "Bean not found during lazy load or refresh." + " id[" + id + "] type[" + desc.getBeanType() + "]";
|
||||
throw new EntityNotFoundException(msg);
|
||||
}
|
||||
|
||||
desc.resetManyProperties(dbBean);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,36 +17,10 @@ import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.AdminAutofetch;
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.BeanState;
|
||||
import com.avaje.ebean.CallableSql;
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.ExpressionFactory;
|
||||
import com.avaje.ebean.Filter;
|
||||
import com.avaje.ebean.FutureIds;
|
||||
import com.avaje.ebean.FutureList;
|
||||
import com.avaje.ebean.FutureRowCount;
|
||||
import com.avaje.ebean.PagedList;
|
||||
import com.avaje.ebean.PagingList;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.QueryResultVisitor;
|
||||
import com.avaje.ebean.SqlFutureList;
|
||||
import com.avaje.ebean.SqlQuery;
|
||||
import com.avaje.ebean.SqlRow;
|
||||
import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.TxCallable;
|
||||
import com.avaje.ebean.TxIsolation;
|
||||
import com.avaje.ebean.TxRunnable;
|
||||
import com.avaje.ebean.TxScope;
|
||||
import com.avaje.ebean.TxType;
|
||||
import com.avaje.ebean.Update;
|
||||
import com.avaje.ebean.ValuePair;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.CallStack;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
@@ -65,7 +39,6 @@ import com.avaje.ebean.meta.MetaBeanInfo;
|
||||
import com.avaje.ebean.meta.MetaInfoManager;
|
||||
import com.avaje.ebean.text.csv.CsvReader;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import com.avaje.ebean.text.json.JsonElement;
|
||||
import com.avaje.ebeaninternal.api.LoadBeanRequest;
|
||||
import com.avaje.ebeaninternal.api.LoadManyRequest;
|
||||
import com.avaje.ebeaninternal.api.ScopeTrans;
|
||||
@@ -164,7 +137,6 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
private final CQueryEngine cqueryEngine;
|
||||
|
||||
//@Deprecated
|
||||
private DdlGenerator ddlGenerator;
|
||||
|
||||
private final ExpressionFactory expressionFactory;
|
||||
@@ -184,6 +156,11 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
*/
|
||||
private String mbeanName;
|
||||
|
||||
/**
|
||||
* The default PersistenceContextScope used if it is not explicitly set on a query.
|
||||
*/
|
||||
private final PersistenceContextScope defaultPersistenceContextScope;
|
||||
|
||||
/**
|
||||
* The MBeanServer Ebean is registered with.
|
||||
*/
|
||||
@@ -242,6 +219,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
this.cqueryEngine = config.getCQueryEngine();
|
||||
this.expressionFactory = config.getExpressionFactory();
|
||||
this.encryptKeyManager = serverConfig.getEncryptKeyManager();
|
||||
this.defaultPersistenceContextScope = serverConfig.getPersistenceContextScope();
|
||||
|
||||
this.beanDescriptorManager = config.getBeanDescriptorManager();
|
||||
beanDescriptorManager.setEbeanServer(this);
|
||||
@@ -274,17 +252,21 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
List<SpiEbeanPlugin> spiPlugins = new ArrayList<SpiEbeanPlugin>();
|
||||
|
||||
final Iterator<SpiEbeanPlugin> plugins = ServiceLoader.load(SpiEbeanPlugin.class).iterator();
|
||||
|
||||
while (plugins.hasNext()) {
|
||||
SpiEbeanPlugin plugin = plugins.next();
|
||||
for (SpiEbeanPlugin plugin : ServiceLoader.load(SpiEbeanPlugin.class)) {
|
||||
spiPlugins.add(plugin);
|
||||
plugin.setup(this, this.getDatabasePlatform(), config.getServerConfig());
|
||||
|
||||
if (plugin instanceof DdlGenerator) {
|
||||
// backwards compatible
|
||||
ddlGenerator = (DdlGenerator)plugin;
|
||||
}
|
||||
ddlGenerator = (DdlGenerator) plugin;
|
||||
}
|
||||
}
|
||||
|
||||
if (ddlGenerator == null) {
|
||||
// ServiceLoader not finding ddlGenerator (typically OSGi)
|
||||
ddlGenerator = new DdlGenerator();
|
||||
spiPlugins.add(ddlGenerator);
|
||||
ddlGenerator.setup(this, this.getDatabasePlatform(), config.getServerConfig());
|
||||
}
|
||||
|
||||
ebeanPlugins = Collections.unmodifiableList(spiPlugins);
|
||||
@@ -671,6 +653,15 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
return (T) ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(TransactionCallback transactionCallback) {
|
||||
Transaction transaction = currentTransaction();
|
||||
if (transaction == null) {
|
||||
throw new PersistenceException("Not currently active transaction when trying to register transactionCallback");
|
||||
}
|
||||
transaction.register(transactionCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Transaction that is NOT stored in TransactionThreadLocal. Use
|
||||
* this when you want a thread to have a second independent transaction.
|
||||
@@ -1112,7 +1103,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
// predicates on *ToMany properties
|
||||
if (query.initManyWhereJoins()) {
|
||||
// we need a sql distinct now
|
||||
query.setDistinct(true);
|
||||
query.setSqlDistinct(true);
|
||||
}
|
||||
|
||||
boolean allowOneManyFetch = true;
|
||||
@@ -1154,8 +1145,8 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
t = getCurrentServerTransaction();
|
||||
}
|
||||
PersistenceContext context = null;
|
||||
if (t != null) {
|
||||
// first look in the persistence context
|
||||
if (t != null && useTransactionPersistenceContext(query)) {
|
||||
// first look in the transaction scoped persistence context
|
||||
context = t.getPersistenceContext();
|
||||
if (context != null) {
|
||||
WithOption o = context.getWithOption(beanDescriptor.getBeanType(), query.getId());
|
||||
@@ -1178,7 +1169,22 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
// Hit the L2 bean cache
|
||||
return beanDescriptor.cacheBeanGet(query, context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if transactions PersistenceContext should be used.
|
||||
*/
|
||||
private <T> boolean useTransactionPersistenceContext(SpiQuery<T> query) {
|
||||
return PersistenceContextScope.TRANSACTION.equals(getPersistenceContextScope(query));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the PersistenceContextScope to use defined at query or server level.
|
||||
*/
|
||||
public PersistenceContextScope getPersistenceContextScope(SpiQuery<?> query) {
|
||||
PersistenceContextScope scope = query.getPersistenceContextScope();
|
||||
return (scope != null) ? scope : defaultPersistenceContextScope;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T findId(Query<T> query, Transaction t) {
|
||||
|
||||
@@ -1198,18 +1204,12 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
}
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(desc, spiQuery, t);
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return (T) request.findId();
|
||||
|
||||
T bean = (T) request.findId();
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return bean;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1256,15 +1256,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
Set<T> set = (Set<T>) request.findSet();
|
||||
return (Set<T>) request.findSet();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return set;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
// String stackTrace = throwablePrinter.print(ex);
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1280,15 +1275,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
Map<?, T> map = (Map<?, T>) request.findMap();
|
||||
return (Map<?, T>) request.findMap();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return map;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
// String stackTrace = throwablePrinter.print(ex);
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1303,14 +1293,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ROWCOUNT, query, t);
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
int rowCount = request.findRowCount();
|
||||
return request.findRowCount();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return rowCount;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1326,14 +1312,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.ID_LIST, query, t);
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
List<Object> list = request.findIds();
|
||||
return request.findIds();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return list;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1431,14 +1413,27 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
request.findVisit(visitor);
|
||||
request.initTransIfRequired();
|
||||
request.findVisit(visitor);
|
||||
// no try finally - findVisit guarantee's cleanup of the transaction if required
|
||||
}
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
public <T> void findEach(Query<T> query, QueryEachConsumer<T> consumer, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
|
||||
|
||||
request.initTransIfRequired();
|
||||
request.findEach(consumer);
|
||||
// no try finally - findVisit guarantee's cleanup of the transaction if required
|
||||
}
|
||||
|
||||
public <T> void findEachWhile(Query<T> query, QueryEachWhileConsumer<T> consumer, Transaction t) {
|
||||
|
||||
SpiOrmQueryRequest<T> request = createQueryRequest(Type.LIST, query, t);
|
||||
|
||||
request.initTransIfRequired();
|
||||
request.findEachWhile(consumer);
|
||||
// no try finally - findVisit guarantee's cleanup of the transaction if required
|
||||
}
|
||||
|
||||
public <T> QueryIterator<T> findIterate(Query<T> query, Transaction t) {
|
||||
@@ -1448,10 +1443,9 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
return request.findIterate();
|
||||
// request.endTransIfRequired();
|
||||
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
request.endTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
@@ -1468,14 +1462,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
List<T> list = request.findList();
|
||||
return request.findList();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return list;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1518,14 +1508,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
List<SqlRow> list = request.findList();
|
||||
return request.findList();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return list;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1535,14 +1521,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
Set<SqlRow> set = request.findSet();
|
||||
return request.findSet();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return set;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1551,14 +1533,10 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
RelationalQueryRequest request = new RelationalQueryRequest(this, relationalQueryEngine, query, t);
|
||||
try {
|
||||
request.initTransIfRequired();
|
||||
Map<?, SqlRow> map = request.findMap();
|
||||
return request.findMap();
|
||||
|
||||
} finally {
|
||||
request.endTransIfRequired();
|
||||
|
||||
return map;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
request.rollbackTransIfRequired();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1576,6 +1554,16 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
persister.save(checkEntityBean(bean), t);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void markAsDirty(Object bean) {
|
||||
if (!(bean instanceof EntityBean)) {
|
||||
throw new IllegalArgumentException("This bean is not an EntityBean?");
|
||||
}
|
||||
// mark the bean as dirty (so that an update will not get skipped)
|
||||
((EntityBean)bean)._ebean_getIntercept().setDirty(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the bean using the default 'updatesDeleteMissingChildren' setting.
|
||||
*/
|
||||
@@ -1677,7 +1665,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
if (bean == null) {
|
||||
throw new IllegalArgumentException(Message.msg("bean.isnull"));
|
||||
}
|
||||
if (bean instanceof EntityBean == false) {
|
||||
if (!(bean instanceof EntityBean)) {
|
||||
throw new IllegalArgumentException("Was expecting an EntityBean but got a "+bean.getClass());
|
||||
}
|
||||
return (EntityBean)bean;
|
||||
@@ -1986,14 +1974,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
public boolean isSupportedType(java.lang.reflect.Type genericType) {
|
||||
|
||||
TypeInfo typeInfo = ParamTypeHelper.getTypeInfo(genericType);
|
||||
if (typeInfo == null) {
|
||||
return false;
|
||||
}
|
||||
Class<?> beanType = typeInfo.getBeanType();
|
||||
if (JsonElement.class.isAssignableFrom(beanType)) {
|
||||
return true;
|
||||
}
|
||||
return getBeanDescriptor(typeInfo.getBeanType()) != null;
|
||||
return typeInfo != null && getBeanDescriptor(typeInfo.getBeanType()) != null;
|
||||
}
|
||||
|
||||
public Object getBeanId(Object bean) {
|
||||
@@ -2112,11 +2093,18 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
return new CallStack(finalTrace);
|
||||
}
|
||||
|
||||
public JsonContext createJsonContext() {
|
||||
|
||||
@Override
|
||||
public JsonContext json() {
|
||||
// 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) {
|
||||
|
||||
@@ -1,22 +1,3 @@
|
||||
/**
|
||||
* Copyright (C) 2006 Robin Bygrave
|
||||
*
|
||||
* This file is part of Ebean.
|
||||
*
|
||||
* Ebean is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Ebean is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Ebean; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
@@ -93,6 +93,11 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
|
||||
*/
|
||||
private final String sql;
|
||||
|
||||
/**
|
||||
* The actual sql with named parameters converted.
|
||||
*/
|
||||
private String generatedSql;
|
||||
|
||||
/**
|
||||
* Some descriptive text that can be put into the transaction log.
|
||||
*/
|
||||
@@ -170,7 +175,16 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
public String getGeneratedSql() {
|
||||
return generatedSql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGeneratedSql(String generatedSql) {
|
||||
this.generatedSql = generatedSql;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -9,8 +11,6 @@ import com.avaje.ebean.config.ExternalTransactionManager;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import com.avaje.ebean.text.json.JsonValueAdapter;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManager;
|
||||
@@ -22,6 +22,7 @@ import com.avaje.ebeaninternal.server.deploy.parse.DeployCreateProperties;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployInherit;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployUtil;
|
||||
import com.avaje.ebeaninternal.server.expression.DefaultExpressionFactory;
|
||||
import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool;
|
||||
import com.avaje.ebeaninternal.server.persist.Binder;
|
||||
import com.avaje.ebeaninternal.server.persist.DefaultPersister;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryEngine;
|
||||
@@ -30,7 +31,7 @@ import com.avaje.ebeaninternal.server.query.DefaultRelationalQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManager;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManagerFactory;
|
||||
import com.avaje.ebeaninternal.server.text.json.DJsonContext;
|
||||
import com.avaje.ebeaninternal.server.text.json.DefaultJsonValueAdapter;
|
||||
import com.avaje.ebeaninternal.server.transaction.AutoCommitTransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.ExternalTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.JtaTransactionManager;
|
||||
@@ -38,6 +39,7 @@ import com.avaje.ebeaninternal.server.transaction.TransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.type.DefaultTypeManager;
|
||||
import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
|
||||
/**
|
||||
* Used to extend the ServerConfig with additional objects used to configure and
|
||||
@@ -87,10 +89,13 @@ public class InternalConfiguration {
|
||||
|
||||
private final XmlConfig xmlConfig;
|
||||
|
||||
private final JsonFactory jsonFactory;
|
||||
|
||||
public InternalConfiguration(XmlConfig xmlConfig, ClusterManager clusterManager,
|
||||
ServerCacheManager cacheManager, SpiBackgroundExecutor backgroundExecutor,
|
||||
ServerConfig serverConfig, BootupClasses bootupClasses, PstmtBatch pstmtBatch) {
|
||||
|
||||
this.jsonFactory = serverConfig.getJsonFactory();
|
||||
this.xmlConfig = xmlConfig;
|
||||
this.pstmtBatch = pstmtBatch;
|
||||
this.clusterManager = clusterManager;
|
||||
@@ -113,8 +118,7 @@ public class InternalConfiguration {
|
||||
this.beanDescriptorManager = new BeanDescriptorManager(this);
|
||||
beanDescriptorManager.deploy();
|
||||
|
||||
this.transactionManager = new TransactionManager(clusterManager, backgroundExecutor,
|
||||
serverConfig, beanDescriptorManager, this.getBootupClasses());
|
||||
this.transactionManager = createTransactionManager();
|
||||
|
||||
this.cQueryEngine = new CQueryEngine(serverConfig.getDatabasePlatform(), binder);
|
||||
|
||||
@@ -131,19 +135,38 @@ public class InternalConfiguration {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the TransactionManager taking into account autoCommit mode.
|
||||
*/
|
||||
private TransactionManager createTransactionManager() {
|
||||
|
||||
if (isAutoCommitMode()) {
|
||||
return new AutoCommitTransactionManager(clusterManager, backgroundExecutor, serverConfig, beanDescriptorManager, this.getBootupClasses());
|
||||
}
|
||||
|
||||
return new TransactionManager(clusterManager, backgroundExecutor, serverConfig, beanDescriptorManager, this.getBootupClasses());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if autoCommit mode is on.
|
||||
*/
|
||||
private boolean isAutoCommitMode() {
|
||||
if (serverConfig.isAutoCommitMode()) {
|
||||
// explicitly set
|
||||
return true;
|
||||
}
|
||||
DataSource dataSource = serverConfig.getDataSource();
|
||||
if (dataSource instanceof DataSourcePool && ((DataSourcePool)dataSource).getAutoCommit()) {
|
||||
// We know the DataSourcePool is using autoCommit
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public JsonContext createJsonContext(SpiEbeanServer server) {
|
||||
|
||||
String s = serverConfig.getProperty("json.pretty", "false");
|
||||
boolean dfltPretty = "true".equalsIgnoreCase(s);
|
||||
|
||||
s = serverConfig.getProperty("json.jsonValueAdapter", null);
|
||||
|
||||
JsonValueAdapter va = new DefaultJsonValueAdapter();
|
||||
if (s != null) {
|
||||
va = (JsonValueAdapter) ClassUtil.newInstance(s, this.getClass());
|
||||
}
|
||||
return new DJsonContext(server, va, dfltPretty);
|
||||
return new DJsonContext(server, jsonFactory);
|
||||
}
|
||||
|
||||
public XmlConfig getXmlConfig() {
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.ExpressionFactory;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.ExternalTransactionManager;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManager;
|
||||
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManagerFactory;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployOrmXml;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployCreateProperties;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployInherit;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployUtil;
|
||||
import com.avaje.ebeaninternal.server.expression.DefaultExpressionFactory;
|
||||
import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool;
|
||||
import com.avaje.ebeaninternal.server.persist.Binder;
|
||||
import com.avaje.ebeaninternal.server.persist.DefaultPersister;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.query.DefaultOrmQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.query.DefaultRelationalQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManager;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManagerFactory;
|
||||
import com.avaje.ebeaninternal.server.text.json.DJsonContext;
|
||||
<<<<<<< HEAD
|
||||
import com.avaje.ebeaninternal.server.text.json.DefaultJsonValueAdapter;
|
||||
import com.avaje.ebeaninternal.server.transaction.AutoCommitTransactionManager;
|
||||
=======
|
||||
>>>>>>> json-refactor
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.ExternalTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.JtaTransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.type.DefaultTypeManager;
|
||||
import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
|
||||
/**
|
||||
* Used to extend the ServerConfig with additional objects used to configure and
|
||||
* construct an EbeanServer.
|
||||
*/
|
||||
public class InternalConfiguration {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(InternalConfiguration.class);
|
||||
|
||||
private final ServerConfig serverConfig;
|
||||
|
||||
private final BootupClasses bootupClasses;
|
||||
|
||||
private final DeployInherit deployInherit;
|
||||
|
||||
private final ResourceManager resourceManager;
|
||||
|
||||
private final DeployOrmXml deployOrmXml;
|
||||
|
||||
private final TypeManager typeManager;
|
||||
|
||||
private final Binder binder;
|
||||
|
||||
private final DeployCreateProperties deployCreateProperties;
|
||||
|
||||
private final DeployUtil deployUtil;
|
||||
|
||||
private final BeanDescriptorManager beanDescriptorManager;
|
||||
|
||||
private final TransactionManager transactionManager;
|
||||
|
||||
private final TransactionScopeManager transactionScopeManager;
|
||||
|
||||
private final CQueryEngine cQueryEngine;
|
||||
|
||||
private final ClusterManager clusterManager;
|
||||
|
||||
private final ServerCacheManager cacheManager;
|
||||
|
||||
private final ExpressionFactory expressionFactory;
|
||||
|
||||
private final SpiBackgroundExecutor backgroundExecutor;
|
||||
|
||||
private final PstmtBatch pstmtBatch;
|
||||
|
||||
private final XmlConfig xmlConfig;
|
||||
|
||||
public InternalConfiguration(XmlConfig xmlConfig, ClusterManager clusterManager,
|
||||
ServerCacheManager cacheManager, SpiBackgroundExecutor backgroundExecutor,
|
||||
ServerConfig serverConfig, BootupClasses bootupClasses, PstmtBatch pstmtBatch) {
|
||||
|
||||
this.xmlConfig = xmlConfig;
|
||||
this.pstmtBatch = pstmtBatch;
|
||||
this.clusterManager = clusterManager;
|
||||
this.backgroundExecutor = backgroundExecutor;
|
||||
this.cacheManager = cacheManager;
|
||||
this.serverConfig = serverConfig;
|
||||
this.bootupClasses = bootupClasses;
|
||||
this.expressionFactory = new DefaultExpressionFactory();
|
||||
|
||||
this.typeManager = new DefaultTypeManager(serverConfig, bootupClasses);
|
||||
this.binder = new Binder(typeManager);
|
||||
|
||||
this.resourceManager = ResourceManagerFactory.createResourceManager(serverConfig);
|
||||
this.deployOrmXml = new DeployOrmXml(resourceManager.getResourceSource());
|
||||
this.deployInherit = new DeployInherit(bootupClasses);
|
||||
|
||||
this.deployCreateProperties = new DeployCreateProperties(typeManager);
|
||||
this.deployUtil = new DeployUtil(typeManager, serverConfig);
|
||||
|
||||
this.beanDescriptorManager = new BeanDescriptorManager(this);
|
||||
beanDescriptorManager.deploy();
|
||||
|
||||
this.transactionManager = createTransactionManager();
|
||||
|
||||
this.cQueryEngine = new CQueryEngine(serverConfig.getDatabasePlatform(), binder);
|
||||
|
||||
ExternalTransactionManager externalTransactionManager = serverConfig.getExternalTransactionManager();
|
||||
if (externalTransactionManager == null && serverConfig.isUseJtaTransactionManager()) {
|
||||
externalTransactionManager = new JtaTransactionManager();
|
||||
}
|
||||
if (externalTransactionManager != null) {
|
||||
externalTransactionManager.setTransactionManager(transactionManager);
|
||||
this.transactionScopeManager = new ExternalTransactionScopeManager(transactionManager, externalTransactionManager);
|
||||
logger.info("Using Transaction Manager [" + externalTransactionManager.getClass() + "]");
|
||||
} else {
|
||||
this.transactionScopeManager = new DefaultTransactionScopeManager(transactionManager);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the TransactionManager taking into account autoCommit mode.
|
||||
*/
|
||||
private TransactionManager createTransactionManager() {
|
||||
|
||||
if (isAutoCommitMode()) {
|
||||
return new AutoCommitTransactionManager(clusterManager, backgroundExecutor, serverConfig, beanDescriptorManager, this.getBootupClasses());
|
||||
}
|
||||
|
||||
return new TransactionManager(clusterManager, backgroundExecutor, serverConfig, beanDescriptorManager, this.getBootupClasses());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if autoCommit mode is on.
|
||||
*/
|
||||
private boolean isAutoCommitMode() {
|
||||
if (serverConfig.isAutoCommitMode()) {
|
||||
// explicitly set
|
||||
return true;
|
||||
}
|
||||
DataSource dataSource = serverConfig.getDataSource();
|
||||
if (dataSource instanceof DataSourcePool && ((DataSourcePool)dataSource).getAutoCommit()) {
|
||||
// We know the DataSourcePool is using autoCommit
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public JsonContext createJsonContext(SpiEbeanServer server) {
|
||||
|
||||
return new DJsonContext(server);
|
||||
}
|
||||
|
||||
public XmlConfig getXmlConfig() {
|
||||
return xmlConfig;
|
||||
}
|
||||
|
||||
public AutoFetchManager createAutoFetchManager(SpiEbeanServer server) {
|
||||
return AutoFetchManagerFactory.create(server, serverConfig, resourceManager);
|
||||
}
|
||||
|
||||
public RelationalQueryEngine createRelationalQueryEngine() {
|
||||
return new DefaultRelationalQueryEngine(binder, serverConfig.getDatabaseBooleanTrue());
|
||||
}
|
||||
|
||||
public OrmQueryEngine createOrmQueryEngine() {
|
||||
return new DefaultOrmQueryEngine(beanDescriptorManager, cQueryEngine);
|
||||
}
|
||||
|
||||
public Persister createPersister(SpiEbeanServer server) {
|
||||
return new DefaultPersister(server, binder, beanDescriptorManager, pstmtBatch);
|
||||
}
|
||||
|
||||
public PstmtBatch getPstmtBatch() {
|
||||
return pstmtBatch;
|
||||
}
|
||||
|
||||
public ServerCacheManager getCacheManager() {
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
public BootupClasses getBootupClasses() {
|
||||
return bootupClasses;
|
||||
}
|
||||
|
||||
public DatabasePlatform getDatabasePlatform() {
|
||||
return serverConfig.getDatabasePlatform();
|
||||
}
|
||||
|
||||
public ServerConfig getServerConfig() {
|
||||
return serverConfig;
|
||||
}
|
||||
|
||||
public ExpressionFactory getExpressionFactory() {
|
||||
return expressionFactory;
|
||||
}
|
||||
|
||||
public TypeManager getTypeManager() {
|
||||
return typeManager;
|
||||
}
|
||||
|
||||
public Binder getBinder() {
|
||||
return binder;
|
||||
}
|
||||
|
||||
public BeanDescriptorManager getBeanDescriptorManager() {
|
||||
return beanDescriptorManager;
|
||||
}
|
||||
|
||||
public DeployInherit getDeployInherit() {
|
||||
return deployInherit;
|
||||
}
|
||||
|
||||
public ResourceManager getResourceManager() {
|
||||
return resourceManager;
|
||||
}
|
||||
|
||||
public DeployOrmXml getDeployOrmXml() {
|
||||
return deployOrmXml;
|
||||
}
|
||||
|
||||
public DeployCreateProperties getDeployCreateProperties() {
|
||||
return deployCreateProperties;
|
||||
}
|
||||
|
||||
public DeployUtil getDeployUtil() {
|
||||
return deployUtil;
|
||||
}
|
||||
|
||||
public TransactionManager getTransactionManager() {
|
||||
return transactionManager;
|
||||
}
|
||||
|
||||
public TransactionScopeManager getTransactionScopeManager() {
|
||||
return transactionScopeManager;
|
||||
}
|
||||
|
||||
public CQueryEngine getCQueryEngine() {
|
||||
return cQueryEngine;
|
||||
}
|
||||
|
||||
public ClusterManager getClusterManager() {
|
||||
return clusterManager;
|
||||
}
|
||||
|
||||
public SpiBackgroundExecutor getBackgroundExecutor() {
|
||||
return backgroundExecutor;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,9 +6,7 @@ import java.util.Set;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.QueryResultVisitor;
|
||||
import com.avaje.ebean.RawSql;
|
||||
import com.avaje.ebean.*;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
@@ -55,7 +53,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
private HashQuery cacheKey;
|
||||
|
||||
private HashQueryPlan queryPlanHash;
|
||||
|
||||
|
||||
/**
|
||||
* Create the InternalQueryRequest.
|
||||
*/
|
||||
@@ -71,8 +69,17 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
this.readOnly = query.isReadOnly();
|
||||
}
|
||||
|
||||
public void executeSecondaryQueries(int defaultQueryBatch) {
|
||||
loadContext.executeSecondaryQueries(this, defaultQueryBatch);
|
||||
|
||||
/**
|
||||
* Return the database platform like clause.
|
||||
*/
|
||||
@Override
|
||||
public String getDBLikeClause() {
|
||||
return ebeanServer.getDatabasePlatform().getLikeClause();
|
||||
}
|
||||
|
||||
public void executeSecondaryQueries() {
|
||||
loadContext.executeSecondaryQueries(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,31 +183,32 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
persistenceContext = new DefaultPersistenceContext();
|
||||
loadContext.setPersistenceContext(persistenceContext);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the TransactionContext either explicitly set on the query or
|
||||
* transaction scoped.
|
||||
*/
|
||||
private PersistenceContext getPersistenceContext(SpiQuery<?> query, SpiTransaction t) {
|
||||
|
||||
// check if there is already a persistence context set which is the case
|
||||
// when lazy loading or query joins are executed
|
||||
PersistenceContext ctx = query.getPersistenceContext();
|
||||
if (ctx == null) {
|
||||
ctx = t.getPersistenceContext();
|
||||
}
|
||||
return ctx;
|
||||
if (ctx != null) return ctx;
|
||||
|
||||
// determine the scope (from the query and then server)
|
||||
PersistenceContextScope scope = ebeanServer.getPersistenceContextScope(query);
|
||||
return (scope == PersistenceContextScope.QUERY) ? new DefaultPersistenceContext() : t.getPersistenceContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will end a locally created transaction.
|
||||
* <p>
|
||||
* It ends the transaction by using a rollback() as the transaction is known
|
||||
* to be readOnly.
|
||||
* It ends the query only transaction.
|
||||
* </p>
|
||||
*/
|
||||
public void endTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
// we can rollback as readOnly transaction
|
||||
transaction.rollback();
|
||||
transaction.endQueryOnly();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,6 +235,30 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
return idList.getIdList();
|
||||
}
|
||||
|
||||
public void findEach(QueryEachConsumer<T> consumer) {
|
||||
QueryIterator<T> it = queryEngine.findIterate(this);
|
||||
try {
|
||||
while (it.hasNext()) {
|
||||
consumer.accept(it.next());
|
||||
}
|
||||
} finally {
|
||||
it.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void findEachWhile(QueryEachWhileConsumer<T> consumer) {
|
||||
QueryIterator<T> it = queryEngine.findIterate(this);
|
||||
try {
|
||||
while (it.hasNext()) {
|
||||
if (!consumer.accept(it.next())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
it.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void findVisit(QueryResultVisitor<T> visitor) {
|
||||
QueryIterator<T> it = queryEngine.findIterate(this);
|
||||
try {
|
||||
@@ -362,9 +394,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
* Log the SQL if the logLevel is appropriate.
|
||||
*/
|
||||
public void logSql(String sql) {
|
||||
if (transaction.isLogSql()) {
|
||||
transaction.logSql(sql);
|
||||
}
|
||||
transaction.logSql(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,4 +404,12 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
return query.isLogSecondaryQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the batch size for lazy loading on this bean query request.
|
||||
*/
|
||||
public int getLazyLoadBatchSize() {
|
||||
|
||||
int batchSize = query.getLazyLoadBatchSize();
|
||||
return (batchSize > 0) ? batchSize : ebeanServer.getLazyLoadBatchSize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,106 +34,107 @@ import com.avaje.ebeaninternal.server.transaction.BeanPersistIdMap;
|
||||
*/
|
||||
public final class PersistRequestBean<T> extends PersistRequest implements BeanPersistRequest<T> {
|
||||
|
||||
private final BeanManager<T> beanManager;
|
||||
private final BeanManager<T> beanManager;
|
||||
|
||||
private final BeanDescriptor<T> beanDescriptor;
|
||||
private final BeanDescriptor<T> beanDescriptor;
|
||||
|
||||
private final BeanPersistListener<T> beanPersistListener;
|
||||
private final BeanPersistListener beanPersistListener;
|
||||
|
||||
/**
|
||||
* For per post insert update delete control.
|
||||
*/
|
||||
private final BeanPersistController controller;
|
||||
/**
|
||||
* For per post insert update delete control.
|
||||
*/
|
||||
private final BeanPersistController controller;
|
||||
|
||||
/**
|
||||
/**
|
||||
* The bean being persisted.
|
||||
*/
|
||||
private final T bean;
|
||||
|
||||
private final EntityBean entityBean;
|
||||
|
||||
/**
|
||||
* The associated intercept.
|
||||
*/
|
||||
private final EntityBeanIntercept intercept;
|
||||
private final T bean;
|
||||
|
||||
/**
|
||||
* The parent bean for unidirectional save.
|
||||
*/
|
||||
private final Object parentBean;
|
||||
private final EntityBean entityBean;
|
||||
|
||||
private final boolean dirty;
|
||||
/**
|
||||
* The associated intercept.
|
||||
*/
|
||||
private final EntityBeanIntercept intercept;
|
||||
|
||||
private ConcurrencyMode concurrencyMode;
|
||||
/**
|
||||
* The parent bean for unidirectional save.
|
||||
*/
|
||||
private final Object parentBean;
|
||||
|
||||
/**
|
||||
* The unique id used for logging summary.
|
||||
*/
|
||||
private Object idValue;
|
||||
private final boolean dirty;
|
||||
|
||||
/**
|
||||
* Hash value used to handle cascade delete both ways in a relationship.
|
||||
*/
|
||||
private Integer beanHash;
|
||||
private ConcurrencyMode concurrencyMode;
|
||||
|
||||
private boolean notifyCache;
|
||||
/**
|
||||
* The unique id used for logging summary.
|
||||
*/
|
||||
private Object idValue;
|
||||
|
||||
private boolean deleteMissingChildren;
|
||||
|
||||
private final Set<String> dirtyPropertyNames;
|
||||
/**
|
||||
* Hash value used to handle cascade delete both ways in a relationship.
|
||||
*/
|
||||
private Integer beanHash;
|
||||
|
||||
private boolean notifyCache;
|
||||
|
||||
private boolean deleteMissingChildren;
|
||||
|
||||
/**
|
||||
* Flag used to detect when only many properties where updated via a cascade. Used to ensure
|
||||
* appropriate caches are updated in that case.
|
||||
*/
|
||||
private boolean updatedManysOnly;
|
||||
|
||||
/**
|
||||
* Many properties that were cascade saved (and hence might need caches updated later).
|
||||
*/
|
||||
private boolean updatedManysOnly;
|
||||
|
||||
/**
|
||||
* Many properties that were cascade saved (and hence might need caches updated later).
|
||||
*/
|
||||
private List<BeanPropertyAssocMany<?>> updatedManys;
|
||||
|
||||
public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager<T> mgr,
|
||||
SpiTransaction t, PersistExecute persistExecute, PersistRequest.Type type) {
|
||||
/**
|
||||
* Need to get and store the updated properties because the persist listener is notified
|
||||
* later on a different thread and the bean has been reset at that point.
|
||||
*/
|
||||
private Set<String> updatedProperties;
|
||||
|
||||
super(server, t, persistExecute);
|
||||
this.entityBean = (EntityBean)bean;
|
||||
public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager<T> mgr, SpiTransaction t,
|
||||
PersistExecute persistExecute, PersistRequest.Type type, boolean saveRecurse) {
|
||||
|
||||
super(server, t, persistExecute);
|
||||
this.entityBean = (EntityBean) bean;
|
||||
this.intercept = entityBean._ebean_getIntercept();
|
||||
this.beanManager = mgr;
|
||||
this.beanDescriptor = mgr.getBeanDescriptor();
|
||||
this.beanPersistListener = beanDescriptor.getPersistListener();
|
||||
|
||||
if (PersistRequest.Type.DETERMINE != type) {
|
||||
this.type = type;
|
||||
} else {
|
||||
// determine mode during cascade save (supporting stateless update)
|
||||
this.type = beanDescriptor.isInsertMode(intercept) ? Type.INSERT : Type.UPDATE;
|
||||
this.beanManager = mgr;
|
||||
this.beanDescriptor = mgr.getBeanDescriptor();
|
||||
this.beanPersistListener = beanDescriptor.getPersistListener();
|
||||
this.bean = bean;
|
||||
this.parentBean = parentBean;
|
||||
this.controller = beanDescriptor.getPersistController();
|
||||
this.type = type;
|
||||
|
||||
if (saveRecurse) {
|
||||
this.persistCascade = t.isPersistCascade();
|
||||
}
|
||||
|
||||
if (this.type == Type.UPDATE && intercept.isNew() ) {
|
||||
// 'stateless update' - set bean up for doing update
|
||||
intercept.setNewBeanForUpdate();
|
||||
|
||||
if (this.type == Type.UPDATE) {
|
||||
if (intercept.isNew()) {
|
||||
// 'stateless update' - set loaded properties as dirty
|
||||
intercept.setNewBeanForUpdate();
|
||||
}
|
||||
// Mark Mutable scalar properties (like Hstore) as dirty where necessary
|
||||
beanDescriptor.checkMutableProperties(intercept);
|
||||
}
|
||||
|
||||
// derive the set of property names now as we will pass them to a beanPersistListener later
|
||||
this.dirtyPropertyNames = (beanPersistListener == null) ? null : intercept.getDirtyPropertyNames();
|
||||
|
||||
this.bean = bean;
|
||||
this.parentBean = parentBean;
|
||||
this.controller = beanDescriptor.getPersistController();
|
||||
this.concurrencyMode = beanDescriptor.getConcurrencyMode(intercept);
|
||||
this.dirty = intercept.isDirty();
|
||||
}
|
||||
this.dirty = intercept.isDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is an insert request.
|
||||
*/
|
||||
/**
|
||||
* Return true if this is an insert request.
|
||||
*/
|
||||
public boolean isInsert() {
|
||||
return Type.INSERT == type;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@Override
|
||||
public Set<String> getLoadedProperties() {
|
||||
return intercept.getLoadedPropertyNames();
|
||||
}
|
||||
@@ -148,18 +149,18 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
return intercept.getDirtyValues();
|
||||
}
|
||||
|
||||
public boolean isNotify(TransactionEvent txnEvent) {
|
||||
this.notifyCache = beanDescriptor.isCacheNotify();
|
||||
return notifyCache || isNotifyPersistListener();
|
||||
}
|
||||
public boolean isNotify(TransactionEvent txnEvent) {
|
||||
this.notifyCache = beanDescriptor.isCacheNotify();
|
||||
return notifyCache || isNotifyPersistListener();
|
||||
}
|
||||
|
||||
public boolean isNotifyPersistListener() {
|
||||
return beanPersistListener != null;
|
||||
}
|
||||
public boolean isNotifyPersistListener() {
|
||||
return beanPersistListener != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify/Update the local L2 cache after the transaction has successfully committed.
|
||||
*/
|
||||
/**
|
||||
* Notify/Update the local L2 cache after the transaction has successfully committed.
|
||||
*/
|
||||
public void notifyCache() {
|
||||
if (notifyCache) {
|
||||
switch (type) {
|
||||
@@ -178,414 +179,420 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
}
|
||||
}
|
||||
|
||||
public void addToPersistMap(BeanPersistIdMap beanPersistMap) {
|
||||
public void addToPersistMap(BeanPersistIdMap beanPersistMap) {
|
||||
|
||||
beanPersistMap.add(beanDescriptor, type, idValue);
|
||||
}
|
||||
beanPersistMap.add(beanDescriptor, type, idValue);
|
||||
}
|
||||
|
||||
public boolean notifyLocalPersistListener() {
|
||||
if (beanPersistListener == null) {
|
||||
return false;
|
||||
public boolean notifyLocalPersistListener() {
|
||||
if (beanPersistListener == null) {
|
||||
return false;
|
||||
|
||||
} else {
|
||||
switch (type) {
|
||||
case INSERT:
|
||||
return beanPersistListener.inserted(bean);
|
||||
} else {
|
||||
switch (type) {
|
||||
case INSERT:
|
||||
return beanPersistListener.inserted(bean);
|
||||
|
||||
case UPDATE:
|
||||
return beanPersistListener.updated(bean, dirtyPropertyNames);
|
||||
case UPDATE:
|
||||
return beanPersistListener.updated(bean, updatedProperties);
|
||||
|
||||
case DELETE:
|
||||
return beanPersistListener.deleted(bean);
|
||||
case DELETE:
|
||||
return beanPersistListener.deleted(bean);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isParent(Object o) {
|
||||
return o == parentBean;
|
||||
}
|
||||
public boolean isParent(Object o) {
|
||||
return o == parentBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this bean has been already been persisted
|
||||
* (inserted or updated) in this transaction.
|
||||
*/
|
||||
public boolean isRegisteredBean() {
|
||||
return transaction.isRegisteredBean(bean);
|
||||
}
|
||||
|
||||
public void unRegisterBean() {
|
||||
transaction.unregisterBean(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* The hash used to register the bean with the transaction.
|
||||
* <p>
|
||||
* Takes into account the class type and id value.
|
||||
* </p>
|
||||
*/
|
||||
private Integer getBeanHash() {
|
||||
if (beanHash == null) {
|
||||
Object id = beanDescriptor.getId(entityBean);
|
||||
int hc = 31 * bean.getClass().getName().hashCode();
|
||||
if (id != null) {
|
||||
hc += id.hashCode();
|
||||
}
|
||||
beanHash = Integer.valueOf(hc);
|
||||
}
|
||||
return beanHash;
|
||||
}
|
||||
|
||||
public void registerDeleteBean() {
|
||||
Integer hash = getBeanHash();
|
||||
transaction.registerDeleteBean(hash);
|
||||
}
|
||||
|
||||
public void unregisterDeleteBean() {
|
||||
Integer hash = getBeanHash();
|
||||
transaction.unregisterDeleteBean(hash);
|
||||
}
|
||||
|
||||
public boolean isRegisteredForDeleteBean() {
|
||||
if (transaction == null){
|
||||
return false;
|
||||
} else {
|
||||
Integer hash = getBeanHash();
|
||||
return transaction.isRegisteredDeleteBean(hash);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Return true if this bean has been already been persisted (inserted or updated) in this
|
||||
* transaction.
|
||||
*/
|
||||
public boolean isRegisteredBean() {
|
||||
return transaction.isRegisteredBean(bean);
|
||||
}
|
||||
|
||||
public BeanManager<T> getBeanManager() {
|
||||
return beanManager;
|
||||
}
|
||||
public void unRegisterBean() {
|
||||
transaction.unregisterBean(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanDescriptor for the associated bean.
|
||||
*/
|
||||
public BeanDescriptor<T> getBeanDescriptor() {
|
||||
return beanDescriptor;
|
||||
}
|
||||
/**
|
||||
* The hash used to register the bean with the transaction.
|
||||
* <p>
|
||||
* Takes into account the class type and id value.
|
||||
* </p>
|
||||
*/
|
||||
private Integer getBeanHash() {
|
||||
if (beanHash == null) {
|
||||
Object id = beanDescriptor.getId(entityBean);
|
||||
int hc = 31 * bean.getClass().getName().hashCode();
|
||||
if (id != null) {
|
||||
hc += id.hashCode();
|
||||
}
|
||||
beanHash = Integer.valueOf(hc);
|
||||
}
|
||||
return beanHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if a stateless update should also delete any missing details
|
||||
* beans.
|
||||
*/
|
||||
public boolean isDeleteMissingChildren() {
|
||||
return deleteMissingChildren;
|
||||
}
|
||||
public void registerDeleteBean() {
|
||||
Integer hash = getBeanHash();
|
||||
transaction.registerDeleteBean(hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if deleteMissingChildren occurs on cascade save to OneToMany or ManyToMany.
|
||||
*/
|
||||
public void setDeleteMissingChildren(boolean deleteMissingChildren) {
|
||||
this.deleteMissingChildren = deleteMissingChildren;
|
||||
}
|
||||
public void unregisterDeleteBean() {
|
||||
Integer hash = getBeanHash();
|
||||
transaction.unregisterDeleteBean(hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to skip updates if we know the bean is not dirty. This is the case
|
||||
* for EntityBeans that have not been modified.
|
||||
*/
|
||||
public boolean isDirty() {
|
||||
return dirty;
|
||||
}
|
||||
public boolean isRegisteredForDeleteBean() {
|
||||
if (transaction == null) {
|
||||
return false;
|
||||
} else {
|
||||
Integer hash = getBeanHash();
|
||||
return transaction.isRegisteredDeleteBean(hash);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the concurrency mode used for this persist.
|
||||
*/
|
||||
public ConcurrencyMode getConcurrencyMode() {
|
||||
return concurrencyMode;
|
||||
}
|
||||
public BeanManager<T> getBeanManager() {
|
||||
return beanManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a description of the request. This is typically the bean class
|
||||
* name or the base table for MapBeans.
|
||||
* <p>
|
||||
* Used to determine common persist requests for queueing and statement
|
||||
* batching.
|
||||
* </p>
|
||||
*/
|
||||
public String getFullName() {
|
||||
return beanDescriptor.getFullName();
|
||||
}
|
||||
/**
|
||||
* Return the BeanDescriptor for the associated bean.
|
||||
*/
|
||||
public BeanDescriptor<T> getBeanDescriptor() {
|
||||
return beanDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean associated with this request.
|
||||
*/
|
||||
public T getBean() {
|
||||
return bean;
|
||||
}
|
||||
/**
|
||||
* Return true if a stateless update should also delete any missing details beans.
|
||||
*/
|
||||
public boolean isDeleteMissingChildren() {
|
||||
return deleteMissingChildren;
|
||||
}
|
||||
|
||||
|
||||
public EntityBean getEntityBean() {
|
||||
/**
|
||||
* Set if deleteMissingChildren occurs on cascade save to OneToMany or ManyToMany.
|
||||
*/
|
||||
public void setDeleteMissingChildren(boolean deleteMissingChildren) {
|
||||
this.deleteMissingChildren = deleteMissingChildren;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the update after potential modifications in a BeanPersistController.
|
||||
*/
|
||||
public void postControllerPrepareUpdate() {
|
||||
if (intercept.isNew() && controller != null) {
|
||||
// 'stateless update' - set dirty properties modified in controller preUpdate
|
||||
intercept.setNewBeanForUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to skip updates if we know the bean is not dirty. This is the case for EntityBeans that
|
||||
* have not been modified.
|
||||
*/
|
||||
public boolean isDirty() {
|
||||
return dirty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the concurrency mode used for this persist.
|
||||
*/
|
||||
public ConcurrencyMode getConcurrencyMode() {
|
||||
return concurrencyMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a description of the request. This is typically the bean class name or the base table
|
||||
* for MapBeans.
|
||||
* <p>
|
||||
* Used to determine common persist requests for queueing and statement batching.
|
||||
* </p>
|
||||
*/
|
||||
public String getFullName() {
|
||||
return beanDescriptor.getFullName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean associated with this request.
|
||||
*/
|
||||
public T getBean() {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public EntityBean getEntityBean() {
|
||||
return entityBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Id value for the bean.
|
||||
*/
|
||||
public Object getBeanId() {
|
||||
return beanDescriptor.getId(entityBean);
|
||||
}
|
||||
* Return the Id value for the bean.
|
||||
*/
|
||||
public Object getBeanId() {
|
||||
return beanDescriptor.getId(entityBean);
|
||||
}
|
||||
|
||||
public BeanDelta createDeltaBean() {
|
||||
return new BeanDelta(beanDescriptor, getBeanId());
|
||||
}
|
||||
public BeanDelta createDeltaBean() {
|
||||
return new BeanDelta(beanDescriptor, getBeanId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parent bean for cascading save with unidirectional
|
||||
* relationship.
|
||||
*/
|
||||
public Object getParentBean() {
|
||||
return parentBean;
|
||||
}
|
||||
/**
|
||||
* Return the parent bean for cascading save with unidirectional relationship.
|
||||
*/
|
||||
public Object getParentBean() {
|
||||
return parentBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the controller if there is one associated with this type of bean.
|
||||
* This returns null if there is no controller associated.
|
||||
*/
|
||||
public BeanPersistController getBeanController() {
|
||||
return controller;
|
||||
}
|
||||
/**
|
||||
* Return the controller if there is one associated with this type of bean. This returns null if
|
||||
* there is no controller associated.
|
||||
*/
|
||||
public BeanPersistController getBeanController() {
|
||||
return controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the intercept if there is one.
|
||||
*/
|
||||
public EntityBeanIntercept getEntityBeanIntercept() {
|
||||
return intercept;
|
||||
}
|
||||
/**
|
||||
* Return the intercept if there is one.
|
||||
*/
|
||||
public EntityBeanIntercept getEntityBeanIntercept() {
|
||||
return intercept;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this property is loaded (full bean or included in partial
|
||||
* bean).
|
||||
*/
|
||||
public boolean isLoadedProperty(BeanProperty prop) {
|
||||
return intercept.isLoadedProperty(prop.getPropertyIndex());
|
||||
}
|
||||
/**
|
||||
* Return true if this property is loaded (full bean or included in partial bean).
|
||||
*/
|
||||
public boolean isLoadedProperty(BeanProperty prop) {
|
||||
return intercept.isLoadedProperty(prop.getPropertyIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeNow() {
|
||||
switch (type) {
|
||||
case INSERT:
|
||||
persistExecute.executeInsertBean(this);
|
||||
return -1;
|
||||
@Override
|
||||
public int executeNow() {
|
||||
switch (type) {
|
||||
case INSERT:
|
||||
persistExecute.executeInsertBean(this);
|
||||
return -1;
|
||||
|
||||
case UPDATE:
|
||||
persistExecute.executeUpdateBean(this);
|
||||
return -1;
|
||||
case UPDATE:
|
||||
if (beanPersistListener != null) {
|
||||
// store the updated properties for sending later
|
||||
updatedProperties = getUpdatedProperties();
|
||||
}
|
||||
persistExecute.executeUpdateBean(this);
|
||||
return -1;
|
||||
|
||||
case DELETE:
|
||||
persistExecute.executeDeleteBean(this);
|
||||
return -1;
|
||||
case DELETE:
|
||||
persistExecute.executeDeleteBean(this);
|
||||
return -1;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Invalid type " + type);
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new RuntimeException("Invalid type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeOrQueue() {
|
||||
@Override
|
||||
public int executeOrQueue() {
|
||||
|
||||
boolean batch = transaction.isBatchThisRequest();
|
||||
boolean batch = transaction.isBatchThisRequest();
|
||||
|
||||
BatchControl control = transaction.getBatchControl();
|
||||
if (control != null) {
|
||||
return control.executeOrQueue(this, batch);
|
||||
}
|
||||
if (batch) {
|
||||
control = persistExecute.createBatchControl(transaction);
|
||||
return control.executeOrQueue(this, batch);
|
||||
BatchControl control = transaction.getBatchControl();
|
||||
if (control != null) {
|
||||
return control.executeOrQueue(this, batch);
|
||||
}
|
||||
if (batch) {
|
||||
control = persistExecute.createBatchControl(transaction);
|
||||
return control.executeOrQueue(this, batch);
|
||||
|
||||
} else {
|
||||
return executeNow();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return executeNow();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the generated key back to the bean. Only used for inserts with
|
||||
* getGeneratedKeys.
|
||||
*/
|
||||
public void setGeneratedKey(Object idValue) {
|
||||
if (idValue != null) {
|
||||
// remember it for logging summary
|
||||
this.idValue = beanDescriptor.convertSetId(idValue, entityBean);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Set the generated key back to the bean. Only used for inserts with getGeneratedKeys.
|
||||
*/
|
||||
public void setGeneratedKey(Object idValue) {
|
||||
if (idValue != null) {
|
||||
// remember it for logging summary
|
||||
this.idValue = beanDescriptor.convertSetId(idValue, entityBean);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Id value that was bound. Used for the purposes of logging summary
|
||||
* information on this request.
|
||||
*/
|
||||
public void setBoundId(Object idValue) {
|
||||
this.idValue = idValue;
|
||||
}
|
||||
/**
|
||||
* Set the Id value that was bound. Used for the purposes of logging summary information on this
|
||||
* request.
|
||||
*/
|
||||
public void setBoundId(Object idValue) {
|
||||
this.idValue = idValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for optimistic concurrency exception.
|
||||
*/
|
||||
public final void checkRowCount(int rowCount) throws SQLException {
|
||||
if (rowCount != 1) {
|
||||
String m = Message.msg("persist.conc2", "" + rowCount);
|
||||
throw new OptimisticLockException(m, null, bean);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Check for optimistic concurrency exception.
|
||||
*/
|
||||
public final void checkRowCount(int rowCount) throws SQLException {
|
||||
if (rowCount != 1) {
|
||||
String m = Message.msg("persist.conc2", "" + rowCount);
|
||||
throw new OptimisticLockException(m, null, bean);
|
||||
}
|
||||
}
|
||||
|
||||
public void postDelete() {
|
||||
|
||||
// Delete the bean from the PersistenceContent
|
||||
transaction.getPersistenceContext().clear(beanDescriptor.getBeanType(), idValue);
|
||||
// Delete from cache early even if transaction fails
|
||||
beanDescriptor.cacheHandleDelete(idValue, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Post processing.
|
||||
*/
|
||||
public void postExecute() throws SQLException {
|
||||
public void postDelete() {
|
||||
|
||||
if (controller != null) {
|
||||
controllerPost();
|
||||
}
|
||||
// Delete the bean from the PersistenceContent
|
||||
transaction.getPersistenceContext().clear(beanDescriptor.getBeanType(), idValue);
|
||||
// Delete from cache early even if transaction fails
|
||||
beanDescriptor.cacheHandleDelete(idValue, this);
|
||||
}
|
||||
|
||||
if (intercept != null) {
|
||||
// if bean persisted again then should result in an update
|
||||
intercept.setLoaded();
|
||||
}
|
||||
/**
|
||||
* Post processing.
|
||||
*/
|
||||
public void postExecute() throws SQLException {
|
||||
|
||||
addEvent();
|
||||
if (controller != null) {
|
||||
controllerPost();
|
||||
}
|
||||
|
||||
if (isLogSummary()) {
|
||||
logSummary();
|
||||
}
|
||||
}
|
||||
if (intercept != null) {
|
||||
// if bean persisted again then should result in an update
|
||||
intercept.setLoaded();
|
||||
}
|
||||
|
||||
private void controllerPost() {
|
||||
switch (type) {
|
||||
case INSERT:
|
||||
controller.postInsert(this);
|
||||
break;
|
||||
case UPDATE:
|
||||
controller.postUpdate(this);
|
||||
break;
|
||||
case DELETE:
|
||||
controller.postDelete(this);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
addEvent();
|
||||
|
||||
private void logSummary() {
|
||||
if (isLogSummary()) {
|
||||
logSummary();
|
||||
}
|
||||
}
|
||||
|
||||
String name = beanDescriptor.getName();
|
||||
switch (type) {
|
||||
case INSERT:
|
||||
transaction.logSummary("Inserted [" + name + "] [" + idValue + "]");
|
||||
break;
|
||||
case UPDATE:
|
||||
transaction.logSummary("Updated [" + name + "] [" + idValue + "]");
|
||||
break;
|
||||
case DELETE:
|
||||
transaction.logSummary("Deleted [" + name + "] [" + idValue + "]");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void controllerPost() {
|
||||
switch (type) {
|
||||
case INSERT:
|
||||
controller.postInsert(this);
|
||||
break;
|
||||
case UPDATE:
|
||||
controller.postUpdate(this);
|
||||
break;
|
||||
case DELETE:
|
||||
controller.postDelete(this);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the bean to the TransactionEvent. This will be used by
|
||||
* TransactionManager to synch Cache, Cluster and text indexes.
|
||||
*/
|
||||
private void addEvent() {
|
||||
private void logSummary() {
|
||||
|
||||
TransactionEvent event = transaction.getEvent();
|
||||
if (event != null) {
|
||||
event.add(this);
|
||||
}
|
||||
}
|
||||
String name = beanDescriptor.getName();
|
||||
switch (type) {
|
||||
case INSERT:
|
||||
transaction.logSummary("Inserted [" + name + "] [" + idValue + "]");
|
||||
break;
|
||||
case UPDATE:
|
||||
transaction.logSummary("Updated [" + name + "] [" + idValue + "]");
|
||||
break;
|
||||
case DELETE:
|
||||
transaction.logSummary("Deleted [" + name + "] [" + idValue + "]");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the concurrency mode depending on fully/partially populated
|
||||
* bean.
|
||||
* <p>
|
||||
* Specifically with version concurrency we want to check that the version
|
||||
* property was one of the loaded properties.
|
||||
* </p>
|
||||
*/
|
||||
public ConcurrencyMode determineConcurrencyMode() {
|
||||
|
||||
// 'partial bean' update/delete...
|
||||
if (concurrencyMode.equals(ConcurrencyMode.VERSION)) {
|
||||
// check the version property was loaded
|
||||
BeanProperty prop = beanDescriptor.getVersionProperty();
|
||||
if (prop != null && intercept.isLoadedProperty(prop.getPropertyIndex())) {
|
||||
// OK to use version property
|
||||
} else {
|
||||
concurrencyMode = ConcurrencyMode.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
return concurrencyMode;
|
||||
}
|
||||
/**
|
||||
* Add the bean to the TransactionEvent. This will be used by TransactionManager to synch Cache,
|
||||
* Cluster and text indexes.
|
||||
*/
|
||||
private void addEvent() {
|
||||
|
||||
/**
|
||||
* Return true if the update DML/SQL must be dynamically generated.
|
||||
* <p>
|
||||
* This is the case for updates/deletes of partially populated beans.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isDynamicUpdateSql() {
|
||||
return beanDescriptor.isUpdateChangesOnly() || !intercept.isFullyLoadedBean();
|
||||
}
|
||||
TransactionEvent event = transaction.getEvent();
|
||||
if (event != null) {
|
||||
event.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a GenerateDmlRequest used to generate the DML.
|
||||
* <p>
|
||||
* Will used changed properties or loaded properties depending on the
|
||||
* BeanDescriptor.isUpdateChangesOnly() value.
|
||||
* </p>
|
||||
*/
|
||||
public GenerateDmlRequest createGenerateDmlRequest(boolean emptyStringAsNull) {
|
||||
return new GenerateDmlRequest(emptyStringAsNull, intercept, beanDescriptor.isUpdateChangesOnly());
|
||||
}
|
||||
/**
|
||||
* Determine the concurrency mode depending on fully/partially populated bean.
|
||||
* <p>
|
||||
* Specifically with version concurrency we want to check that the version property was one of the
|
||||
* loaded properties.
|
||||
* </p>
|
||||
*/
|
||||
public ConcurrencyMode determineConcurrencyMode() {
|
||||
|
||||
/**
|
||||
* Test if the property value has changed and if so include it in the
|
||||
* update.
|
||||
*/
|
||||
public boolean isAddToUpdate(BeanProperty prop) {
|
||||
return intercept.isDirtyProperty(prop.getPropertyIndex());
|
||||
}
|
||||
// 'partial bean' update/delete...
|
||||
if (concurrencyMode.equals(ConcurrencyMode.VERSION)) {
|
||||
// check the version property was loaded
|
||||
BeanProperty prop = beanDescriptor.getVersionProperty();
|
||||
if (prop != null && intercept.isLoadedProperty(prop.getPropertyIndex())) {
|
||||
// OK to use version property
|
||||
} else {
|
||||
concurrencyMode = ConcurrencyMode.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
return concurrencyMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the update DML/SQL must be dynamically generated.
|
||||
* <p>
|
||||
* This is the case for updates/deletes of partially populated beans.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isDynamicUpdateSql() {
|
||||
return beanDescriptor.isUpdateChangesOnly() || !intercept.isFullyLoadedBean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a GenerateDmlRequest used to generate the DML.
|
||||
* <p>
|
||||
* Will used changed properties or loaded properties depending on the
|
||||
* BeanDescriptor.isUpdateChangesOnly() value.
|
||||
* </p>
|
||||
*/
|
||||
public GenerateDmlRequest createGenerateDmlRequest(boolean emptyStringAsNull) {
|
||||
return new GenerateDmlRequest(emptyStringAsNull, intercept, beanDescriptor.isUpdateChangesOnly());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the property value has changed and if so include it in the update.
|
||||
*/
|
||||
public boolean isAddToUpdate(BeanProperty prop) {
|
||||
return intercept.isDirtyProperty(prop.getPropertyIndex());
|
||||
}
|
||||
|
||||
public List<DerivedRelationshipData> getDerivedRelationships() {
|
||||
return transaction.getDerivedRelationship(bean);
|
||||
}
|
||||
|
||||
public void postInsert() {
|
||||
// mark all properties as loaded after an insert to support immediate update
|
||||
// mark all properties as loaded after an insert to support immediate update
|
||||
int len = intercept.getPropertyLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
intercept.setLoadedProperty(i);
|
||||
intercept.setLoadedProperty(i);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isReference() {
|
||||
return beanDescriptor.isReference(intercept);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This many property has been cascade saved. Keep note of this and update the 'many property'
|
||||
* cache on post commit.
|
||||
*/
|
||||
public void addUpdatedManyProperty(BeanPropertyAssocMany<?> updatedAssocMany) {
|
||||
//if (notifyCache) {
|
||||
if (updatedManys == null) {
|
||||
updatedManys = new ArrayList<BeanPropertyAssocMany<?>>(5);
|
||||
}
|
||||
updatedManys.add(updatedAssocMany);
|
||||
//}
|
||||
// if (notifyCache) {
|
||||
if (updatedManys == null) {
|
||||
updatedManys = new ArrayList<BeanPropertyAssocMany<?>>(5);
|
||||
}
|
||||
updatedManys.add(updatedAssocMany);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,15 +40,6 @@ public final class RelationalQueryRequest {
|
||||
this.trans = (SpiTransaction) t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the transaction if it was created for this request.
|
||||
*/
|
||||
public void rollbackTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
trans.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a transaction if none currently exists.
|
||||
*/
|
||||
@@ -58,10 +49,6 @@ public final class RelationalQueryRequest {
|
||||
if (trans == null || !trans.isActive()) {
|
||||
// create a local readOnly transaction
|
||||
trans = ebeanServer.createServerTransaction(false, -1);
|
||||
|
||||
// commented out for performance reasons...
|
||||
// TODO: review performance of trans.setReadOnly(true)
|
||||
// trans.setReadOnly(true);
|
||||
createdTransaction = true;
|
||||
}
|
||||
}
|
||||
@@ -72,8 +59,7 @@ public final class RelationalQueryRequest {
|
||||
*/
|
||||
public void endTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
// we can rollback as a readOnly transaction.
|
||||
trans.rollback();
|
||||
trans.endQueryOnly();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user