Compare commits

...
207 Commits
Author SHA1 Message Date
rob bygrave 1e88a52208 [maven-release-plugin] prepare release ebean-10.4.1 2017-07-05 21:40:58 +12:00
rob bygrave e770a42175 Bump to 10.4.1-SNAPSHOT (due to ServerConfig h2ProductionMode removal) 2017-07-05 21:39:12 +12:00
Thibault MeyerandRob Bygrave 35b467c04f JSON simple implementation for MSSQL (#1057)
- Use JSON_VALUE
  - Use NVARCHAR type

Signed-off-by: Thibault Meyer <meyer.thibault@gmail.com>
2017-07-03 20:45:48 +12:00
Roland PramlandRob Bygrave 2001539755 Sqlserver support (#1053)
* made some tests sqlserver ready (No effective code change in src/main)

* FIX enhance packages and let all testcases inherit from BaseTestCase, so that they can be launched directly from eclipse

* ADD sqldriver in pom and datasource

* FIX: DDL-generation for sqlserver - not yet all sqlserver tests passing
mvn verify -Ddatasource.default=mssql => Tests run: 1980, Failures: 22, Errors: 44, Skipped: 16

* BaseDdlHandlerTest checks against correct sqlserver-ddl now
2017-07-03 20:27:37 +12:00
rob bygrave e49c4bfe5a #867 - ENH: Add ability to globally use quoted identifiers on all tables and columns 2017-07-02 21:07:58 +12:00
rob bygrave 15be31fd5f #1051 - Remove ServerConfig h2ProductionMode ... means for testing with h2 explicitly set ddlGenerate and ddlRun 2017-07-02 11:42:56 +12:00
rob bygrave 4777ec46be #1050 - Bump db-migration to 10.1.10 2017-07-02 11:12:03 +12:00
rob bygrave 80ab731aec Use older postgres jdbc driver 2017-06-25 22:56:21 +12:00
rob bygrave 080bafe18f #1048 - Fix connection leak on failed findIterate() 2017-06-25 22:39:04 +12:00
rob bygrave e913f88f52 Fix test - TestCommitAndContinue ... close extra transactions used in asserts 2017-06-25 21:43:37 +12:00
rob bygrave e94c5484a0 #1047 - Fix connection leak on failed beginTransaction() 2017-06-25 21:42:51 +12:00
rob bygrave 4af00c51d3 travis - dist: trusty ... to get PG 9.6 2017-06-25 19:57:31 +12:00
rob bygrave 23d1256dbf Update to postgres 9.6 for travis test runs 2017-06-25 19:43:05 +12:00
rob bygrave ed0ef46d2e No effective change - update postgresql jdbc driver 2017-06-25 19:03:07 +12:00
rob bygrave 1860ded735 [maven-release-plugin] prepare for next development iteration 2017-06-25 16:01:50 +12:00
rob bygrave d432854b82 [maven-release-plugin] prepare release ebean-10.3.2 2017-06-25 16:01:37 +12:00
rob bygrave 93582c8ea3 Downgrade postgres jdbc driver for commit and continue test 2017-06-25 15:54:14 +12:00
rob bygrave 520d35b1d6 #963 - NullPointerException on no version provided (when setVersion(null) is used) 2017-06-25 14:44:13 +12:00
rob bygrave 8ca3599cbf #1046 Bump DB migration to 10.1.9 - fix for Checksum mismatch does not stop migration 2017-06-25 14:29:46 +12:00
rob bygrave 283ae74219 Update javadoc on ScalarTypeConverter. Should look to officially deprecate this in favor of AttributeConverter. 2017-06-24 11:35:58 +12:00
rob bygrave cebd3f92a4 #1045 - MySql - DbMigration generate wrong comment syntax - should be alter table comment = syntax 2017-06-24 11:23:21 +12:00
rob bygrave 4b2481d3ea #1039 Fix for - reset of dirty flag on L2 cached entities after lazy load 2017-06-23 23:20:17 +12:00
rob bygrave f1f2a416d3 No effective change - reformat only 2017-06-23 23:19:22 +12:00
rob bygrave 74dd97a55f No effective change 2017-06-23 23:18:57 +12:00
rob bygrave 3f04f7f363 Merge branch 'master' of https://github.com/SamhammerAG/ebean into SamhammerAG-master 2017-06-23 19:52:55 +12:00
rob bygrave 800f854a12 #1043 Additional test for RawSql with upper case SQL 2017-06-23 19:46:47 +12:00
rob bygrave bef9e6d54f Merge branch 'master' of github.com:ebean-orm/ebean 2017-06-23 19:43:45 +12:00
Tigran_DadaiantsandRob Bygrave 0e4c0ae6c3 #1043 RawSql should automatically map upper-case column alias to lower-case bean property (#1044) 2017-06-23 19:43:15 +12:00
rob bygrave a0ea9887df No effective change - remove unused imports 2017-06-23 19:37:24 +12:00
Roland PramlandRob Bygrave 0413c22e6e no effective code change - fixed warnings about serialization, override, raw-types (#1032) 2017-06-23 19:33:03 +12:00
rob bygrave 989ae44a6d Merge branch 'pr/id-in-as-collection' of https://github.com/FOCONIS/ebean into FOCONIS-pr/id-in-as-collection 2017-06-23 19:28:25 +12:00
rob bygrave 100d314e63 #1035 Update for - FIX: deleting and adding same bean in beanCollection leads to deletion in DB
If use Modify mode we need to listen for both adds and removes to support sorting (can't rely on undoDelete() due to ordering)
2017-06-19 23:34:44 +12:00
rob bygrave dbf4e99187 #1035 tests for - FIX: deleting and adding same bean in beanCollection leads to deletion in DB 2017-06-19 23:32:58 +12:00
Roland PramlandRob Bygrave 7b8a85106c FIX: deleting and adding same bean in beanCollection leads to deletion in DB (#1035) 2017-06-19 22:50:20 +12:00
rob bygrave 58c5f01e2b #1042 - JtaTransaction is TenantMode.DB aware 2017-06-19 22:28:15 +12:00
Roland PramlandRob Bygrave bc74d35651 FIX: correct behavior of "startsWith, "contains" etc (#1031)
* FIX: correct behavior of "startsWith" if string contains "like"-wildcards

* Removed likeClasues with disabled escaping in database platforms as bind values are properly escaped now.
2017-06-19 22:21:26 +12:00
Roland PramlandRob Bygrave a1f95bf25e Pr/id in as collection2 (#1034)
* ENH: Changed  idIn(List) to idIn(Collection)

* ADD: sanity checks in IdBinder & special case if ID-list is empty
2017-06-19 22:05:56 +12:00
rob bygrave c454e1f8a7 No effective change - add test 2017-06-19 21:53:35 +12:00
Koen De GrooteandRob Bygrave 5a3669e1db Noticed that this boolean parameter was ignored. (#1041)
After some quick analysis, implemented that way it probably should be used.

Of course, this could have been on purpose, please advise.
2017-06-19 21:39:58 +12:00
rob bygrave 7a2e0b3695 Bump to the later agent 2017-06-19 21:34:18 +12:00
AWoelfel ce6d6269cd Step to reproduce reset of dirty flag on L2 cached entities after lazy load 2017-06-08 15:07:32 +02:00
Roland Praml 7d800b7080 ENH: Changed idIn(List) to idIn(Collection) 2017-05-29 15:22:48 +02:00
rob bygrave 136154e247 [maven-release-plugin] prepare for next development iteration 2017-05-21 21:56:29 +12:00
rob bygrave 0a5ce1bee8 [maven-release-plugin] prepare release ebean-10.3.1 2017-05-21 21:56:16 +12:00
Koen De GrooteandRob Bygrave b4e2c89e2d Moved a few variables closer to the point where they are actually used, but only in cases where this means moving them past a (potential) return/throw statement. (#1029) 2017-05-21 21:51:58 +12:00
Koen De GrooteandRob Bygrave 9e2923f571 For debug and trace levels, either added isEnabled check or made arguments parameterized. (#1028) 2017-05-21 21:50:13 +12:00
rob bygrave d0c1ae76f4 #955 - Migration "add column" DDL with check constraint is missing constraint name 2017-05-21 01:23:55 +12:00
rob bygrave fe9500e6d0 #1011 - Create valid migration scripts for non-Postgres databases and @DbArray columns.
Merge branch 'test/dbarray-create-migration' of https://github.com/FOCONIS/ebean into FOCONIS-test/dbarray-create-migration

commit 3a8f32b173
Author: Michael Benz <michael.benz@foconis.de>
Date:   Wed Apr 19 18:16:51 2017 +0200

    adding dbmigration ddlgeneration test for Ebean @DbArray extension.
2017-05-20 23:40:02 +12:00
rob bygrave 79f7c73983 #999 - Refactor tidy for ... @DiscriminatorColumn columnDefinition is ignored for DDL generation 2017-05-20 15:22:06 +12:00
rob bygrave d04954e46f #999 - @DiscriminatorColumn columnDefinition is ignored for DDL generation 2017-05-20 15:03:21 +12:00
rob bygrave 88c6ec358c #981 Additional refactor to 981 - use composed key in multi tenant environment - Expose TenantAwareKey handling for plugins 2017-05-20 13:53:46 +12:00
Roland PramlandRob Bygrave d3ea01b76e use composed key in multi tenant environment instead a cache per tenant (#981) 2017-05-20 12:35:34 +12:00
rob bygrave 0c1a9786a3 #996 Add findOne() and findOneOrEmpty() - SqlQuery 2017-05-19 23:48:41 +12:00
rob bygrave db298a349e #996 Add findOne() and findOneOrEmpty() 2017-05-19 23:38:40 +12:00
rob bygrave c1bed9f578 #996 Add findOne() and findOneOrEmpty() 2017-05-19 23:38:24 +12:00
rob bygrave c7cbe4ead8 Read the new @Length annotation 2017-05-19 23:00:10 +12:00
rob bygrave 4064aaf714 #1004 - Ebean migrations can not be executed if they contain ';' into a string 2017-05-15 22:18:24 +12:00
rob bygrave 6ad808003a Refactor - remove unused ebeandeploy.dtd 2017-05-14 21:11:00 +12:00
rob bygrave 70de6101db Refactor, remove unused SqlReservedWords 2017-05-14 21:10:24 +12:00
Roland PramlandRob Bygrave 933595ceea ADD: Testcases for "fetchDistinct" (#1024)
* ADD: Testcases for "fetchDistinct"

* Updated the tests for #1024
2017-05-14 17:39:07 +12:00
rob bygrave 461c2aef60 #946 - Treat primitive numbers (long, int, short, float, double) as NOT NULL wrt DDL generation 2017-05-14 01:31:28 +12:00
Rob Bygrave 0c49b6514c [maven-release-plugin] prepare for next development iteration 2017-05-11 23:54:47 +12:00
Rob Bygrave 0ec425928b [maven-release-plugin] prepare release ebean-10.2.3 2017-05-11 23:54:33 +12:00
rob bygrave 711701932a #1023 - Bug with findSingleAttributeList() when used against @ManyToOne / foreign key 2017-05-11 23:20:19 +12:00
Koen De GrooteandRob Bygrave 951e517caf Replaced Tail Recursion while while/true loops. (#1019) 2017-05-11 22:07:10 +12:00
rob bygrave 8cef603d1c #1021 Fix for query plan clash with single inheritance and cached query 2017-05-11 21:57:24 +12:00
Rien Nentjes 2a64a02211 Discriminator query cache error 2017-05-04 14:16:38 +02:00
Rob Bygrave 67ef0cd5d9 Refactor - repackage / move test code only 2017-05-01 20:39:49 +12:00
Rob Bygrave 9f2334362a [maven-release-plugin] prepare for next development iteration 2017-04-30 23:15:34 +12:00
Rob Bygrave 44ff304423 [maven-release-plugin] prepare release ebean-10.2.2 2017-04-30 23:15:20 +12:00
Roland PramlandRob Bygrave f9c70d2a2b Fix/select distinct cascaded fetch (#1015)
Fix/select distinct cascaded fetch with findSingleAttributeList() on associated property path
2017-04-30 23:07:35 +12:00
Rob Bygrave e51f7f11f1 Fix tests for #1016 2017-04-30 22:56:07 +12:00
Yuan XueguiandRob Bygrave 54ef0e7465 FIX BUG:and blank space after 1=1 (#1016)
FIX BUG:and blank space after 1=1 (Noop expression for equals null with @SoftDelete)
2017-04-30 22:50:03 +12:00
OndrejPacayandRob Bygrave 63def00626 #1012 - Filtering on embedded values in a joined table does not produce a sql join (#1013) 2017-04-30 22:33:02 +12:00
Koen De GrooteandRob Bygrave 335c4de109 Static code analysis. (#1017) 2017-04-30 14:47:02 +12:00
Rob Bygrave a120c2aaee #947 - Treat primitive boolean as NOT NULL - DDL as not null 2017-04-25 13:17:58 +12:00
Koen De GrooteandRob Bygrave 43408fcb87 Java language level updates concerning Maps. (#1008)
* Java language level updates concerning Maps.

* Reverts when comments indicated no sync can happen.
2017-04-22 15:48:46 +12:00
Koen De GrooteandRob Bygrave 8432f7b0d5 Some changes that are possible in Java language level 7 and 8. (#1007) 2017-04-22 15:43:56 +12:00
Koen De GrooteandRob Bygrave bdd7884f42 Changes for ArrayStack. (#1006)
Removed old inspection suppression.
2017-04-22 15:42:25 +12:00
Alexander WinklerandRob Bygrave 485e62b5d6 Added multi tenant catalog support. (#987) 2017-04-01 00:41:08 +13:00
Roland PramlandRob Bygrave 0557e6cd08 Wrong alter table / alter column DDL was generated (#988)
* FIX: alter column type uses correct DB-type now.

* FIX: Oracle test case
2017-04-01 00:38:23 +13:00
Koen De GrooteandRob Bygrave b821702b8d Moving defaultservercache implementation to use nanoseconds to determine whether or not something needs to be evicted from the cache. (#998)
The old implementation used System.currentTimeMillis(), which might be unreliable, for instance during a jump in DST.
Thanks @rPraml for noticing and suggesting the fix.
2017-04-01 00:30:01 +13:00
Rob Bygrave c5b23c321e #1002 - Bump ebean-dbmigration to 10.1.6 (better support for schema & sql server) 2017-04-01 00:28:46 +13:00
Rob Bygrave 964d2d00a2 #1001 - Add @Length and @NotNull, (plus move @Transactional to ebean-annotation) 2017-03-31 21:56:30 +13:00
Rob Bygrave 1778afa17d [maven-release-plugin] prepare for next development iteration 2017-03-13 23:15:12 +13:00
Rob Bygrave 0d9f9982b7 [maven-release-plugin] prepare release ebean-10.2.1 2017-03-13 23:15:00 +13:00
Rob Bygrave 7178085680 #993 - ENH: Add flush() to EbeanServer and Model to make it more accessible than the current transaction.flushBatch() - Add Ebean.flush() 2017-03-13 23:13:41 +13:00
Rob Bygrave 4d82b86f81 #993 - ENH: Add flush() to EbeanServer and Model to make it more accessible than the current transaction.flushBatch() 2017-03-13 23:07:17 +13:00
Rob Bygrave 1d99a5c5a4 #992 - API Change - Change Transaction.close() to throw PersistenceException rather than IOException 2017-03-13 22:10:08 +13:00
Rob Bygrave 41a7f2c97e Bump to 10.2.1-SNAPSHOT 2017-03-13 21:11:34 +13:00
Rob Bygrave c8d01828b3 #991 ENH: Add forUpdateNoWait() and forUpdateSkipLocked() options ... #528 ENH: Improve exception handling 2017-03-13 20:50:22 +13:00
Péter CsubákandRob Bygrave a3dbd4538f Wrong cast to query and childid propblem fix (#990) 2017-03-11 12:21:34 +13:00
Rob Bygrave 3051412d90 #989 - ENH: Support @DbArray with Set ... (addition to the existing List support) 2017-03-10 20:50:07 +13:00
Rob Bygrave a22eb555d0 [maven-release-plugin] prepare for next development iteration 2017-03-05 22:44:48 +13:00
Rob Bygrave cb89300027 [maven-release-plugin] prepare release ebean-10.1.7 2017-03-05 22:44:37 +13:00
Rob Bygrave 27cb0d062d Bump ebean-dbmigration to 10.1.4 2017-03-05 22:42:00 +13:00
Rob Bygrave 140c1dd965 #985 - IllegalArgumentException when using @DbArray of type List<String> with @ChangeLog 2017-03-05 11:40:17 +13:00
Rob Bygrave 75b9e748f4 #985 - IllegalArgumentException when using @DbArray of type List<String> with @ChangeLog 2017-03-05 11:40:08 +13:00
Koen De GrooteandRob Bygrave 289c0253b1 Warning suppressions. (#986)
* Went over compilation warnings with Xlint. Only imports for DateMidnight are left, as they cannot receive a suppression annotation.

Not doing this one.

* Doing inline fully qualified path of the deprecated path.
2017-03-05 11:08:45 +13:00
Rob Bygrave 07ce758302 #984 - ENH: DocumentStore API - add RawDoc with findEach() and findEachWhile() 2017-03-02 01:12:02 +13:00
Rob Bygrave d91729f65d #983 - Add credentials configuration support for document store (like basic auth for ElasticSearch) 2017-03-01 22:15:28 +13:00
Rob Bygrave 9e64d09e07 Update maven plugin (with separate testEnhance goal and enhance goal) 2017-03-01 22:07:47 +13:00
Roland PramlandRob Bygrave 5f63d5c35f Fix multi tenant bean change (#982)
* FIX: beanChange has tenant-id

* FIX: NPE in DefaultServer.currentTenantId()
2017-02-26 13:12:26 +13:00
Rob Bygrave 23e1ab4bfd No effective change - imports 2017-02-26 13:10:42 +13:00
Rob Bygrave 0e2900d796 #980 - fix several bugs in findSingleAttibute - Refactor moving logic into DefaultOrmQuery setDefaultSelectClause() from findSingleAttributeList() (to support alternate calling via EbeanServer) 2017-02-26 13:08:10 +13:00
Roland PramlandRob Bygrave a46e086dc4 fix several bugs in findSingleAttibute (#980)
* add test case for distinct on id property

* suggested fix for "select distinct id"

* add test case for distinct with fetch

* FIX: .setDistinct(true) can be used in conjunction with fetch() now

* add test case for distinct with beans that have a disriminator column

* FIX: discriminator column is only read if also Id is read.

* fine tuned the test case

* added test cases for findSingleAttributeList without distinct

* improved fix to support also findSingleAttribute without distinct

* ADD: Bonus test case - assertion not yet verified
2017-02-26 12:37:36 +13:00
Roland PramlandRob Bygrave 40ca179509 FIX: do not hit database if inherited entity has no children (#974)
* FIX: do not hit database if inherited entity has no children

* ADD: Testcase for creating references of inherited beans
2017-02-26 12:25:55 +13:00
Roland PramlandRob Bygrave 7632910027 FIX: potential NPE - manager can be null - eg when creted with new ExternalJdbcTransaction(conn) (#979) 2017-02-24 12:53:35 +13:00
Roland PramlandRob Bygrave ca777d7967 no effective code change: add some try-with resources (#978)
* no effective code change: add some try-with resources

* moved return statement outside try-with-resources, because otherwise the order changes
2017-02-24 12:52:22 +13:00
Roland PramlandRob Bygrave a315c7c11e More small fixes (#977)
* no effecitve code change: add @FunctionalInterface to designated interfaces

* no effective code change: removed obsolete imports

* no effective code change: removed obsolete @SuppressWarnings

* no effective code change: add @SuppressWarnings to UUID_PLACEHOLDER
2017-02-24 08:42:27 +13:00
Rob Bygrave 35f3f53443 No effective change - format and imports only 2017-02-24 00:06:13 +13:00
Roland PramlandRob Bygrave 40f5596837 add missing @override (#975)
* no effective code change: add missing @override in "io.ebean.*" package
* no effective code change: add missing @override in "io.ebeaninternal.api.*" package
* no effective code change: add missing @override in "io.ebeaninternal.server.*" package
* no effective code change: add missing @override in "io.ebeaninternal.util.*" package
* no effective code change: add missing @override in "io.ebeanservice.*" package
* no effective code change: add missing @override in "src/test/java/"
2017-02-24 00:01:25 +13:00
maksym-kitandRob Bygrave 43c978e41a Pass dataType to DataBind for Types.OTHER (#923) 2017-02-23 23:50:43 +13:00
Koen De GrooteandRob Bygrave 6120a465e1 Simple fixes (#976)
* Should be only the really simple stuff.
* Final cleanups.
2017-02-23 23:46:51 +13:00
Rob Bygrave 8bb884374b #970 - FOR UPDATE queries are not honored when beans are already cached 2017-02-21 22:53:14 +13:00
Rob Bygrave 3d8db775f7 #966 - ENH: Add serverConfig.setDbOffline(true) ... for creating new EbeanServer without a DataSource (for DbMigration typically) 2017-02-21 22:04:28 +13:00
Rob Bygrave b3b8f6b154 #973 - Refactor - Tidy internals of DefaultBeanLoader 2017-02-21 21:57:11 +13:00
Rob Bygrave e4c80582a5 [maven-release-plugin] prepare for next development iteration 2017-02-13 22:18:56 +13:00
Rob Bygrave 1846427859 [maven-release-plugin] prepare release ebean-10.1.6 2017-02-13 22:18:44 +13:00
Rob Bygrave 82102340b8 #960 - Incorrect query when using '.betweenProperties' with '@SoftDelete' 2017-02-09 23:43:45 +13:00
Rob Bygrave d9e884b8bd #969 - ENH: Add Finder.query(String ormQuery) ... helper method 2017-02-09 23:27:13 +13:00
Rob Bygrave 6744c7886a #968 - Refactor - Update ANTLR 4 generated code to 4.6 2017-02-09 23:20:33 +13:00
Rob Bygrave 271b4ee095 Modify pom - bump java8-parent to 1.3 2017-02-09 23:12:11 +13:00
Rob Bygrave 7cfdd331ca Merge branch 'master' of github.com:ebean-orm/ebean 2017-02-09 22:37:58 +13:00
Rob Bygrave 7e15faa9a8 #967 - ENH: Add DocStoreConfig.setAllowAllCertificates(true) ... 2017-02-09 22:37:25 +13:00
Roland PramlandRob Bygrave 1292c86b76 removed duplicate StringHelper (#958) 2017-01-31 22:10:45 +13:00
Rob Bygrave 0260a73cb6 #957 - Javadoc update only 2017-01-27 00:36:25 +13:00
Rob Bygrave 085fdaf177 #956 - Bump dependencies - avaje-datasource and ebean-dbmigration 2017-01-26 23:30:58 +13:00
Rob Bygrave a4b49dfa27 No effective change - Fix javadoc issues in Finder 2017-01-12 18:53:34 +13:00
Rob Bygrave d056151852 [maven-release-plugin] prepare for next development iteration 2017-01-12 00:46:22 +13:00
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
2226 changed files with 21520 additions and 18536 deletions
+2 -1
View File
@@ -1,3 +1,4 @@
dist: trusty
sudo: required
language: java
jdk:
@@ -7,7 +8,7 @@ git:
depth: 3
addons:
postgresql: "9.4"
postgresql: "9.6"
services:
- postgresql
+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
+41 -39
View File
@@ -4,27 +4,30 @@
<parent>
<groupId>org.avaje</groupId>
<artifactId>java8-parent</artifactId>
<version>1.1</version>
<version>1.3</version>
</parent>
<groupId>org.avaje.ebean</groupId>
<groupId>io.ebean</groupId>
<artifactId>ebean</artifactId>
<version>9.3.1</version>
<version>10.4.1</version>
<packaging>jar</packaging>
<name>ebean</name>
<url>http://ebean-orm.github.io/</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<scm>
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
<tag>ebean-9.3.1</tag>
<tag>ebean-10.4.1</tag>
</scm>
<dependencies>
<!-- MS SQL Server dependency is now publicly available -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>6.1.3.jre8-preview</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
@@ -33,15 +36,15 @@
</dependency>
<dependency>
<groupId>org.avaje.ebean</groupId>
<groupId>io.ebean</groupId>
<artifactId>persistence-api</artifactId>
<version>2.1.3</version>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.avaje.ebean</groupId>
<groupId>io.ebean</groupId>
<artifactId>ebean-annotation</artifactId>
<version>1.4</version>
<version>2.3</version>
</dependency>
<dependency>
@@ -53,7 +56,7 @@
<dependency>
<groupId>org.avaje</groupId>
<artifactId>avaje-datasource</artifactId>
<version>1.1.3</version>
<version>2.1.1</version>
</dependency>
<dependency>
@@ -65,13 +68,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.10</version>
</dependency>
<dependency>
@@ -83,7 +86,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 -->
@@ -112,21 +115,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>
@@ -134,7 +137,7 @@
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4-1202-jdbc41</version>
<version>9.4.1212</version>
<scope>provided</scope>
</dependency>
@@ -157,14 +160,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.3.1</version>
<scope>test</scope>
</dependency>
@@ -173,28 +176,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>
@@ -209,14 +212,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>
@@ -227,19 +230,18 @@
<plugins>
<plugin>
<groupId>org.avaje.ebean</groupId>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>8.1.1</version>
<version>10.3.1</version>
<executions>
<execution>
<id>test</id>
<phase>process-test-classes</phase>
<configuration>
<classSource>target/test-classes</classSource>
<transformArgs>debug=1</transformArgs>
</configuration>
<goals>
<goal>enhance</goal>
<goal>testEnhance</goal>
</goals>
</execution>
</executions>
@@ -283,11 +285,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>
-888
View File
@@ -1,888 +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;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* 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(Consumer)}
*/
public void findEach(Consumer<T> consumer) {
query().findEach(consumer);
}
/**
* Execute the query consuming each bean one at a time.
* <p>
* Equivalent to {@link Query#findEachWhile(Predicate)}
* <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(Predicate)}
*/
public void findEachWhile(Predicate<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,119 +0,0 @@
package com.avaje.ebean.annotation;
import com.avaje.ebean.Query;
import com.avaje.ebean.config.Platform;
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;
/**
* 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)
@Repeatable(Formula.List.class)
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 "";
Platform[] platforms() default {};
/**
* Repeatable support for {@link Formula}.
*/
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@interface List {
Formula[] value() default {};
}
}
@@ -1,138 +0,0 @@
package com.avaje.ebean.annotation;
import com.avaje.ebean.TxIsolation;
import com.avaje.ebean.TxType;
import com.avaje.ebean.config.PersistBatch;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specify transaction scoping for a method.
* <p>
* <b><i> This is only supported if "Enhancement" is used via javaagent, ANT
* task or IDE enhancement plugin etc. </i></b>
* </p>
* <p>
* Note: Currently there are 3 known annotations that perform this role.
* <ul>
* <li>EJB's javax.ejb.TransactionAttribute</li>
* <li>Spring's org.springframework.transaction.annotation.Transactional</li>
* <li>and this one, Ebean's own com.avaje.ebean.annotation.Transactional</li>
* </ul>
* Spring created their one because the EJB annotation does not support features
* such as isolation level and specifying rollbackOn, noRollbackOn exceptions.
* This one exists for Ebean because I agree that the standard one is
* insufficient and don't want to include a dependency on Spring.
* </p>
* <p>
* The default behaviour of EJB (and hence Spring) is to NOT ROLLBACK on checked
* exceptions. I find this very counter-intuitive. Ebean will provide a property
* to set the default behaviour to rollback on any exception and optionally
* change the setting to be consistent with EJB/Spring if people wish to do so.
* </p>
* <p>
* <pre>{@code
*
* // a normal class
* public class MySimpleUserService {
*
* // this method is transactional automatically handling
* // transaction begin, commit and rollback etc
* @Transactional
* public void runInTrans() throws IOException {
*
* // tasks performed within the transaction
* ...
* // find some objects
* Customer cust = ebeanServer.find(Customer.class, 42);
*
* Order order = ...;
* ...
* // save some objects
* ebeanServer.save(customer);
* ebeanServer.save(order);
* }
*
* }</pre>
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional {
/**
* The type of transaction scoping. Defaults to REQUIRED.
*/
TxType type() default TxType.REQUIRED;
/**
* Persist batch mode for the transaction.
*/
PersistBatch batch() default PersistBatch.INHERIT;
/**
* Persist batch mode for the request if not set on the transaction.
* <p>
* If batch is set to NONE then batchOnCascade can be set to INSERT or ALL
* and then each save(), delete(), insert(), update() request that cascades
* to child beans can use JDBC batch.
* </p>
*/
PersistBatch batchOnCascade() default PersistBatch.INHERIT;
/**
* The batch size to use when using JDBC batch mode.
* <p>
* If unset this defaults to the value set in ServerConfig.
* </p>
*/
int batchSize() default 0;
/**
* Set to false when we want to skip getting generatedKeys.
* <p>
* This is typically used in the case of large batch inserts where we get a
* performance benefit from not calling getGeneratedKeys (as we are going to
* insert a lot of rows and have no need for the Id values after the insert).
* </p>
*/
boolean getGeneratedKeys() default true;
/**
* The transaction isolation level this transaction should have.
* <p>
* This will only be used if this scope creates the transaction. If the
* transaction has already started then this will currently be ignored (you
* could argue that it should throw an exception).
* </p>
*/
TxIsolation isolation() default TxIsolation.DEFAULT;
/**
* Set this to true if the transaction should be only contain queries.
*/
boolean readOnly() default false;
/**
* The name of the server that you want the transaction to be created from.
* <p>
* If left blank the 'default' server is used.
* </p>
*/
String serverName() default "";
// int timeout() default 0;
/**
* The Throwable's that will explicitly cause a rollback to occur.
*/
Class<? extends Throwable>[] rollbackFor() default {};
/**
* The Throwable's that will explicitly NOT cause a rollback to occur.
*/
Class<? extends Throwable>[] noRollbackFor() default {};
}
@@ -1,68 +0,0 @@
package com.avaje.ebean.annotation;
import com.avaje.ebean.config.Platform;
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;
/**
* 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)
@Repeatable(Where.List.class)
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();
/**
* The platform where this annotation is active. Default: any platform
*/
Platform[] platforms() default {};
/**
* Repeatable support for {@link Where}.
*/
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@interface List {
Where[] value() default {};
}
}
@@ -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,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,15 +0,0 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
/**
* H2 platform specific DDL.
*/
public class H2Ddl extends PlatformDdl {
public H2Ddl(DatabasePlatform platform) {
super(platform);
this.historyDdl = new H2HistoryDdl();
}
}
@@ -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 +0,0 @@
package com.avaje.ebeaninternal.server.cache;
@@ -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,121 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebeaninternal.server.core.InternString;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanTable;
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoinColumn;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Used for associated beans in place of a BeanDescriptor. This is done to avoid
* recursion issues due to the potentially bi-directional and circular
* relationships between beans.
* <p>
* It holds the main deployment information and not all the detail that is held
* in a BeanDescriptor.
* </p>
*/
public class BeanTable {
private static final Logger logger = LoggerFactory.getLogger(BeanTable.class);
private final Class<?> beanType;
/**
* The base table.
*/
private final String baseTable;
private final BeanProperty[] idProperties;
/**
* Create the BeanTable.
*/
public BeanTable(DeployBeanTable mutable, BeanDescriptorMap owner) {
this.beanType = mutable.getBeanType();
this.baseTable = InternString.intern(mutable.getBaseTable());
this.idProperties = mutable.createIdProperties(owner);
}
public String toString(){
return baseTable;
}
/**
* Return the base table for this BeanTable.
* This is used to determine the join information
* for associations.
*/
public String getBaseTable() {
return baseTable;
}
/**
* Gets the unqualified base table.
*
* @return the unqualified base table
*/
public String getUnqualifiedBaseTable(){
final String[] chunks = baseTable.split("\\.");
return chunks.length == 2 ? chunks[1] :chunks[0];
}
/**
* Return the Id properties.
*/
public BeanProperty[] getIdProperties() {
return idProperties;
}
/**
* Return the class for this beanTable.
*/
public Class<?> getBeanType() {
return beanType;
}
public void createJoinColumn(String foreignKeyPrefix, DeployTableJoin join, boolean reverse, String sqlFormulaSelect) {
boolean complexKey = false;
BeanProperty[] props = idProperties;
if (idProperties.length == 1){
if (idProperties[0] instanceof BeanPropertyAssocOne<?>) {
BeanPropertyAssocOne<?> assocOne = (BeanPropertyAssocOne<?>)idProperties[0];
props = assocOne.getProperties();
complexKey = true;
}
}
for (BeanProperty prop : props) {
String lc = prop.getDbColumn();
String fk = lc;
if (foreignKeyPrefix != null) {
fk = foreignKeyPrefix + "_" + fk;
}
if (complexKey) {
// just to copy the column name rather than prefix with the foreignKeyPrefix.
// I think that with complex keys this is the more common approach.
String msg = "On table[" + baseTable + "] foreign key column [" + lc + "]";
logger.debug(msg);
fk = lc;
}
if (sqlFormulaSelect != null) {
fk = sqlFormulaSelect;
}
DeployTableJoinColumn joinCol = new DeployTableJoinColumn(lc, fk);
joinCol.setForeignSqlFormula(sqlFormulaSelect);
if (reverse) {
joinCol = joinCol.reverse();
}
join.addJoinColumn(joinCol);
}
}
}
@@ -1,185 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.event.BeanPersistController;
import com.avaje.ebean.event.BeanPersistRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
/**
* Chains multiple BeanPersistController's together.
*
* Used when multiple BeanPersistController register for the same bean type.
*/
public class ChainedBeanPersistController implements BeanPersistController {
private static final Sorter SORTER = new Sorter();
private final List<BeanPersistController> list;
private final BeanPersistController[] chain;
/**
* Construct adding 2 BeanPersistController's.
*/
public ChainedBeanPersistController(BeanPersistController c1, BeanPersistController c2) {
this(addList(c1, c2));
}
/**
* Helper method used to create a list from 2 BeanPersistController's.
*/
private static List<BeanPersistController> addList(BeanPersistController c1, BeanPersistController c2) {
ArrayList<BeanPersistController> addList = new ArrayList<>(2);
addList.add(c1);
addList.add(c2);
return addList;
}
/**
* Construct given the list of BeanPersistController's.
*/
public ChainedBeanPersistController(List<BeanPersistController> list) {
this.list = list;
BeanPersistController[] c = list.toArray(new BeanPersistController[list.size()]);
Arrays.sort(c, SORTER);
this.chain = c;
}
/**
* Return the size of the chain.
*/
protected int size() {
return chain.length;
}
/**
* Register a new BeanPersistController and return the resulting chain.
*/
public ChainedBeanPersistController register(BeanPersistController c) {
if (list.contains(c)){
return this;
} else {
ArrayList<BeanPersistController> newList = new ArrayList<>();
newList.addAll(list);
newList.add(c);
return new ChainedBeanPersistController(newList);
}
}
/**
* De-register a BeanPersistController and return the resulting chain.
*/
public ChainedBeanPersistController deregister(BeanPersistController c) {
if (!list.contains(c)){
return this;
} else {
ArrayList<BeanPersistController> newList = new ArrayList<>();
newList.addAll(list);
newList.remove(c);
return new ChainedBeanPersistController(newList);
}
}
/**
* Always returns 0 (not used for this object).
*/
@Override
public int getExecutionOrder() {
return 0;
}
/**
* Always returns false (not used for this object).
*/
@Override
public boolean isRegisterFor(Class<?> cls) {
return false;
}
@Override
public void postDelete(BeanPersistRequest<?> request) {
for (BeanPersistController aChain : chain) {
aChain.postDelete(request);
}
}
@Override
public void postInsert(BeanPersistRequest<?> request) {
for (BeanPersistController aChain : chain) {
aChain.postInsert(request);
}
}
@Override
public void postUpdate(BeanPersistRequest<?> request) {
for (BeanPersistController aChain : chain) {
aChain.postUpdate(request);
}
}
@Override
public void postSoftDelete(BeanPersistRequest<?> request) {
for (BeanPersistController aChain : chain) {
aChain.postSoftDelete(request);
}
}
@Override
public boolean preDelete(BeanPersistRequest<?> request) {
for (BeanPersistController aChain : chain) {
if (!aChain.preDelete(request)) {
return false;
}
}
return true;
}
@Override
public boolean preSoftDelete(BeanPersistRequest<?> request) {
for (BeanPersistController aChain : chain) {
if (!aChain.preSoftDelete(request)) {
return false;
}
}
return true;
}
@Override
public boolean preInsert(BeanPersistRequest<?> request) {
for (BeanPersistController aChain : chain) {
if (!aChain.preInsert(request)) {
return false;
}
}
return true;
}
@Override
public boolean preUpdate(BeanPersistRequest<?> request) {
for (BeanPersistController aChain : chain) {
if (!aChain.preUpdate(request)) {
return false;
}
}
return true;
}
/**
* Helper to order the BeanPersistController's in a chain.
*/
private static class Sorter implements Comparator<BeanPersistController> {
public int compare(BeanPersistController o1, BeanPersistController o2) {
int i1 = o1.getExecutionOrder() ;
int i2 = o2.getExecutionOrder() ;
return (i1<i2 ? -1 : (i1==i2 ? 0 : 1));
}
}
}
@@ -1,109 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import com.avaje.ebean.event.BeanPersistListener;
/**
* Handles multiple BeanPersistListener's for a given entity type.
*/
public class ChainedBeanPersistListener implements BeanPersistListener {
private final List<BeanPersistListener> list;
private final BeanPersistListener[] chain;
/**
* Construct adding 2 BeanPersistListener's.
*/
ChainedBeanPersistListener(BeanPersistListener c1, BeanPersistListener c2) {
this(addList(c1, c2));
}
/**
* Return the size of the chain.
*/
protected int size() {
return chain.length;
}
@Override
public boolean isRegisterFor(Class<?> cls) {
// never called
return false;
}
/**
* Helper method used to create a list from 2 BeanPersistListener.
*/
private static List<BeanPersistListener> addList(BeanPersistListener c1, BeanPersistListener c2) {
ArrayList<BeanPersistListener> addList = new ArrayList<>(2);
addList.add(c1);
addList.add(c2);
return addList;
}
/**
* Construct given the list of BeanPersistListener's.
*/
public ChainedBeanPersistListener(List<BeanPersistListener> list) {
this.list = list;
this.chain = list.toArray(new BeanPersistListener[list.size()]);
}
/**
* Register a new BeanPersistListener and return the resulting chain.
*/
public ChainedBeanPersistListener register(BeanPersistListener c) {
if (list.contains(c)){
return this;
} else {
List<BeanPersistListener> newList = new ArrayList<>();
newList.addAll(list);
newList.add(c);
return new ChainedBeanPersistListener(newList);
}
}
/**
* De-register a BeanPersistListener and return the resulting chain.
*/
public ChainedBeanPersistListener deregister(BeanPersistListener c) {
if (!list.contains(c)){
return this;
} else {
ArrayList<BeanPersistListener> newList = new ArrayList<>();
newList.addAll(list);
newList.remove(c);
return new ChainedBeanPersistListener(newList);
}
}
public void deleted(Object bean) {
for (BeanPersistListener aChain : chain) {
aChain.deleted(bean);
}
}
public void softDeleted(Object bean) {
for (BeanPersistListener aChain : chain) {
aChain.softDeleted(bean);
}
}
public void inserted(Object bean) {
for (BeanPersistListener aChain : chain) {
aChain.inserted(bean);
}
}
public void updated(Object bean, Set<String> updatedProperties) {
for (BeanPersistListener aChain : chain) {
aChain.updated(bean, updatedProperties);
}
}
}
@@ -1,77 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.event.BeanPostLoad;
import java.util.ArrayList;
import java.util.List;
/**
* Handles multiple BeanPostLoad's for a given entity type.
*/
public class ChainedBeanPostLoad implements BeanPostLoad {
private final List<BeanPostLoad> list;
private final BeanPostLoad[] chain;
/**
* Construct given the list of BeanPostLoad's.
*/
public ChainedBeanPostLoad(List<BeanPostLoad> list) {
this.list = list;
this.chain = list.toArray(new BeanPostLoad[list.size()]);
}
/**
* Register a new BeanPostLoad and return the resulting chain.
*/
public ChainedBeanPostLoad register(BeanPostLoad c) {
if (list.contains(c)){
return this;
} else {
List<BeanPostLoad> newList = new ArrayList<>();
newList.addAll(list);
newList.add(c);
return new ChainedBeanPostLoad(newList);
}
}
/**
* De-register a BeanPostLoad and return the resulting chain.
*/
public ChainedBeanPostLoad deregister(BeanPostLoad c) {
if (!list.contains(c)){
return this;
} else {
ArrayList<BeanPostLoad> newList = new ArrayList<>();
newList.addAll(list);
newList.remove(c);
return new ChainedBeanPostLoad(newList);
}
}
/**
* Return the size of the chain.
*/
protected int size() {
return chain.length;
}
@Override
public boolean isRegisterFor(Class<?> cls) {
// never called
return false;
}
/**
* Fire postLoad on all registered BeanPostLoad implementations.
*/
@Override
public void postLoad(Object bean) {
for (BeanPostLoad aChain : chain) {
aChain.postLoad(bean);
}
}
}
@@ -1,96 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import com.avaje.ebean.event.BeanQueryAdapter;
import com.avaje.ebean.event.BeanQueryRequest;
/**
* Handles multiple BeanQueryAdapter for a given entity type.
*/
public class ChainedBeanQueryAdapter implements BeanQueryAdapter {
private static final Sorter SORTER = new Sorter();
private final List<BeanQueryAdapter> list;
private final BeanQueryAdapter[] chain;
/**
* Construct given the list of BeanQueryAdapter's.
*/
public ChainedBeanQueryAdapter(List<BeanQueryAdapter> list) {
this.list = list;
BeanQueryAdapter[] c = list.toArray(new BeanQueryAdapter[list.size()]);
Arrays.sort(c, SORTER);
this.chain = c;
}
/**
* Register a new BeanQueryAdapter and return the resulting chain.
*/
public ChainedBeanQueryAdapter register(BeanQueryAdapter c) {
if (list.contains(c)){
return this;
} else {
List<BeanQueryAdapter> newList = new ArrayList<>();
newList.addAll(list);
newList.add(c);
return new ChainedBeanQueryAdapter(newList);
}
}
/**
* De-register a BeanQueryAdapter and return the resulting chain.
*/
public ChainedBeanQueryAdapter deregister(BeanQueryAdapter c) {
if (!list.contains(c)){
return this;
} else {
ArrayList<BeanQueryAdapter> newList = new ArrayList<>();
newList.addAll(list);
newList.remove(c);
return new ChainedBeanQueryAdapter(newList);
}
}
/**
* Return 0 as not used by this Chained adapter.
*/
public int getExecutionOrder() {
return 0;
}
/**
* Return false as only individual adapters are registered.
*/
public boolean isRegisterFor(Class<?> cls) {
return false;
}
public void preQuery(BeanQueryRequest<?> request) {
for (BeanQueryAdapter aChain : chain) {
aChain.preQuery(request);
}
}
/**
* Helper to order the BeanQueryAdapter's in a chain.
*/
private static class Sorter implements Comparator<BeanQueryAdapter> {
public int compare(BeanQueryAdapter o1, BeanQueryAdapter o2) {
int i1 = o1.getExecutionOrder() ;
int i2 = o2.getExecutionOrder() ;
return (i1<i2 ? -1 : (i1==i2 ? 0 : 1));
}
}
}
@@ -1,170 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
import java.util.Set;
/**
* Converts logical property names to database columns.
*/
public abstract class DeployParser {
/**
* used to identify sql literal.
*/
protected static final char SINGLE_QUOTE = '\'';
/**
* used to identify query named parameters.
*/
protected static final char COLON = ':';
/**
* Used to determine when a column name terminates.
*/
protected static final char UNDERSCORE = '_';
/**
* Used to determine when a column name terminates.
*/
protected static final char PERIOD = '.';
protected boolean encrypted;
protected String source;
protected StringBuilder sb;
protected int sourceLength;
protected int pos;
protected String word;
protected char wordTerminator;
protected abstract String convertWord();
public abstract String getDeployWord(String expression);
/**
* Return the join includes.
*/
public abstract Set<String> getIncludes();
public void setEncrypted(boolean encrypted) {
this.encrypted = encrypted;
}
public String parse(String source) {
if (source == null) {
return null;
}
pos = -1;
this.source = source;
this.sourceLength = source.length();
this.sb = new StringBuilder(source.length() + 20);
while (nextWord()) {
String deployWord = convertWord();
sb.append(deployWord);
if (pos < sourceLength) {
sb.append(wordTerminator);
if (wordTerminator == SINGLE_QUOTE) {
readLiteral();
}
}
}
return sb.toString();
}
private boolean nextWord() {
if (!findWordStart()) {
return false;
}
StringBuilder wordBuffer = new StringBuilder();
wordBuffer.append(source.charAt(pos));
while (++pos < sourceLength) {
char ch = source.charAt(pos);
if (isWordPart(ch)) {
wordBuffer.append(ch);
} else {
wordTerminator = ch;
break;
}
}
word = wordBuffer.toString();
return true;
}
private boolean findWordStart() {
while (++pos < sourceLength) {
char ch = source.charAt(pos);
if (ch == SINGLE_QUOTE) {
// read a literal value and just
// append to string builder
sb.append(ch);
readLiteral();
} else if (ch == COLON) {
// read a named parameter
// just append to string builder
sb.append(ch);
readNamedParameter();
} else if (isWordStart(ch)) {
// its the start of a word that could
// be translated
return true;
} else {
sb.append(ch);
}
}
return false;
}
/**
* Read the rest of a literal value. These do not get translated so are just
* read and appended to the string builder.
*/
private void readLiteral() {
while (++pos < sourceLength) {
char ch = source.charAt(pos);
sb.append(ch);
if (ch == SINGLE_QUOTE) {
break;
}
}
}
/**
* Read a named parameter. These are not translated. They will be replaced
* by positioned parameters later.
*/
private void readNamedParameter() {
while (++pos < sourceLength) {
char ch = source.charAt(pos);
sb.append(ch);
if (Character.isWhitespace(ch)) {
break;
} else if (ch == ',') {
break;
}
}
}
/**
* return true if the char is a letter, digit or underscore.
*/
private boolean isWordPart(char ch) {
return Character.isLetterOrDigit(ch) || ch == UNDERSCORE || ch == PERIOD;
}
private boolean isWordStart(char ch) {
return Character.isLetter(ch);
}
}
@@ -1,52 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
import java.util.HashSet;
import java.util.Set;
import com.avaje.ebeaninternal.server.el.ElPropertyDeploy;
/**
* Converts logical property names to database columns with table alias.
* <p>
* In doing so it builds an 'includes' set which becomes the joins required to
* support the properties parsed.
* </p>
*/
public final class DeployPropertyParser extends DeployParser {
private final BeanDescriptor<?> beanDescriptor;
private final Set<String> includes = new HashSet<>();
public DeployPropertyParser(BeanDescriptor<?> beanDescriptor) {
this.beanDescriptor = beanDescriptor;
}
public Set<String> getIncludes() {
return includes;
}
@Override
public String getDeployWord(String expression) {
ElPropertyDeploy elProp = beanDescriptor.getElPropertyDeploy(expression);
if (elProp == null){
return null;
} else {
addIncludes(elProp.getElPrefix());
return elProp.getElPlaceholder(encrypted);
}
}
@Override
public String convertWord() {
String r = getDeployWord(word);
return r == null ? word : r;
}
private void addIncludes(String prefix) {
if (prefix != null){
includes.add(prefix);
}
}
}
@@ -1,90 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
import java.util.Set;
import com.avaje.ebeaninternal.server.el.ElPropertyDeploy;
/**
* For updates converts logical property names to database columns and bean type to base table.
*/
public final class DeployUpdateParser extends DeployParser {
private final BeanDescriptor<?> beanDescriptor;
public DeployUpdateParser(BeanDescriptor<?> beanDescriptor) {
this.beanDescriptor = beanDescriptor;
}
/**
* Return null as not used for updates.
*/
@Override
public Set<String> getIncludes() {
return null;
}
public String convertWord() {
String dbWord = getDeployWord(word);
if (dbWord != null) {
return dbWord;
}
// maybe tableAlias.propertyName
return convertSubword(0, word, null);
}
private String convertSubword(int start, String currentWord, StringBuilder localBuffer) {
int dotPos = currentWord.indexOf('.', start);
if (start == 0 && dotPos == -1){
return currentWord;
}
if (start == 0){
localBuffer = new StringBuilder();
}
if (dotPos == -1){
// no match...
localBuffer.append(currentWord.substring(start));
return localBuffer.toString();
}
// append up to the dot
localBuffer.append(currentWord.substring(start, dotPos+1));
if (dotPos == currentWord.length()-1){
// ends with a "." ???
return localBuffer.toString();
}
// get the remainder after the dot
start = dotPos+1;
String remainder = currentWord.substring(start, currentWord.length());
//String dbWord = deployMap.get(remainder.toLowerCase());
String dbWord = getDeployWord(remainder);
if (dbWord != null){
// we have found a match for the remainder
localBuffer.append(dbWord);
return localBuffer.toString();
} else {
//
return convertSubword(start, currentWord, localBuffer);
}
}
public String getDeployWord(String expression) {
if (expression.equalsIgnoreCase(beanDescriptor.getName())){
return beanDescriptor.getBaseTable();
}
ElPropertyDeploy elProp = beanDescriptor.getElPropertyDeploy(expression);
if (elProp != null){
return elProp.getDbColumn();
} else {
return null;
}
}
}
@@ -1,13 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
/**
* Used to visit all the InheritInfo in a single inheritance hierarchy.
*/
public interface InheritInfoVisitor {
/**
* visit the InheritInfo for this node.
*/
void visit(InheritInfo inheritInfo);
}
@@ -1,78 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* Helper object to find generic parameter types for a given class.
*/
public class ParamTypeUtil {
/**
* Find and return the parameter type given a generic interface or class.
* <p>
* This assumes there is only one generic parameter.
* </p>
* <p>
* Returns null if no match was found.
* </p>
* @param cls the class to search for the parameter type
* @param matchType the type which has the generic parameter
*/
public static Class<?> findParamType(Class<?> cls, Class<?> matchType) {
// search for: implementing a generic interface
Type paramType = matchByInterfaces(cls, matchType);
if (paramType == null){
// search for: extending a generic class
Type genericSuperclass = cls.getGenericSuperclass();
if (genericSuperclass != null){
paramType = matchParamType(genericSuperclass, matchType);
}
}
if (paramType instanceof Class<?>){
// only interested in classes
return (Class<?>)paramType;
} else {
return null;
}
}
/**
* Check if the type is a generic one with parameters and of the correct type we are
* searching for. Return the parameter type if this matches otherwise return null.
*/
private static Type matchParamType(Type type, Class<?> matchType) {
if (type instanceof ParameterizedType){
ParameterizedType pt = (ParameterizedType)type;
Type rawType = pt.getRawType();
boolean isAssignable = matchType.isAssignableFrom((Class<?>) rawType);
if (isAssignable) {
// assume there is only one parameter type
Type[] typeArguments = pt.getActualTypeArguments();
if (typeArguments.length != 1){
String m = "Expecting only 1 generic paramater but got "+typeArguments.length+" for "+type;
throw new RuntimeException(m);
}
return typeArguments[0];
}
}
return null;
}
/**
* Search the interfaces this class implements.
*/
private static Type matchByInterfaces(Class<?> cls, Class<?> matchType) {
Type[] gis = cls.getGenericInterfaces();
for (Type gi : gis) {
Type match = matchParamType(gi, matchType);
if (match != null) {
return match;
}
}
return null;
}
}
@@ -1,42 +0,0 @@
package com.avaje.ebeaninternal.server.deploy;
import com.avaje.ebean.event.BeanPersistListener;
import com.avaje.ebeaninternal.server.core.bootup.BootupClasses;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* Manages the assignment/registration of BeanPersistListener with their
* respective DeployBeanDescriptor's.
*/
public class PersistListenerManager {
private static final Logger logger = LoggerFactory.getLogger(PersistListenerManager.class);
private final List<BeanPersistListener> list;
public PersistListenerManager(BootupClasses bootupClasses) {
list = bootupClasses.getBeanPersistListeners();
}
public int getRegisterCount() {
return list.size();
}
/**
* Return the BeanPersistController for a given entity type.
*/
public <T> void addPersistListeners(DeployBeanDescriptor<T> deployDesc) {
for (BeanPersistListener listener : list) {
if (listener.isRegisterFor(deployDesc.getBeanType())) {
logger.debug("BeanPersistListener on[{}] {}", deployDesc.getFullName(), listener.getClass().getName());
deployDesc.addPersistListener(listener);
}
}
}
}
@@ -1,10 +0,0 @@
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
<TITLE>Helpers for Id property conversion</TITLE>
</HEAD>
<Body BGCOLOR="#ffffff">
Helpers for Id property conversion
</Body>
</HTML>
@@ -1,150 +0,0 @@
package com.avaje.ebeaninternal.server.deploy.meta;
import com.avaje.ebeaninternal.server.deploy.BeanCascadeInfo;
import com.avaje.ebeaninternal.server.deploy.BeanTable;
/**
* Abstract base for properties mapped to an associated bean, list, set or map.
*/
public abstract class DeployBeanPropertyAssoc<T> extends DeployBeanProperty {
/**
* The type of the joined bean.
*/
protected Class<T> targetType;
/**
* Persist settings.
*/
private final BeanCascadeInfo cascadeInfo = new BeanCascadeInfo();
/**
* The join table information.
*/
private BeanTable beanTable;
/**
* Join between the beans.
*/
protected final DeployTableJoin tableJoin = new DeployTableJoin();
/**
* Literal added to where clause of lazy loading query.
*/
private String extraWhere;
/**
* From the deployment mappedBy attribute.
*/
private String mappedBy;
private String docStoreDoc;
/**
* Construct the property.
*/
DeployBeanPropertyAssoc(DeployBeanDescriptor<?> desc, Class<T> targetType) {
super(desc, targetType, null, null);
this.targetType = targetType;
}
/**
* Return the target DeployBeanDescriptor for this associated bean property.
*/
public DeployBeanDescriptor<?> getTargetDeploy() {
return desc.getDeploy(targetType).getDescriptor();
}
/**
* Return the type of the target.
* <p>
* This is the class of the associated bean, or beans contained in a list,
* set or map.
* </p>
*/
public Class<T> getTargetType() {
return targetType;
}
/**
* Return a literal expression that is added to the query that lazy loads
* the collection.
*/
public String getExtraWhere() {
return extraWhere;
}
/**
* Set a literal expression to add to the query that lazy loads the
* collection.
*/
public void setExtraWhere(String extraWhere) {
this.extraWhere = extraWhere;
}
/**
* return the join to use for the bean.
*/
public DeployTableJoin getTableJoin() {
return tableJoin;
}
/**
* Return the BeanTable for this association.
* <p>
* This has the table name which is used to determine the relationship for
* this association.
* </p>
*/
public BeanTable getBeanTable() {
return beanTable;
}
/**
* Set the bean table.
*/
public void setBeanTable(BeanTable beanTable) {
this.beanTable = beanTable;
getTableJoin().setTable(beanTable.getBaseTable());
}
/**
* Get the persist info.
*/
public BeanCascadeInfo getCascadeInfo() {
return cascadeInfo;
}
/**
* Return the mappedBy deployment attribute.
* <p>
* This is the name of the property in the 'detail' bean that maps back to
* this 'master' bean.
* </p>
*/
public String getMappedBy() {
return mappedBy;
}
/**
* Set mappedBy deployment attribute.
*/
public void setMappedBy(String mappedBy) {
if (!"".equals(mappedBy)) {
this.mappedBy = mappedBy;
}
}
/**
* Set DocStoreEmbedded deployment information.
*/
public void setDocStoreEmbedded(String embeddedDoc) {
this.docStoreDoc = embeddedDoc;
}
public String getDocStoreDoc() {
return docStoreDoc;
}
}
@@ -1,209 +0,0 @@
package com.avaje.ebeaninternal.server.deploy.meta;
import com.avaje.ebean.bean.BeanCollection.ModifyListenMode;
import com.avaje.ebeaninternal.server.deploy.ManyType;
import com.avaje.ebeaninternal.server.deploy.TableJoin;
/**
* Property mapped to a List Set or Map.
*/
public class DeployBeanPropertyAssocMany<T> extends DeployBeanPropertyAssoc<T> {
/**
* The type of the many, set, list or map.
*/
final ManyType manyType;
ModifyListenMode modifyListenMode = ModifyListenMode.NONE;
/**
* Flag to indicate manyToMany relationship.
*/
boolean manyToMany;
/**
* Flag to indicate this is a unidirectional relationship.
*/
boolean unidirectional;
/**
* Join for manyToMany intersection table.
*/
DeployTableJoin intersectionJoin;
/**
* For ManyToMany this is the Inverse join used to build reference queries.
*/
DeployTableJoin inverseJoin;
String fetchOrderBy;
String mapKey;
String intersectionDraftTable;
/**
* Create this property.
*/
public DeployBeanPropertyAssocMany(DeployBeanDescriptor<?> desc, Class<T> targetType, ManyType manyType) {
super(desc, targetType);
this.manyType = manyType;
}
/**
* When generics is not used for manyType you can specify via annotations.
* <p>
* Really only expect this for Scala due to a Scala compiler bug at the moment.
* Otherwise I'd probably not bother support this.
* </p>
*/
@SuppressWarnings("unchecked")
public void setTargetType(Class<?> cls){
this.targetType = (Class<T>)cls;
}
/**
* Return the many type.
*/
public ManyType getManyType() {
return manyType;
}
/**
* Return true if this is many to many.
*/
public boolean isManyToMany() {
return manyToMany;
}
/**
* Set to true if this is a many to many.
*/
public void setManyToMany() {
this.manyToMany = true;
}
/**
* Return the mode for listening to changes to the List Set or Map.
*/
public ModifyListenMode getModifyListenMode() {
return modifyListenMode;
}
/**
* Set the mode for listening to changes to the List Set or Map.
*/
public void setModifyListenMode(ModifyListenMode modifyListenMode) {
this.modifyListenMode = modifyListenMode;
}
/**
* Return true if this is a unidirectional relationship.
*/
public boolean isUnidirectional() {
return unidirectional;
}
/**
* Set to true if this is a unidirectional relationship.
*/
public void setUnidirectional() {
this.unidirectional = true;
}
/**
* Create the immutable version of the intersection join.
*/
public TableJoin createIntersectionTableJoin() {
if (intersectionJoin != null){
return new TableJoin(intersectionJoin);
} else {
return null;
}
}
/**
* Create the immutable version of the inverse join.
*/
public TableJoin createInverseTableJoin() {
if (inverseJoin != null){
return new TableJoin(inverseJoin);
} else {
return null;
}
}
/**
* ManyToMany only, join from local table to intersection table.
*/
public DeployTableJoin getIntersectionJoin() {
return intersectionJoin;
}
public DeployTableJoin getInverseJoin() {
return inverseJoin;
}
/**
* ManyToMany only, join from local table to intersection table.
*/
public void setIntersectionJoin(DeployTableJoin intersectionJoin) {
this.intersectionJoin = intersectionJoin;
}
/**
* ManyToMany only, join from foreign table to intersection table.
*/
public void setInverseJoin(DeployTableJoin inverseJoin) {
this.inverseJoin = inverseJoin;
}
/**
* Return the order by clause used to order the fetching of the data for
* this list, set or map.
*/
public String getFetchOrderBy() {
return fetchOrderBy;
}
/**
* Return the default mapKey when returning a Map.
*/
public String getMapKey() {
return mapKey;
}
/**
* Set the default mapKey to use when returning a Map.
*/
public void setMapKey(String mapKey) {
if (mapKey != null && !mapKey.isEmpty()) {
this.mapKey = mapKey;
}
}
/**
* Set the order by clause used to order the fetching or the data for this
* list, set or map.
*/
public void setFetchOrderBy(String orderBy) {
if (orderBy != null && !orderBy.isEmpty()) {
fetchOrderBy = orderBy;
}
}
/**
* Return a draft table for intersection between 2 @Draftable entities.
*/
public String getIntersectionDraftTable() {
return (intersectionDraftTable != null) ? intersectionDraftTable : intersectionJoin.getTable();
}
/**
* ManyToMany between 2 @Draftable entities to also need draft intersection table.
*/
public void setIntersectionDraftTable() {
this.intersectionDraftTable = intersectionJoin.getTable()+"_draft";
}
}
@@ -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,90 +0,0 @@
package com.avaje.ebeaninternal.server.deploy.meta;
import java.util.List;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorMap;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
/**
* Used for associated beans in place of a BeanDescriptor. This is done to avoid
* recursion issues due to the potentially bi-directional and circular
* relationships between beans.
* <p>
* It holds the main deployment information and not all the detail that is held
* in a BeanDescriptor.
* </p>
*/
public class DeployBeanTable {
private final Class<?> beanType;
/**
* The base table.
*/
private String baseTable;
private List<DeployBeanProperty> idProperties;
/**
* Create the BeanTable.
*/
public DeployBeanTable(Class<?> beanType) {
this.beanType = beanType;
}
/**
* Return the base table for this BeanTable.
* This is used to determine the join information
* for associations.
*/
public String getBaseTable() {
return baseTable;
}
/**
* Set the base table for this BeanTable.
*/
public void setBaseTable(String baseTable) {
this.baseTable = baseTable;
}
/**
* Return the id properties.
*/
public BeanProperty[] createIdProperties(BeanDescriptorMap owner) {
BeanProperty[] props = new BeanProperty[idProperties.size()];
for (int i = 0; i < idProperties.size(); i++) {
props[i] = createProperty(owner, idProperties.get(i));
}
return props;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private BeanProperty createProperty(BeanDescriptorMap owner, DeployBeanProperty prop){
if (prop instanceof DeployBeanPropertyAssocOne<?>){
return new BeanPropertyAssocOne(owner, (DeployBeanPropertyAssocOne<?>)prop);
} else {
return new BeanProperty(prop);
}
}
/**
* Set the Id properties.
*/
public void setIdProperties(List<DeployBeanProperty> idProperties) {
this.idProperties = idProperties;
}
/**
* Return the class for this beanTable.
*/
public Class<?> getBeanType() {
return beanType;
}
}
@@ -1,185 +0,0 @@
package com.avaje.ebeaninternal.server.deploy.meta;
import javax.persistence.JoinColumn;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanTable;
/**
* A join pair of local and foreign properties.
*/
public class DeployTableJoinColumn {
/**
* The local database column name.
*/
String localDbColumn;
/**
* SQL formula used for local column
*/
String localSqlFormula;
/**
* The foreign database column name.
*/
String foreignDbColumn;
/**
* SQL formula used for foreign column
*/
String foreignSqlFormula;
boolean insertable;
boolean updateable;
/**
* Construct when automatically determining the join.
* <p>
* Assume that we want the foreign key to be insertable and updateable.
* </p>
*/
public DeployTableJoinColumn(String localDbColumn, String foreignDbColumn) {
this(localDbColumn, foreignDbColumn, true, true);
}
/**
* Construct with explicit insertable and updateable flags.
*/
public DeployTableJoinColumn(String localDbColumn, String foreignDbColumn, boolean insertable, boolean updateable) {
this.localDbColumn = nullEmptyString(localDbColumn);
this.foreignDbColumn = nullEmptyString(foreignDbColumn);
this.insertable = insertable;
this.updateable = updateable;
}
public void setLocalSqlFormula(String localSqlFormula) {
if (localSqlFormula != null) {
this.localSqlFormula = localSqlFormula;
this.localDbColumn = null;
this.insertable = false;
this.updateable = false;
}
}
public String getLocalSqlFormula() {
return localSqlFormula;
}
public void setForeignSqlFormula(String foreignSqlFormula) {
if (foreignSqlFormula != null) {
this.foreignSqlFormula = foreignSqlFormula;
this.foreignDbColumn = null;
this.insertable = false;
this.updateable = false;
}
}
public String getForeignSqlFormula() {
return foreignSqlFormula;
}
public DeployTableJoinColumn(boolean order, JoinColumn jc, BeanTable beanTable) {
this(jc.referencedColumnName(), jc.name(), jc.insertable(), jc.updatable());
setReferencedColumn(beanTable);
if (!order){
reverse();
}
}
private void setReferencedColumn(BeanTable beanTable){
if (localDbColumn == null){
BeanProperty[] idProperties = beanTable.getIdProperties();
if (idProperties.length == 1){
localDbColumn = idProperties[0].getDbColumn();
}
}
}
/**
* Reverse the direction of the join.
*/
public DeployTableJoinColumn reverse() {
String temp = localDbColumn;
localDbColumn = foreignDbColumn;
foreignDbColumn = temp;
temp = localSqlFormula;
localSqlFormula = foreignSqlFormula;
foreignSqlFormula = temp;
return this;
}
/**
* Helper method to null out empty strings.
*/
private String nullEmptyString(String s){
if ("".equals(s)){
return null;
}
return s;
}
public DeployTableJoinColumn copy(boolean reverse) {
// Note that the insertable and updateable are just copied
// which may not always be the correct thing to do
// but will leave it like this for now
DeployTableJoinColumn ret;
if (reverse){
ret = new DeployTableJoinColumn(foreignDbColumn, localDbColumn, insertable, updateable);
ret.setLocalSqlFormula(foreignSqlFormula);
ret.setForeignSqlFormula(localSqlFormula);
} else {
ret = new DeployTableJoinColumn(localDbColumn, foreignDbColumn, insertable, updateable);
ret.setLocalSqlFormula(localSqlFormula);
ret.setForeignSqlFormula(foreignSqlFormula);
}
return ret;
}
public String toString() {
return localDbColumn + " = " + foreignDbColumn;
}
/**
* Return true if this column should be insertable.
*/
public boolean isInsertable() {
return insertable;
}
/**
* Return true if this column should be updateable.
*/
public boolean isUpdateable() {
return updateable;
}
/**
* Return the foreign database column name.
*/
public String getForeignDbColumn() {
return foreignDbColumn;
}
/**
* Return the local database column name.
*/
public String getLocalDbColumn() {
return localDbColumn;
}
/**
* Set the local database column name.
*/
public void setLocalDbColumn(String localDbColumn) {
this.localDbColumn = localDbColumn;
}
}
@@ -1,10 +0,0 @@
<html>
<head>
<meta HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
<title>Temporary objects used to collect deployment information</title>
</head>
<body BGCOLOR="#ffffff">
Temporary objects used to collect deployment information
</body>
</html>
@@ -1,14 +0,0 @@
<html>
<head>
<meta HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
<title>Bean description</title>
</head>
<body BGCOLOR="#ffffff">
Bean description
<p>
Describes beans with their properties and configuration.
</p>
</body>
</html>
@@ -1,92 +0,0 @@
package com.avaje.ebeaninternal.server.deploy.parse;
import com.avaje.ebean.RawSql;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
import com.avaje.ebeaninternal.server.query.SqlJoinType;
import java.util.HashMap;
/**
* Wraps information about a bean during deployment parsing.
*/
public class DeployBeanInfo<T> {
/**
* Holds TableJoins for secondary table properties.
*/
private final HashMap<String,DeployTableJoin> tableJoinMap = new HashMap<>();
private final DeployUtil util;
private final DeployBeanDescriptor<T> descriptor;
/**
* Create with a DeployUtil and BeanDescriptor.
*/
public DeployBeanInfo(DeployUtil util, DeployBeanDescriptor<T> descriptor) {
this.util = util;
this.descriptor = descriptor;
}
public String toString() {
return ""+descriptor;
}
/**
* Return the BeanDescriptor currently being processed.
*/
public DeployBeanDescriptor<T> getDescriptor() {
return descriptor;
}
/**
* Return the DeployUtil we are using.
*/
public DeployUtil getUtil() {
return util;
}
/**
* Appropriate TableJoin for a property mapped to a secondary table.
*/
public DeployTableJoin getTableJoin(String tableName) {
String key = tableName.toLowerCase();
DeployTableJoin tableJoin = tableJoinMap.get(key);
if (tableJoin == null) {
tableJoin = new DeployTableJoin();
tableJoin.setTable(tableName);
tableJoin.setType(SqlJoinType.INNER);
descriptor.addTableJoin(tableJoin);
tableJoinMap.put(key, tableJoin);
}
return tableJoin;
}
/**
* Set a the join alias for a assoc one property.
*/
public void setBeanJoinType(DeployBeanPropertyAssocOne<?> beanProp, boolean outerJoin) {
DeployTableJoin tableJoin = beanProp.getTableJoin();
tableJoin.setType(outerJoin ? SqlJoinType.OUTER : SqlJoinType.INNER);
}
/**
* Add named RawSql from ebean.xml.
*/
public void addRawSql(String name, RawSql rawSql) {
descriptor.addRawSql(name, rawSql);
}
/**
* Add the named query.
*/
public void addNamedQuery(String name, String query) {
descriptor.addNamedQuery(name, query);
}
}
@@ -1,78 +0,0 @@
package com.avaje.ebeaninternal.server.deploy.parse;
import java.util.HashSet;
/**
* Keywords deemed inappropriate for use as table alias' column or table name.
* <p>
* That is, they might cause sql syntax errors if used.
* </p>
*/
public class SqlReservedWords {
private static final String baseKeyWords =
"ALIAS,ALTER,ADD,ALL,ARE,AND,ANY,ARRAY"
+",AS,ASC,AT"
+",AVG,BEGIN,BETWEEN,BIGINT,BINARY,BIT,BIT_LENGTH,BLOB,BOOLEAN"
+",BOTH,BY,CALL,CALLED,CASCADE,CASCADED,CASE,CAST,CATALOG,CHAR"
+",CHARACTER,CHECK,CLOB,CLOSE,COALESCE,COLLATE"
+",COLLATION,COLUMN,COMMIT,CONDITION,CONNECT,CONNECTION,CONSTRAINT"
+",CONSTRAINTS,CONSTRUCTOR,CONTAINS,CONTINUE,CONVERT"
+",COUNT,CREATE,CROSS,CURRENT_DATE"
+",CURRENT_PATH,CURRENT_ROLE,CURRENT_TIME,CURRENT_TIMESTAMP"
+",CURRENT_USER,CURSOR,DATE"
+",DAY,DEC,DECIMAL,DECLARE,DEFAULT,DELETE"
+",DESC"
+",DISTINCT,DO,DOUBLE,DROP,ELSE,ELSEIF,END,EQUALS"
+",EXEC,EXIT,EXISTS,EXTRACT"
+",FLOAT,FROM,FOR,FREE"
+",GET,GLOBAL,GO,GOTO,GRANT,GROUP,HAVING,HOUR"
+",IF,IN,INNER,INOUT,INSERT"
+",INT,INTEGER,INTO,IS,JOIN"
+",LAST,LIKE,LIMIT"
+",MAX,MIN"
+",NCHAR,NCLOB,NOT"
+",NULL,NULLIF,NUMERIC,"
+",OR,ORDER,OUTER"
+",REAL,REF,REFERENCES"
+",RETURN,RETURNS"
+",SELECT,SSL"
+",SMALLINT,"
+",SYSTEM,SYSTEM_USER,TABLE"
+",TO"
+",TRIGGER,UNION,UNIQUE"
+",UPDATE,USER,VARCHAR,VIEW,WHEN"
+",WHERE,WITH";
private static final HashSet<String> keywords = new HashSet<>();
static {
String[] initialKeywords = baseKeyWords.split(",");
for (String initialKeyword : initialKeywords) {
keywords.add(initialKeyword.trim());
}
}
/**
* Return true if the tableAlias is a keyword.
*/
public static synchronized boolean isKeyword(String keyword){
String s = keyword.trim().toUpperCase();
return keywords.contains(s);
}
/**
* Add a sql keyword to the known set.
*/
public static synchronized void addKeyword(String keyword){
if (keyword != null){
keyword = keyword.trim().toUpperCase();
if (!keyword.isEmpty()){
keywords.add(keyword);
}
}
}
}
@@ -1,48 +0,0 @@
package com.avaje.ebeaninternal.server.deploy.parse;
import java.util.List;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
/**
* Mark transient properties.
*/
public class TransientProperties {
public TransientProperties() {
}
/**
* Mark any additional properties as transient.
*/
public void process(DeployBeanDescriptor<?> desc) {
List<DeployBeanProperty> props = desc.propertiesBase();
for (DeployBeanProperty prop : props) {
if (!prop.isDbRead() && !prop.isDbInsertable() && !prop.isDbUpdateable()) {
// non-transient...
prop.setTransient();
}
}
List<DeployBeanPropertyAssocOne<?>> ones = desc.propertiesAssocOne();
for (DeployBeanPropertyAssocOne<?> prop : ones) {
if (prop.getBeanTable() == null) {
if (!prop.isEmbedded()) {
prop.setTransient();
}
}
}
List<DeployBeanPropertyAssocMany<?>> manys = desc.propertiesAssocMany();
for (DeployBeanPropertyAssocMany<?> prop : manys) {
if (prop.getBeanTable() == null) {
prop.setTransient();
}
}
}
}
@@ -1,16 +0,0 @@
<!ELEMENT ebean (table | iudextender | findextender | datasource | primarykeys | property)* >
<!ELEMENT table EMPTY >
<!ATTLIST table name CDATA #REQUIRED>
<!ELEMENT iudextender EMPTY >
<!ATTLIST iudextender classname CDATA #REQUIRED>
<!ELEMENT findextender EMPTY >
<!ATTLIST findextender classname CDATA #REQUIRED>
<!ELEMENT datasource EMPTY >
<!ATTLIST datasource name CDATA #REQUIRED>
<!ELEMENT primarykeys EMPTY >
<!ATTLIST primarykeys keys CDATA #REQUIRED>
<!ELEMENT property EMPTY >
<!ATTLIST property name CDATA #REQUIRED
datatype CDATA #REQUIRED
deploydatatype CDATA #IMPLIED
deployname CDATA #IMPLIED >
@@ -1,11 +0,0 @@
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
<TITLE>Deployment information parsing</TITLE>
</HEAD>
<Body BGCOLOR="#ffffff">
Deployment information parsing
</Body>
</HTML>
@@ -1 +0,0 @@
package com.avaje.ebeaninternal.server.el;
@@ -1,292 +0,0 @@
package com.avaje.ebeaninternal.server.lib.util;
import java.util.HashMap;
import java.util.Map;
/**
* Utility String class that supports String manipulation functions.
*/
public class StringHelper {
/**
* Parses out a list of Name Value pairs that are delimited together. Will
* always return a StringMap. If allNameValuePairs is null, or no name
* values can be parsed out an empty StringMap is returned.
*
* @param allNameValuePairs the entire string to be parsed.
* @param listDelimiter (typically ';') the delimited between the list
* @param nameValueSeparator (typically '=') the separator between the name and value
*/
public static Map<String, String> delimitedToMap(String allNameValuePairs,
String listDelimiter, String nameValueSeparator) {
HashMap<String, String> params = new HashMap<>();
if ((allNameValuePairs == null) || (allNameValuePairs.isEmpty())) {
return params;
}
// trim off any leading listDelimiter...
allNameValuePairs = trimFront(allNameValuePairs, listDelimiter);
return getKeyValue(params, 0, allNameValuePairs, listDelimiter, nameValueSeparator);
}
/**
* Trims off recurring strings from the front of a string.
*
* @param source the source string
* @param trim the string to trim off the front
*/
public static String trimFront(String source, String trim) {
if (source == null) {
return null;
}
if (source.indexOf(trim) == 0) {
// dp("trim ...");
return trimFront(source.substring(trim.length()), trim);
} else {
return source;
}
}
/**
* Return true if the value is null or an empty string.
*/
public static boolean isNull(String value) {
return value == null || value.trim().isEmpty();
}
/**
* Recursively pulls out the key value pairs from a raw string.
*/
private static HashMap<String, String> getKeyValue(HashMap<String, String> map, int pos,
String allNameValuePairs, String listDelimiter, String nameValueSeparator) {
if (pos >= allNameValuePairs.length()) {
// dp("end as "+pos+" >= "+allNameValuePairs.length() );
return map;
}
int equalsPos = allNameValuePairs.indexOf(nameValueSeparator, pos);
int delimPos = allNameValuePairs.indexOf(listDelimiter, pos);
if (delimPos == -1) {
delimPos = allNameValuePairs.length();
}
if (equalsPos == -1) {
// dp("no more equals...");
return map;
}
if (delimPos == (equalsPos + 1)) {
// dp("Ignoring as nothing between delim and equals...
// delim:"+delimPos+" eq:"+equalsPos);
return getKeyValue(map, delimPos + 1, allNameValuePairs, listDelimiter,
nameValueSeparator);
}
if (equalsPos > delimPos) {
// there is a key without a value?
String key = allNameValuePairs.substring(pos, delimPos);
key = key.trim();
if (!key.isEmpty()) {
map.put(key, null);
}
return getKeyValue(map, delimPos + 1, allNameValuePairs, listDelimiter,
nameValueSeparator);
}
String key = allNameValuePairs.substring(pos, equalsPos);
if (delimPos > -1) {
String value = allNameValuePairs.substring(equalsPos + 1, delimPos);
// dp("cont "+key+","+value+" pos:"+pos+"
// len:"+allNameValuePairs.length());
key = key.trim();
map.put(key, value);
pos = delimPos + 1;
// recurse the rest of the values...
return getKeyValue(map, pos, allNameValuePairs, listDelimiter, nameValueSeparator);
} else {
// dp("ERROR: delimPos < 0 ???");
return map;
}
}
/**
* This method takes a String and will replace all occurrences of the match
* String with that of the replace String.
*
* @param source the source string
* @param match the string used to find a match
* @param replace the string used to replace match with
* @return the source string after the search and replace
*/
public static String replaceString(String source, String match, String replace) {
if (source == null) {
return null;
}
if (replace == null) {
return source;
}
if (match == null) {
throw new NullPointerException("match is null?");
}
if (match.equals(replace)) {
return source;
}
return replaceString(source, match, replace, 30, 0, source.length());
}
/**
* Additionally specify the additionalSize to add to the buffer. This will
* make the buffer bigger so that it doesn't have to grow when replacement
* occurs.
*/
public static String replaceString(String source, String match, String replace,
int additionalSize, int startPos, int endPos) {
if (source == null) {
return null;
}
char match0 = match.charAt(0);
int matchLength = match.length();
if (matchLength == 1 && replace.length() == 1) {
char replace0 = replace.charAt(0);
return source.replace(match0, replace0);
}
if (matchLength >= replace.length()) {
additionalSize = 0;
}
int sourceLength = source.length();
int lastMatch = endPos - matchLength;
StringBuilder sb = new StringBuilder(sourceLength + additionalSize);
if (startPos > 0) {
sb.append(source.substring(0, startPos));
}
char sourceChar;
boolean isMatch;
int sourceMatchPos;
for (int i = startPos; i < sourceLength; i++) {
sourceChar = source.charAt(i);
if (i > lastMatch || sourceChar != match0) {
sb.append(sourceChar);
} else {
// check to see if this is a match
isMatch = true;
sourceMatchPos = i;
// check each following character...
for (int j = 1; j < matchLength; j++) {
sourceMatchPos++;
if (source.charAt(sourceMatchPos) != match.charAt(j)) {
isMatch = false;
break;
}
}
if (isMatch) {
i = i + matchLength - 1;
sb.append(replace);
} else {
// was not a match
sb.append(sourceChar);
}
}
}
return sb.toString();
}
/**
* A search and replace with multiple matching strings.
* <p>
* Useful when converting CRNL CR and NL all to a BR tag for example.
* </p>
* <p>
* <pre><code>
* String[] multi = { &quot;\r\n&quot;, &quot;\r&quot;, &quot;\n&quot; };
* content = StringHelper.replaceStringMulti(content, multi, &quot;&lt;br/&gt;&quot;);
* </code></pre>
*/
public static String replaceStringMulti(String source, String[] match, String replace) {
return replaceStringMulti(source, match, replace, 30, 0, source.length());
}
/**
* Additionally specify an additional size estimate for the buffer plus
* start and end positions.
* <p>
* The start and end positions can limit the search and replace. Otherwise
* these default to startPos = 0 and endPos = source.length().
* </p>
*/
public static String replaceStringMulti(String source, String[] match, String replace,
int additionalSize, int startPos, int endPos) {
int shortestMatch = match[0].length();
char[] match0 = new char[match.length];
for (int i = 0; i < match0.length; i++) {
match0[i] = match[i].charAt(0);
if (match[i].length() < shortestMatch) {
shortestMatch = match[i].length();
}
}
StringBuilder sb = new StringBuilder(source.length() + additionalSize);
char sourceChar;
int len = source.length();
int lastMatch = endPos - shortestMatch;
if (startPos > 0) {
sb.append(source.substring(0, startPos));
}
int matchCount;
for (int i = startPos; i < len; i++) {
sourceChar = source.charAt(i);
if (i > lastMatch) {
sb.append(sourceChar);
} else {
matchCount = 0;
for (int k = 0; k < match0.length; k++) {
if (matchCount == 0 && sourceChar == match0[k]) {
if (match[k].length() + i <= len) {
++matchCount;
int j = 1;
for (; j < match[k].length(); j++) {
if (source.charAt(i + j) != match[k].charAt(j)) {
--matchCount;
break;
}
}
if (matchCount > 0) {
i = i + j - 1;
sb.append(replace);
break;
}
}
}
}
if (matchCount == 0) {
sb.append(sourceChar);
}
}
}
return sb.toString();
}
}
@@ -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 +0,0 @@
package com.avaje.ebeaninternal.server.query;
@@ -1,133 +0,0 @@
package com.avaje.ebeaninternal.server.querydefn;
import com.avaje.ebean.OrderBy;
import com.avaje.ebean.RawSql;
import com.avaje.ebeaninternal.api.BindParams;
import com.avaje.ebeaninternal.api.CQueryPlanKey;
import com.avaje.ebeaninternal.api.HashQueryPlanBuilder;
import com.avaje.ebeaninternal.api.SpiExpression;
import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.server.deploy.TableJoin;
/**
* Query plan key for ORM queries.
*/
class OrmQueryPlanKey implements CQueryPlanKey {
private final String m2mIncludeTable;
private final String orderByAsSting;
private final SpiExpression where;
private final SpiExpression having;
private final RawSql.Key rawSqlKey;
private final boolean hasIdValue;
private final SpiQuery.Type type;
private final int maxRows;
private final int firstRow;
private final boolean disableLazyLoading;
private final boolean distinct;
private final boolean sqlDistinct;
private final String mapKey;
private final SpiQuery.TemporalMode temporalMode;
private final boolean forUpdate;
private final String rootTableAlias;
private final OrmUpdateProperties updateProperties;
private final int planHash;
private final int bindCount;
OrmQueryPlanKey(TableJoin m2mIncludeTable, SpiQuery.Type type, OrmQueryDetail detail, int maxRows, int firstRow, boolean disableLazyLoading, OrderBy<?> orderBy, boolean distinct, boolean sqlDistinct, String mapKey, Object id, BindParams bindParams, SpiExpression whereExpressions, SpiExpression havingExpressions, SpiQuery.TemporalMode temporalMode, boolean forUpdate, String rootTableAlias, RawSql rawSql, OrmUpdateProperties updateProperties) {
this.m2mIncludeTable = m2mIncludeTable == null ? null : m2mIncludeTable.getTable();
this.type = type;
this.maxRows = maxRows;
this.firstRow = firstRow;
this.disableLazyLoading = disableLazyLoading;
this.orderByAsSting = (orderBy == null) ? null : orderBy.toStringFormat();
this.distinct = distinct;
this.sqlDistinct = sqlDistinct;
this.mapKey = mapKey;
this.hasIdValue = (id != null);
this.where = (whereExpressions == null) ? null : whereExpressions.copyForPlanKey();
this.having = (havingExpressions == null) ? null : havingExpressions.copyForPlanKey();
this.temporalMode = temporalMode;
this.forUpdate = forUpdate;
this.rootTableAlias = rootTableAlias;
this.updateProperties = updateProperties;
this.rawSqlKey = (rawSql == null) ? null : rawSql.getKey();
// exclude bind values and things unrelated to the sql being generated
HashQueryPlanBuilder builder = new HashQueryPlanBuilder();
builder.add((type == null ? 0 : type.ordinal() + 1));
builder.add(distinct).add(sqlDistinct);
builder.add(firstRow).add(maxRows);
builder.add(orderBy).add(forUpdate);
builder.add(mapKey);
builder.add(disableLazyLoading);
builder.add(hasIdValue);
builder.add(temporalMode);
builder.add(rawSqlKey == null ? 0 : rawSqlKey.hashCode());
builder.add(this.m2mIncludeTable);
builder.add(rootTableAlias);
if (detail != null) {
detail.queryPlanHash(builder);
}
if (bindParams != null) {
bindParams.buildQueryPlanHash(builder);
}
if (where != null) {
where.queryPlanHash(builder);
}
if (having != null) {
having.queryPlanHash(builder);
}
if (updateProperties != null) {
updateProperties.buildQueryPlanHash(builder);
}
this.planHash = builder.getPlanHash();
this.bindCount = builder.getBindCount();
}
@Override
public String getPartialKey() {
return planHash + "_" + bindCount;
}
@Override
public int hashCode() {
return planHash;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OrmQueryPlanKey that = (OrmQueryPlanKey) o;
if (planHash != that.planHash) return false;
if (bindCount != that.bindCount) return false;
if (maxRows != that.maxRows) return false;
if (firstRow != that.firstRow) return false;
if (disableLazyLoading != that.disableLazyLoading) return false;
if (distinct != that.distinct) return false;
if (sqlDistinct != that.sqlDistinct) return false;
if (forUpdate != that.forUpdate) return false;
if (hasIdValue != that.hasIdValue) return false;
if (type != that.type) return false;
if (temporalMode != that.temporalMode) return false;
if (m2mIncludeTable != null ? !m2mIncludeTable.equals(that.m2mIncludeTable) : that.m2mIncludeTable != null)
return false;
if (orderByAsSting != null ? !orderByAsSting.equals(that.orderByAsSting) : that.orderByAsSting != null)
return false;
if (where != null ? !where.isSameByPlan(that.where) : that.where != null) return false;
if (having != null ? !having.isSameByPlan(that.having) : that.having != null) return false;
if (updateProperties != null ? !updateProperties.isSameByPlan(that.updateProperties) : that.updateProperties != null)
return false;
if (rawSqlKey != null ? !rawSqlKey.equals(that.rawSqlKey) : that.rawSqlKey != null) return false;
if (mapKey != null ? !mapKey.equals(that.mapKey) : that.mapKey != null) return false;
return rootTableAlias != null ? rootTableAlias.equals(that.rootTableAlias) : that.rootTableAlias == null;
}
}
@@ -1 +0,0 @@
package com.avaje.ebeaninternal.server.querydefn;
@@ -1 +0,0 @@
package com.avaje.ebeaninternal.server.text.csv;
@@ -1,25 +0,0 @@
package com.avaje.ebeaninternal.server.transaction;
import javax.sql.DataSource;
/**
* Supply the DataSource to the transaction manager.
* <p>
* Implementations can support multi-tenancy via DB or SCHEMA.
* </p>
*/
public interface DataSourceSupplier {
/**
* Return the DataSource to use for the current request.
* <p>
* This should take into account multi-tenancy and the current tenantId.
* </p>
*/
DataSource getDataSource();
/**
* Shutdown the datasource de-registering the JDBC driver if requested.
*/
void shutdown(boolean deregisterDriver);
}
@@ -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,51 +0,0 @@
package com.avaje.ebeaninternal.server.type;
import com.avaje.ebeaninternal.server.core.BasicTypeConverter;
import org.joda.time.DateMidnight;
import java.sql.Date;
import java.sql.Types;
/**
* ScalarType for Joda DateMidnight. This maps to a JDBC Date.
*/
public class ScalarTypeJodaDateMidnight extends ScalarTypeBaseDate<DateMidnight> {
/**
* Instantiates a new scalar type joda date midnight.
*/
public ScalarTypeJodaDateMidnight() {
super(DateMidnight.class, false, Types.DATE);
}
@Override
public long convertToMillis(DateMidnight value) {
return value.getMillis();
}
@Override
public DateMidnight convertFromDate(Date ts) {
return new DateMidnight(ts.getTime());
}
@Override
public Date convertToDate(DateMidnight t) {
return new Date(t.getMillis());
}
@Override
public Object toJdbcType(Object value) {
if (value instanceof DateMidnight) {
return new Date(((DateMidnight) value).getMillis());
}
return BasicTypeConverter.toDate(value);
}
@Override
public DateMidnight toBeanType(Object value) {
if (value instanceof java.util.Date) {
return new DateMidnight(((java.util.Date) value).getTime());
}
return (DateMidnight) value;
}
}
@@ -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();
}
}
@@ -1,50 +0,0 @@
package com.avaje.ebeaninternal.server.type.reflect;
import com.avaje.ebean.config.CompoundTypeProperty;
import java.lang.reflect.Method;
@SuppressWarnings({"rawtypes"})
public class ReflectionBasedCompoundTypeProperty implements CompoundTypeProperty {
private static final Object[] NO_ARGS = new Object[0];
private final Method reader;
private final String name;
private final Class<?> propertyType;
public ReflectionBasedCompoundTypeProperty(String name, Method reader, Class<?> propertyType) {
this.name = name;
this.reader = reader;
this.propertyType = propertyType;
}
public String toString() {
return name;
}
public int getDbType() {
return 0;
}
public String getName() {
return name;
}
public Object getValue(Object valueObject) {
try {
return reader.invoke(valueObject, NO_ARGS);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public Class<?> getPropertyType() {
return propertyType;
}
}
@@ -1,49 +0,0 @@
package com.avaje.ebeaninternal.server.type.reflect;
import com.avaje.ebean.config.ScalarTypeConverter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
@SuppressWarnings({"rawtypes"})
public class ReflectionBasedScalarTypeConverter implements ScalarTypeConverter {
private static final Object[] NO_ARGS = new Object[0];
private final Constructor<?> constructor;
private final Method reader;
public ReflectionBasedScalarTypeConverter(Constructor<?> constructor, Method reader) {
this.constructor = constructor;
this.reader = reader;
}
public Object getNullValue() {
return null;
}
public Object unwrapValue(Object beanType) {
if (beanType == null) {
return null;
}
try {
return reader.invoke(beanType, NO_ARGS);
} catch (Exception e) {
String msg = "Error invoking read method " + reader.getName()
+ " on " + beanType.getClass().getName();
throw new RuntimeException(msg);
}
}
public Object wrapValue(Object scalarType) {
try {
return constructor.newInstance(scalarType);
} catch (Exception e) {
String msg = "Error invoking constructor " + constructor + " with " + scalarType;
throw new RuntimeException(msg);
}
}
}
@@ -1,78 +0,0 @@
package com.avaje.ebeaninternal.server.type.reflect;
import com.avaje.ebeaninternal.server.type.ScalarType;
import com.avaje.ebeaninternal.server.type.ScalarTypeWrapper;
import com.avaje.ebeaninternal.server.type.TypeManager;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectionBasedTypeBuilder {
private final TypeManager typeManager;
public ReflectionBasedTypeBuilder(TypeManager typeManager) {
this.typeManager = typeManager;
}
@SuppressWarnings({"unchecked", "rawtypes"})
public ScalarType<?> buildScalarType(ImmutableMeta meta) {
if (meta.isCompoundType()) {
throw new RuntimeException("Must be scalar");
}
Constructor<?> constructor = meta.getConstructor();
Class<?> logicalType = constructor.getDeclaringClass();
Method[] readers = meta.getReaders();
Class<?> returnType = readers[0].getReturnType();
ScalarType<?> scalarType = typeManager.recursiveCreateScalarTypes(returnType);
ReflectionBasedScalarTypeConverter r = new ReflectionBasedScalarTypeConverter(constructor, readers[0]);
return new ScalarTypeWrapper(logicalType, scalarType, r);
}
public ReflectionBasedCompoundType buildCompound(ImmutableMeta meta) {
Constructor<?> constructor = meta.getConstructor();
Method[] readers = meta.getReaders();
ReflectionBasedCompoundTypeProperty[] props = new ReflectionBasedCompoundTypeProperty[readers.length];
for (int i = 0; i < readers.length; i++) {
Class<?> returnType = readers[i].getReturnType();
// ensure that return type is also a ScalarDataReader
typeManager.recursiveCreateScalarDataReader(returnType);
String name = getPropertyName(readers[i]);
props[i] = new ReflectionBasedCompoundTypeProperty(name, readers[i], returnType);
}
return new ReflectionBasedCompoundType(constructor, props);
}
private String getPropertyName(Method method) {
String name = method.getName();
if (name.startsWith("is")) {
return lowerFirstChar(name.substring(2));
} else if (name.startsWith("get")) {
return lowerFirstChar(name.substring(3));
}
String msg = "Expecting method " + name + " to start with is or get "
+ " so as to follow bean specification?";
throw new RuntimeException(msg);
}
private String lowerFirstChar(String name) {
return Character.toLowerCase(name.charAt(0)) + name.substring(1);
}
}
@@ -1 +0,0 @@
package com.avaje.ebeaninternal.server.type.reflect;
@@ -1,26 +0,0 @@
package com.avaje.ebeanservice.docstore.api;
import com.avaje.ebean.text.json.JsonReadOptions;
import com.avaje.ebeaninternal.api.SpiQuery;
/**
* A Query request for the document store.
*/
public interface DocQueryRequest<T> {
/**
* Return the query for this request.
*/
SpiQuery<T> getQuery();
/**
* Create JsonReadOptions taking into account persistence context and lazy loading support.
*/
JsonReadOptions createJsonReadOptions();
/**
* Execute secondary queries.
*/
void executeSecondaryQueries(boolean forEach);
}
@@ -1,4 +0,0 @@
/**
* Mapping for document store integration.
*/
package com.avaje.ebeanservice.docstore.api.mapping;
@@ -0,0 +1,21 @@
package io.ebean;
import javax.persistence.PessimisticLockException;
/**
* Thrown when failing to acquire a pessimistic lock.
* <p>
* Typically when "select for update nowait" or "select for update" is being used and
* the lock can not be obtained (as it is held by another transaction).
* </p>
*/
public class AcquireLockException extends PessimisticLockException {
private static final long serialVersionUID = -8585962352965876691L;
/**
* Create with a message and cause.
*/
public AcquireLockException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
/**
* Administrative control of AutoTune during runtime.
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
import java.beans.PropertyChangeListener;
import java.util.Map;
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
import java.sql.CallableStatement;
import java.sql.SQLException;
@@ -73,8 +73,8 @@ import java.sql.SQLException;
* }
* }</pre>
*
* @see com.avaje.ebean.SqlUpdate
* @see com.avaje.ebean.Ebean#execute(CallableSql)
* @see SqlUpdate
* @see Ebean#execute(CallableSql)
*/
public interface CallableSql {
@@ -1,6 +1,6 @@
package com.avaje.ebean;
package io.ebean;
import com.avaje.ebean.RawSql.ColumnMapping;
import io.ebean.RawSql.ColumnMapping;
import javax.persistence.PersistenceException;
import java.util.ArrayList;
@@ -1,7 +1,7 @@
package com.avaje.ebean;
package io.ebean;
import com.avaje.ebean.RawSql.Sql;
import com.avaje.ebeaninternal.server.querydefn.SimpleTextParser;
import io.ebean.RawSql.Sql;
import io.ebeaninternal.server.querydefn.SimpleTextParser;
/**
* Parses sql-select queries to try and determine the location where WHERE and
@@ -0,0 +1,17 @@
package io.ebean;
import javax.persistence.PersistenceException;
/**
* Thrown when a foreign key constraint is enforced.
*/
public class DataIntegrityException extends PersistenceException {
private static final long serialVersionUID = -6740171949170180970L;
/**
* Create with a message and cause.
*/
public DataIntegrityException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
/**
* Bean holding the details to update the document store.
@@ -1,6 +1,7 @@
package com.avaje.ebean;
package io.ebean;
import com.avaje.ebeanservice.docstore.api.DocQueryRequest;
import io.ebeanservice.docstore.api.DocQueryRequest;
import io.ebeanservice.docstore.api.RawDoc;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
@@ -165,6 +166,24 @@ public interface DocumentStore {
*/
<T> void findEachWhile(DocQueryRequest<T> query, Predicate<T> consumer);
/**
* Find each processing raw documents.
*
* @param indexNameType The full index name and type
* @param rawQuery The query to execute
* @param consumer Consumer to process each document
*/
void findEach(String indexNameType, String rawQuery, Consumer<RawDoc> consumer);
/**
* Find each processing raw documents stopping when the predicate returns false.
*
* @param indexNameType The full index name and type
* @param rawQuery The query to execute
* @param consumer Consumer to process each document until false is returned
*/
void findEachWhile(String indexNameType, String rawQuery, Predicate<RawDoc> consumer);
/**
* Process the queue entries sending updates to the document store or queuing them for later processing.
*/
@@ -0,0 +1,15 @@
package io.ebean;
/**
* Thrown when a duplicate is attempted on a unique constraint.
*/
public class DuplicateKeyException extends DataIntegrityException {
private static final long serialVersionUID = -4771932723285724817L;
/**
* Create with a message and cause.
*/
public DuplicateKeyException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -1,9 +1,9 @@
package com.avaje.ebean;
package io.ebean;
import com.avaje.ebean.cache.ServerCacheManager;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.text.csv.CsvReader;
import com.avaje.ebean.text.json.JsonContext;
import io.ebean.cache.ServerCacheManager;
import io.ebean.config.ServerConfig;
import io.ebean.text.csv.CsvReader;
import io.ebean.text.json.JsonContext;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -154,7 +154,7 @@ public final class Ebean {
} else {
// look to see if there is a default server defined
String defaultName = PrimaryServer.getDefaultServerName();
logger.debug("defaultName:" + defaultName);
logger.debug("defaultName:{}", defaultName);
if (defaultName != null && !defaultName.trim().isEmpty()) {
defaultServer = getWithCreate(defaultName.trim());
}
@@ -428,6 +428,24 @@ public final class Ebean {
return serverMgr.getDefaultServer().currentTransaction();
}
/**
* The batch will be flushing automatically but you can use this to explicitly
* flush the batch if you like.
* <p>
* Flushing occurs automatically when:
* </p>
* <ul>
* <li>the batch size is reached</li>
* <li>A query is executed on the same transaction</li>
* <li>UpdateSql or CallableSql are mixed with bean save and delete</li>
* <li>Transaction commit occurs</li>
* <li>A getter method is called on a batched bean</li>
* </ul>
*/
public static void flush() {
currentTransaction().flush();
}
/**
* Register a TransactionCallback on the currently active transaction.
* <p/>
@@ -1012,6 +1030,30 @@ public final class Ebean {
return serverMgr.getDefaultServer().find(beanType);
}
/**
* Create a query using native SQL.
* <p>
* The native SQL can contain named parameters or positioned parameters.
* </p>
* <pre>{@code
*
* String sql = "select c.id, c.name from customer c where c.name like ? order by c.name";
*
* Query<Customer> query = ebeanServer.findNative(Customer.class, sql);
* query.setParameter(1, "Rob%");
*
* List<Customer> customers = query.findList();
*
* }</pre>
*
* @param beanType The type of entity bean to fetch
* @param nativeSql The SQL that can contain named or positioned parameters
* @return The query to set parameters and execute
*/
public static <T> Query<T> findNative(Class<T> beanType, String nativeSql) {
return serverMgr.getDefaultServer().findNative(beanType, nativeSql);
}
/**
* Create an Update query to perform a bulk update.
* <p>
@@ -1,11 +1,11 @@
package com.avaje.ebean;
package io.ebean;
import com.avaje.ebean.cache.ServerCacheManager;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.meta.MetaInfoManager;
import com.avaje.ebean.plugin.SpiServer;
import com.avaje.ebean.text.csv.CsvReader;
import com.avaje.ebean.text.json.JsonContext;
import io.ebean.cache.ServerCacheManager;
import io.ebean.config.ServerConfig;
import io.ebean.meta.MetaInfoManager;
import io.ebean.plugin.SpiServer;
import io.ebean.text.csv.CsvReader;
import io.ebean.text.json.JsonContext;
import org.jetbrains.annotations.Nullable;
import javax.persistence.NonUniqueResultException;
@@ -14,6 +14,7 @@ import javax.persistence.PersistenceException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -232,9 +233,9 @@ public interface EbeanServer {
*
* // Find order additionally fetching the customer, details and details.product name.
*
* String eql = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
* String ormQuery = "fetch customer fetch details fetch details.product (name) where id = :orderId ";
*
* Query<Order> query = Ebean.createQuery(Order.class, eql);
* Query<Order> query = Ebean.createQuery(Order.class, ormQuery);
* query.setParameter("orderId", 2);
*
* Order order = query.findUnique();
@@ -251,11 +252,11 @@ public interface EbeanServer {
* }</pre>
*
* @param beanType The type of bean to fetch
* @param eql The Ebean query
* @param ormQuery The Ebean ORM query
* @param <T> The type of the entity bean
* @return The query with expressions defined as per the parsed query statement
*/
<T> Query<T> createQuery(Class<T> beanType, String eql);
<T> Query<T> createQuery(Class<T> beanType, String ormQuery);
/**
* Create a query for a type of entity bean.
@@ -298,6 +299,28 @@ public interface EbeanServer {
*/
<T> Query<T> find(Class<T> beanType);
/**
* Create a query using native SQL.
* <p>
* The native SQL can contain named parameters or positioned parameters.
* </p>
* <pre>{@code
*
* String sql = "select c.id, c.name from customer c where c.name like ? order by c.name";
*
* Query<Customer> query = ebeanServer.findNative(Customer.class, sql);
* query.setParameter(1, "Rob%");
*
* List<Customer> customers = query.findList();
*
* }</pre>
*
* @param beanType The type of entity bean to fetch
* @param nativeSql The SQL that can contain named or positioned parameters
* @return The query to set parameters and execute
*/
<T> Query<T> findNative(Class<T> beanType, String nativeSql);
/**
* Return the next unique identity value for a given bean type.
* <p>
@@ -591,6 +614,19 @@ public interface EbeanServer {
*/
Transaction currentTransaction();
/**
* Flush the JDBC batch on the current transaction.
* <p>
* This only is useful when JDBC batch is used. Flush occurs automatically when the
* transaction commits or batch size is reached. This manually flushes the JDBC batch
* buffer.
* </p>
* <p>
* This is the same as <code>currentTransaction().flush()</code>.
* </p>
*/
void flush();
/**
* Commit the current transaction.
*/
@@ -885,7 +921,7 @@ public interface EbeanServer {
* @param query the query to execute the row count on
* @param transaction the transaction (can be null).
* @return a Future object for the row count query
* @see com.avaje.ebean.Query#findFutureCount()
* @see Query#findFutureCount()
*/
<T> FutureRowCount<T> findFutureCount(Query<T> query, Transaction transaction);
@@ -900,7 +936,7 @@ public interface EbeanServer {
* @param query the query to execute the fetch Id's on
* @param transaction the transaction (can be null).
* @return a Future object for the list of Id's
* @see com.avaje.ebean.Query#findFutureIds()
* @see Query#findFutureIds()
*/
<T> FutureIds<T> findFutureIds(Query<T> query, Transaction transaction);
@@ -1031,7 +1067,7 @@ public interface EbeanServer {
* This will throw a NonUniqueResultException if the query finds more than one result.
* </p>
* <p>
* Generally you are able to use {@link Query#findUnique()} rather than
* Generally you are able to use {@link Query#findOne()} rather than
* explicitly calling this method. You could use this method if you wish to
* explicitly control the transaction used for the query.
* </p>
@@ -1041,7 +1077,22 @@ public interface EbeanServer {
* @param transaction the transaction to use (can be null).
* @return the list of fetched beans.
* @throws NonUniqueResultException if more than one result was found
* @see Query#findUnique()
* @see Query#findOne()
*/
@Nullable
<T> T findOne(Query<T> query, Transaction transaction);
/**
* Similar to findOne() but returns an Optional (rather than nullable).
*/
<T> Optional<T> findOneOrEmpty(Query<T> query, Transaction transaction);
/**
* Synonym for findOne().
* <p>
* This proceeded findOne which was introduced to better match spring data.
* This will be deprecated at some future point.
* </p>
*/
@Nullable
<T> T findUnique(Query<T> query, Transaction transaction);
@@ -1126,6 +1177,16 @@ public interface EbeanServer {
* @see SqlQuery#findUnique()
*/
@Nullable
SqlRow findOne(SqlQuery query, Transaction transaction);
/**
* Synonym for findOne().
* <p>
* This proceeded findOne which was introduced to better match spring data.
* This will be deprecated at some future point.
* </p>
*/
@Nullable
SqlRow findUnique(SqlQuery query, Transaction transaction);
/**
@@ -1,9 +1,9 @@
package com.avaje.ebean;
package io.ebean;
import com.avaje.ebean.common.SpiContainer;
import com.avaje.ebean.config.ContainerConfig;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
import io.ebean.common.SpiContainer;
import io.ebean.config.ContainerConfig;
import io.ebean.config.ServerConfig;
import io.ebeaninternal.server.lib.ShutdownManager;
import javax.persistence.PersistenceException;
import java.lang.reflect.Constructor;
@@ -30,7 +30,7 @@ import java.util.Properties;
public class EbeanServerFactory {
private static final String DEFAULT_CONTAINER = "com.avaje.ebeaninternal.server.core.DefaultContainer";
private static final String DEFAULT_CONTAINER = "io.ebeaninternal.server.core.DefaultContainer";
private static SpiContainer container;
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
/**
* Query by Example expression.
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
import java.util.Collection;
import java.util.Map;
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
/**
* An expression that is part of a WHERE or HAVING clause.
@@ -1,13 +1,12 @@
package com.avaje.ebean;
package io.ebean;
import com.avaje.ebean.search.Match;
import com.avaje.ebean.search.MultiMatch;
import com.avaje.ebean.search.TextCommonTerms;
import com.avaje.ebean.search.TextQueryString;
import com.avaje.ebean.search.TextSimple;
import io.ebean.search.Match;
import io.ebean.search.MultiMatch;
import io.ebean.search.TextCommonTerms;
import io.ebean.search.TextQueryString;
import io.ebean.search.TextSimple;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
@@ -308,9 +307,9 @@ public interface ExpressionFactory {
Expression idIn(Object... idValues);
/**
* Id IN a list of Id values.
* Id IN a collection of Id values.
*/
Expression idIn(List<?> idList);
Expression idIn(Collection<?> idCollection);
/**
* All Equal - Map containing property names and their values.
@@ -1,10 +1,10 @@
package com.avaje.ebean;
package io.ebean;
import com.avaje.ebean.search.Match;
import com.avaje.ebean.search.MultiMatch;
import com.avaje.ebean.search.TextCommonTerms;
import com.avaje.ebean.search.TextQueryString;
import com.avaje.ebean.search.TextSimple;
import io.ebean.search.Match;
import io.ebean.search.MultiMatch;
import io.ebean.search.TextCommonTerms;
import io.ebean.search.TextQueryString;
import io.ebean.search.TextSimple;
import org.jetbrains.annotations.Nullable;
import javax.persistence.NonUniqueResultException;
@@ -12,6 +12,7 @@ import java.sql.Timestamp;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -118,6 +119,27 @@ public interface ExpressionList<T> {
*/
Query<T> asDraft();
/**
* Execute using "for update" clause which results in the DB locking the record.
*/
Query<T> forUpdate();
/**
* Execute using "for update" clause with No Wait option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
*/
Query<T> forUpdateNoWait();
/**
* Execute using "for update" clause with Skip Locked option.
* <p>
* This is typically a Postgres and Oracle only option at this stage.
* </p>
*/
Query<T> forUpdateSkipLocked();
/**
* Execute the query including soft deleted rows.
*/
@@ -245,6 +267,21 @@ public interface ExpressionList<T> {
* @see Query#findUnique()
*/
@Nullable
T findOne();
/**
* Execute the query returning an optional bean.
*/
Optional<T> findOneOrEmpty();
/**
* Synonym for findOne().
* <p>
* This proceeded findOne which was introduced to better match spring data.
* This will be deprecated at some future point.
* </p>
*/
@Nullable
T findUnique();
/**
@@ -799,9 +836,9 @@ public interface ExpressionList<T> {
ExpressionList<T> idIn(Object... idValues);
/**
* Id IN a list of id values.
* Id IN a collection of id values.
*/
ExpressionList<T> idIn(List<?> idValues);
ExpressionList<T> idIn(Collection<?> idValues);
/**
* Id Equal to - ID property is equal to the value.
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
import java.io.Serializable;
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
import java.util.Set;
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
import java.util.List;
import java.util.Set;
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
import org.jetbrains.annotations.Nullable;
@@ -18,7 +18,7 @@ import java.util.List;
* </p>
* <pre>{@code
*
* public class CustomerFinder extends Finder<Customer> {
* public class CustomerFinder extends Finder<Long,Customer> {
*
* public CustomerFinder() {
* super(Customer.class);
@@ -31,7 +31,7 @@ import java.util.List;
* }
*
* public List<Customer> findNew() {
* return query()
* return query().where()
* .eq("status", Customer.Status.NEW)
* .orderBy("name")
* .findList()
@@ -157,4 +157,17 @@ public class Finder<I, T> {
return db().find(type);
}
/**
* Creates a native sql query.
*/
public Query<T> nativeSql(String nativeSql) {
return db().findNative(type, nativeSql);
}
/**
* Creates a query using the ORM query language.
*/
public Query<T> query(String ormQuery) {
return db().createQuery(type, ormQuery);
}
}
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
import java.util.List;
import java.util.concurrent.Future;
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
import javax.persistence.PersistenceException;
import java.util.List;
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
import java.util.concurrent.Future;
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
/**
* Represents a Conjunction or a Disjunction.
@@ -1,4 +1,4 @@
package com.avaje.ebean;
package io.ebean;
/**
* Used to specify the type of like matching used.
@@ -6,22 +6,22 @@ package com.avaje.ebean;
public enum LikeType {
/**
* You need to put in your own wildcards.
* You need to put in your own wildcards - no escaping is performed.
*/
RAW,
/**
* The % wildcard is added to the end of the search word.
* The % wildcard is added to the end of the search word and search word is escaped.
*/
STARTS_WITH,
/**
* The % wildcard is added to the beginning of the search word.
* The % wildcard is added to the beginning of the search word and search word is escaped.
*/
ENDS_WITH,
/**
* The % wildcard is added to the beginning and end of the search word.
* The % wildcard is added to the beginning and end of the search word and search word is escaped.
*/
CONTAINS,
@@ -32,4 +32,4 @@ public enum LikeType {
* </p>
*/
EQUAL_TO
}
}
+286
View File
@@ -0,0 +1,286 @@
package io.ebean;
import io.ebean.bean.EntityBean;
import javax.persistence.MappedSuperclass;
/**
* 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 ebean-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 Finder} 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;
*
* @WhenCreated Timestamp whenCreated;
*
* @WhenUpdated Timestamp whenUpdated;
*
* ...
*
* }</pre>
* <p>
* <h3>Extend the Model</h3>
* <pre>{@code
*
* // Extend the mappedSuperclass
*
* @Entity @Table(name="o_account")
* public class Customer extends BaseModel {
*
* 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>
*/
@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);
}
/**
* Flush any batched changes to the database.
* <p>
* When using JDBC batch flushing occurs automatically at commit() time or when the batch size
* is reached. This provides the ability to manually flush the batch.
* </p>
*/
public void flush() {
db().flush();
}
/**
* 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);
}
}

Some files were not shown because too many files have changed in this diff Show More