Compare commits

...
122 Commits
Author SHA1 Message Date
Rob Bygrave f9ba6f9a3a [maven-release-plugin] prepare release ebean-10.1.5 2017-01-12 00:46:11 +13:00
Rob Bygrave 2fa4345742 #945 - Invalid SQL when using @Aggregation with a fetch() to a ManyToOne - missing columns in GROUP BY 2017-01-12 00:42:27 +13:00
Rob Bygrave d9147327c1 #944 - Incorrect join (should be outer join) when predicate only path traverses an optional relationship to a mandatory relationship 2017-01-11 23:21:50 +13:00
Rob Bygrave 5ad9a611f9 #941 - @Transactional( type = TxType.MANDATORY ) creates a new transaction even if there is one available 2017-01-11 22:41:22 +13:00
Rob Bygrave 3fb497b651 No effective change - style, merge ifs 2017-01-11 22:17:29 +13:00
Rob Bygrave fbfe5d1ff8 #943 - Refactor internals - Performance tweak / tidy for WhoCreated, WhoModified on OneToMany connections. #942 2017-01-11 21:42:23 +13:00
Rob Bygrave b6f21f8649 No effective change - refactor merge AnnotationFields initWhoModified() and initWhoCreated() methods 2017-01-11 20:59:11 +13:00
Nagy VilmosandRob Bygrave 8fd04807c7 WhoCreated, WhoModified on OneToMany connections. (#942)
* WhoCreated, WhoModified on OneToMany connections.

* PostgreSQL table name fix in tests.
2017-01-11 20:54:20 +13:00
Rob Bygrave e49c42302a [maven-release-plugin] prepare for next development iteration 2017-01-09 22:39:47 +13:00
Rob Bygrave d96abece75 [maven-release-plugin] prepare release ebean-10.1.4 2017-01-09 22:39:36 +13:00
Rob Bygrave c953da637e Bump ebean-annotation to 2.2 for meta-annotation support on @Formula 2017-01-09 22:37:10 +13:00
Rob Bygrave 8d39b0a996 #940 - Allow findNative to use @Formula properties (add test for MySql := use with RawSql and findNative) 2017-01-09 22:29:15 +13:00
Rob Bygrave 0efcf1eeb3 Merge branch 'master' of github.com:ebean-orm/ebean 2017-01-09 19:40:23 +13:00
Rob Bygrave 335cef870f #939 - Make ModifyAwareSet serializable ... (for serializable entity beans with @DbJson etc) 2017-01-09 19:39:54 +13:00
Michael BenzandRob Bygrave 4c40962f04 MigrationXmlWriter adds DOCTYPE xml to avoid warning of missing external DTD in eclipse IDE. (#937) 2017-01-05 09:16:39 +13:00
Thibault MeyerandRob Bygrave 9be0d22cfb Upgrade provided dependencies (#936)
- javax.validation from 1.0.0.GA to 1.1.0.Final
- servlet-api from 2.4 to javax.servlet-api 3.1.0
- joda-time from 1.6 to 2.9.7
- postgresql from 9.4.1202-jdbc41 to 9.4.1212.jre7
- h2 from 1.4.192 to 1.4.193

Signed-off-by: Thibault Meyer <meyer.thibault@gmail.com>
2017-01-01 19:57:02 +13:00
Thibault MeyerandRob Bygrave 2893d73fad Upgrade test dependencies (#935)
- avaje-agentloader from 2.1.1 to 2.1.2
- avaje-moduuid from 1.2 to 2.1
- commons-io from 2.4 to 2.5
- hsqldb from 2.0.0 to 2.3.4
- mysql-connector-java from 5.1.36 to 6.0.5
- sqlite-jdbc from 3.8.11.2 to 3.15.1

Signed-off-by: Thibault Meyer <meyer.thibault@gmail.com>
2017-01-01 19:55:56 +13:00
Thibault MeyerandRob Bygrave 33d66ea9d1 Upgrade antlr4-runtime to prior version 4.6 (#934)
Signed-off-by: Thibault Meyer <meyer.thibault@gmail.com>
2017-01-01 19:54:25 +13:00
Nagy VilmosandRob Bygrave 073ea9c550 SQL Server boolean mapping fix (#932) 2017-01-01 19:52:57 +13:00
Rob Bygrave 8467934021 [maven-release-plugin] prepare for next development iteration 2016-12-23 16:14:19 +13:00
Rob Bygrave 96ba63407f [maven-release-plugin] prepare release ebean-10.1.3 2016-12-23 16:14:10 +13:00
Rob Bygrave 88df6ffc6e #931 - Refactor internals - DefaultTypeManager ... 2016-12-23 13:33:11 +13:00
Rob Bygrave 3efcfec300 #930 - Refactor (renames etc) for SQL Server History support 2016-12-23 13:18:15 +13:00
Rob BygraveandGitHub e51eb00889 Merge pull request #929 from vilmosnagy/feature/sqlServer2016History
SqlServer 2016 history support.
2016-12-23 13:00:23 +13:00
vilmos.nagy 9ae27ddcdd SqlServer 2016 history support. 2016-12-22 19:22:44 +01:00
Rob Bygrave b9516e64a3 #928 - Pom - change over to io.ebean persistence-api from org.avaje.ebean one. 2016-12-22 23:45:35 +13:00
Rob Bygrave f7f5552bf0 #927 - Pom - bump ebean-dbmigration to 10.1.2 2016-12-22 23:38:18 +13:00
Rob Bygrave adec2ab1b8 #926 - Pom - bump avaje-datasource to 1.1.4 2016-12-22 22:42:24 +13:00
Rob Bygrave da6d7284f8 No effective change - update Readme to maven groupId io.ebean 2016-12-22 00:00:35 +13:00
Rob Bygrave 1c160fea5a No functional change - update enhancement agent to 10.1.2 2016-12-21 23:38:32 +13:00
Rob Bygrave cc87de76d7 [maven-release-plugin] prepare for next development iteration 2016-12-21 00:09:30 +13:00
Rob Bygrave 70b380e6e7 [maven-release-plugin] prepare release ebean-10.1.2 2016-12-21 00:09:19 +13:00
Rob Bygrave 3e419d3e3a No effective change - test ebean.properties back to H2 for default 2016-12-20 21:31:02 +13:00
Rob Bygrave 7e2be20b6e #925 - Change generated SQL for H2, Postgres and MySql to not use column alias' 2016-12-20 21:30:00 +13:00
Rob Bygrave ab2d5fb4c8 No effective change - update test to use trimmed sql (trim out sql column alias to allow it to be optional) 2016-12-20 21:14:12 +13:00
Rob Bygrave 809901ff13 No effective change - update H2 specific test 2016-12-20 21:02:36 +13:00
Rob Bygrave fcc58d77e8 No effective change - update tests using Platform enum rather than name 2016-12-20 20:41:55 +13:00
Rob Bygrave bc93a82b1a #900 - Error - Can't fetch JsonDB field - org.postgresql.util.PSQLException: ERROR: could not identify an equality operator for type json 2016-12-20 03:00:08 +13:00
Rob Bygrave 84e1e12b66 #900 - Error - Can't fetch JsonDB field - org.postgresql.util.PSQLException: ERROR: could not identify an equality operator for type json 2016-12-20 02:59:47 +13:00
Rob Bygrave 2eb0c12213 #924 - Bump ebean-dbmigration dependency to 10.1.1 (sql server fix) 2016-12-19 22:19:53 +13:00
Rob Bygrave 4941134ce1 #922 - NPE Issue with ebean-elastic and multi-tenant Ebean ... NPE at DLoadContext line 96 2016-12-14 00:53:30 +13:00
Rob Bygrave cf37fda3f4 #921 - Refactor internals - Change internal use of "findRowCount" to "findCount" 2016-12-13 19:51:11 +13:00
Rob Bygrave f429811f79 [maven-release-plugin] prepare for next development iteration 2016-12-12 02:10:10 +13:00
Rob Bygrave 70fd988d8c [maven-release-plugin] prepare release ebean-10.1.1 2016-12-12 02:09:55 +13:00
Rob Bygrave fe4167ed60 #920 - Update DBMigration to io.ebean 2016-12-12 02:07:52 +13:00
Rob Bygrave 0eef69a277 #920 - Change logger package to io.ebean (e.g. for logging SQL instead of org.avaje.ebean.SQL use io.ebean.SQL) 2016-12-11 23:42:38 +13:00
Rob Bygrave 76bfd805c0 #919 - io.ebean package, use ebean-annotation 2016-12-11 23:34:29 +13:00
Rob Bygrave 971e2dc91b #919 - io.ebean package initial 2016-12-11 23:23:22 +13:00
Rob Bygrave 5821dc96b9 [maven-release-plugin] prepare for next development iteration 2016-12-10 00:08:52 +13:00
Rob Bygrave e027110006 [maven-release-plugin] prepare release ebean-9.5.1 2016-12-10 00:08:42 +13:00
Rob Bygrave b5e6e9a66c Bump pom to 9.5.1-SNAPSHOT 2016-12-10 00:06:09 +13:00
Rob Bygrave 514047e680 #918 - Remove DbMigrationConfig.generateOnStart() ... migrate to offline generation 2016-12-10 00:04:41 +13:00
Rob Bygrave a727a98a21 #917 - ENH: Add findNative() ... ala automatic mapping of native SQL into object graphs / paths. 2016-12-09 23:45:57 +13:00
Rob Bygrave e75b5e8b30 #916 - Refactor internals - bump use of 31 in hashes to 92821 2016-12-08 23:28:58 +13:00
Rob Bygrave ad0e085ff5 #915 - Refactor internals - Change update plan to string key 2016-12-08 23:23:19 +13:00
Rob Bygrave 322a2f500d No effective change - move method - BeanDescriptor.merge() 2016-12-08 23:01:05 +13:00
Rob Bygrave 1c7454d249 [maven-release-plugin] prepare for next development iteration 2016-12-08 22:26:13 +13:00
Rob Bygrave e1efca6736 [maven-release-plugin] prepare release ebean-9.4.2 2016-12-08 22:26:04 +13:00
Rob Bygrave 8ae61074ad #914 - Fix multi-tenancy support such that it automatically propagates the tenantId for lazy loading 2016-12-08 22:04:18 +13:00
Rob Bygrave c3bc0c4975 #913 - IllegalArgumentException: No enum constant com.avaje.ebean.config.Platform.HSQLDB 2016-12-07 21:58:07 +13:00
Rob Bygrave 611bba272a Modify testAggregationCount to make MySql happy - avoid count(u1.*) 2016-12-07 21:39:26 +13:00
Rob Bygrave 4c9ec38c88 [maven-release-plugin] prepare for next development iteration 2016-12-06 23:44:35 +13:00
Rob Bygrave e2731a99be [maven-release-plugin] prepare release ebean-9.4.1 2016-12-06 23:44:26 +13:00
Rob Bygrave 7d56df3b23 Bump pom to 9.4.1-SNAPSHOT 2016-12-06 23:43:37 +13:00
Rob Bygrave bebef48332 Update test ebean.properties 2016-12-03 22:03:55 +13:00
Rob Bygrave f66ea12fbf #912 - Refactor - move platform specfic code into subpackages 2016-12-03 15:39:24 +13:00
Rob Bygrave b08f1580f9 #910 - SQL Server update - Add ANSI based row limiter (2012+) and make as default platform 2016-12-03 15:10:11 +13:00
Rob Bygrave 707912f7ad No effective change - add some wait into history test (TestHistoryInsert) 2016-12-03 13:55:45 +13:00
Rob Bygrave 5ce31b16d4 #910 - SQL Server update - refactor rename platform to SqlServerPlatform 2016-12-03 13:30:17 +13:00
Rob Bygrave a5945b1d5d #911 - SQL Server - remove old MsSqlServer2000Platform (expecting users migrated to SQL Server 2005+) 2016-12-03 13:24:52 +13:00
Rob Bygrave b8577ae6d0 #910 - SQL Server update - tidy whitespace for MsSqlServer2005SqlLimiter 2016-12-03 13:19:15 +13:00
Rob Bygrave 14dedb7b9a #910 - SQL Server update 2016-12-03 13:18:33 +13:00
Rob Bygrave 2dbd543127 #909 - @Lob with @Size ... produces incorrect DDL for Postgres 2016-12-03 08:42:46 +13:00
Rob Bygrave cc989af1c6 #908 - Remove support for Immutable Compound Values 2016-12-02 22:49:00 +13:00
Rob Bygrave 0aad285f35 #907 - Remove Model.Finder ... migrate to Finder 2016-12-02 21:47:30 +13:00
Rob Bygrave a3754e31f2 #906 - Add NamingConvention Support for JoinColumn (OneToMany, ManyToOne) - was PR #887 2016-12-02 21:21:19 +13:00
Rob Bygrave 1dd0f3f609 [maven-release-plugin] prepare for next development iteration 2016-12-01 21:04:18 +13:00
Rob Bygrave f9b381b10a [maven-release-plugin] prepare release ebean-9.3.1 2016-12-01 21:04:09 +13:00
Rob Bygrave 6e2d7a89f8 #493 - ENH: Multi-tenant support - update bootup DataSource check 2016-12-01 21:02:52 +13:00
Rob Bygrave dfa336239f #493 - ENH: Multi-tenant support - update bootup DataSource check 2016-12-01 20:43:47 +13:00
Rob Bygrave 3a28dd0d55 #493 - ENH: Multi-tenant support - nice error when explicit DatabasePlatform not set, turn off DDL run automatically 2016-12-01 20:23:42 +13:00
Rob Bygrave 502e9daaf2 #493 - ENH: Multi-tenant support - cache tidy up 2016-12-01 00:27:32 +13:00
Rob Bygrave b7c92aec3d No effective change - rename var 2016-11-30 23:09:31 +13:00
Rob Bygrave c0341458c3 #493 - ENH: Multi-tenant support 2016-11-29 01:34:45 +13:00
Rob Bygrave aecac211d9 pom bump ebean-annotation to 1.4 2016-11-28 22:55:57 +13:00
Rob Bygrave c46b235eff #904 - ENH: Add @PreSoftDelete @PostSoftDelete ... such that methods on beans can be used for these callbacks 2016-11-28 22:24:17 +13:00
Rob Bygrave a585447dc9 #903 - Refactor: Internals, BeanPropertyAccess getter and setter methods can be cached and don't need constructor 2016-11-28 22:02:45 +13:00
Rob Bygrave 85bb05d90e Bump ebean-annotation to 1.4-SNAPSHOT 2016-11-28 21:51:37 +13:00
Rob Bygrave 027dd1eba9 #899 - @Unmapped JSON, handle wildcard use (Kotlin Any) 2016-11-28 21:29:16 +13:00
Rob Bygrave 588d5c5cfa #902 - EJsonWriter.write(Object object, Writer writer) ... closes the writer but should not 2016-11-28 21:27:14 +13:00
Rob Bygrave 7ba86f7cf2 #901 - ENH: Use "db" as default EbeanServer name 2016-11-26 00:54:11 +13:00
Rob Bygrave 609dc233a8 #899 - ENH: Add @UnmappedJson support ... (mostly for document store only use / ElasticSearch) 2016-11-25 23:58:55 +13:00
Rob Bygrave 5d7c287821 Bump pom to 9.3.1-SNAPSHOT 2016-11-25 21:18:35 +13:00
Rob Bygrave ff325057c4 #882 - ENH: Support document store only - Add Query.setDocIndexName() 2016-11-25 21:18:16 +13:00
Rob Bygrave cc6469851b #897 - Remove @EmbeddedColumns ... replace with @Embedded(prefix="...") 2016-11-24 22:05:27 +13:00
Rob Bygrave 7f31104439 #827 - ENH: Add support for AttributeConverter from JPA 2.1 2016-11-24 20:21:48 +13:00
Rob Bygrave 2ab98a922d #896 - Bump persistence API 2.1.2 with @Repeatable annotations (most notably, @AttributeOverride and @JoinColumn) 2016-11-24 19:47:08 +13:00
Rob Bygrave 063c1825ca #895 - Refactor: Remove unnecessary coalesce on soft delete (as predicate on left join etc) 2016-11-24 17:19:46 +13:00
Rob Bygrave d0e9c6a218 No effective change - explicit import required 2016-11-24 02:22:23 +13:00
Rob Bygrave 81d829f74e #894 - ENH: Add support for @OneToMany orphanRemoval = true (which is the same as @PrivateOwned) 2016-11-24 02:21:54 +13:00
Rob Bygrave b4a0d9f5ea #893 - Move to persistence API version 2.1.1 2016-11-24 02:17:54 +13:00
Rob Bygrave f0044aba91 #892 - Refactor: Replace Ebean's QueryEachWhileConsumer with java.util.function.Predicate 2016-11-24 00:19:16 +13:00
Rob Bygrave 6f322dcfb2 #891 - Refactor: Replace Ebean's QueryEachConsumer with java.util.function.Consumer 2016-11-24 00:02:23 +13:00
Rob Bygrave a391a25b7f No effective change - update Javadoc on QueryIterator with try with resources 2016-11-23 23:44:54 +13:00
Rob Bygrave 4af350bd14 No effective change - modify one of the QueryIterator tests to use try with resources 2016-11-23 23:40:57 +13:00
Rob Bygrave cdb319f0ef #885 - DbMigrationConfig.loadSettings config has wrong 2016-11-23 23:30:23 +13:00
Rob Bygrave 60ed64cb37 #883 Soft-delete when using fetch (not including soft deleted children) 2016-11-23 23:12:37 +13:00
Rob Bygrave 79efe006ec #888 - Move annotations - remove types that are now in ebean-annotation 2016-11-23 22:05:05 +13:00
Rob Bygrave 70f929949d #888 - Move annotations - bump dependency to ebean-annotation 1.1 (released) 2016-11-23 21:58:17 +13:00
Rob Bygrave d7916eb3ee #888 - Move Ebean annotations into a separate module (initial remove) 2016-11-23 20:36:00 +13:00
Rob Bygrave f724982776 #889 - Refactor: Change @Where @Formula to use Platform (enum) rather than DatabasePlatform (class) 2016-11-23 20:33:35 +13:00
Rob Bygrave 182a47697e #882 - ENH: Support document store only use (ie. Use @DocStore without @Entity and persist, fetch only against ElasticSearch with no SQL DB) 2016-11-21 00:17:28 +13:00
Rob Bygrave d6b37bdf83 No effective change - format only 2016-11-21 00:00:00 +13:00
Rob BygraveandGitHub 0bc2dc7d4c Merge pull request #847 from FOCONIS/feature/platform-dependent-annotations
platform dependent @Formula and @Where annotations
2016-11-20 20:56:27 +13:00
Roland Praml 1263f0f049 Merge remote-tracking branch 'ebean/master' into feature/platform-dependent-annotations
# Conflicts:
#	src/main/java/com/avaje/ebean/annotation/Formula.java
#	src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationParser.java
2016-11-17 13:31:22 +01:00
Rob Bygrave f4b32e89f5 [maven-release-plugin] prepare for next development iteration 2016-11-17 23:55:50 +13:00
Roland Praml 4fa9f739d4 Merge remote-tracking branch 'ebean/master' into feature/platform-dependent-annotations
# Conflicts:
#	pom.xml
2016-11-04 09:42:37 +01:00
Roland Praml ba0509dadc Merge remote-tracking branch 'ebean/master' into feature/platform-dependent-annotations 2016-11-02 14:22:24 +01:00
Roland Praml 64c67e3755 removed debug code and completed documentation 2016-11-01 00:43:17 +01:00
Roland Praml 6142dd34f4 No effective code change - removed unused imports 2016-11-01 00:27:12 +01:00
Roland Praml 06e265ec47 Provide test case 2016-11-01 00:02:44 +01:00
Roland Praml 7b19973836 Better support for repeatable annotations (needs Java 8) 2016-10-31 23:36:43 +01:00
2207 changed files with 15146 additions and 16656 deletions
+4 -4
View File
@@ -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
* [![Maven Central : ebean](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean) - ebean
* [![Maven Central : ebean-agent](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent) - ebean-agent
* [![Maven Central : ebean-maven-plugin](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin) - ebean-maven-plugin
* [![Maven Central : ebean](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean) - ebean
* [![Maven Central : ebean-agent](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-agent) - ebean-agent
* [![Maven Central : ebean-maven-plugin](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean-maven-plugin) - ebean-maven-plugin
+38 -32
View File
@@ -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>
-886
View File
@@ -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(&quot;Roberto&quot;);
* 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);
}
}
}
-50
View File
@@ -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;
@@ -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();
}
}
@@ -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);
}
}
@@ -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);
}
}
}
@@ -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);
}
}
}
@@ -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;
@@ -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);
}
@@ -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