mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
122
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9ba6f9a3a | ||
|
|
2fa4345742 | ||
|
|
d9147327c1 | ||
|
|
5ad9a611f9 | ||
|
|
3fb497b651 | ||
|
|
fbfe5d1ff8 | ||
|
|
b6f21f8649 | ||
|
|
8fd04807c7 | ||
|
|
e49c42302a | ||
|
|
d96abece75 | ||
|
|
c953da637e | ||
|
|
8d39b0a996 | ||
|
|
0efcf1eeb3 | ||
|
|
335cef870f | ||
|
|
4c40962f04 | ||
|
|
9be0d22cfb | ||
|
|
2893d73fad | ||
|
|
33d66ea9d1 | ||
|
|
073ea9c550 | ||
|
|
8467934021 | ||
|
|
96ba63407f | ||
|
|
88df6ffc6e | ||
|
|
3efcfec300 | ||
|
|
e51eb00889 | ||
|
|
9ae27ddcdd | ||
|
|
b9516e64a3 | ||
|
|
f7f5552bf0 | ||
|
|
adec2ab1b8 | ||
|
|
da6d7284f8 | ||
|
|
1c160fea5a | ||
|
|
cc87de76d7 | ||
|
|
70b380e6e7 | ||
|
|
3e419d3e3a | ||
|
|
7e2be20b6e | ||
|
|
ab2d5fb4c8 | ||
|
|
809901ff13 | ||
|
|
fcc58d77e8 | ||
|
|
bc93a82b1a | ||
|
|
84e1e12b66 | ||
|
|
2eb0c12213 | ||
|
|
4941134ce1 | ||
|
|
cf37fda3f4 | ||
|
|
f429811f79 | ||
|
|
70fd988d8c | ||
|
|
fe4167ed60 | ||
|
|
0eef69a277 | ||
|
|
76bfd805c0 | ||
|
|
971e2dc91b | ||
|
|
5821dc96b9 | ||
|
|
e027110006 | ||
|
|
b5e6e9a66c | ||
|
|
514047e680 | ||
|
|
a727a98a21 | ||
|
|
e75b5e8b30 | ||
|
|
ad0e085ff5 | ||
|
|
322a2f500d | ||
|
|
1c7454d249 | ||
|
|
e1efca6736 | ||
|
|
8ae61074ad | ||
|
|
c3bc0c4975 | ||
|
|
611bba272a | ||
|
|
4c9ec38c88 | ||
|
|
e2731a99be | ||
|
|
7d56df3b23 | ||
|
|
bebef48332 | ||
|
|
f66ea12fbf | ||
|
|
b08f1580f9 | ||
|
|
707912f7ad | ||
|
|
5ce31b16d4 | ||
|
|
a5945b1d5d | ||
|
|
b8577ae6d0 | ||
|
|
14dedb7b9a | ||
|
|
2dbd543127 | ||
|
|
cc989af1c6 | ||
|
|
0aad285f35 | ||
|
|
a3754e31f2 | ||
|
|
1dd0f3f609 | ||
|
|
f9b381b10a | ||
|
|
6e2d7a89f8 | ||
|
|
dfa336239f | ||
|
|
3a28dd0d55 | ||
|
|
502e9daaf2 | ||
|
|
b7c92aec3d | ||
|
|
c0341458c3 | ||
|
|
aecac211d9 | ||
|
|
c46b235eff | ||
|
|
a585447dc9 | ||
|
|
85bb05d90e | ||
|
|
027dd1eba9 | ||
|
|
588d5c5cfa | ||
|
|
7ba86f7cf2 | ||
|
|
609dc233a8 | ||
|
|
5d7c287821 | ||
|
|
ff325057c4 | ||
|
|
cc6469851b | ||
|
|
7f31104439 | ||
|
|
2ab98a922d | ||
|
|
063c1825ca | ||
|
|
d0e9c6a218 | ||
|
|
81d829f74e | ||
|
|
b4a0d9f5ea | ||
|
|
f0044aba91 | ||
|
|
6f322dcfb2 | ||
|
|
a391a25b7f | ||
|
|
4af350bd14 | ||
|
|
cdb319f0ef | ||
|
|
60ed64cb37 | ||
|
|
79efe006ec | ||
|
|
70f929949d | ||
|
|
d7916eb3ee | ||
|
|
f724982776 | ||
|
|
182a47697e | ||
|
|
d6b37bdf83 | ||
|
|
0bc2dc7d4c | ||
|
|
1263f0f049 | ||
|
|
f4b32e89f5 | ||
|
|
4fa9f739d4 | ||
|
|
ba0509dadc | ||
|
|
64c67e3755 | ||
|
|
6142dd34f4 | ||
|
|
06e265ec47 | ||
|
|
7b19973836 |
@@ -6,12 +6,12 @@ Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Web
|
||||
|
||||
|
||||
## Maven cental links:
|
||||
[Maven central - ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.avaje.ebean%22%20AND%20a%3A%22ebean%22 "maven central ebean")
|
||||
[Maven central - ebean](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22io.ebean%22%20AND%20a%3A%22ebean%22 "maven central ebean")
|
||||
|
||||
[Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects")
|
||||
|
||||
## Current versions
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean) - ebean
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent) - ebean-agent
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin) - ebean-maven-plugin
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean) - ebean
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent) - ebean-agent
|
||||
* [](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin) - ebean-maven-plugin
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
<version>1.1</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>9.2.1</version>
|
||||
<version>10.1.5</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ebean</name>
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-9.2.1</tag>
|
||||
<tag>ebean-10.1.5</tag>
|
||||
</scm>
|
||||
|
||||
<dependencies>
|
||||
@@ -33,9 +33,15 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.persistence</groupId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>2.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>2.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -47,7 +53,7 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-datasource</artifactId>
|
||||
<version>1.1.3</version>
|
||||
<version>1.1.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -59,13 +65,13 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-classpath-scanner</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<version>2.2.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-dbmigration</artifactId>
|
||||
<version>1.2.1</version>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-dbmigration</artifactId>
|
||||
<version>10.1.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -77,7 +83,7 @@
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>antlr4-runtime</artifactId>
|
||||
<version>4.5.3</version>
|
||||
<version>4.6</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson core used internally by Ebean -->
|
||||
@@ -106,21 +112,21 @@
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
<version>1.0.0.GA</version>
|
||||
<version>1.1.0.Final</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.4</version>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>1.6</version>
|
||||
<version>2.9.7</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -128,7 +134,7 @@
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>9.4-1202-jdbc41</version>
|
||||
<version>9.4.1212.jre7</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -151,14 +157,14 @@
|
||||
<dependency>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>avaje-agentloader</artifactId>
|
||||
<version>1.1.1</version>
|
||||
<version>2.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-agent</artifactId>
|
||||
<version>8.1.1</version>
|
||||
<version>10.1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -167,28 +173,28 @@
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.192</version>
|
||||
<version>1.4.193</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.8.11.2</version>
|
||||
<version>3.15.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<version>2.3.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.36</version>
|
||||
<version>6.0.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -203,14 +209,14 @@
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.4</version>
|
||||
<version>2.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.avaje.moduuid</groupId>
|
||||
<artifactId>avaje-moduuid</artifactId>
|
||||
<version>1.2</version>
|
||||
<version>2.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -221,9 +227,9 @@
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.avaje.ebean</groupId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-maven-plugin</artifactId>
|
||||
<version>8.1.1</version>
|
||||
<version>10.1.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
@@ -277,11 +283,11 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration>
|
||||
<doctitle>Ebean 9</doctitle>
|
||||
<overview>src/main/java/com/avaje/ebean/overview.html</overview>
|
||||
<doctitle>Ebean 10</doctitle>
|
||||
<overview>src/main/java/io/ebean/overview.html</overview>
|
||||
<source>1.8</source>
|
||||
<doclet>org.avaje.doclet.PygmentsDoclet</doclet>
|
||||
<excludePackageNames>com.avaje.ebeaninternal.*:com.avaje.ebean.util:com.avaje.ebean.dbmigration.ddlgeneration:com.avaje.ebean.dbmigration.migration:com.avaje.ebean.dbmigration.migrationreader:com.avaje.ebean.dbmigration.model</excludePackageNames>
|
||||
<excludePackageNames>io.ebeaninternal.*:com.avaje.ebean.util:io.ebean.dbmigration.ddlgeneration:io.ebean.dbmigration.migration:io.ebean.dbmigration.migrationreader:io.ebean.dbmigration.model</excludePackageNames>
|
||||
<docletArtifact>
|
||||
<groupId>org.avaje</groupId>
|
||||
<artifactId>pygments-doclet</artifactId>
|
||||
@@ -310,5 +316,5 @@
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
||||
|
||||
@@ -1,886 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.util.ClassUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A MappedSuperclass base class that provides convenience methods for inserting, updating and
|
||||
* deleting beans.
|
||||
* <p>
|
||||
* By having your entity beans extend this it provides a 'Active Record' style programming model for
|
||||
* Ebean users.
|
||||
* <p>
|
||||
* Note that there is a avaje-ebeanorm-mocker project that enables you to use Mockito or similar
|
||||
* tools to still mock out the underlying 'default EbeanServer' for testing purposes.
|
||||
* <p>
|
||||
* You may choose not use this Model mapped superclass if you don't like the 'Active Record' style
|
||||
* or if you believe it 'pollutes' your entity beans.
|
||||
* <p>
|
||||
* You can use Dependency Injection like Guice or Spring to construct and wire a EbeanServer instance
|
||||
* and have that same instance used with this Model and Finder. The way that works is that when the
|
||||
* DI container creates the EbeanServer instance it can be registered with the Ebean singleton. In this
|
||||
* way the EbeanServer instance can be injected as per normal Guice / Spring dependency injection and
|
||||
* that same instance also used to support the Model and Finder active record style.
|
||||
* <p>
|
||||
* If you choose to use the Model mapped superclass you will probably also chose to additionally add
|
||||
* a {@link Find} as a public static field to complete the active record pattern and provide a
|
||||
* relatively nice clean way to write queries.
|
||||
* <p>
|
||||
* <h3>Typical common @MappedSuperclass</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Typically there is a common base model that has some
|
||||
* // common properties like the ones below
|
||||
*
|
||||
* @MappedSuperclass
|
||||
* public class BaseModel extends Model {
|
||||
*
|
||||
* @Id Long id;
|
||||
*
|
||||
* @Version Long version;
|
||||
*
|
||||
* @CreatedTimestamp Timestamp whenCreated;
|
||||
*
|
||||
* @UpdatedTimestamp Timestamp whenUpdated;
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Extend the Model</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Extend the mappedSuperclass
|
||||
*
|
||||
* @Entity @Table(name="oto_account")
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* // Add a static Find
|
||||
* // ... with Long being the type of our @Id property.
|
||||
* // ... Note the {} at the end as Find is an abstract class.
|
||||
*
|
||||
* public static final Find<Long,Account> find = new Find<Long,Account>(){};
|
||||
*
|
||||
* String name;
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Modal: save()</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Active record style ... save(), delete() etc
|
||||
* Customer customer = new Customer();
|
||||
* customer.setName("AC234");
|
||||
*
|
||||
* // save() method inherited from Model
|
||||
* customer.save();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Find byId</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // find byId
|
||||
* Customer customer = Customer.find.byId(42);
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Find where</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // find where ...
|
||||
* List<Customer> customers =
|
||||
* Customer.find
|
||||
* .where().gt("startDate", lastMonth)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public abstract class Model {
|
||||
|
||||
/**
|
||||
* Return the underlying 'default' EbeanServer.
|
||||
* <p>
|
||||
* This provides full access to the API such as explicit transaction demarcation etc.
|
||||
* <p>
|
||||
* Example:
|
||||
* <pre>{@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 static EbeanServer db() {
|
||||
return Ebean.getDefaultServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a named EbeanServer that is typically different to the default server.
|
||||
* <p>
|
||||
* If you are using multiple databases then each database has a name and maps to a single
|
||||
* EbeanServer. You can use this method to get an EbeanServer for another database.
|
||||
*
|
||||
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is returned.
|
||||
*/
|
||||
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.
|
||||
* <p>
|
||||
* <pre>{@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>
|
||||
*
|
||||
* @see EbeanServer#markAsDirty(Object)
|
||||
*/
|
||||
public void markAsDirty() {
|
||||
db().markAsDirty(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the property as unset or 'not loaded'.
|
||||
* <p>
|
||||
* This would be used to specify a property that we did not wish to include in a stateless update.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // populate an entity bean from JSON or whatever
|
||||
* User user = ...;
|
||||
*
|
||||
* // mark the email property as 'unset' so that it is not
|
||||
* // included in a 'stateless update'
|
||||
* user.markPropertyUnset("email");
|
||||
*
|
||||
* user.update();
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param propertyName the name of the property on the bean to be marked as 'unset'
|
||||
*/
|
||||
public void markPropertyUnset(String propertyName) {
|
||||
((EntityBean) this)._ebean_getIntercept().setPropertyLoaded(propertyName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert or update this entity depending on its state.
|
||||
* <p>
|
||||
* Ebean will detect if this is a new bean or a previously fetched bean and perform either an
|
||||
* insert or an update based on that.
|
||||
*
|
||||
* @see EbeanServer#save(Object)
|
||||
*/
|
||||
public void save() {
|
||||
db().save(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this entity.
|
||||
*
|
||||
* @see EbeanServer#update(Object)
|
||||
*/
|
||||
public void update() {
|
||||
db().update(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert this entity.
|
||||
*
|
||||
* @see EbeanServer#insert(Object)
|
||||
*/
|
||||
public void insert() {
|
||||
db().insert(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete this bean.
|
||||
* <p>
|
||||
* This will return true if the bean was deleted successfully or JDBC batch is being used.
|
||||
* </p>
|
||||
* <p>
|
||||
* If there is no current transaction one will be created and committed for
|
||||
* you automatically.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the Bean does not have a version property (or loaded version property) and
|
||||
* the bean does not exist then this returns false indicating that nothing was
|
||||
* deleted. Note that, if JDBC batch mode is used then this always returns true.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#delete(Object)
|
||||
*/
|
||||
public boolean delete() {
|
||||
return db().delete(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bean permanently without soft delete.
|
||||
* <p>
|
||||
* This is used when the bean contains a <code>@SoftDelete</code> property and we
|
||||
* want to perform a hard/permanent delete.
|
||||
* </p>
|
||||
*
|
||||
* @see EbeanServer#deletePermanent(Object)
|
||||
*/
|
||||
public boolean deletePermanent() {
|
||||
return db().deletePermanent(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an update using this entity against the specified server.
|
||||
*/
|
||||
public void update(String server) {
|
||||
db(server).update(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an insert using this entity against the specified server.
|
||||
*/
|
||||
public void insert(String server) {
|
||||
db(server).insert(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a delete using this entity against the specified server.
|
||||
*/
|
||||
public boolean delete(String server) {
|
||||
return db(server).delete(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes this entity from the database.
|
||||
*
|
||||
* @see EbeanServer#refresh(Object)
|
||||
*/
|
||||
public void refresh() {
|
||||
db().refresh(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* A concrete implementation of Find.
|
||||
* <p>
|
||||
* It should be preferred to use {@link Find} instead of Finder as that can use reflection to determine the class
|
||||
* literal type of the entity bean.
|
||||
* </p>
|
||||
*
|
||||
* @param <I> type of the Id property
|
||||
* @param <T> type of the entity bean
|
||||
*/
|
||||
public static class Finder<I, T> extends Find<I, T> {
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final Finder<Long,Customer> find = new Finder<Long,Customer>(Customer.class);
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <p/>
|
||||
* The preferred approach is to instead use <code>Find</code> as below. This approach is more DRY in that it does
|
||||
* not require the class literal Customer.class to be passed into the constructor.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
public Finder(Class<T> type) {
|
||||
super(null, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with the type of the entity bean and specific server name.
|
||||
*/
|
||||
public Finder(String serverName, Class<T> type) {
|
||||
super(serverName, type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper object for performing queries.
|
||||
* <p>
|
||||
* <p>
|
||||
* Typically a Find instance is defined as a public static field on an entity bean class to provide a
|
||||
* nice way to write queries.
|
||||
* <p>
|
||||
* <h3>Example use:</h3>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
* <p/>
|
||||
* This enables you to write code like:
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer = Customer.find.byId(42L);
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* Customer.find
|
||||
* .select("name, dateOfBirth")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Kotlin</h3>
|
||||
* In Kotlin you would typically create Find as a companion object.
|
||||
* <pre>{@code
|
||||
*
|
||||
* // kotlin
|
||||
* companion object : Model.Find<Long, Product>() {}
|
||||
*
|
||||
* }</pre>
|
||||
*
|
||||
* @param <I> The Id type. This is most often a {@link Long} but is also often a {@link UUID} or
|
||||
* {@link String}.
|
||||
* @param <T> The entity bean type
|
||||
*/
|
||||
public static abstract class Find<I, T> {
|
||||
|
||||
/**
|
||||
* The entity bean type.
|
||||
*/
|
||||
private final Class<T> type;
|
||||
|
||||
/**
|
||||
* The name of the EbeanServer, null for the default server.
|
||||
*/
|
||||
private final String serverName;
|
||||
|
||||
/**
|
||||
* Creates a finder for entity of type <code>T</code> with ID of type <code>I</code>.
|
||||
* <p/>
|
||||
* Typically you create Find as a public static field on each entity bean as the example below.
|
||||
* <p>
|
||||
* <p/>
|
||||
* Note that Find is an abstract class and hence <code>{}</code> is required. This is done so
|
||||
* that the type (class literal) of the entity bean can be derived from the generics parameter.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Entity
|
||||
* public class Customer extends BaseModel {
|
||||
*
|
||||
* // Note the trailing {} as Find is an abstract class.
|
||||
* // We do this so that we can derive the type literal Customer.class
|
||||
* // via reflection
|
||||
* public static final Find<Long,Customer> find = new Find<Long,Customer>(){};
|
||||
* ...
|
||||
*
|
||||
* }</pre>
|
||||
* <p/>
|
||||
* This enables you to write code like:
|
||||
* <pre>{@code
|
||||
*
|
||||
* Customer customer = Customer.find.byId(42L);
|
||||
*
|
||||
* List<Customer> customers =
|
||||
* Customer.find
|
||||
* .select("name, email, dateOfBirth")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Kotlin</h3>
|
||||
* In Kotlin you would typically create it as a companion object.
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // kotlin
|
||||
* companion object : Model.Find<Long, Product>() {}
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Find() {
|
||||
this.serverName = null;
|
||||
this.type = (Class<T>) ClassUtil.getSecondArgumentType(getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct passing the class literal type of the entity type.
|
||||
*/
|
||||
protected Find(String serverName, Class<T> type) {
|
||||
this.serverName = serverName;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying 'default' EbeanServer.
|
||||
* <p>
|
||||
* <p>
|
||||
* This provides full access to the API such as explicit transaction demarcation etc.
|
||||
*/
|
||||
public EbeanServer db() {
|
||||
return Ebean.getServer(serverName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return typically a different EbeanServer to the default.
|
||||
* <p>
|
||||
* This is equivalent to {@link Ebean#getServer(String)}
|
||||
*
|
||||
* @param server The name of the EbeanServer. If this is null then the default EbeanServer is
|
||||
* returned.
|
||||
*/
|
||||
public EbeanServer db(String server) {
|
||||
return Ebean.getServer(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Finder for the named EbeanServer.
|
||||
* <p>
|
||||
* <p>
|
||||
* Create and return a new Finder for a different server.
|
||||
*/
|
||||
public Finder<I, T> on(String server) {
|
||||
return new Finder<>(server, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bean by Id.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#delete(Class, Object)}
|
||||
*/
|
||||
public void deleteById(I id) {
|
||||
db().delete(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all entities of the given type.
|
||||
* <p>
|
||||
* <p>
|
||||
* This is the same as (synonym for) {@link #findList()}
|
||||
*/
|
||||
public List<T> all() {
|
||||
return findList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an entity by ID.
|
||||
* <p>
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#find(Class, Object)}
|
||||
*/
|
||||
@Nullable
|
||||
public T byId(I id) {
|
||||
return db().find(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an entity reference for this ID.
|
||||
* <p>
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#getReference(Class, Object)}
|
||||
*/
|
||||
public T ref(I id) {
|
||||
return db().getReference(type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a filter for sorting and filtering lists of entities locally without going back to
|
||||
* the database.
|
||||
* <p>
|
||||
* Equivalent to {@link EbeanServer#filter(Class)}
|
||||
*/
|
||||
public Filter<T> filter() {
|
||||
return db().filter(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#apply(FetchPath)}
|
||||
*/
|
||||
public Query<T> apply(FetchPath fetchPath) {
|
||||
return db().find(type).apply(fetchPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next identity value.
|
||||
*
|
||||
* @see EbeanServer#nextId(Class)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public I nextId() {
|
||||
return (I) db().nextId(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a query and returns the results as a list of IDs.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findIds()}
|
||||
*/
|
||||
public <A> List<A> 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>
|
||||
* Equivalent to {@link Query#findEachWhile(QueryEachWhileConsumer)}
|
||||
* <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>
|
||||
* Equivalent to {@link Query#findList()}
|
||||
*/
|
||||
public List<T> findList() {
|
||||
return query().findList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the entities of the given type as a set.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findSet()}
|
||||
*/
|
||||
public Set<T> findSet() {
|
||||
return query().findSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all entities of the given type as a map of objects.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findMap()}
|
||||
*/
|
||||
public <K> Map<K, T> findMap() {
|
||||
return query().findMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a find row count query in a background thread.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findFutureCount()}
|
||||
*/
|
||||
public FutureRowCount<T> findFutureCount() {
|
||||
return query().findFutureCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated in favor of findFutureCount().
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findFutureCount()}
|
||||
*/
|
||||
public FutureRowCount<T> findFutureRowCount() {
|
||||
return query().findFutureCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of entities for this type. *
|
||||
* <p>
|
||||
* Equivalent to {@link Query#findCount()}
|
||||
*/
|
||||
public int findCount() {
|
||||
return query().findCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated in favor of findCount().
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public int findRowCount() {
|
||||
return query().findCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>ExpressionFactory</code> used by this query.
|
||||
*/
|
||||
public ExpressionFactory getExpressionFactory() {
|
||||
return query().getExpressionFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly sets a comma delimited list of the properties to fetch on the 'main' entity bean,
|
||||
* to load a partial object.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#select(String)}
|
||||
*/
|
||||
public Query<T> select(String fetchProperties) {
|
||||
return query().select(fetchProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a path to load including all its properties.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#fetch(String)}
|
||||
*/
|
||||
public Query<T> fetch(String path) {
|
||||
return query().fetch(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Additionally specifies a <code>FetchConfig</code> to specify a 'query join' and/or define the
|
||||
* lazy loading query.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#fetch(String, FetchConfig)}
|
||||
*/
|
||||
public Query<T> fetch(String path, FetchConfig joinConfig) {
|
||||
return query().fetch(path, joinConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a path to fetch with a specific list properties to include, to load a partial
|
||||
* object.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#fetch(String, String)}
|
||||
*/
|
||||
public Query<T> fetch(String path, String fetchProperties) {
|
||||
return query().fetch(path, fetchProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Additionally specifies a <code>FetchConfig</code> to use a separate query or lazy loading to
|
||||
* load this path.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#fetch(String, String, FetchConfig)}
|
||||
*/
|
||||
public Query<T> fetch(String assocProperty, String fetchProperties, FetchConfig fetchConfig) {
|
||||
return query().fetch(assocProperty, fetchProperties, fetchConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds expressions to the <code>where</code> clause with the ability to chain on the
|
||||
* <code>ExpressionList</code>.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#where()}
|
||||
*/
|
||||
public ExpressionList<T> where() {
|
||||
return query().where();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>order by</code> clause so that you can append an ascending or descending
|
||||
* property to the <code>order by</code> clause.
|
||||
* <p>
|
||||
* This is exactly the same as {@link #orderBy}.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#order()}
|
||||
*/
|
||||
public OrderBy<T> order() {
|
||||
return query().order();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the <code>order by</code> clause, replacing the existing <code>order by</code> clause if
|
||||
* there is one.
|
||||
* <p>
|
||||
* This is exactly the same as {@link #orderBy(String)}.
|
||||
*/
|
||||
public Query<T> order(String orderByClause) {
|
||||
return query().order(orderByClause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>order by</code> clause so that you can append an ascending or descending
|
||||
* property to the <code>order by</code> clause.
|
||||
* <p>
|
||||
* This is exactly the same as {@link #order}.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#orderBy()}
|
||||
*/
|
||||
public OrderBy<T> orderBy() {
|
||||
return query().orderBy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>order by</code> clause replacing the existing <code>order by</code> clause if
|
||||
* there is one.
|
||||
* <p>
|
||||
* This is exactly the same as {@link #order(String)}.
|
||||
*/
|
||||
public Query<T> orderBy(String orderByClause) {
|
||||
return query().orderBy(orderByClause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the first row to return for this query.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#setFirstRow(int)}
|
||||
*/
|
||||
public Query<T> setFirstRow(int firstRow) {
|
||||
return query().setFirstRow(firstRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of rows to return in the query.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#setMaxRows(int)}
|
||||
*/
|
||||
public Query<T> setMaxRows(int maxRows) {
|
||||
return query().setMaxRows(maxRows);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ID value to query.
|
||||
* <p>
|
||||
* <p>
|
||||
* 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>
|
||||
* Equivalent to {@link Query#setId(Object)}
|
||||
*/
|
||||
public Query<T> setId(Object id) {
|
||||
return query().setId(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new query based on the <code>RawSql</code>.
|
||||
* <p>
|
||||
* Equivalent to {@link Query#setRawSql(RawSql)}
|
||||
*/
|
||||
public Query<T> setRawSql(RawSql rawSql) {
|
||||
return query().setRawSql(rawSql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query with explicit 'AutoTune' use.
|
||||
*/
|
||||
public Query<T> setAutoTune(boolean autoTune) {
|
||||
return query().setAutoTune(autoTune);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query with the select with "for update" specified.
|
||||
* <p>
|
||||
* <p>
|
||||
* This will typically create row level database locks on the selected rows.
|
||||
*/
|
||||
public Query<T> setForUpdate(boolean forUpdate) {
|
||||
return query().setForUpdate(forUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query specifying whether the returned beans will be read-only.
|
||||
*/
|
||||
public Query<T> setReadOnly(boolean readOnly) {
|
||||
return query().setReadOnly(readOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query specifying if the beans should be loaded into the L2 cache.
|
||||
*/
|
||||
public Query<T> setLoadBeanCache(boolean loadBeanCache) {
|
||||
return query().setLoadBeanCache(loadBeanCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query specifying if the L2 bean cache should be used.
|
||||
*/
|
||||
public Query<T> setUseCache(boolean useBeanCache) {
|
||||
return query().setUseCache(useBeanCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a query specifying if the L2 query cache should be used.
|
||||
*/
|
||||
public Query<T> setUseQueryCache(boolean useQueryCache) {
|
||||
return query().setUseQueryCache(useQueryCache);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Used to process a query result one bean at a time via a callback to this
|
||||
* visitor.
|
||||
* <p>
|
||||
* If you wish to stop further processing return false from the accept method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Unlike findList() and findSet() using a QueryResultVisitor does not require
|
||||
* all the beans in the query result to be held in memory at once. This makes
|
||||
* QueryResultVisitor useful for processing large queries.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .where().eq("status", Status.NEW)
|
||||
* .order().asc("id");
|
||||
*
|
||||
* query.findEach((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
|
||||
*/
|
||||
void accept(T bean);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Used to process a query result one bean at a time via a callback to this
|
||||
* visitor.
|
||||
* <p>
|
||||
* If you wish to stop further processing return false from the accept method.
|
||||
* </p>
|
||||
* <p>
|
||||
* Unlike findList() and findSet() using a QueryResultVisitor does not require
|
||||
* all the beans in the query result to be held in memory at once. This makes
|
||||
* QueryResultVisitor useful for processing large queries.
|
||||
* </p>
|
||||
* <p/>
|
||||
* <pre>{@code
|
||||
*
|
||||
* Query<Customer> query = server.find(Customer.class)
|
||||
* .fetchQuery("contacts")
|
||||
* .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.
|
||||
*/
|
||||
boolean accept(T bean);
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* The Transaction Isolation levels.
|
||||
* <p>
|
||||
* These match those of java.sql.Connection with the addition of DEFAULT which
|
||||
* implies the configured default of the DataSource.
|
||||
* </p>
|
||||
* <p>
|
||||
* This can be used with TxScope to define transactional scopes to execute
|
||||
* method within.
|
||||
* </p>
|
||||
*
|
||||
* @see TxScope
|
||||
*/
|
||||
public enum TxIsolation {
|
||||
|
||||
/**
|
||||
* Read Committed Isolation level. This is typically the default for most
|
||||
* configurations.
|
||||
*/
|
||||
READ_COMMITED(Connection.TRANSACTION_READ_COMMITTED),
|
||||
|
||||
/**
|
||||
* Read uncommitted Isolation level.
|
||||
*/
|
||||
READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),
|
||||
|
||||
/**
|
||||
* Repeatable Read Isolation level.
|
||||
*/
|
||||
REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),
|
||||
|
||||
/**
|
||||
* Serializable Isolation level.
|
||||
*/
|
||||
SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE),
|
||||
|
||||
/**
|
||||
* No Isolation level.
|
||||
*/
|
||||
NONE(Connection.TRANSACTION_NONE),
|
||||
|
||||
/**
|
||||
* The default isolation level. This typically means the default that the
|
||||
* DataSource is using or configured to use.
|
||||
*/
|
||||
DEFAULT(-1);
|
||||
|
||||
final int level;
|
||||
|
||||
TxIsolation(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the level as per java.sql.Connection.
|
||||
* <p>
|
||||
* Note that -1 denotes the default isolation level.
|
||||
* </p>
|
||||
*/
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TxIsolation given the java.sql.Connection isolation level.
|
||||
* <p>
|
||||
* Note that -1 denotes the default isolation level.
|
||||
* </p>
|
||||
*/
|
||||
public static TxIsolation fromLevel(int connectionIsolationLevel) {
|
||||
|
||||
switch (connectionIsolationLevel) {
|
||||
case Connection.TRANSACTION_READ_UNCOMMITTED:
|
||||
return TxIsolation.READ_UNCOMMITTED;
|
||||
|
||||
case Connection.TRANSACTION_READ_COMMITTED:
|
||||
return TxIsolation.READ_COMMITED;
|
||||
|
||||
case Connection.TRANSACTION_REPEATABLE_READ:
|
||||
return TxIsolation.REPEATABLE_READ;
|
||||
|
||||
case Connection.TRANSACTION_SERIALIZABLE:
|
||||
return TxIsolation.SERIALIZABLE;
|
||||
|
||||
case Connection.TRANSACTION_NONE:
|
||||
return TxIsolation.NONE;
|
||||
|
||||
case -1:
|
||||
return TxIsolation.DEFAULT;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Unknown isolation level " + connectionIsolationLevel);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
/**
|
||||
* Used to define the transactional scope for executing a method. Matches the
|
||||
* types defined in the EJB TransactionAttributeType.
|
||||
* <p>
|
||||
* Used with the Transactional annotation and the {@link TxScope} with
|
||||
* {@link Ebean#execute(TxScope, TxCallable)} and
|
||||
* {@link Ebean#execute(TxScope, TxRunnable)}.
|
||||
* </p>
|
||||
*
|
||||
* @see TxScope
|
||||
*/
|
||||
public enum TxType {
|
||||
|
||||
/**
|
||||
* Uses an existing transaction and if none exists will starts a new
|
||||
* Transaction. This is the default.
|
||||
*/
|
||||
REQUIRED,
|
||||
|
||||
/**
|
||||
* A transaction MUST already have been started. Throws
|
||||
* TransactionRequiredException.
|
||||
*/
|
||||
MANDATORY,
|
||||
|
||||
/**
|
||||
* Uses the existing transaction if one exists, otherwise the method does not
|
||||
* run with a transaction. Used this with caution.
|
||||
*/
|
||||
SUPPORTS,
|
||||
|
||||
/**
|
||||
* Always start a new transaction. Suspend an existing once if required.
|
||||
*/
|
||||
REQUIRES_NEW,
|
||||
|
||||
/**
|
||||
* Suspends an existing transaction if required. Method runs without a
|
||||
* transaction.
|
||||
*/
|
||||
NOT_SUPPORTED,
|
||||
|
||||
/**
|
||||
* If there is an existing transaction throws an Exception. Method runs
|
||||
* without a transaction.
|
||||
*/
|
||||
NEVER
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify a property to be an aggregation formula.
|
||||
* <p>
|
||||
* The aggregation formula should be a sum, count, avg, min or max.
|
||||
* By default aggregation properties are treated as transient and not
|
||||
* included in a query. To populate the aggregation property it must be
|
||||
* explicitly included in the select().
|
||||
* </p>
|
||||
* <p>
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @Aggregation("count(details)")
|
||||
* Long totalCount;
|
||||
*
|
||||
* @Aggregation("sum(details.quantity*details.unitPrice)")
|
||||
* Long totalAmount;
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Example query</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* List<TEventOne> list = Ebean.find(TEventOne.class)
|
||||
* .select("name, totalCount, totalUnits, totalAmount")
|
||||
* .where()
|
||||
* .startsWith("logs.description", "a")
|
||||
* .having()
|
||||
* .ge("count", 1)
|
||||
* .orderBy().asc("name")
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Aggregation {
|
||||
|
||||
/**
|
||||
* Aggregation formula using sum, count, avg, min, max.
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the default cache use specific entity type.
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Cache {
|
||||
|
||||
/**
|
||||
* Set this to true to enable the use of query cache.
|
||||
* <p>
|
||||
* By default query caching is disabled as the query cache invalidates
|
||||
* frequently and so it is typically used for specific bean types and cases.
|
||||
* </p>
|
||||
*/
|
||||
boolean enableQueryCache() default false;
|
||||
|
||||
/**
|
||||
* Set this to false to disable the use of bean cache.
|
||||
* <p>
|
||||
* By default bean caching is expected so this defaults to true. We might
|
||||
* set this to false on a bean type that we want to use query caching but no
|
||||
* bean caching (and this is expected to be a rare case).
|
||||
* </p>
|
||||
* <p>
|
||||
* When bean caching is enabled by default "find by id" and "find by unique natural key"
|
||||
* queries will try to use the bean cache. We use {@link com.avaje.ebean.Query#setUseCache(boolean)}
|
||||
* with <code>false</code> for the case when we do NOT want to use the bean cache.
|
||||
* </p>
|
||||
*/
|
||||
boolean enableBeanCache() default true;
|
||||
|
||||
/**
|
||||
* Specify the property that is a natural unique identifier for the bean.
|
||||
* <p>
|
||||
* When a findUnique() query is used with this property as the sole expression
|
||||
* then there will be a lookup into the L2 natural key cache.
|
||||
* </p>
|
||||
*/
|
||||
String naturalKey() default "";
|
||||
|
||||
/**
|
||||
* When set to true the beans returned from a query will default to be
|
||||
* readOnly.
|
||||
* <p>
|
||||
* If the bean is readOnly and has no relationships then it may be sharable.
|
||||
* </p>
|
||||
* <p>
|
||||
* If you try to modify a readOnly bean it will throw an
|
||||
* IllegalStateException.
|
||||
* </p>
|
||||
*/
|
||||
boolean readOnly() default false;
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Cache tuning hints for the L2 bean cache of a specific entity type.
|
||||
* <p>
|
||||
* Note that this is not useful when distributed L2 bean caches are used like
|
||||
* ElasticSearch, Hazelcast, Ignite etc.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CacheBeanTuning {
|
||||
|
||||
/**
|
||||
* The maximum size for the cache.
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxSize() default 0;
|
||||
|
||||
/**
|
||||
* The maximum time (in seconds) that a cache entry is allowed to stay in the
|
||||
* cache when it has not been accessed.
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxIdleSecs() default 0;
|
||||
|
||||
/**
|
||||
* The maximum time (in seconds) a cache entry is allowed to stay in the
|
||||
* cache.
|
||||
* <p>
|
||||
* This is not generally required as the cache entries are automatically
|
||||
* evicted when related data changes are committed.
|
||||
* </p>
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxSecsToLive() default 0;
|
||||
|
||||
/**
|
||||
* The frequency (in seconds) that cache trimming should occur.
|
||||
* <p>
|
||||
* This is a hint for cache implementations that use background cache trimming.
|
||||
* </p>
|
||||
*/
|
||||
int trimFrequency() default 0;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify cache tuning for query caching on a specific entity type.
|
||||
* <p>
|
||||
* If this is not specified then the system default settings are used.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CacheQueryTuning {
|
||||
|
||||
/**
|
||||
* The maximum size for the cache.
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxSize() default 0;
|
||||
|
||||
/**
|
||||
* The maximum time (in seconds) that a cache entry is allowed to stay in the
|
||||
* cache when it has not been accessed.
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxIdleSecs() default 0;
|
||||
|
||||
/**
|
||||
* The maximum time (in seconds) a cache entry is allowed to stay in the
|
||||
* cache.
|
||||
* <p>
|
||||
* This is not generally required as the cache entries are automatically
|
||||
* evicted when related data changes are committed.
|
||||
* </p>
|
||||
* <p>
|
||||
* This defaults to 0 which means unlimited.
|
||||
* </p>
|
||||
*/
|
||||
int maxSecsToLive() default 0;
|
||||
|
||||
/**
|
||||
* The frequency (in seconds) that cache trimming should occur.
|
||||
* <p>
|
||||
* This is a hint for cache implementations that use background cache trimming.
|
||||
* </p>
|
||||
*/
|
||||
int trimFrequency() default 0;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks an entity bean as being included in the change logging.
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ChangeLog {
|
||||
|
||||
/**
|
||||
* Specify if inserts should be explicitly Included or Excluded.
|
||||
* <p>
|
||||
* If not defined explicitly then the server default behaviour defined
|
||||
* on ServerConfig is used.
|
||||
* </p>
|
||||
*/
|
||||
ChangeLogInsertMode inserts() default ChangeLogInsertMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* When specified only include update requests that have at least one
|
||||
* of the given properties as a dirty property.
|
||||
* <p>
|
||||
* This provides a way to filter requests to include in the change log such that
|
||||
* only updates that include at least one of the given properties is included
|
||||
* in the change log.
|
||||
* </p>
|
||||
*/
|
||||
String[] updatesThatInclude() default {};
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
/**
|
||||
* The mode used to determine if inserts should be included or not for a given bean type.
|
||||
*/
|
||||
public enum ChangeLogInsertMode {
|
||||
|
||||
/**
|
||||
* Use the default behaviour as defined on ServerConfig.
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
/**
|
||||
* Include inserts in the change log.
|
||||
*/
|
||||
INCLUDE,
|
||||
|
||||
/**
|
||||
* Exclude inserts in the change log.
|
||||
*/
|
||||
EXCLUDE
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* For a timestamp property that is set to the datetime when the entity is
|
||||
* created/inserted.
|
||||
* <p>
|
||||
* This is effectively an alias for @WhenCreated which was added as it hints
|
||||
* towards a better naming convention (WhenCreated, WhenModified).
|
||||
* </p>
|
||||
* <p>
|
||||
* An alternative to using this annotation would be to use insertable=false,
|
||||
* updateable=false with @Column and have the DB insert the current time
|
||||
* (default value on the DB column is SYSTIME etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* The downside to this approach is that the inserted entity does not have the
|
||||
* timestamp value after the insert has occurred. You need to fetch the entity
|
||||
* back to get the inserted timestamp if you want to used it.
|
||||
* </p>
|
||||
* <p>
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @CreatedTimestamp
|
||||
* Timestamp whenCreated;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CreatedTimestamp {
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify a collection property that will be stored into a DB ARRAY type.
|
||||
* <p>
|
||||
* If the target database does not support ARRAY type (so not Postgres)
|
||||
* then the collection will be stored in JSON format into a VARCHAR column.
|
||||
* </p>
|
||||
* <p>
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Store as ARRAY of UUID on Postgres
|
||||
* @DbArray
|
||||
* List<UUID> uids = new ArrayList<>();
|
||||
*
|
||||
* // Store as ARRAY on Postgres
|
||||
* @DbArray
|
||||
* List<String> phoneNumbers = new ArrayList<>();
|
||||
*
|
||||
* // Store as ARRAY of INTEGER on Postgres
|
||||
* @DbArray
|
||||
* List<Long> someLongs = new ArrayList<>();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DbArray {
|
||||
|
||||
/**
|
||||
* For VARCHAR storage specify the column length (defaults to 1000).
|
||||
*/
|
||||
int length() default 0;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* A database table or column comment.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
|
||||
public @interface DbComment {
|
||||
|
||||
/**
|
||||
* The database table or column comment.
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
/**
|
||||
* Specify the DB storage type used to with <code>@DbEnumValue</code>.
|
||||
*/
|
||||
public enum DbEnumType {
|
||||
|
||||
/**
|
||||
* Store values as database INTEGER.
|
||||
*/
|
||||
INTEGER,
|
||||
|
||||
/**
|
||||
* Store values as database VARCHAR.
|
||||
*/
|
||||
VARCHAR
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify a method on an Enum that returns the value that should be stored in the DB.
|
||||
* <p>
|
||||
* This is the preferred option for mapping Enum's to DB values (preferred over the JPA
|
||||
* standard @Enumerated and Ebean's @EnumValue annotations).
|
||||
* </p>
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* public enum Status {
|
||||
* NEW("N"),
|
||||
* ACTIVE("A"),
|
||||
* INACTIVE("I");
|
||||
*
|
||||
* String dbValue;
|
||||
* Status(String dbValue) {
|
||||
* this.dbValue = dbValue;
|
||||
* }
|
||||
*
|
||||
* @DbEnumValue
|
||||
* public String getValue() {
|
||||
* return dbValue;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface DbEnumValue {
|
||||
|
||||
/**
|
||||
* Specify the database type used to store the values (VARCHAR or INTEGER).
|
||||
*/
|
||||
DbEnumType storage() default DbEnumType.VARCHAR;
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used for mapping a Map<String,String> type property to Postgres HSTORE data type.
|
||||
* <p>
|
||||
* The Map property should have keys and values of type String.
|
||||
* </p>
|
||||
* <p>
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @DbHstore
|
||||
* Map<String, String> tags;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DbHstore {
|
||||
|
||||
/**
|
||||
* For VARCHAR storage specify the column length (defaults to 1000).
|
||||
*/
|
||||
int length() default 0;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify a property holding JSON content.
|
||||
* <p>
|
||||
* By default the content will be stored in a DB Clob except on Postgres where DB JSON type is used.
|
||||
* </p>
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Store as JSON on Postgres or Clob on other databases
|
||||
* @DbJson
|
||||
* Map<String,Object> content;
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Example with JSONB storage</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Store as JSONB on Postgres or Clob on other databases
|
||||
* @DbJson(storage = DbJsonType.JSONB)
|
||||
* Map<String,Object> content;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DbJson {
|
||||
|
||||
/**
|
||||
* Specify the database type used to store the JSON content.
|
||||
*/
|
||||
DbJsonType storage() default DbJsonType.JSON;
|
||||
|
||||
/**
|
||||
* For VARCHAR storage specify the column length (defaults to 3000).
|
||||
*/
|
||||
int length() default 0;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify a property holding JSON content.
|
||||
* <p>
|
||||
* The content will be stored on Postgres using it's JSONB type and as Clob for other databases.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is equivalent to using <code>@DbJson(storage = DbJsonType.JSONB)</code>
|
||||
* </p>
|
||||
* <p>
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Store as JSONB on Postgres or Clob on other databases
|
||||
* @DbJsonB
|
||||
* Map<String,Object> content;
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* <h3>Equivalent to:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // Store as JSONB on Postgres or Clob on other databases
|
||||
* @DbJson(storage = DbJsonType.JSONB)
|
||||
* Map<String,Object> content;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DbJsonB {
|
||||
|
||||
/**
|
||||
* For VARCHAR storage specify the column length.
|
||||
*/
|
||||
int length() default 0;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
/**
|
||||
* Specify the DB storage type used to store JSON content.
|
||||
*/
|
||||
public enum DbJsonType {
|
||||
|
||||
/**
|
||||
* Store as JSON on Postgres and for other databases store as CLOB.
|
||||
*/
|
||||
JSON,
|
||||
|
||||
/**
|
||||
* Store as JSONB on Postgres and for other databases store as CLOB.
|
||||
*/
|
||||
JSONB,
|
||||
|
||||
/**
|
||||
* Store as database VARCHAR.
|
||||
*/
|
||||
VARCHAR,
|
||||
|
||||
/**
|
||||
* Store as database CLOB.
|
||||
*/
|
||||
CLOB,
|
||||
|
||||
/**
|
||||
* Store as database BLOB.
|
||||
*/
|
||||
BLOB
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used to indicate that a particular string property should be treated as a 'code' and not analysed for text searching.
|
||||
* <p>
|
||||
* By default all Id properties and all Enum properties are treated as 'code' and not analysed.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocCode {
|
||||
|
||||
/**
|
||||
* Set to true to have the property additionally stored separately from _source.
|
||||
*/
|
||||
boolean store() default false;
|
||||
|
||||
/**
|
||||
* Set a boost value specific to this property.
|
||||
*/
|
||||
float boost() default 1;
|
||||
|
||||
/**
|
||||
* Set a value to use instead of null.
|
||||
*/
|
||||
String nullValue() default "";
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the property is included in the parent document store index.
|
||||
* <pre>{@code
|
||||
*
|
||||
*
|
||||
* @DocStore
|
||||
* @Entity @Table(name = "o_order")
|
||||
* public class Order {
|
||||
*
|
||||
* ...
|
||||
* // include some customer details including
|
||||
* // nested billingAddress
|
||||
* @DocEmbedded(doc = "id,status,name,billingAddress(*,country(*)")
|
||||
* @ManyToOne
|
||||
* Customer customer;
|
||||
*
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocEmbedded {
|
||||
|
||||
/**
|
||||
* The properties on the embedded bean to include in the index.
|
||||
*/
|
||||
String doc() default "";
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the entity type maps to a document store (like ElasticSearch).
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocMapping {
|
||||
|
||||
/**
|
||||
* The property name the mapping applies to.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Mapping options.
|
||||
*/
|
||||
DocProperty options();
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the entity type maps to a document store (like ElasticSearch).
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocProperty {
|
||||
|
||||
/**
|
||||
* Set this to true to indicate that this property should be un-analysed.
|
||||
*/
|
||||
boolean code() default false;
|
||||
|
||||
/**
|
||||
* Set this to true to get an additional un-analysed 'raw' field to use for sorting etc.
|
||||
*/
|
||||
boolean sortable() default false;
|
||||
|
||||
/**
|
||||
* Set to true to have the property additionally stored separately from _source.
|
||||
*/
|
||||
boolean store() default false;
|
||||
|
||||
/**
|
||||
* Set a boost value specific to this property.
|
||||
*/
|
||||
float boost() default 1;
|
||||
|
||||
/**
|
||||
* Set a value to use instead of null.
|
||||
*/
|
||||
String nullValue() default "";
|
||||
|
||||
/**
|
||||
* Set this to false to exclude this from the _all property.
|
||||
*/
|
||||
boolean includeInAll() default true;
|
||||
|
||||
/**
|
||||
* The analyzer to use.
|
||||
*/
|
||||
String analyzer() default "";
|
||||
|
||||
/**
|
||||
* The analyzer to use for searches.
|
||||
*/
|
||||
String searchAnalyzer() default "";
|
||||
|
||||
/**
|
||||
* The index options for this property.
|
||||
*/
|
||||
Option options() default Option.DEFAULT;
|
||||
|
||||
/**
|
||||
* Set this to false such that doc values are not stored separately for this property.
|
||||
*/
|
||||
boolean docValues() default true;
|
||||
|
||||
/**
|
||||
* Set a copyTo field.
|
||||
*/
|
||||
String copyTo() default "";
|
||||
|
||||
/**
|
||||
* Set to false to disable the field from indexing, it will only be get/set in _source.
|
||||
*/
|
||||
boolean enabled() default true;
|
||||
|
||||
/**
|
||||
* Set to false such that norms are not stored.
|
||||
*/
|
||||
boolean norms() default true;
|
||||
|
||||
/**
|
||||
* Index options for a property.
|
||||
*/
|
||||
enum Option {
|
||||
|
||||
/**
|
||||
* Only index the doc number.
|
||||
*/
|
||||
DOCS,
|
||||
|
||||
/**
|
||||
* Doc number and term frequencies are indexed.
|
||||
*/
|
||||
FREQS,
|
||||
|
||||
/**
|
||||
* Doc number, term frequencies and term positions are indexed.
|
||||
*/
|
||||
POSITIONS,
|
||||
|
||||
/**
|
||||
* Doc number, term frequencies, term positions and start/end offsets are indexed.
|
||||
*/
|
||||
OFFSETS,
|
||||
|
||||
/**
|
||||
* Use the default which means analysed string properties use POSITIONS as the default and all other types use DOCS.
|
||||
*/
|
||||
DEFAULT
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used to indicate that a particular string property should support sorting. What this typically means is that
|
||||
* for ElasticSearch an additional 'raw' field is added that stores the un-analysed value. This un-analysed value
|
||||
* can be used for sorting etc and the original field used for text searching.
|
||||
* <p>
|
||||
* For example, customer name and product name are good candidates for marking with @DocSortable.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocSortable {
|
||||
|
||||
/**
|
||||
* Set to true to have the property additionally stored separately from _source.
|
||||
*/
|
||||
boolean store() default false;
|
||||
|
||||
/**
|
||||
* Set a boost value specific to this property.
|
||||
*/
|
||||
float boost() default 1;
|
||||
|
||||
/**
|
||||
* Set a value to use instead of null.
|
||||
*/
|
||||
String nullValue() default "";
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the entity type maps to a document store (like ElasticSearch).
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DocStore {
|
||||
|
||||
/**
|
||||
* A unique Id used when queuing reindex events.
|
||||
*/
|
||||
String queueId() default "";
|
||||
|
||||
/**
|
||||
* The ElasticSearch index name. If left unspecified the short name of the bean type is used.
|
||||
*/
|
||||
String indexName() default "";
|
||||
|
||||
/**
|
||||
* The ElasticSearch index type. If left unspecified the short name of the bean type is used.
|
||||
*/
|
||||
String indexType() default "";
|
||||
|
||||
/**
|
||||
* The number of shards this index should use.
|
||||
*/
|
||||
int shards() default 0;
|
||||
|
||||
/**
|
||||
* The number of replicas this index should use.
|
||||
*/
|
||||
int replicas() default 0;
|
||||
|
||||
/**
|
||||
* Additional mapping that can be defined on the properties.
|
||||
*/
|
||||
DocMapping[] mapping() default {};
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Insert, Update, Delete events occur.
|
||||
*/
|
||||
DocStoreMode persist() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Insert occurs.
|
||||
*/
|
||||
DocStoreMode insert() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Update occurs.
|
||||
*/
|
||||
DocStoreMode update() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify the behavior when bean Delete occurs.
|
||||
*/
|
||||
DocStoreMode delete() default DocStoreMode.DEFAULT;
|
||||
|
||||
/**
|
||||
* Specify to include only some properties in the doc store document.
|
||||
* <p>
|
||||
* If this is left as default then all scalar properties are included,
|
||||
* all @ManyToOne properties are included with just the nested id property
|
||||
* and no @OneToMany properties are included.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that typically DocStoreEmbedded is used on @ManyToOne and @OneToMany
|
||||
* properties to indicate what part of the nested document should be included.
|
||||
* </p>
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // only include the customer id and name
|
||||
* @DocStore(doc = "id,name")
|
||||
* @Entity @Table(name = "o_order")
|
||||
* public class Customer {
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
String doc() default "";
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
/**
|
||||
* Defines the behavior options when a Insert, Update or Delete event occurs
|
||||
* on a bean with an associated ElasticSearch index.
|
||||
* <p>
|
||||
* For some indexes or some transactions it can be beneficial to queue the event
|
||||
* for later processing rather than look to update ElasticSearch at that time.
|
||||
* </p>
|
||||
*/
|
||||
public enum DocStoreMode {
|
||||
|
||||
/**
|
||||
* Add the event to the queue for processing later (delaying the update to the document store).
|
||||
*/
|
||||
QUEUE,
|
||||
|
||||
/**
|
||||
* Update the document store when transaction succeeds.
|
||||
*/
|
||||
UPDATE,
|
||||
|
||||
/**
|
||||
* Ignore the event and not update the document store.
|
||||
* <p>
|
||||
* This can be used on a index or for a transaction where you want to have more
|
||||
* manual programmatic control over the updating of the document store. Say you want to
|
||||
* IGNORE on a particular transaction and instead manually queue a bulk update.
|
||||
* </p>
|
||||
*/
|
||||
IGNORE,
|
||||
|
||||
/**
|
||||
* The actual mode of QUEUE, UPDATE or IGNORE is set from the default configuration.
|
||||
*/
|
||||
DEFAULT
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks a boolean property on a @Draftable bean that indicates if the bean instance is a 'draft' or 'live' bean.
|
||||
* The property is transient and has no underlying DB column.
|
||||
* <p>
|
||||
* For beans returned from an <code>asDraft()</code> query this property will be set to true.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Draft {
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks a boolean property on a @Draftable bean that only exists on the 'draft' table
|
||||
* and is used to detect when a draft has unpublished changes.
|
||||
* <p>
|
||||
* This property will automatically have it's value set to true when a draft is saved and
|
||||
* automatically have it's value set to false when the bean is published.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DraftDirty {
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks a property on a @Draftable bean that only exists on the 'draft' and not the 'live' table.
|
||||
* <p>
|
||||
* Typically this would be used on a property that is used as part of application 'workflow' such as
|
||||
* a publish workflow status or when publish timestamp.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DraftOnly {
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks a property on a @Draftable bean that is set to null on the 'draft bean' on publish.
|
||||
* <p>
|
||||
* This is expected to be put on properties that get 'reset' or 'cleared' after a publish.
|
||||
* These properties might represent a publish comment or publish timestamp.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface DraftReset {
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used to indicate an entity bean that has 'draftable' support.
|
||||
* <p>
|
||||
* This means that a second set of tables is created to hold draft versions of
|
||||
* the rows and that these can then be published which effectively copies/transfers
|
||||
* the values from the 'draft' table to the 'live' table.
|
||||
* </p>
|
||||
* <p>
|
||||
* Ebean Query supports 'find as draft' which builds the resulting object graph using
|
||||
* the draft tables. This object graph is typically edited, approved in some application
|
||||
* specific manor and then published.
|
||||
* </p>
|
||||
* <p>
|
||||
* EbeanServer has a publish method which transfers/copies the draft object graph to
|
||||
* the 'live' tables.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface Draftable {
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used to indicate an entity bean that has 'draftable' support but it not a 'top level'
|
||||
* (or root level) bean but instead child related to another @Draftable entity bean.
|
||||
* <p>
|
||||
* Relationships to @DraftableElements (@OneToMany, @ManyToMany etc) are automatically
|
||||
* deemed to have Cascade.ALL for save and delete (as well as orphan removal mode).
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface DraftableElement {
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify property name to db column mapping for Embedded beans.
|
||||
* <p>
|
||||
* This is designed to be easier to use than the AttributeOverride annotation in
|
||||
* standard JPA.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EmbeddedColumns {
|
||||
|
||||
/**
|
||||
* A list of property names mapped to DB columns.
|
||||
* <p>
|
||||
* For example <code>currency=IN_CURR, amount=IN_AMOUNT</code>
|
||||
* </p>
|
||||
* <p>
|
||||
* Where currency and amount are properties and IN_CURR and IN_AMOUNT are the
|
||||
* respective DB columns these properties will be mapped to.
|
||||
* </p>
|
||||
*/
|
||||
String columns() default "";
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify that the property is stored in encrypted form.
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Encrypted {
|
||||
|
||||
/**
|
||||
* When true try to use DB encryption rather than local java encryption.
|
||||
*/
|
||||
boolean dbEncryption() default true;
|
||||
|
||||
/**
|
||||
* Used to specify the DB column length.
|
||||
*/
|
||||
int dbLength() default 0;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Enables you to specify a value to use to persist for an enum value.
|
||||
* <pre>{@code
|
||||
*
|
||||
* public enum Status {
|
||||
*
|
||||
* @EnumValue("N")
|
||||
* NEW,
|
||||
*
|
||||
* @EnumValue("A")
|
||||
* ACTIVE,
|
||||
*
|
||||
* @EnumValue("I")
|
||||
* INACTIVE,
|
||||
* }
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* This is an alternative to using the JPA standard approach or Ebean's
|
||||
* {@link DbEnumValue} annotation.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that if all the EnumValue values are parsable as Integers then Ebean
|
||||
* will persist and fetch them as integers - otherwise they will be persisted
|
||||
* and fetched as strings.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface EnumValue {
|
||||
|
||||
/**
|
||||
* Specify the value to persist for a specific enum value.
|
||||
* <p>
|
||||
* If all the values are parsable as Integers then Ebean will persist and
|
||||
* fetch them as integers rather than strings.
|
||||
* </p>
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/*
|
||||
Copied from gson!!!
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Expose {
|
||||
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is written out in the JSON while
|
||||
* serializing. If {@code false}, the field marked with this annotation is skipped from the
|
||||
* serialized output. Defaults to {@code true}.
|
||||
*/
|
||||
boolean serialize() default true;
|
||||
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is deserialized from the JSON.
|
||||
* If {@code false}, the field marked with this annotation is skipped during deserialization.
|
||||
* Defaults to {@code true}.
|
||||
*/
|
||||
boolean deserialize() default true;
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Assign to a property to be based on a SQL formula.
|
||||
* <p>
|
||||
* This is typically a SQL Literal value, SQL case statement, SQL function or
|
||||
* similar.
|
||||
* </p>
|
||||
* <p>
|
||||
* Any property based on a formula becomes a read only property.
|
||||
* </p>
|
||||
* <p>
|
||||
* You may also put use the Transient annotation with the Formula annotation.
|
||||
* The effect of the Transient annotation in this case is that the formula will
|
||||
* <b>NOT</b> be included in queries by default - you have to explicitly include
|
||||
* it via {@link Query#select(String)} or {@link Query#fetch(String, String, com.avaje.ebean.FetchConfig)}.
|
||||
* You may want to do this if the Formula is relatively expensive and only want
|
||||
* it included in the query when you explicitly state it.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
* // On the Order "master" bean
|
||||
* // ... a formula using the Order details
|
||||
* // ... sum(order_qty*unit_price)
|
||||
* @Transient
|
||||
* @Formula(select = "_b${ta}.total_amount", join = "join (select order_id, sum(order_qty*unit_price) as total_amount from o_order_detail group by order_id) as _b${ta} on _b${ta}.order_id = ${ta}.id")
|
||||
* Double totalAmount;
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* As the totalAmount formula is also Transient it is not included by default in
|
||||
* queries - it needs to be explicitly included.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* // find by Id
|
||||
* Order o1 = Ebean.find(Order.class)
|
||||
* .select("id, totalAmount")
|
||||
* .setId(1).findUnique();
|
||||
*
|
||||
* // find list ... using totalAmount in the where clause
|
||||
* List<Order> list = Ebean.find(Order.class)
|
||||
* .select("id, totalAmount")
|
||||
* .where()
|
||||
* .eq("status", Order.Status.NEW)
|
||||
* .gt("totalAmount", 10)
|
||||
* .findList();
|
||||
*
|
||||
* // as a join from customer
|
||||
* List<Customer> l0 = Ebean.find(Customer.class)
|
||||
* .select("id, name")
|
||||
* .fetch("orders", "status, totalAmount")
|
||||
* .where()
|
||||
* .gt("id", 0)
|
||||
* .gt("orders.totalAmount", 10)
|
||||
* .findList();
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Formula {
|
||||
|
||||
/**
|
||||
* The SQL to be used in the SELECT part of the SQL to populate a property.
|
||||
*/
|
||||
String select();
|
||||
|
||||
/**
|
||||
* OPTIONAL - the SQL to be used in the JOIN part of the SQL to support the
|
||||
* formula.
|
||||
* <p>
|
||||
* This is commonly used to join a 'dynamic view' to support aggregation such
|
||||
* as count, sum etc.
|
||||
* </p>
|
||||
* <p>
|
||||
* The join string should start with either "left join" or "join".
|
||||
* </p>
|
||||
* <p>
|
||||
* You will almost certainly use the "${ta}" as a place holder for the table
|
||||
* alias of the table you are joining back to (the "base table" of the entity
|
||||
* bean).
|
||||
* </p>
|
||||
* <p>
|
||||
* The example below is used to support a total count of topics created by a
|
||||
* user.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* join (select user_id, count(*) as topic_count from f_topic group by user_id) as _tc on _tc.user_id = ${ta}.id
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
String join() default "";
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks an entity bean as having history support.
|
||||
* <p>
|
||||
* In Postgres for example this means there is an associated history table which is
|
||||
* typically automatically populated via database triggers.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface History {
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks a property as being excluded from history.
|
||||
* <p>
|
||||
* This means the property values are not maintained in the history table. Typically this
|
||||
* would be placed on relatively large properties (Clobs, Blobs, large varchar columns etc)
|
||||
* that are considered not interesting enough to maintain history on excluding them reduces
|
||||
* underlying database costs.
|
||||
* </p>
|
||||
* <p>
|
||||
* When placed on a ManyToMany this means that the intersection table does not have history
|
||||
* support.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface HistoryExclude {
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation for declaring an index.
|
||||
*
|
||||
* @author rvbiljouw
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(Indices.class)
|
||||
public @interface Index {
|
||||
|
||||
/**
|
||||
* Name of the index. If left blank a name is derived using the built in naming convention.
|
||||
*/
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* If set true indicates this is a unique index.
|
||||
*/
|
||||
boolean unique() default false;
|
||||
|
||||
/**
|
||||
* When placed on the class (rather than field) you can specify the columns
|
||||
* to include in the index in order.
|
||||
* <p>
|
||||
* Wnen placed on a field, and columnNames are specified, the field-column has to be included.
|
||||
* You can use "${fa}" for alias
|
||||
*/
|
||||
String[] columnNames() default {};
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation for declaring multiple indices at class or field level.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Indices {
|
||||
|
||||
/**
|
||||
* Array with {@link Index} definitions.
|
||||
*/
|
||||
Index[] value() default {};
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Similar to Jackson JsonIgnore but provides the option to just ignore serialize or deserialize.
|
||||
* <p>
|
||||
* This provides the same features as Expose but from the opposite perspective which is probably
|
||||
* more common and more familiar to Jackson users.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface JsonIgnore {
|
||||
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is written out in the JSON while
|
||||
* serializing. If {@code false}, the field marked with this annotation is skipped from the
|
||||
* serialized output. Defaults to {@code false}.
|
||||
*/
|
||||
boolean serialize() default false;
|
||||
|
||||
/**
|
||||
* If {@code true}, the field marked with this annotation is deserialized from the JSON.
|
||||
* If {@code false}, the field marked with this annotation is skipped during deserialization.
|
||||
* Defaults to {@code false}.
|
||||
*/
|
||||
boolean deserialize() default false;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify that the elements of a OneToMany are private owned.
|
||||
* <p>
|
||||
* This means that if they are removed from the List/Set/Map they will be
|
||||
* deleted when their parent object is saved.
|
||||
* </p>
|
||||
* <p>
|
||||
* This could also be described as deleting orphans - in that beans removed from
|
||||
* the List/Set/Map will be deleted automatically when the parent bean is saved.
|
||||
* They are considered 'orphans' when they have been removed from the collection
|
||||
* in that they are no longer associated/linked to their parent bean.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface PrivateOwned {
|
||||
|
||||
/**
|
||||
* Set this to false if you don't want cascade REMOVE on this relationship.
|
||||
* <p>
|
||||
* That is, by default PrivateOwned implicitly adds a cascade REMOVE to the
|
||||
* relationship and if you don't want that you need to set this to false.
|
||||
* </p>
|
||||
*/
|
||||
boolean cascadeRemove() default true;
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks an entity bean as being included in read auditing.
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ReadAudit {
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Used to indicate a property on an entity bean used to control 'soft delete'
|
||||
* (also known as 'logical delete').
|
||||
* <p>
|
||||
* The property should be of type boolean.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @SoftDelete
|
||||
* boolean deleted;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface SoftDelete {
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Mark and entity bean that is used solely via RawSql.
|
||||
* <p>
|
||||
* This means the entity bean has no base table specified (via @Table).
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Sql {
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specify the update mode for the specific entity type.
|
||||
* <p>
|
||||
* Control whether all 'loaded' properties are included in an Update or whether
|
||||
* just properties that have changed will be included in the update.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that the default can be set via ebean.properties.
|
||||
* </p>
|
||||
* <p>
|
||||
* <pre>
|
||||
* ## Set to update all loaded properties
|
||||
* ebean.updateChangesOnly=false
|
||||
* </pre>
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface UpdateMode {
|
||||
|
||||
/**
|
||||
* Set to false if you want to include all the 'loaded' properties in the
|
||||
* update. Otherwise, just the properties that have changed will be included
|
||||
* in the update.
|
||||
*/
|
||||
boolean updateChangesOnly() default true;
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* For a timestamp property that is set to the datetime when the entity was last
|
||||
* updated.
|
||||
* <p>
|
||||
* This is effectively an alias for @WhenModified which was added as it hints
|
||||
* towards a better naming convention (WhenCreated, WhenModified).
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface UpdatedTimestamp {
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotate an entity bean with @View to indicates the bean is based on a view.
|
||||
* <p>
|
||||
* As such typically the view is defined in <code>extra-ddl.xml</code> using
|
||||
* <code>create or replace view ...</code>.
|
||||
* </p>
|
||||
* <p>
|
||||
* When using extra-ddl.xml Ebean will run the resulting DDL script after the
|
||||
* <code>create-all</code> DDL (which is typically used during development) and for
|
||||
* DB Migration will copy the scripts as <code>repeatable migration scripts</code> that
|
||||
* will be run by FlywayDb (or Ebean's own migration runner) when their MD5 hash changes.
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface View {
|
||||
|
||||
/**
|
||||
* The name of the view this entity bean is based on.
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Tables this view is dependent on.
|
||||
* <p>
|
||||
* This is used with l2 caching to invalidate the query cache. Changes to these
|
||||
* tables invalidate the query cache for the entity based on this view.
|
||||
* </p>
|
||||
*/
|
||||
String[] dependentTables() default {};
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* For a timestamp property that is set to the datetime when the entity is
|
||||
* created/inserted.
|
||||
* <p>
|
||||
* This is effectively an alias for @CreatedTimestamp and added to hint
|
||||
* towards a better naming convention (WhenCreated, WhenModified).
|
||||
* </p>
|
||||
* <p>
|
||||
* An alternative to using this annotation would be to use insertable=false,
|
||||
* updateable=false with @Column and have the DB insert the current time
|
||||
* (default value on the DB column is SYSTIME etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* The downside to this approach is that the inserted entity does not have the
|
||||
* timestamp value after the insert has occurred. You need to fetch the entity
|
||||
* back to get the inserted timestamp if you want to used it.
|
||||
* </p>
|
||||
* <p>
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @WhenCreated
|
||||
* Timestamp whenCreated;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WhenCreated {
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* For a timestamp property that is set to the datetime when the entity was last modified.
|
||||
* <p>
|
||||
* This is effectively an alias for @UpdatedTimestamp and added to hint
|
||||
* towards a better naming convention (WhenCreated, WhenModified).
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WhenModified {
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Add an Literal to add to the where clause when a many property (List, Set or
|
||||
* Map) is loaded or refreshed.
|
||||
* <pre>{@code
|
||||
*
|
||||
* // on a OneToMany property...
|
||||
*
|
||||
* @OneToMany
|
||||
* @Where(clause = "deleted='y'")
|
||||
* List<Topic> topics;
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Note that you can include "${ta}" as a place holder for the table alias if
|
||||
* you need to include the table alias in the clause.
|
||||
* </p>
|
||||
* <pre>{@code
|
||||
* // ... including the ${ta} table alias placeholder...
|
||||
*
|
||||
* @OneToMany
|
||||
* @Where(clause = "${ta}.deleted='y'")
|
||||
* List<Topic> topics;
|
||||
*
|
||||
* }</pre>
|
||||
* <p>
|
||||
* This will be added to the where clause when lazy loading the OneToMany
|
||||
* property or when there is a join to that OneToMany property.
|
||||
* </p>
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Where {
|
||||
|
||||
/**
|
||||
* The clause added to the lazy load query.
|
||||
* <p>
|
||||
* Note that you can include "${ta}" as a place holder for the table alias if
|
||||
* you need to include the table alias in the clause.
|
||||
* </p>
|
||||
*/
|
||||
String clause();
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Mapped onto a entity bean property that represents the user id of
|
||||
* who created the entity>
|
||||
* <p>
|
||||
* To use this annotation you need to implement CurrentUserProvider.
|
||||
* The type of the bean property should match the type returned by
|
||||
* CurrentUserProvider.
|
||||
* </p>
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @WhoCreated
|
||||
* String whoCreated;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WhoCreated {
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.avaje.ebean.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Mapped onto a entity bean property that represents the user id of
|
||||
* who last modified the entity>
|
||||
* <p>
|
||||
* To use this annotation you need to implement CurrentUserProvider.
|
||||
* The type of the bean property should match the type returned by
|
||||
* CurrentUserProvider.
|
||||
* </p>
|
||||
* <h3>Example:</h3>
|
||||
* <pre>{@code
|
||||
*
|
||||
* @WhoModified
|
||||
* String whoModified;
|
||||
*
|
||||
* }</pre>
|
||||
*/
|
||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WhoModified {
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
|
||||
<TITLE>Extra deployment annotations</TITLE>
|
||||
</HEAD>
|
||||
<Body BGCOLOR="#ffffff">
|
||||
Extra deployment annotations
|
||||
|
||||
<p>
|
||||
Extra deployment annotations for entity beans.
|
||||
</p>
|
||||
|
||||
</Body>
|
||||
</HTML>
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.avaje.ebean.cache;
|
||||
|
||||
/**
|
||||
* The type of L2 caches.
|
||||
*/
|
||||
public enum ServerCacheType {
|
||||
|
||||
/**
|
||||
* Bean cache.
|
||||
*/
|
||||
BEAN,
|
||||
|
||||
/**
|
||||
* Natural key cache.
|
||||
*/
|
||||
NATURAL_KEY,
|
||||
|
||||
/**
|
||||
* Collection Ids for Many properties.
|
||||
*/
|
||||
COLLECTION_IDS,
|
||||
|
||||
/**
|
||||
* Query cache.
|
||||
*/
|
||||
QUERY
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* API from creating and getting property values from an Immutable Compound
|
||||
* Value Object.
|
||||
* <p>
|
||||
* A Compound Value object should contain multiple properties that are stored
|
||||
* separately. If you only have a single scalar value you should instead look to
|
||||
* use {@link ScalarTypeConverter}.
|
||||
* </p>
|
||||
* <p>
|
||||
* For each property in the compound type you need to implement the
|
||||
* {@link CompoundTypeProperty} interface. These must be returned from
|
||||
* {@link #getProperties()} in the same order that the properties appear in the
|
||||
* constructor.
|
||||
* </p>
|
||||
* <p>
|
||||
* If your compound type is mutable then you should look to use the JPA Embedded
|
||||
* annotation instead of implementing this interface.
|
||||
* </p>
|
||||
* <p>
|
||||
* When using classpath search Ebean will detect and automatically register any
|
||||
* implementations of this interface (along with detecting the entity classes
|
||||
* etc).
|
||||
* </p>
|
||||
*
|
||||
* @param <V> The type of the Value Object
|
||||
* @author rbygrave
|
||||
* @see ScalarTypeConverter
|
||||
*/
|
||||
public interface CompoundType<V> {
|
||||
|
||||
/**
|
||||
* Create an instance of the compound type given its property values.
|
||||
*/
|
||||
V create(Object[] propertyValues);
|
||||
|
||||
/**
|
||||
* Return the properties in the order they appear in the constructor.
|
||||
*/
|
||||
CompoundTypeProperty<V, ?>[] getProperties();
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Represents a Property of a Compound Value Object.
|
||||
* <p>
|
||||
* For each property in a {@link CompoundType} you need an implementation of
|
||||
* this CompoundTypeProperty interface.
|
||||
* </p>
|
||||
*
|
||||
* @param <V> The type of the Compound value object
|
||||
* @param <P> The type of the property
|
||||
* @author rbygrave
|
||||
* @see CompoundType
|
||||
* @see ScalarTypeConverter
|
||||
*/
|
||||
public interface CompoundTypeProperty<V, P> {
|
||||
|
||||
/**
|
||||
* The name of this property.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Return the property value from the containing compound value object.
|
||||
*
|
||||
* @param valueObject the compound value object
|
||||
* @return the property value.
|
||||
*/
|
||||
P getValue(V valueObject);
|
||||
|
||||
/**
|
||||
* This should <b>ONLY</b> be used when the persistence type is different from
|
||||
* the logical type returned. It most cases just return 0 and Ebean will
|
||||
* persist the logical type.
|
||||
* <p>
|
||||
* Typically this should be used when the logical type is long but the
|
||||
* persistence type is java.sql.Timestamp. In this case return
|
||||
* java.sql.Types.TIMESTAMP (rather than 0).
|
||||
* </p>
|
||||
*
|
||||
* @return Return the java.sql.Type that you want to use to persist this
|
||||
* property or 0 and Ebean will use the logical type.
|
||||
*/
|
||||
int getDbType();
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Defines the mode for JDBC batch processing.
|
||||
* <p>
|
||||
* Used both at a per transaction basis and per request basis.
|
||||
* </p>
|
||||
*
|
||||
* @see com.avaje.ebean.config.ServerConfig#setPersistBatch(PersistBatch)
|
||||
* @see com.avaje.ebean.config.ServerConfig#setPersistBatchOnCascade(PersistBatch)
|
||||
* @see com.avaje.ebean.Transaction#setBatch(PersistBatch)
|
||||
* @see com.avaje.ebean.Transaction#setBatchOnCascade(PersistBatch)
|
||||
*/
|
||||
public enum PersistBatch {
|
||||
|
||||
/**
|
||||
* Do not use JDBC Batch mode.
|
||||
*/
|
||||
NONE(false),
|
||||
|
||||
/**
|
||||
* Use JDBC Batch mode on Inserts.
|
||||
*/
|
||||
INSERT(true),
|
||||
|
||||
/**
|
||||
* Use JDBC Batch mode on Inserts, Updates and Deletes.
|
||||
*/
|
||||
ALL(true),
|
||||
|
||||
/**
|
||||
* You should not use this value explicitly. It should only used on the Transactional annotation
|
||||
* to indicate that the value should inherit from the ServerConfig setting.
|
||||
*/
|
||||
INHERIT(false);
|
||||
|
||||
|
||||
final boolean forInsert;
|
||||
|
||||
PersistBatch(boolean forInsert) {
|
||||
this.forInsert = forInsert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if persist cascade should use JDBC batch for inserts.
|
||||
*/
|
||||
public boolean forInsert() {
|
||||
return forInsert;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
/**
|
||||
* Built in supported platforms.
|
||||
*/
|
||||
public enum Platform {
|
||||
|
||||
/**
|
||||
* Generic base platform configured via properties or code.
|
||||
*/
|
||||
GENERIC,
|
||||
|
||||
/**
|
||||
* H2.
|
||||
*/
|
||||
H2,
|
||||
|
||||
/**
|
||||
* Postgres.
|
||||
*/
|
||||
POSTGRES,
|
||||
|
||||
/**
|
||||
* MySql.
|
||||
*/
|
||||
MYSQL,
|
||||
|
||||
/**
|
||||
* Oracle.
|
||||
*/
|
||||
ORACLE,
|
||||
|
||||
/**
|
||||
* Microsoft SQL Server.
|
||||
*/
|
||||
SQLSERVER,
|
||||
|
||||
/**
|
||||
* DB2.
|
||||
*/
|
||||
DB2,
|
||||
|
||||
/**
|
||||
* SQLite.
|
||||
*/
|
||||
SQLITE
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.config.PersistBatch;
|
||||
|
||||
/**
|
||||
* Microsoft SQL Server 2000 specific platform.
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>supportsGetGeneratedKeys = false</li>
|
||||
* <li>Use select @@IDENTITY to return the generated Id instead</li>
|
||||
* <li>Uses LIMIT OFFSET clause</li>
|
||||
* <li>Uses [ & ] for quoted identifiers</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*/
|
||||
public class MsSqlServer2000Platform extends DatabasePlatform {
|
||||
|
||||
public MsSqlServer2000Platform() {
|
||||
super();
|
||||
this.name = "mssqlserver2000";
|
||||
this.persistBatchOnCascade = PersistBatch.NONE;
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(false);
|
||||
this.dbIdentity.setSelectLastInsertedIdTemplate("select @@IDENTITY as X");
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
this.openQuote = "[";
|
||||
this.closeQuote = "]";
|
||||
|
||||
dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0"));
|
||||
|
||||
dbTypeMap.put(DbType.BIGINT, new DbPlatformType("numeric", 19));
|
||||
dbTypeMap.put(DbType.REAL, new DbPlatformType("float(16)"));
|
||||
dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float(32)"));
|
||||
dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint"));
|
||||
dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 28));
|
||||
|
||||
dbTypeMap.put(DbType.BLOB, new DbPlatformType("image"));
|
||||
dbTypeMap.put(DbType.CLOB, new DbPlatformType("text"));
|
||||
dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("image"));
|
||||
dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("text"));
|
||||
|
||||
dbTypeMap.put(DbType.DATE, new DbPlatformType("datetime"));
|
||||
dbTypeMap.put(DbType.TIME, new DbPlatformType("datetime"));
|
||||
dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime"));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.autotune.service;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.autotune.AutoTuneService;
|
||||
|
||||
public class AutoTuneServiceFactory {
|
||||
|
||||
public static AutoTuneService create(SpiEbeanServer server, ServerConfig serverConfig) {
|
||||
|
||||
return new DefaultAutoTuneService(server, serverConfig);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.cache;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheBeanTuning;
|
||||
import com.avaje.ebean.annotation.CacheQueryTuning;
|
||||
import com.avaje.ebean.cache.ServerCache;
|
||||
import com.avaje.ebean.cache.ServerCacheFactory;
|
||||
import com.avaje.ebean.cache.ServerCacheOptions;
|
||||
import com.avaje.ebean.cache.ServerCacheType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Manages the construction of caches.
|
||||
*/
|
||||
public class DefaultCacheHolder {
|
||||
|
||||
private final ConcurrentHashMap<String, ServerCache> concMap = new ConcurrentHashMap<>();
|
||||
|
||||
private final HashMap<String, ServerCache> synchMap = new HashMap<>();
|
||||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final ServerCacheFactory cacheFactory;
|
||||
|
||||
private final ServerCacheOptions defaultOptions;
|
||||
|
||||
/**
|
||||
* Create with a cache factory and default cache options.
|
||||
*
|
||||
* @param cacheFactory the factory for creating the cache
|
||||
* @param defaultOptions the default options for tuning the cache
|
||||
*/
|
||||
public DefaultCacheHolder(ServerCacheFactory cacheFactory, ServerCacheOptions defaultOptions) {
|
||||
this.cacheFactory = cacheFactory;
|
||||
this.defaultOptions = defaultOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache for a given bean type.
|
||||
*/
|
||||
public ServerCache getCache(String cacheKey, ServerCacheType type) {
|
||||
|
||||
ServerCache cache = concMap.get(cacheKey);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
}
|
||||
synchronized (monitor) {
|
||||
cache = synchMap.get(cacheKey);
|
||||
if (cache == null) {
|
||||
ServerCacheOptions options = getCacheOptions(cacheKey, type);
|
||||
cache = cacheFactory.createCache(type, cacheKey, options);
|
||||
synchMap.put(cacheKey, cache);
|
||||
concMap.put(cacheKey, cache);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
public void clearCache(String cacheKey) {
|
||||
|
||||
ServerCache cache = concMap.get(cacheKey);
|
||||
if (cache != null) {
|
||||
cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is an active cache for this bean type.
|
||||
*/
|
||||
public boolean isCaching(String beanType) {
|
||||
return concMap.containsKey(beanType);
|
||||
}
|
||||
|
||||
public void clearAll() {
|
||||
for (ServerCache serverCache : concMap.values()) {
|
||||
serverCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache options for a given bean type.
|
||||
*/
|
||||
ServerCacheOptions getCacheOptions(String beanType, ServerCacheType type) {
|
||||
|
||||
try {
|
||||
Class<?> cls = Class.forName(beanType);
|
||||
switch (type) {
|
||||
case QUERY:
|
||||
return getQueryOptions(cls);
|
||||
default:
|
||||
return getBeanOptions(cls);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return defaultOptions.copy();
|
||||
}
|
||||
|
||||
private ServerCacheOptions getQueryOptions(Class<?> cls) {
|
||||
CacheQueryTuning tuning = cls.getAnnotation(CacheQueryTuning.class);
|
||||
if (tuning != null) {
|
||||
ServerCacheOptions o = new ServerCacheOptions(tuning);
|
||||
o.applyDefaults(defaultOptions);
|
||||
return o;
|
||||
}
|
||||
return defaultOptions.copy();
|
||||
}
|
||||
|
||||
private ServerCacheOptions getBeanOptions(Class<?> cls) {
|
||||
CacheBeanTuning tuning = cls.getAnnotation(CacheBeanTuning.class);
|
||||
if (tuning != null) {
|
||||
ServerCacheOptions o = new ServerCacheOptions(tuning);
|
||||
o.applyDefaults(defaultOptions);
|
||||
return o;
|
||||
}
|
||||
return defaultOptions.copy();
|
||||
}
|
||||
|
||||
}
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.cache;
|
||||
|
||||
import com.avaje.ebean.cache.ServerCache;
|
||||
import com.avaje.ebean.cache.ServerCacheFactory;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.cache.ServerCacheOptions;
|
||||
import com.avaje.ebean.cache.ServerCacheType;
|
||||
|
||||
|
||||
/**
|
||||
* Manages the bean and query caches.
|
||||
*/
|
||||
public class DefaultServerCacheManager implements ServerCacheManager {
|
||||
|
||||
private final DefaultCacheHolder beanCache;
|
||||
|
||||
private final DefaultCacheHolder queryCache;
|
||||
|
||||
private final DefaultCacheHolder naturalKeyCache;
|
||||
|
||||
private final DefaultCacheHolder collectionIdsCache;
|
||||
|
||||
private final boolean localL2Caching;
|
||||
|
||||
/**
|
||||
* Create with a cache factory and default cache options.
|
||||
*/
|
||||
public DefaultServerCacheManager(boolean localL2Caching, ServerCacheFactory cacheFactory, ServerCacheOptions defaultBeanOptions, ServerCacheOptions defaultQueryOptions) {
|
||||
this.localL2Caching = localL2Caching;
|
||||
this.beanCache = new DefaultCacheHolder(cacheFactory, defaultBeanOptions);
|
||||
this.queryCache = new DefaultCacheHolder(cacheFactory, defaultQueryOptions);
|
||||
this.naturalKeyCache = new DefaultCacheHolder(cacheFactory, defaultBeanOptions);
|
||||
this.collectionIdsCache = new DefaultCacheHolder(cacheFactory, defaultBeanOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct when l2 cache is disabled.
|
||||
*/
|
||||
public DefaultServerCacheManager() {
|
||||
this(true, new DefaultServerCacheFactory(), new ServerCacheOptions(), new ServerCacheOptions());
|
||||
}
|
||||
|
||||
public boolean isLocalL2Caching() {
|
||||
return localL2Caching;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear both the bean cache and the query cache for a
|
||||
* given bean type.
|
||||
*/
|
||||
public void clear(Class<?> beanType) {
|
||||
String beanName = beanType.getName();
|
||||
beanCache.clearCache(beanName);
|
||||
naturalKeyCache.clearCache(beanName);
|
||||
collectionIdsCache.clearCache(beanName);
|
||||
queryCache.clearCache(beanName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all caches.
|
||||
*/
|
||||
public void clearAll() {
|
||||
beanCache.clearAll();
|
||||
queryCache.clearAll();
|
||||
naturalKeyCache.clearAll();
|
||||
collectionIdsCache.clearAll();
|
||||
}
|
||||
|
||||
public ServerCache getCollectionIdsCache(Class<?> beanType, String propertyName) {
|
||||
return collectionIdsCache.getCache(beanType.getName() + "." + propertyName, ServerCacheType.COLLECTION_IDS);
|
||||
}
|
||||
|
||||
public ServerCache getNaturalKeyCache(Class<?> beanType) {
|
||||
return naturalKeyCache.getCache(beanType.getName(), ServerCacheType.NATURAL_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the query cache for a given bean type.
|
||||
*/
|
||||
public ServerCache getQueryCache(Class<?> beanType) {
|
||||
return queryCache.getCache(beanType.getName(), ServerCacheType.QUERY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bean cache for a given bean type.
|
||||
*/
|
||||
public ServerCache getBeanCache(Class<?> beanType) {
|
||||
return beanCache.getCache(beanType.getName(), ServerCacheType.BEAN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is an active cache for the given bean type.
|
||||
*/
|
||||
public boolean isBeanCaching(Class<?> beanType) {
|
||||
return beanCache.isCaching(beanType.getName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.cache;
|
||||
@@ -1,27 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
|
||||
import com.avaje.ebean.QueryEachConsumer;
|
||||
import com.avaje.ebean.QueryEachWhileConsumer;
|
||||
import com.avaje.ebean.SqlRow;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface RelationalQueryEngine {
|
||||
|
||||
/**
|
||||
* Find a list of beans using relational query.
|
||||
*/
|
||||
List<SqlRow> findList(RelationalQueryRequest request);
|
||||
|
||||
/**
|
||||
* Find each query using relational query.
|
||||
*/
|
||||
void findEach(RelationalQueryRequest request, QueryEachConsumer<SqlRow> consumer);
|
||||
|
||||
/**
|
||||
* Find each while query using relational query.
|
||||
*/
|
||||
void findEach(RelationalQueryRequest request, QueryEachWhileConsumer<SqlRow> consumer);
|
||||
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.text.json.EJson;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyChainBuilder;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
import com.avaje.ebeaninternal.server.query.SqlBeanLoad;
|
||||
import com.avaje.ebeaninternal.server.text.json.ReadJson;
|
||||
import com.avaje.ebeaninternal.server.text.json.WriteJson;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundPropertyElAdapter;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Property mapped to an Immutable Compound Value Object.
|
||||
* <p>
|
||||
* An Immutable Compound Value Object is similar to an Embedded bean but it
|
||||
* doesn't require enhancement and MUST be treated as an Immutable type.
|
||||
* </p>
|
||||
*/
|
||||
public class BeanPropertyCompound extends BeanProperty {
|
||||
|
||||
private final CtCompoundType<?> compoundType;
|
||||
|
||||
private final BeanProperty[] scalarProperties;
|
||||
|
||||
private final LinkedHashMap<String, BeanProperty> propertyMap = new LinkedHashMap<>();
|
||||
|
||||
private final LinkedHashMap<String, CtCompoundPropertyElAdapter> nonScalarMap = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* Create the property.
|
||||
*/
|
||||
public BeanPropertyCompound(BeanDescriptor<?> descriptor, DeployBeanPropertyCompound deploy) {
|
||||
|
||||
super(descriptor, deploy);
|
||||
this.compoundType = deploy.getCompoundType();
|
||||
|
||||
BeanPropertyCompoundRoot root = deploy.getFlatProperties();
|
||||
this.scalarProperties = root.getScalarProperties();
|
||||
|
||||
for (BeanProperty scalarProperty : scalarProperties) {
|
||||
propertyMap.put(scalarProperty.getName(), scalarProperty);
|
||||
}
|
||||
|
||||
List<CtCompoundProperty> nonScalarPropsList = root.getNonScalarProperties();
|
||||
|
||||
for (CtCompoundProperty ctProp : nonScalarPropsList) {
|
||||
CtCompoundPropertyElAdapter adapter = new CtCompoundPropertyElAdapter(ctProp);
|
||||
nonScalarMap.put(ctProp.getRelativeName(), adapter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialise() {
|
||||
// do nothing for normal BeanProperty
|
||||
if (!isTransient && compoundType == null) {
|
||||
String msg = "No cvoInternalType assigned to " + descriptor.getFullName() + "." + getName();
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeployOrder(int deployOrder) {
|
||||
this.deployOrder = deployOrder;
|
||||
for (CtCompoundPropertyElAdapter adapter : nonScalarMap.values()) {
|
||||
adapter.setDeployOrder(deployOrder);
|
||||
}
|
||||
}
|
||||
|
||||
public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) {
|
||||
|
||||
if (chain == null) {
|
||||
chain = new ElPropertyChainBuilder(true, propName);
|
||||
}
|
||||
|
||||
// first add this property
|
||||
chain.add(this);
|
||||
|
||||
// handle all the rest of the chain handled by the
|
||||
// BeanProperty (all depth for nested compound type)
|
||||
BeanProperty p = propertyMap.get(remainder);
|
||||
if (p != null) {
|
||||
return chain.add(p).build();
|
||||
}
|
||||
CtCompoundPropertyElAdapter elAdapter = nonScalarMap.get(remainder);
|
||||
if (elAdapter == null) {
|
||||
throw new RuntimeException("property [" + remainder + "] not found in " + getFullBeanName());
|
||||
}
|
||||
return chain.add(elAdapter).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendSelect(DbSqlContext ctx, boolean subQuery) {
|
||||
if (!isTransient) {
|
||||
for (BeanProperty scalarProperty : scalarProperties) {
|
||||
scalarProperty.appendSelect(ctx, subQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BeanProperty[] getScalarProperties() {
|
||||
return scalarProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException {
|
||||
|
||||
Object v = compoundType.read(ctx.getDataReader());
|
||||
setValue(bean, v);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the data from the resultSet effectively ignoring it and returning
|
||||
* null.
|
||||
*/
|
||||
@Override
|
||||
public Object read(DbReadContext ctx) throws SQLException {
|
||||
return compoundType.read(ctx.getDataReader());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadIgnore(DbReadContext ctx) {
|
||||
compoundType.loadIgnore(ctx.getDataReader());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(SqlBeanLoad sqlBeanLoad) {
|
||||
sqlBeanLoad.load(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object pathGetNested(Object bean) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void jsonWrite(WriteJson ctx, EntityBean bean) throws IOException {
|
||||
if (!jsonSerialize) {
|
||||
return;
|
||||
}
|
||||
Object value = getValueIntercept(bean);
|
||||
if (value == null) {
|
||||
ctx.writeNullField(name);
|
||||
} else {
|
||||
ctx.writeFieldName(name);
|
||||
compoundType.jsonWrite(ctx, value, name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonRead(ReadJson readJson, EntityBean bean) throws IOException {
|
||||
|
||||
if (!jsonDeserialize) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> map = EJson.parseObject(readJson.getParser());
|
||||
if (map == null) {
|
||||
setValue(bean, null);
|
||||
} else {
|
||||
Object objValue = compoundType.jsonConvert(map);
|
||||
setValue(bean, objValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertySetter;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents the root BeanProperty for properties of a compound type.
|
||||
* <p>
|
||||
* Holds all the scalar and non-scalar properties of the compound type. The
|
||||
* scalar properties match to DB columns and the non-scalar ones are here solely
|
||||
* to support EL expression language for nested compound types.
|
||||
* </p>
|
||||
*/
|
||||
public class BeanPropertyCompoundRoot {
|
||||
|
||||
private final BeanPropertySetter setter;
|
||||
|
||||
private final String name;
|
||||
private final String fullBeanName;
|
||||
|
||||
private final ArrayList<BeanPropertyCompoundScalar> propList;
|
||||
|
||||
private List<CtCompoundProperty> nonScalarProperties;
|
||||
|
||||
public BeanPropertyCompoundRoot(DeployBeanProperty deploy) {
|
||||
this.fullBeanName = deploy.getFullBeanName();
|
||||
this.name = deploy.getName();
|
||||
this.setter = deploy.getSetter();
|
||||
this.propList = new ArrayList<>();
|
||||
}
|
||||
|
||||
public BeanProperty[] getScalarProperties() {
|
||||
|
||||
return propList.toArray(new BeanProperty[propList.size()]);
|
||||
}
|
||||
|
||||
public void register(BeanPropertyCompoundScalar prop) {
|
||||
propList.add(prop);
|
||||
}
|
||||
|
||||
public List<CtCompoundProperty> getNonScalarProperties() {
|
||||
return nonScalarProperties;
|
||||
}
|
||||
|
||||
public void setNonScalarProperties(List<CtCompoundProperty> nonScalarProperties) {
|
||||
this.nonScalarProperties = nonScalarProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the property without interception or
|
||||
* PropertyChangeSupport.
|
||||
*/
|
||||
public void setRootValue(EntityBean bean, Object value) {
|
||||
try {
|
||||
setter.set(bean, value);
|
||||
} catch (Exception ex) {
|
||||
String beanType = bean == null ? "null" : bean.getClass().getName();
|
||||
String msg = "set " + name + " with arg[" + value + "] on [" + fullBeanName + "] with type[" + beanType + "] threw error";
|
||||
throw new RuntimeException(msg, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the property.
|
||||
*/
|
||||
public void setRootValueIntercept(EntityBean bean, Object value) {
|
||||
try {
|
||||
setter.setIntercept(bean, value);
|
||||
} catch (Exception ex) {
|
||||
String beanType = bean == null ? "null" : bean.getClass().getName();
|
||||
String msg = "setIntercept " + name + " arg[" + value + "] on [" + fullBeanName + "] with type[" + beanType + "] threw error";
|
||||
throw new RuntimeException(msg, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
|
||||
|
||||
/**
|
||||
* A BeanProperty owned by a Compound value object that maps to
|
||||
* a real scalar type.
|
||||
*/
|
||||
public class BeanPropertyCompoundScalar extends BeanProperty {
|
||||
|
||||
private final BeanPropertyCompoundRoot rootProperty;
|
||||
|
||||
private final CtCompoundProperty ctProperty;
|
||||
|
||||
public BeanPropertyCompoundScalar(BeanPropertyCompoundRoot rootProperty, DeployBeanProperty scalarDeploy, CtCompoundProperty ctProperty) {
|
||||
super(scalarDeploy);
|
||||
this.rootProperty = rootProperty;
|
||||
this.ctProperty = ctProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return one of the scalar values from a compound type.
|
||||
*/
|
||||
public Object getValueObject(Object compoundValue) {
|
||||
return ctProperty.getValue(compoundValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(EntityBean valueObject) {
|
||||
return ctProperty.getValue(valueObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(EntityBean bean, Object value) {
|
||||
setValueInCompound(bean, value, false);
|
||||
}
|
||||
|
||||
public void setValueInCompound(EntityBean bean, Object value, boolean intercept) {
|
||||
|
||||
Object compoundValue = ctProperty.setValue(bean, value);
|
||||
|
||||
if (compoundValue != null) {
|
||||
// we are at the top level and we have a compound value
|
||||
// that we can set using the root property
|
||||
if (intercept) {
|
||||
rootProperty.setRootValueIntercept(bean, compoundValue);
|
||||
} else {
|
||||
rootProperty.setRootValue(bean, compoundValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* No interception on embedded scalar values inside a CVO.
|
||||
*/
|
||||
@Override
|
||||
public void setValueIntercept(EntityBean bean, Object value) {
|
||||
setValueInCompound(bean, value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* No interception on embedded scalar values inside a CVO.
|
||||
*/
|
||||
@Override
|
||||
public Object getValueIntercept(EntityBean bean) {
|
||||
return getValue(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object pathGetNested(Object bean) {
|
||||
return pathGet(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object pathGet(Object bean) {
|
||||
return ctProperty.getValue(bean);
|
||||
}
|
||||
|
||||
}
|
||||
-100
@@ -1,100 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.meta;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompoundRoot;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompoundScalar;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundProperty;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundType;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundTypeScalarList;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
|
||||
/**
|
||||
* Property mapped to a joined bean.
|
||||
*/
|
||||
public class DeployBeanPropertyCompound extends DeployBeanProperty {
|
||||
|
||||
private final CtCompoundType<?> compoundType;
|
||||
|
||||
private DeployBeanEmbedded deployEmbedded;
|
||||
|
||||
/**
|
||||
* Create the property.
|
||||
*/
|
||||
public DeployBeanPropertyCompound(DeployBeanDescriptor<?> desc, Class<?> targetType, CtCompoundType<?> compoundType) {
|
||||
|
||||
super(desc, targetType, null, null);
|
||||
this.compoundType = compoundType;
|
||||
}
|
||||
|
||||
public BeanPropertyCompoundRoot getFlatProperties() {
|
||||
|
||||
// get a 'flat' list of all the scalar types, their relative property names
|
||||
// and also set their matching dbColumn
|
||||
|
||||
// represents the root property
|
||||
BeanPropertyCompoundRoot rootProperty = new BeanPropertyCompoundRoot(this);
|
||||
|
||||
// Walk the tree of a compound type collecting the
|
||||
// scalar types and non-scalar properties
|
||||
CtCompoundTypeScalarList ctMeta = new CtCompoundTypeScalarList();
|
||||
|
||||
compoundType.accumulateScalarTypes(null, ctMeta);
|
||||
|
||||
|
||||
// for each of the scalar types inside a compound value object
|
||||
// build a BeanPropertyCompoundScalar with appropriate deployment
|
||||
// information.
|
||||
|
||||
for (Entry<String, ScalarType<?>> entry : ctMeta.entries()) {
|
||||
|
||||
String relativePropertyName = entry.getKey();
|
||||
ScalarType<?> scalarType = entry.getValue();
|
||||
|
||||
CtCompoundProperty ctProp = ctMeta.getCompoundType(relativePropertyName);
|
||||
|
||||
|
||||
String dbColumn = (getName() + "." + relativePropertyName).replace(".", "_");
|
||||
dbColumn = getDbColumn(relativePropertyName, dbColumn);
|
||||
|
||||
DeployBeanProperty deploy = new DeployBeanProperty(null, scalarType.getType(), scalarType, null);
|
||||
deploy.setScalarType(scalarType);
|
||||
deploy.setDbColumn(dbColumn);
|
||||
deploy.setName(relativePropertyName);
|
||||
deploy.setDbInsertable(true);
|
||||
deploy.setDbUpdateable(true);
|
||||
deploy.setDbRead(true);
|
||||
|
||||
rootProperty.register(new BeanPropertyCompoundScalar(rootProperty, deploy, ctProp));
|
||||
}
|
||||
|
||||
rootProperty.setNonScalarProperties(ctMeta.getNonScalarProperties());
|
||||
return rootProperty;
|
||||
}
|
||||
|
||||
private String getDbColumn(String propName, String defaultDbColumn) {
|
||||
if (deployEmbedded == null) {
|
||||
return defaultDbColumn;
|
||||
}
|
||||
String dbColumn = deployEmbedded.getPropertyColumnMap().get(propName);
|
||||
return dbColumn == null ? defaultDbColumn : dbColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the deploy information specifically for the deployment
|
||||
* of Embedded beans.
|
||||
*/
|
||||
public DeployBeanEmbedded getDeployEmbedded() {
|
||||
// deployment should be single threaded
|
||||
if (deployEmbedded == null) {
|
||||
deployEmbedded = new DeployBeanEmbedded();
|
||||
}
|
||||
return deployEmbedded;
|
||||
}
|
||||
|
||||
public CtCompoundType<?> getCompoundType() {
|
||||
return compoundType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import com.avaje.ebean.config.NamingConvention;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides some base methods for processing deployment annotations.
|
||||
*/
|
||||
public abstract class AnnotationBase {
|
||||
|
||||
protected final DatabasePlatform databasePlatform;
|
||||
protected final NamingConvention namingConvention;
|
||||
protected final DeployUtil util;
|
||||
|
||||
protected AnnotationBase(DeployUtil util) {
|
||||
this.util = util;
|
||||
this.databasePlatform = util.getDbPlatform();
|
||||
this.namingConvention = util.getNamingConvention();
|
||||
}
|
||||
|
||||
/**
|
||||
* read the deployment annotations.
|
||||
*/
|
||||
public abstract void parse();
|
||||
|
||||
/**
|
||||
* Checks string is null or empty .
|
||||
*/
|
||||
protected boolean isEmpty(String s) {
|
||||
return s == null || s.trim().isEmpty();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the annotation for the property.
|
||||
* <p>
|
||||
* Looks first at the field and then at the getter method.
|
||||
* </p>
|
||||
*/
|
||||
protected <T extends Annotation> T get(DeployBeanProperty prop, Class<T> annClass) {
|
||||
T a = null;
|
||||
Field field = prop.getField();
|
||||
if (field != null) {
|
||||
a = findAnnotation(field, annClass);
|
||||
}
|
||||
if (a == null) {
|
||||
Method m = prop.getReadMethod();
|
||||
if (m != null) {
|
||||
a = findAnnotation(m, annClass);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the annotation for the property.
|
||||
* <p>
|
||||
* Looks first at the field and then at the getter method. then at class level.
|
||||
* </p>
|
||||
*/
|
||||
protected <T extends Annotation> T find(DeployBeanProperty prop, Class<T> annClass) {
|
||||
T a = get(prop, annClass);
|
||||
if (a == null) {
|
||||
a = findAnnotation(prop.getOwningType(), annClass);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
// this code is taken from the spring framework to find annotations recursively
|
||||
|
||||
/**
|
||||
* Determine if the supplied {@link Annotation} is defined in the core JDK {@code java.lang.annotation} package.
|
||||
*/
|
||||
public static boolean isInJavaLangAnnotationPackage(Annotation annotation) {
|
||||
return annotation.annotationType().getName().startsWith("java.lang.annotation");
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a single {@link Annotation} of {@code annotationType} on the supplied {@link AnnotatedElement}.
|
||||
* <p>
|
||||
* Meta-annotations will be searched if the annotation is not <em>directly present</em> on the supplied element.
|
||||
* <p>
|
||||
* <strong>Warning</strong>: this method operates generically on annotated elements. In other words, this method
|
||||
* does not execute specialized search algorithms for classes or methods. It only traverses through Annotations!
|
||||
*/
|
||||
public static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
|
||||
if (annotationType == null) {
|
||||
return null;
|
||||
}
|
||||
// check if directly present, if not, start recursive traversal
|
||||
A ann = annotatedElement.getAnnotation(annotationType);
|
||||
if (ann != null) {
|
||||
return ann;
|
||||
} else {
|
||||
return findAnnotation(annotatedElement, annotationType, new HashSet<>());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a single {@link Annotation} of {@code annotationType} on the supplied class.
|
||||
* <p>Meta-annotations will be searched if the annotation is not directly present on
|
||||
* the supplied element.
|
||||
* <p><strong>Note</strong>: this method searches for annotations at class & superClass(es)!
|
||||
*/
|
||||
public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) {
|
||||
if (annotationType == null) {
|
||||
return null;
|
||||
}
|
||||
// check if directly present, if not, start recursive traversal
|
||||
A ann = clazz.getAnnotation(annotationType);
|
||||
if (ann != null) {
|
||||
return ann;
|
||||
} else {
|
||||
while (clazz != null && clazz != Object.class) {
|
||||
ann = findAnnotation(clazz, annotationType, new HashSet<>());
|
||||
if (ann != null) {
|
||||
return ann;
|
||||
}
|
||||
// not present at this class - traverse to superclass
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the search algorithm avoiding endless recursion by tracking which
|
||||
* annotations have already been visited.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType, Set<Annotation> visited) {
|
||||
|
||||
Annotation[] anns = annotatedElement.getDeclaredAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
if (ann.annotationType() == annotationType) {
|
||||
return (A) ann;
|
||||
}
|
||||
}
|
||||
for (Annotation ann : anns) {
|
||||
if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
|
||||
A annotation = findAnnotation(ann.annotationType(), annotationType, visited);
|
||||
if (annotation != null) {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.el;
|
||||
@@ -1 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.loadcontext;
|
||||
@@ -1,59 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.persist.dml.GenerateDmlRequest;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Bindable for a Immutable Compound value object.
|
||||
*/
|
||||
public class BindableCompound implements Bindable {
|
||||
|
||||
private final BindableProperty[] items;
|
||||
|
||||
private final BeanPropertyCompound compound;
|
||||
|
||||
public BindableCompound(BeanPropertyCompound embProp, List<BindableProperty> list) {
|
||||
this.compound = embProp;
|
||||
this.items = list.toArray(new BindableProperty[list.size()]);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "BindableCompound " + compound + " items:" + Arrays.toString(items);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDraftOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void dmlAppend(GenerateDmlRequest request) {
|
||||
|
||||
for (BindableProperty item : items) {
|
||||
item.dmlAppend(request);
|
||||
}
|
||||
}
|
||||
|
||||
public void addToUpdate(PersistRequestBean<?> request, List<Bindable> list) {
|
||||
if (request.isAddToUpdate(compound)) {
|
||||
list.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void dmlBind(BindableRequest bindRequest, EntityBean bean) throws SQLException {
|
||||
|
||||
// get the compound type value
|
||||
Object valueObject = compound.getValue(bean);
|
||||
|
||||
// bind each of the underlying scalar values for this compound type
|
||||
for (BindableProperty item : items) {
|
||||
item.dmlBindObject(bindRequest, valueObject);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-67
@@ -1,67 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.persist.dml.DmlMode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Add base properties to the BindableList for a bean type.
|
||||
* <p>
|
||||
* This excludes unique embedded and associated properties.
|
||||
* </p>
|
||||
*/
|
||||
public class FactoryBaseProperties {
|
||||
|
||||
private final FactoryProperty factoryProperty;
|
||||
|
||||
|
||||
public FactoryBaseProperties(boolean bindEncryptDataFirst) {
|
||||
factoryProperty = new FactoryProperty(bindEncryptDataFirst);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Bindable for the base properties to the list.
|
||||
*/
|
||||
public void create(List<Bindable> list, BeanDescriptor<?> desc, DmlMode mode, boolean withLobs) {
|
||||
|
||||
add(desc.propertiesBaseScalar(), list, mode, withLobs);
|
||||
|
||||
BeanPropertyCompound[] compoundProps = desc.propertiesBaseCompound();
|
||||
for (BeanPropertyCompound compoundProp : compoundProps) {
|
||||
BeanProperty[] props = compoundProp.getScalarProperties();
|
||||
|
||||
List<BindableProperty> newList = new ArrayList<>(props.length);
|
||||
addCompound(props, newList, mode, withLobs);
|
||||
|
||||
BindableCompound compoundBindable = new BindableCompound(compoundProp, newList);
|
||||
|
||||
list.add(compoundBindable);
|
||||
}
|
||||
}
|
||||
|
||||
private void add(BeanProperty[] props, List<Bindable> list, DmlMode mode, boolean withLobs) {
|
||||
|
||||
for (BeanProperty prop : props) {
|
||||
Bindable item = factoryProperty.create(prop, mode, withLobs);
|
||||
if (item != null) {
|
||||
list.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addCompound(BeanProperty[] props, List<BindableProperty> list, DmlMode mode, boolean withLobs) {
|
||||
|
||||
for (BeanProperty prop : props) {
|
||||
BindableProperty item = (BindableProperty) factoryProperty.create(prop, mode, withLobs);
|
||||
if (item != null) {
|
||||
list.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.properties;
|
||||
|
||||
/**
|
||||
* Provides getter setter and construction methods for beans.
|
||||
* <p>
|
||||
* This enables the implementation to use standard reflection or
|
||||
* code generation.
|
||||
* </p>
|
||||
*/
|
||||
public interface BeanPropertyInfo {
|
||||
|
||||
/**
|
||||
* Create an EntityBean for this type.
|
||||
*/
|
||||
Object createEntityBean();
|
||||
|
||||
/**
|
||||
* Return the getter for a given bean property.
|
||||
*/
|
||||
BeanPropertyGetter getGetter(int position);
|
||||
|
||||
/**
|
||||
* Return the setter for a given bean property.
|
||||
*/
|
||||
BeanPropertySetter getSetter(int position);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.properties;
|
||||
|
||||
|
||||
/**
|
||||
* Creates BeanReflect object used to provide getter setter and construction
|
||||
* for the beans.
|
||||
*/
|
||||
public interface BeanPropertyInfoFactory {
|
||||
|
||||
/**
|
||||
* Create the BeanReflect for the given plain bean and its EntityBean equivalent.
|
||||
*/
|
||||
BeanPropertyInfo create(Class<?> entityBeanType);
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.properties;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
/**
|
||||
* A BeanReflect implementation based on the enhancement that creates EntityBean
|
||||
* implementations.
|
||||
*/
|
||||
public final class EnhanceBeanPropertyInfo implements BeanPropertyInfo {
|
||||
|
||||
private static final Object[] constuctorArgs = new Object[0];
|
||||
|
||||
private final Constructor<?> constructor;
|
||||
|
||||
public EnhanceBeanPropertyInfo(Class<?> clazz) {
|
||||
try {
|
||||
if (Modifier.isAbstract(clazz.getModifiers())) {
|
||||
this.constructor = null;
|
||||
} else {
|
||||
this.constructor = defaultConstructor(clazz);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Constructor<?> defaultConstructor(Class<?> cls) {
|
||||
try {
|
||||
Class<?>[] params = new Class[0];
|
||||
return cls.getDeclaredConstructor(params);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public Object createEntityBean() {
|
||||
try {
|
||||
return constructor.newInstance(constuctorArgs);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public BeanPropertyGetter getGetter(int position) {
|
||||
return new Getter(position);
|
||||
}
|
||||
|
||||
public BeanPropertySetter getSetter(int position) {
|
||||
return new Setter(position);
|
||||
}
|
||||
|
||||
static final class Getter implements BeanPropertyGetter {
|
||||
|
||||
private final int fieldIndex;
|
||||
|
||||
Getter(int fieldIndex) {
|
||||
this.fieldIndex = fieldIndex;
|
||||
}
|
||||
|
||||
public Object get(EntityBean bean) {
|
||||
return bean._ebean_getField(fieldIndex);
|
||||
}
|
||||
|
||||
public Object getIntercept(EntityBean bean) {
|
||||
return bean._ebean_getFieldIntercept(fieldIndex);
|
||||
}
|
||||
}
|
||||
|
||||
static final class Setter implements BeanPropertySetter {
|
||||
|
||||
private final int fieldIndex;
|
||||
|
||||
Setter(int fieldIndex) {
|
||||
this.fieldIndex = fieldIndex;
|
||||
}
|
||||
|
||||
public void set(EntityBean bean, Object value) {
|
||||
bean._ebean_setField(fieldIndex, value);
|
||||
}
|
||||
|
||||
public void setIntercept(EntityBean bean, Object value) {
|
||||
bean._ebean_setFieldIntercept(fieldIndex, value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.properties;
|
||||
|
||||
/**
|
||||
* Creates a BeanReflectFactory based on the enhancement that
|
||||
* creates EntityBean implementations.
|
||||
*/
|
||||
public final class EnhanceBeanPropertyInfoFactory implements BeanPropertyInfoFactory {
|
||||
|
||||
public BeanPropertyInfo create(Class<?> entityBeanType) {
|
||||
return new EnhanceBeanPropertyInfo(entityBeanType);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
@@ -1 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.querydefn;
|
||||
@@ -1 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.text.csv;
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.transaction;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeanservice.docstore.api.DocStoreUpdateProcessor;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
/**
|
||||
* AutoCommit based TransactionManager.
|
||||
* <p>
|
||||
* Intended to be used if when autoCommit mode is desired.
|
||||
*/
|
||||
public class AutoCommitTransactionManager extends TransactionManager {
|
||||
|
||||
public AutoCommitTransactionManager(boolean localL2Caching, ServerConfig serverConfig, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor,
|
||||
DocStoreUpdateProcessor indexUpdateProcessor, BeanDescriptorManager descMgr) {
|
||||
|
||||
super(localL2Caching, serverConfig, clusterManager, backgroundExecutor, indexUpdateProcessor, descMgr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an autoCommit based Transaction.
|
||||
*/
|
||||
@Override
|
||||
protected SpiTransaction createTransaction(boolean explicit, Connection c, long id) {
|
||||
|
||||
return new AutoCommitJdbcTransaction(prefix + id, explicit, c, this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebean.config.CompoundType;
|
||||
import com.avaje.ebean.config.CompoundTypeProperty;
|
||||
|
||||
import java.time.Period;
|
||||
|
||||
/**
|
||||
* Compound type for Period value type.
|
||||
* <p>
|
||||
* Persists the Period into 3 separate integer columns for years, months and days.
|
||||
* </p>
|
||||
*/
|
||||
public class CompoundTypePeriod implements CompoundType<Period> {
|
||||
|
||||
final CompoundTypeProperty[] properties = new CompoundTypeProperty[3];
|
||||
|
||||
public CompoundTypePeriod() {
|
||||
properties[0] = new CTPeriodYear();
|
||||
properties[1] = new CTPeriodMonth();
|
||||
properties[2] = new CTPeriodDay();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Period create(Object[] propertyValues) {
|
||||
return Period.of((Integer) propertyValues[0], (Integer) propertyValues[1], (Integer) propertyValues[2]);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public CompoundTypeProperty<Period, ?>[] getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
static class CTPeriodYear implements CompoundTypeProperty<Period, Integer> {
|
||||
|
||||
public String getName() {
|
||||
return "years";
|
||||
}
|
||||
|
||||
public Integer getValue(Period valueObject) {
|
||||
return valueObject.getYears();
|
||||
}
|
||||
|
||||
public int getDbType() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class CTPeriodMonth implements CompoundTypeProperty<Period, Integer> {
|
||||
|
||||
public String getName() {
|
||||
return "months";
|
||||
}
|
||||
|
||||
public Integer getValue(Period valueObject) {
|
||||
return valueObject.getMonths();
|
||||
}
|
||||
|
||||
public int getDbType() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class CTPeriodDay implements CompoundTypeProperty<Period, Integer> {
|
||||
|
||||
public String getName() {
|
||||
return "days";
|
||||
}
|
||||
|
||||
public Integer getValue(Period valueObject) {
|
||||
return valueObject.getDays();
|
||||
}
|
||||
|
||||
public int getDbType() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebean.config.CompoundTypeProperty;
|
||||
|
||||
/**
|
||||
* Wraps a CompoundTypeProperty with it's type and parent for nested compound
|
||||
* types.
|
||||
*/
|
||||
public class CtCompoundProperty {
|
||||
|
||||
private final String relativeName;
|
||||
|
||||
private final CtCompoundProperty parent;
|
||||
|
||||
private final CtCompoundType<?> compoundType;
|
||||
|
||||
@SuppressWarnings({"rawtypes"})
|
||||
private final CompoundTypeProperty property;
|
||||
|
||||
public CtCompoundProperty(String relativeName, CtCompoundProperty parent, CtCompoundType<?> ctType,
|
||||
CompoundTypeProperty<?, ?> property) {
|
||||
|
||||
this.relativeName = relativeName;
|
||||
this.parent = parent;
|
||||
this.compoundType = ctType;
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
/**
|
||||
* The property name relative to the root of the compound type.
|
||||
*/
|
||||
public String getRelativeName() {
|
||||
return relativeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The property name local to its type.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return property.getName();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return relativeName;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object getValue(Object valueObject) {
|
||||
if (valueObject == null) {
|
||||
return null;
|
||||
}
|
||||
if (parent != null) {
|
||||
valueObject = parent.getValue(valueObject);
|
||||
}
|
||||
return property.getValue(valueObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a scalar value that is used to build the immutable compound value
|
||||
* object.
|
||||
* <p>
|
||||
* When all the scalar values have been collected then the compound value
|
||||
* object is built and this can be recursive for nested compound types.
|
||||
* </p>
|
||||
*/
|
||||
public Object setValue(Object bean, Object value) {
|
||||
|
||||
// compoundType and propertyName should be correct depth
|
||||
Object compoundValue = ImmutableCompoundTypeBuilder.set(compoundType, property.getName(), value);
|
||||
|
||||
if (compoundValue != null && parent != null) {
|
||||
// Continue up the tree
|
||||
return parent.setValue(bean, compoundValue);
|
||||
|
||||
} else {
|
||||
return compoundValue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.text.StringParser;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionRequest;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
|
||||
|
||||
/**
|
||||
* Adapter for CtCompoundProperty to ElPropertyValue.
|
||||
* <p>
|
||||
* This is used for non-scalar properties of a Compound Value Object. These only
|
||||
* occur in nested compound types.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class CtCompoundPropertyElAdapter implements ElPropertyValue {
|
||||
|
||||
private final CtCompoundProperty prop;
|
||||
|
||||
private int deployOrder;
|
||||
|
||||
public CtCompoundPropertyElAdapter(CtCompoundProperty prop) {
|
||||
this.prop = prop;
|
||||
}
|
||||
|
||||
public void setDeployOrder(int deployOrder) {
|
||||
this.deployOrder = deployOrder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAggregation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object convert(Object value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object pathGetNested(Object bean) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object pathGet(Object bean) {
|
||||
return prop.getValue(bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pathSet(Object bean, Object value) {
|
||||
prop.setValue(bean, value);
|
||||
}
|
||||
|
||||
public String getAssocIdExpression(String prefix, String operator) {
|
||||
throw new RuntimeException("Not Supported or Expected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAssocIsEmpty(SpiExpressionRequest request, String path) {
|
||||
throw new RuntimeException("Not Supported or Expected");
|
||||
}
|
||||
|
||||
public Object[] getAssocIdValues(EntityBean bean) {
|
||||
throw new RuntimeException("Not Supported or Expected");
|
||||
}
|
||||
|
||||
public String getAssocIdInExpr(String prefix) {
|
||||
throw new RuntimeException("Not Supported or Expected");
|
||||
}
|
||||
|
||||
public String getAssocIdInValueExpr(int size) {
|
||||
throw new RuntimeException("Not Supported or Expected");
|
||||
}
|
||||
|
||||
public BeanProperty getBeanProperty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StringParser getStringParser() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isDbEncrypted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isLocalEncrypted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAssocMany() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAssocId() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isAssocProperty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isDateTimeCapable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getJdbcType() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Object parseDateTime(long systemTimeMillis) {
|
||||
throw new RuntimeException("Not Supported or Expected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsFormulaWithJoin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean containsMany() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean containsManySince(String sinceProperty) {
|
||||
return containsMany();
|
||||
}
|
||||
|
||||
public String getDbColumn() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getElPlaceholder(boolean encrypted) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getElPrefix() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return prop.getPropertyName();
|
||||
}
|
||||
|
||||
public String getElName() {
|
||||
return prop.getPropertyName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebean.config.CompoundType;
|
||||
import com.avaje.ebean.config.CompoundTypeProperty;
|
||||
import com.avaje.ebeaninternal.server.text.json.WriteJson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The internal representation of a Compound Type (Immutable Compound Value Object).
|
||||
*
|
||||
* @param <V> The Type of the "Immutable Compound Value Object".
|
||||
*/
|
||||
public final class CtCompoundType<V> implements ScalarDataReader<V> {
|
||||
|
||||
private final Class<V> cvoClass;
|
||||
|
||||
private final CompoundType<V> cvoType;
|
||||
|
||||
private final ScalarDataReader<Object>[] propReaders;
|
||||
|
||||
private final CompoundTypeProperty<V, ?>[] properties;
|
||||
|
||||
public CtCompoundType(Class<V> cvoClass, CompoundType<V> cvoType, ScalarDataReader<Object>[] propReaders) {
|
||||
|
||||
this.cvoClass = cvoClass;
|
||||
this.cvoType = cvoType;
|
||||
this.properties = cvoType.getProperties();
|
||||
this.propReaders = propReaders;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return cvoClass.toString();
|
||||
}
|
||||
|
||||
public Class<V> getCompoundTypeClass() {
|
||||
return cvoClass;
|
||||
}
|
||||
|
||||
public V create(Object[] propertyValues) {
|
||||
return cvoType.create(propertyValues);
|
||||
}
|
||||
|
||||
|
||||
public V create(Map<String, Object> valueMap) {
|
||||
|
||||
if (valueMap.size() != properties.length) {
|
||||
// not enough elements in the map
|
||||
return null;
|
||||
}
|
||||
|
||||
// we expect the map to contain a value for
|
||||
// each property and that the values are the
|
||||
// correct type
|
||||
Object[] propertyValues = new Object[properties.length];
|
||||
for (int i = 0; i < properties.length; i++) {
|
||||
propertyValues[i] = valueMap.get(properties[i].getName());
|
||||
if (propertyValues[i] == null) {
|
||||
String m = "Null value for " + properties[i].getName() + " in map " + valueMap;
|
||||
throw new RuntimeException(m);
|
||||
}
|
||||
}
|
||||
|
||||
return create(propertyValues);
|
||||
}
|
||||
|
||||
public V read(DataReader source) throws SQLException {
|
||||
|
||||
boolean nullValue = false;
|
||||
Object[] values = new Object[propReaders.length];
|
||||
|
||||
for (int i = 0; i < propReaders.length; i++) {
|
||||
Object o = propReaders[i].read(source);
|
||||
values[i] = o;
|
||||
if (o == null) {
|
||||
nullValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (nullValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return create(values);
|
||||
}
|
||||
|
||||
public void loadIgnore(DataReader dataReader) {
|
||||
for (ScalarDataReader<Object> propReader : propReaders) {
|
||||
propReader.loadIgnore(dataReader);
|
||||
}
|
||||
}
|
||||
|
||||
public void bind(DataBind b, V value) throws SQLException {
|
||||
|
||||
CompoundTypeProperty<V, ?>[] props = cvoType.getProperties();
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
Object o = props[i].getValue(value);
|
||||
propReaders[i].bind(b, o);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively accumulate all the scalar types (in depth first order).
|
||||
* <p>
|
||||
* This creates a flat list of scalars even when compound types are embedded
|
||||
* inside compound types.
|
||||
* </p>
|
||||
*/
|
||||
public void accumulateScalarTypes(String parent, CtCompoundTypeScalarList list) {
|
||||
|
||||
CompoundTypeProperty<V, ?>[] props = cvoType.getProperties();
|
||||
|
||||
for (int i = 0; i < propReaders.length; i++) {
|
||||
String propName = getFullPropName(parent, props[i].getName());
|
||||
|
||||
list.addCompoundProperty(propName, this, props[i]);
|
||||
|
||||
propReaders[i].accumulateScalarTypes(propName, list);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full property name (for compound types embedded in other
|
||||
* compound types).
|
||||
*
|
||||
* @param parent the parent property name
|
||||
* @param propName the local property name
|
||||
*/
|
||||
private String getFullPropName(String parent, String propName) {
|
||||
if (parent == null) {
|
||||
return propName;
|
||||
} else {
|
||||
return parent + "." + propName;
|
||||
}
|
||||
}
|
||||
|
||||
public Object jsonConvert(Map<String, Object> map) {
|
||||
return readJsonElementObject(map);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object readJsonElementObject(Map<String, Object> jsonObject) {
|
||||
|
||||
boolean nullValue = false;
|
||||
Object[] values = new Object[propReaders.length];
|
||||
|
||||
for (int i = 0; i < propReaders.length; i++) {
|
||||
String propName = properties[i].getName();
|
||||
Object jsonElement = jsonObject.get(propName);
|
||||
|
||||
if (propReaders[i] instanceof CtCompoundType<?>) {
|
||||
values[i] = ((CtCompoundType<?>) propReaders[i]).readJsonElementObject((Map<String, Object>) jsonElement);
|
||||
} else {
|
||||
values[i] = ((ScalarType<?>) propReaders[i]).parse(jsonElement.toString());
|
||||
}
|
||||
if (values[i] == null) {
|
||||
nullValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (nullValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return create(values);
|
||||
}
|
||||
|
||||
|
||||
public void jsonWrite(WriteJson ctx, Object valueObject, String propertyName) throws IOException {
|
||||
|
||||
ctx.beginAssocOne(propertyName, valueObject);
|
||||
jsonWriteProps(ctx, valueObject);
|
||||
ctx.endAssocOne();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private void jsonWriteProps(WriteJson ctx, Object valueObject) throws IOException {
|
||||
|
||||
ctx.gen().writeStartObject();
|
||||
|
||||
for (int i = 0; i < properties.length; i++) {
|
||||
String propName = properties[i].getName();
|
||||
Object value = properties[i].getValue((V) valueObject);
|
||||
if (propReaders[i] instanceof CtCompoundType<?>) {
|
||||
ctx.writeFieldName(propName);
|
||||
((CtCompoundType) propReaders[i]).jsonWrite(ctx, value, propName);
|
||||
|
||||
} else {
|
||||
ctx.writeFieldName(propName);
|
||||
((ScalarType) propReaders[i]).jsonWrite(ctx.gen(), value);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.gen().writeEndObject();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebean.config.CompoundTypeProperty;
|
||||
import com.avaje.ebeaninternal.server.query.SplitName;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Used to build a flat list of all the scalar types nested in a compound type.
|
||||
*/
|
||||
public final class CtCompoundTypeScalarList {
|
||||
|
||||
private final LinkedHashMap<String, ScalarType<?>> scalarProps = new LinkedHashMap<>();
|
||||
|
||||
private final LinkedHashMap<String, CtCompoundProperty> compoundProperties = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* Return the list of non-scalar properties. These occur when compound types are nested.
|
||||
*/
|
||||
public List<CtCompoundProperty> getNonScalarProperties() {
|
||||
|
||||
List<CtCompoundProperty> nonScalarProps = new ArrayList<>();
|
||||
|
||||
for (String propKey : compoundProperties.keySet()) {
|
||||
if (!scalarProps.containsKey(propKey)) {
|
||||
nonScalarProps.add(compoundProperties.get(propKey));
|
||||
}
|
||||
}
|
||||
|
||||
return nonScalarProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a property with it's associated compound type and relative name.
|
||||
*/
|
||||
public void addCompoundProperty(String propName, CtCompoundType<?> t, CompoundTypeProperty<?, ?> prop) {
|
||||
|
||||
CtCompoundProperty parent = null;
|
||||
String[] split = SplitName.split(propName);
|
||||
if (split[0] != null) {
|
||||
parent = compoundProperties.get(split[0]);
|
||||
}
|
||||
|
||||
CtCompoundProperty p = new CtCompoundProperty(propName, parent, t, prop);
|
||||
compoundProperties.put(propName, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a scalarType used in the compound type with its given property name.
|
||||
*/
|
||||
public void addScalarType(String propName, ScalarType<?> scalar) {
|
||||
scalarProps.put(propName, scalar);
|
||||
}
|
||||
|
||||
public CtCompoundProperty getCompoundType(String propName) {
|
||||
return compoundProperties.get(propName);
|
||||
}
|
||||
|
||||
public Set<Entry<String, ScalarType<?>>> entries() {
|
||||
return scalarProps.entrySet();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Used to build Immutable Compound Value objects.
|
||||
* <p>
|
||||
* The individual values are collected for a given type and when they have all
|
||||
* been collected then the immutable compound value object is created and
|
||||
* returned.
|
||||
* </p>
|
||||
*/
|
||||
public final class ImmutableCompoundTypeBuilder {
|
||||
|
||||
private static final ThreadLocal<ImmutableCompoundTypeBuilder> local = new ThreadLocal<ImmutableCompoundTypeBuilder>() {
|
||||
protected synchronized ImmutableCompoundTypeBuilder initialValue() {
|
||||
return new ImmutableCompoundTypeBuilder();
|
||||
}
|
||||
};
|
||||
|
||||
private final Map<Class<?>, Entry> entryMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Clear the cache of partial compound objects.
|
||||
*/
|
||||
public static void clear() {
|
||||
local.get().entryMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for the property of a compound type.
|
||||
* <p>
|
||||
* If this is the last value required for the compound type then the
|
||||
* compound type is created and returned, otherwise null is returned (and we
|
||||
* need more values set).
|
||||
* </p>
|
||||
*/
|
||||
public static Object set(CtCompoundType<?> ct, String propName, Object value) {
|
||||
return local.get().setValue(ct, propName, value);
|
||||
}
|
||||
|
||||
private Object setValue(CtCompoundType<?> ct, String propName, Object value) {
|
||||
|
||||
Entry e = getEntry(ct);
|
||||
Object compoundValue = e.set(propName, value);
|
||||
if (compoundValue != null) {
|
||||
removeEntry(ct);
|
||||
}
|
||||
return compoundValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Once we have built a compound value we remove the entry.
|
||||
*/
|
||||
private void removeEntry(CtCompoundType<?> ct) {
|
||||
entryMap.remove(ct.getCompoundTypeClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Entry which contains the values collected so far for this type.
|
||||
*/
|
||||
private Entry getEntry(CtCompoundType<?> ct) {
|
||||
Entry e = entryMap.get(ct.getCompoundTypeClass());
|
||||
if (e == null) {
|
||||
e = new Entry(ct);
|
||||
entryMap.put(ct.getCompoundTypeClass(), e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds the values collected so far for a given compound type.
|
||||
*/
|
||||
private static class Entry {
|
||||
|
||||
private final CtCompoundType<?> ct;
|
||||
|
||||
private final Map<String, Object> valueMap;
|
||||
|
||||
private Entry(CtCompoundType<?> ct) {
|
||||
this.ct = ct;
|
||||
this.valueMap = new HashMap<>();
|
||||
}
|
||||
|
||||
private Object set(String propName, Object value) {
|
||||
// collect the values...
|
||||
valueMap.put(propName, value);
|
||||
|
||||
// when got all the values this returns the
|
||||
// compound value, otherwise null
|
||||
return ct.create(valueMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Wraps a Set for the purposes of detecting modifications.
|
||||
*/
|
||||
public class ModifyAwareSet<E> extends ModifyAwareCollection<E> implements Set<E>, ModifyAwareOwner {
|
||||
|
||||
/**
|
||||
* Create with an Owner that is notified of modifications.
|
||||
*/
|
||||
public ModifyAwareSet(ModifyAwareOwner owner, Set<E> s) {
|
||||
super(owner, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create as top level with it's own ModifyAwareOwner instance wrapping the given Set.
|
||||
*/
|
||||
public ModifyAwareSet(Set<E> s) {
|
||||
super(new ModifyAwareFlag(), s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMarkedDirty() {
|
||||
return owner.isMarkedDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsModified() {
|
||||
owner.markAsModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetMarkedDirty() {
|
||||
owner.resetMarkedDirty();
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.type.reflect;
|
||||
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
|
||||
public class CheckImmutable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CheckImmutable.class);
|
||||
|
||||
private final KnownImmutable knownImmutable;
|
||||
|
||||
public CheckImmutable(KnownImmutable knownImmutable) {
|
||||
this.knownImmutable = knownImmutable;
|
||||
}
|
||||
|
||||
public CheckImmutableResponse checkImmutable(Class<?> cls) {
|
||||
|
||||
CheckImmutableResponse res = new CheckImmutableResponse();
|
||||
|
||||
isImmutable(cls, res);
|
||||
|
||||
if (res.isImmutable()) {
|
||||
res.setCompoundType(isCompoundType(cls));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private boolean isCompoundType(Class<?> cls) {
|
||||
|
||||
int maxLength = 0;
|
||||
Constructor<?> chosen = null;
|
||||
|
||||
// find the constructor with the most number of parameters
|
||||
Constructor<?>[] constructors = cls.getConstructors();
|
||||
for (Constructor<?> constructor : constructors) {
|
||||
Class<?>[] parameterTypes = constructor.getParameterTypes();
|
||||
if (parameterTypes.length > maxLength) {
|
||||
maxLength = parameterTypes.length;
|
||||
chosen = constructor;
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("checkImmutable " + cls + " constructor " + chosen);
|
||||
|
||||
return maxLength > 1;
|
||||
}
|
||||
|
||||
private boolean isImmutable(Class<?> cls, CheckImmutableResponse res) {
|
||||
|
||||
|
||||
if (knownImmutable.isKnownImmutable(cls)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (cls.isArray()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (hasDefaultConstructor(cls)) {
|
||||
// must not have a default constructor to be considered immutable
|
||||
res.setReasonNotImmutable(cls + " has a default constructor");
|
||||
return false;
|
||||
}
|
||||
|
||||
// check super class
|
||||
Class<?> superClass = cls.getSuperclass();
|
||||
|
||||
if (!isImmutable(superClass, res)) {
|
||||
res.setReasonNotImmutable("Super not Immutable " + superClass);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hasAllFinalFields(cls, res)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lets hope we didn't forget something
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean hasAllFinalFields(Class<?> cls, CheckImmutableResponse res) {
|
||||
|
||||
// Check all fields defined in the class for type and if they are final
|
||||
Field[] objFields = cls.getDeclaredFields();
|
||||
for (Field objField : objFields) {
|
||||
if (!Modifier.isStatic(objField.getModifiers())) {
|
||||
if (!Modifier.isFinal(objField.getModifiers())) {
|
||||
res.setReasonNotImmutable("Non final field " + cls + "." + objField.getName());
|
||||
return false;
|
||||
}
|
||||
if (!isImmutable(objField.getType(), res)) {
|
||||
res.setReasonNotImmutable("Non Immutable field type " + objField.getType());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private boolean hasDefaultConstructor(Class<?> cls) {
|
||||
|
||||
Class<?>[] noParams = new Class<?>[0];
|
||||
try {
|
||||
cls.getDeclaredConstructor(noParams);
|
||||
return true;
|
||||
|
||||
} catch (SecurityException e) {
|
||||
// this is ok
|
||||
return false;
|
||||
|
||||
} catch (NoSuchMethodException e) {
|
||||
// this is expected for our IVO's
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.type.reflect;
|
||||
|
||||
|
||||
public class CheckImmutableResponse {
|
||||
|
||||
private boolean immutable = true;
|
||||
|
||||
private String reasonNotImmutable;
|
||||
|
||||
private boolean compoundType;
|
||||
|
||||
public String toString() {
|
||||
if (immutable) {
|
||||
return "immutable";
|
||||
} else {
|
||||
return "not immutable due to:" + reasonNotImmutable;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCompoundType() {
|
||||
return compoundType;
|
||||
}
|
||||
|
||||
public void setCompoundType(boolean compoundType) {
|
||||
this.compoundType = compoundType;
|
||||
}
|
||||
|
||||
public void setReasonNotImmutable(String error) {
|
||||
this.immutable = false;
|
||||
this.reasonNotImmutable = error;
|
||||
}
|
||||
|
||||
public boolean isImmutable() {
|
||||
return immutable;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.type.reflect;
|
||||
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ImmutableMeta {
|
||||
|
||||
private final Constructor<?> constructor;
|
||||
|
||||
private final Method[] readers;
|
||||
|
||||
public ImmutableMeta(Constructor<?> constructor, Method[] readers) {
|
||||
this.constructor = constructor;
|
||||
this.readers = readers;
|
||||
}
|
||||
|
||||
|
||||
public Constructor<?> getConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
public Method[] getReaders() {
|
||||
return readers;
|
||||
}
|
||||
|
||||
public boolean isCompoundType() {
|
||||
return readers.length > 1;
|
||||
}
|
||||
}
|
||||
@@ -1,221 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.type.reflect;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class ImmutableMetaFactory {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ImmutableMetaFactory.class);
|
||||
|
||||
public ImmutableMeta createImmutableMeta(Class<?> cls) {
|
||||
|
||||
ScoreConstructor[] scoreConstructors = scoreConstructors(cls);
|
||||
|
||||
ArrayList<RuntimeException> errors = new ArrayList<>();
|
||||
|
||||
// search the constructors in score order ...
|
||||
// ... we need to find a set of readers for each
|
||||
// ... type in the constructor
|
||||
for (ScoreConstructor scoreConstructor : scoreConstructors) {
|
||||
Constructor<?> constructor = scoreConstructor.constructor;
|
||||
|
||||
try {
|
||||
Method[] getters = findGetters(cls, constructor);
|
||||
|
||||
return new ImmutableMeta(constructor, getters);
|
||||
|
||||
} catch (NoSuchMethodException e) {
|
||||
String msg = "Error finding getter method on " + cls + " with constructor " + constructor;
|
||||
errors.add(new RuntimeException(msg, e));
|
||||
}
|
||||
}
|
||||
|
||||
String msg = "Was unable to use reflection to find a constructor and appropriate getters for" +
|
||||
"immutable type " + cls + ". The errors while looking for the getter methods follow:";
|
||||
logger.error(msg);
|
||||
|
||||
for (RuntimeException runtimeException : errors) {
|
||||
logger.error("Error with " + cls, runtimeException);
|
||||
}
|
||||
|
||||
msg = "Unable to use reflection to build ImmutableMeta for " + cls
|
||||
+ ". Associated Errors trying to find a constructor and getter methods have been logged";
|
||||
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
|
||||
private ScoreConstructor getScore(Constructor<?> c) {
|
||||
|
||||
Class<?>[] parameterTypes = c.getParameterTypes();
|
||||
int score = -1000 * parameterTypes.length;
|
||||
|
||||
for (Class<?> parameterType : parameterTypes) {
|
||||
if (parameterType.equals(String.class)) {
|
||||
// string is very generic and we would prefer
|
||||
// a more specific type if that was available
|
||||
score = score + 1;
|
||||
|
||||
} else if (parameterType.equals(BigDecimal.class)) {
|
||||
score = score - 10;
|
||||
} else if (parameterType.equals(Timestamp.class)) {
|
||||
score = score - 10;
|
||||
} else if (parameterType.equals(double.class)) {
|
||||
score = score - 9;
|
||||
} else if (parameterType.equals(Double.class)) {
|
||||
score = score - 8;
|
||||
} else if (parameterType.equals(float.class)) {
|
||||
score = score - 7;
|
||||
} else if (parameterType.equals(Float.class)) {
|
||||
score = score - 6;
|
||||
} else if (parameterType.equals(long.class)) {
|
||||
score = score - 5;
|
||||
} else if (parameterType.equals(Long.class)) {
|
||||
score = score - 4;
|
||||
} else if (parameterType.equals(int.class)) {
|
||||
score = score - 3;
|
||||
} else if (parameterType.equals(Integer.class)) {
|
||||
score = score - 2;
|
||||
}
|
||||
}
|
||||
|
||||
return new ScoreConstructor(score, c);
|
||||
}
|
||||
|
||||
private ScoreConstructor[] scoreConstructors(Class<?> cls) {
|
||||
|
||||
// find the constructor with the most number of parameters
|
||||
int maxParamCount = 0;
|
||||
|
||||
Constructor<?>[] constructors = cls.getConstructors();
|
||||
|
||||
ScoreConstructor[] score = new ScoreConstructor[constructors.length];
|
||||
|
||||
for (int i = 0; i < constructors.length; i++) {
|
||||
score[i] = getScore(constructors[i]);
|
||||
if (score[i].hasDuplicateParamTypes()) {
|
||||
String msg = "Duplicate parameter types in " + score[i].constructor;
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
if (score[i].getParamCount() > maxParamCount) {
|
||||
maxParamCount = score[i].getParamCount();
|
||||
}
|
||||
}
|
||||
|
||||
// filter out any constructors with less parameters than the max
|
||||
ArrayList<ScoreConstructor> list = new ArrayList<>();
|
||||
for (ScoreConstructor aScore : score) {
|
||||
if (aScore.getParamCount() == maxParamCount) {
|
||||
list.add(aScore);
|
||||
}
|
||||
}
|
||||
|
||||
score = list.toArray(new ScoreConstructor[list.size()]);
|
||||
|
||||
// sort into score ascending order
|
||||
Arrays.sort(score);
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
|
||||
private Method[] findGetters(Class<?> cls, Constructor<?> c) throws NoSuchMethodException {
|
||||
|
||||
Method[] methods = cls.getMethods();
|
||||
|
||||
Class<?>[] paramTypes = c.getParameterTypes();
|
||||
|
||||
Method[] readers = new Method[paramTypes.length];
|
||||
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
Method getter = findGetter(paramTypes[i], methods);
|
||||
if (getter == null && paramTypes.length == 1 && paramTypes[i].equals(String.class)) {
|
||||
getter = findToString(cls);
|
||||
}
|
||||
if (getter == null) {
|
||||
throw new NoSuchMethodException("Get Method not found for " + paramTypes[i] + " in " + cls);
|
||||
}
|
||||
readers[i] = getter;
|
||||
}
|
||||
|
||||
return readers;
|
||||
}
|
||||
|
||||
private Method findToString(Class<?> cls) throws NoSuchMethodException {
|
||||
|
||||
try {
|
||||
return cls.getDeclaredMethod("toString", new Class<?>[0]);
|
||||
} catch (SecurityException e) {
|
||||
throw new NoSuchMethodException("SecurityException " + e + " trying to find toString method on " + cls);
|
||||
}
|
||||
}
|
||||
|
||||
private Method findGetter(Class<?> paramType, Method[] methods) {
|
||||
|
||||
for (Method method : methods) {
|
||||
if (!Modifier.isStatic(method.getModifiers())) {
|
||||
if (method.getParameterTypes().length == 0) {
|
||||
// could be a getter
|
||||
String methName = method.getName();
|
||||
if (!methName.equals("hashCode") && !methName.equals("toString")) {
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (paramType.equals(returnType)) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class ScoreConstructor implements Comparable<ScoreConstructor> {
|
||||
|
||||
final int score;
|
||||
final Constructor<?> constructor;
|
||||
|
||||
private ScoreConstructor(int score, Constructor<?> constructor) {
|
||||
this.score = score;
|
||||
this.constructor = constructor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
// remove FindBugs warning
|
||||
return obj == this;
|
||||
}
|
||||
|
||||
public int compareTo(ScoreConstructor o) {
|
||||
return (score < o.score ? -1 : (score == o.score ? 0 : 1));
|
||||
}
|
||||
|
||||
public int getParamCount() {
|
||||
return constructor.getParameterTypes().length;
|
||||
}
|
||||
|
||||
public boolean hasDuplicateParamTypes() {
|
||||
|
||||
Class<?>[] parameterTypes = constructor.getParameterTypes();
|
||||
if (parameterTypes.length < 2) {
|
||||
return false;
|
||||
}
|
||||
HashSet<Class<?>> set = new HashSet<>();
|
||||
for (Class<?> parameterType : parameterTypes) {
|
||||
if (!set.add(parameterType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.type.reflect;
|
||||
|
||||
public interface KnownImmutable {
|
||||
|
||||
boolean isKnownImmutable(Class<?> cls);
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.type.reflect;
|
||||
|
||||
import com.avaje.ebean.config.CompoundType;
|
||||
import com.avaje.ebean.config.CompoundTypeProperty;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Arrays;
|
||||
|
||||
@SuppressWarnings({"rawtypes"})
|
||||
public class ReflectionBasedCompoundType implements CompoundType {
|
||||
|
||||
private final Constructor<?> constructor;
|
||||
|
||||
private final ReflectionBasedCompoundTypeProperty[] props;
|
||||
|
||||
public ReflectionBasedCompoundType(Constructor<?> constructor, ReflectionBasedCompoundTypeProperty[] props) {
|
||||
this.constructor = constructor;
|
||||
this.props = props;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "ReflectionBasedCompoundType " + constructor + " " + Arrays.toString(props);
|
||||
}
|
||||
|
||||
public Object create(Object[] propertyValues) {
|
||||
|
||||
try {
|
||||
return constructor.newInstance(propertyValues);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public CompoundTypeProperty[] getProperties() {
|
||||
return props;
|
||||
}
|
||||
|
||||
public Class<?> getPropertyType(int i) {
|
||||
return props[i].getPropertyType();
|
||||
}
|
||||
|
||||
public Class<?> getCompoundType() {
|
||||
return constructor.getDeclaringClass();
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user