diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 91ff0bd9b..4e4278cdc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,7 +1,10 @@ name: Build -on: [push, pull_request] +on: + pull_request: + push: + branches: master jobs: build: diff --git a/composites/ebean-clickhouse/pom.xml b/composites/ebean-clickhouse/pom.xml index 1327456b0..06d7b16a7 100644 --- a/composites/ebean-clickhouse/pom.xml +++ b/composites/ebean-clickhouse/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean ebean-platform-clickhouse - 14.0.0 + 14.0.1 diff --git a/composites/ebean-cockroach/pom.xml b/composites/ebean-cockroach/pom.xml index 2bda7c244..20acfa443 100644 --- a/composites/ebean-cockroach/pom.xml +++ b/composites/ebean-cockroach/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean ebean-platform-postgres - 14.0.0 + 14.0.1 diff --git a/composites/ebean-db2/pom.xml b/composites/ebean-db2/pom.xml index 364bc8759..18567b46d 100644 --- a/composites/ebean-db2/pom.xml +++ b/composites/ebean-db2/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean ebean-platform-db2 - 14.0.0 + 14.0.1 diff --git a/composites/ebean-h2/pom.xml b/composites/ebean-h2/pom.xml index 867d9aa58..e99c020f1 100644 --- a/composites/ebean-h2/pom.xml +++ b/composites/ebean-h2/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean ebean-platform-h2 - 14.0.0 + 14.0.1 diff --git a/composites/ebean-hana/pom.xml b/composites/ebean-hana/pom.xml index 7b4880994..1bbc036c2 100644 --- a/composites/ebean-hana/pom.xml +++ b/composites/ebean-hana/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean ebean-platform-hana - 14.0.0 + 14.0.1 diff --git a/composites/ebean-mariadb/pom.xml b/composites/ebean-mariadb/pom.xml index fc6c5925c..5e6bd20d8 100644 --- a/composites/ebean-mariadb/pom.xml +++ b/composites/ebean-mariadb/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean ebean-platform-mariadb - 14.0.0 + 14.0.1 diff --git a/composites/ebean-mysql/pom.xml b/composites/ebean-mysql/pom.xml index 602da3ceb..cac8d8a9f 100644 --- a/composites/ebean-mysql/pom.xml +++ b/composites/ebean-mysql/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean ebean-platform-mysql - 14.0.0 + 14.0.1 diff --git a/composites/ebean-nuodb/pom.xml b/composites/ebean-nuodb/pom.xml index a58897819..1b1fb3857 100644 --- a/composites/ebean-nuodb/pom.xml +++ b/composites/ebean-nuodb/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean ebean-platform-nuodb - 14.0.0 + 14.0.1 diff --git a/composites/ebean-oracle/pom.xml b/composites/ebean-oracle/pom.xml index dcf5b76a5..34a27740d 100644 --- a/composites/ebean-oracle/pom.xml +++ b/composites/ebean-oracle/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean ebean-platform-oracle - 14.0.0 + 14.0.1 diff --git a/composites/ebean-postgis/pom.xml b/composites/ebean-postgis/pom.xml index 98b667668..f360523d7 100644 --- a/composites/ebean-postgis/pom.xml +++ b/composites/ebean-postgis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -14,7 +14,7 @@ 2.5.1 - 42.6.0 + 42.7.2 @@ -22,13 +22,13 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 @@ -47,19 +47,19 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean ebean-platform-postgres - 14.0.0 + 14.0.1 io.ebean ebean-postgis-types - 14.0.0 + 14.0.1 diff --git a/composites/ebean-postgres/pom.xml b/composites/ebean-postgres/pom.xml index 6e23f7650..48650fbd4 100644 --- a/composites/ebean-postgres/pom.xml +++ b/composites/ebean-postgres/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean ebean-platform-postgres - 14.0.0 + 14.0.1 diff --git a/composites/ebean-sqlite/pom.xml b/composites/ebean-sqlite/pom.xml index ac7a96dea..e8ba4b984 100644 --- a/composites/ebean-sqlite/pom.xml +++ b/composites/ebean-sqlite/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean ebean-platform-sqlite - 14.0.0 + 14.0.1 diff --git a/composites/ebean-sqlserver/pom.xml b/composites/ebean-sqlserver/pom.xml index 4cebb6dd0..adcfe732c 100644 --- a/composites/ebean-sqlserver/pom.xml +++ b/composites/ebean-sqlserver/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean ebean-platform-sqlserver - 14.0.0 + 14.0.1 diff --git a/composites/ebean-yugabyte/pom.xml b/composites/ebean-yugabyte/pom.xml index 8febd2908..3ef2e2c3a 100644 --- a/composites/ebean-yugabyte/pom.xml +++ b/composites/ebean-yugabyte/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean ebean-platform-postgres - 14.0.0 + 14.0.1 diff --git a/composites/ebean/pom.xml b/composites/ebean/pom.xml index e54b6ea9d..f37e439d6 100644 --- a/composites/ebean/pom.xml +++ b/composites/ebean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -17,31 +17,31 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 io.ebean ebean-joda-time - 13.24.0 + 14.0.0 io.ebean ebean-jackson-jsonnode - 13.24.0 + 14.0.0 io.ebean ebean-jackson-mapper - 14.0.0 + 14.0.1 @@ -60,13 +60,13 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean ebean-platform-all - 14.0.0 + 14.0.1 diff --git a/composites/pom.xml b/composites/pom.xml index 7fb663ed6..b16cabddb 100644 --- a/composites/pom.xml +++ b/composites/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 composites diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index 93960d07d..e2020d174 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ebean api @@ -39,7 +39,7 @@ io.avaje avaje-config - 3.10 + 3.12 diff --git a/ebean-api/src/main/java/io/ebean/DataIntegrityException.java b/ebean-api/src/main/java/io/ebean/DataIntegrityException.java index 495bdd349..c9f451ee7 100644 --- a/ebean-api/src/main/java/io/ebean/DataIntegrityException.java +++ b/ebean-api/src/main/java/io/ebean/DataIntegrityException.java @@ -3,7 +3,7 @@ package io.ebean; import jakarta.persistence.PersistenceException; /** - * Thrown when a foreign key constraint is enforced. + * Thrown when a foreign key constraint is enforced or a field is too large. */ public class DataIntegrityException extends PersistenceException { private static final long serialVersionUID = -6740171949170180970L; @@ -14,4 +14,11 @@ public class DataIntegrityException extends PersistenceException { public DataIntegrityException(String message, Throwable cause) { super(message, cause); } + + /** + * Create with message only. + */ + public DataIntegrityException(String message) { + super(message); + } } diff --git a/ebean-api/src/main/java/io/ebean/Database.java b/ebean-api/src/main/java/io/ebean/Database.java index bb9ab9b72..f4a5b7897 100644 --- a/ebean-api/src/main/java/io/ebean/Database.java +++ b/ebean-api/src/main/java/io/ebean/Database.java @@ -88,16 +88,16 @@ public interface Database { /** * Return a new database builder. - *
{@code
- *
- *   // build the 'default' database using configuration
- *   // from application.properties / application.yaml
- *
- *   Database db = Database.builder()
- *     .loadFromProperties()
- *     .build();
- *
- * }
+ *
{@code
+   *
+   *   // build the 'default' database using configuration
+   *   // from application.properties / application.yaml
+   *
+   *   Database db = Database.builder()
+   *     .loadFromProperties()
+   *     .build();
+   *
+   * }
*/ static DatabaseBuilder builder() { return new DatabaseConfig(); diff --git a/ebean-api/src/main/java/io/ebean/DatabaseBuilder.java b/ebean-api/src/main/java/io/ebean/DatabaseBuilder.java index 80ba130b1..bcd228c75 100644 --- a/ebean-api/src/main/java/io/ebean/DatabaseBuilder.java +++ b/ebean-api/src/main/java/io/ebean/DatabaseBuilder.java @@ -85,6 +85,7 @@ public interface DatabaseBuilder { } return this; } + /** * Set the name of the Database. */ @@ -2177,6 +2178,11 @@ public interface DatabaseBuilder { @Deprecated DatabaseBuilder setMetricNaming(Function metricNaming); + /** + * Sets the length check mode. + */ + DatabaseConfig lengthCheck(LengthCheck lengthCheck); + /** * Provides read access (getters) for the DatabaseBuilder configuration * that has been set. @@ -3039,5 +3045,9 @@ public interface DatabaseBuilder { */ Function getMetricNaming(); + /** + * Returns the length check mode. + */ + LengthCheck getLengthCheck(); } } diff --git a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java index c689e7bda..38dc0b5f9 100644 --- a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java +++ b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java @@ -531,6 +531,8 @@ public class DatabaseConfig implements DatabaseBuilder.Settings { private String dumpMetricsOptions; + private LengthCheck lengthCheck = LengthCheck.OFF; + private Function metricNaming = MetricNamingMatch.INSTANCE; /** @@ -2124,6 +2126,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings { jdbcFetchSizeFindEach = p.getInt("jdbcFetchSizeFindEach", jdbcFetchSizeFindEach); jdbcFetchSizeFindList = p.getInt("jdbcFetchSizeFindList", jdbcFetchSizeFindList); databasePlatformName = p.get("databasePlatformName", databasePlatformName); + lengthCheck = p.getEnum(LengthCheck.class, "lengthCheck", lengthCheck); uuidVersion = p.getEnum(UuidVersion.class, "uuidVersion", uuidVersion); uuidStateFile = p.get("uuidStateFile", uuidStateFile); @@ -2500,6 +2503,19 @@ public class DatabaseConfig implements DatabaseBuilder.Settings { return this; } + /** + * Returns the length check mode. + */ + public LengthCheck getLengthCheck() { + return lengthCheck; + } + + @Override + public DatabaseConfig lengthCheck(LengthCheck lengthCheck) { + this.lengthCheck = lengthCheck; + return this; + } + public enum UuidVersion { VERSION4, VERSION1, diff --git a/ebean-api/src/main/java/io/ebean/config/LengthCheck.java b/ebean-api/src/main/java/io/ebean/config/LengthCheck.java new file mode 100644 index 000000000..4f4abf887 --- /dev/null +++ b/ebean-api/src/main/java/io/ebean/config/LengthCheck.java @@ -0,0 +1,22 @@ +package io.ebean.config; + +/** + * Defines the length-check mode. + * + * @author Roland Praml, FOCONIS AG + */ +public enum LengthCheck { + /** + * By default, length checking is off. This means, strings/jsons and files are passed to the DB and the DB might or might not check the length. + * The DB has to check the data length. Note this is not possible for certain datatypes (e.g. clob without size) + */ + OFF, + /** + * When enabling length check, ebean validates strings/json strings and files before saving them to DB. + */ + ON, + /** + * Same as "ON", but take the UTF8-bytelength for validation. This may be useful, if you have an UTF8 based charset (default for DB2) + */ + UTF8 +} diff --git a/ebean-api/src/main/java/io/ebean/event/ShutdownManager.java b/ebean-api/src/main/java/io/ebean/event/ShutdownManager.java index 458199c8e..be85d0e37 100644 --- a/ebean-api/src/main/java/io/ebean/event/ShutdownManager.java +++ b/ebean-api/src/main/java/io/ebean/event/ShutdownManager.java @@ -8,6 +8,7 @@ import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.concurrent.locks.ReentrantLock; @@ -23,7 +24,7 @@ public final class ShutdownManager { private static final System.Logger log = EbeanVersion.log; private static final ReentrantLock lock = new ReentrantLock(); - private static final List databases = new ArrayList<>(); + private static final List databases = Collections.synchronizedList(new ArrayList<>()); private static final ShutdownHook shutdownHook = new ShutdownHook(); private static boolean stopping; @@ -177,12 +178,7 @@ public final class ShutdownManager { * Register an ebeanServer to be shutdown when the JVM is shutdown. */ public static void registerDatabase(Database server) { - lock.lock(); - try { - databases.add(server); - } finally { - lock.unlock(); - } + databases.add(server); } /** @@ -192,12 +188,7 @@ public final class ShutdownManager { *

*/ public static void unregisterDatabase(Database server) { - lock.lock(); - try { - databases.remove(server); - } finally { - lock.unlock(); - } + databases.remove(server); } private static class ShutdownHook extends Thread { diff --git a/ebean-api/src/main/java/io/ebean/text/json/JsonWriteOptions.java b/ebean-api/src/main/java/io/ebean/text/json/JsonWriteOptions.java index 7995f7a84..913ac4114 100644 --- a/ebean-api/src/main/java/io/ebean/text/json/JsonWriteOptions.java +++ b/ebean-api/src/main/java/io/ebean/text/json/JsonWriteOptions.java @@ -22,6 +22,8 @@ public class JsonWriteOptions { protected JsonConfig.Include include; + protected boolean includeLoadedImplicit = true; + protected Map> visitorMap; /** @@ -73,6 +75,20 @@ public class JsonWriteOptions { this.include = include; } + /** + * Should loaded properties be included implicit, if no other fetch path is specified (default = true). + */ + public boolean isIncludeLoadedImplicit() { + return includeLoadedImplicit; + } + + /** + * Set include loaded properties implicit (default = true). + */ + public void setIncludeLoadedImplicit(boolean includeLoadedImplicit) { + this.includeLoadedImplicit = includeLoadedImplicit; + } + /** * Register a JsonWriteBeanVisitor for the root level. */ diff --git a/ebean-api/src/test/java/io/ebean/config/DatabaseConfigTest.java b/ebean-api/src/test/java/io/ebean/config/DatabaseConfigTest.java index 63bc0f2eb..9b5afb2b0 100644 --- a/ebean-api/src/test/java/io/ebean/config/DatabaseConfigTest.java +++ b/ebean-api/src/test/java/io/ebean/config/DatabaseConfigTest.java @@ -75,6 +75,7 @@ class DatabaseConfigTest { props.setProperty("defaultServer", "false"); props.setProperty("skipDataSourceCheck", "true"); props.setProperty("readOnlyDatabase", "true"); + props.setProperty("lengthCheck", "ON"); props.setProperty("queryPlan.enable", "true"); props.setProperty("queryPlan.thresholdMicros", "10000"); @@ -95,6 +96,7 @@ class DatabaseConfigTest { assertTrue(settings.isLoadModuleInfo()); assertTrue(settings.skipDataSourceCheck()); assertTrue(settings.readOnlyDatabase()); + assertThat(settings.getLengthCheck()).isEqualTo(LengthCheck.ON); assertTrue(settings.isIdGeneratorAutomatic()); assertFalse(settings.getPlatformConfig().isCaseSensitiveCollation()); @@ -128,8 +130,11 @@ class DatabaseConfigTest { assertThat(settings.getMappingLocations()).containsExactly("classpath:/foo","bar"); - config.setPersistBatch(PersistBatch.NONE); - config.setPersistBatchOnCascade(PersistBatch.NONE); + config.persistBatch(PersistBatch.NONE) + .persistBatchOnCascade(PersistBatch.NONE) + .lengthCheck(LengthCheck.ON) + .lengthCheck(LengthCheck.UTF8); + Properties props1 = new Properties(); props1.setProperty("ebean.persistBatch", "ALL"); @@ -146,6 +151,7 @@ class DatabaseConfigTest { assertEquals(PersistBatch.ALL, settings.getPersistBatch()); assertEquals(PersistBatch.ALL, settings.getPersistBatchOnCascade()); + assertEquals(LengthCheck.UTF8, settings.getLengthCheck()); config.setEnabledL2Regions("r0,orgs"); assertEquals("r0,orgs", settings.getEnabledL2Regions()); @@ -174,6 +180,7 @@ class DatabaseConfigTest { assertEquals(600, config.getQueryPlanCapturePeriodSecs()); assertEquals(10000L, config.getQueryPlanCaptureMaxTimeMillis()); assertEquals(10, config.getQueryPlanCaptureMaxCount()); + assertThat(config.getLengthCheck()).isEqualTo(LengthCheck.OFF); config.setLoadModuleInfo(false); assertFalse(config.isAutoLoadModuleInfo()); diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index 001501f40..b2881bd78 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ebean bom @@ -89,103 +89,103 @@ io.ebean ebean - 14.0.0 + 14.0.1 io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 io.ebean ebean-core-type - 14.0.0 + 14.0.1 io.ebean ebean-joda-time - 13.24.0 + 14.0.0 io.ebean ebean-jackson-jsonnode - 13.24.0 + 14.0.0 io.ebean ebean-jackson-mapper - 14.0.0 + 14.0.1 io.ebean ebean-ddl-generator - 14.0.0 + 14.0.1 io.ebean ebean-externalmapping-api - 13.18.0 + 14.0.0 io.ebean ebean-externalmapping-xml - 13.18.0 + 14.0.0 io.ebean ebean-autotune - 13.18.0 + 14.0.0 io.ebean ebean-querybean - 14.0.0 + 14.0.1 io.ebean querybean-generator - 14.0.0 + 14.0.1 io.ebean kotlin-querybean-generator - 14.0.0 + 14.0.1 io.ebean ebean-test - 14.0.0 + 14.0.1 io.ebean ebean-redis - 14.0.0 + 14.0.1 io.ebean ebean-spring-txn - 14.0.0 + 14.0.1 @@ -193,79 +193,79 @@ io.ebean ebean-clickhouse - 14.0.0 + 14.0.1 io.ebean ebean-db2 - 14.0.0 + 14.0.1 io.ebean ebean-h2 - 14.0.0 + 14.0.1 io.ebean ebean-hana - 14.0.0 + 14.0.1 io.ebean ebean-mariadb - 14.0.0 + 14.0.1 io.ebean ebean-mysql - 14.0.0 + 14.0.1 io.ebean ebean-nuodb - 14.0.0 + 14.0.1 io.ebean ebean-oracle - 14.0.0 + 14.0.1 io.ebean ebean-postgres - 14.0.0 + 14.0.1 io.ebean ebean-postgis - 14.0.0 + 14.0.1 io.ebean ebean-postgis-types - 14.0.0 + 14.0.1 io.ebean ebean-sqlite - 14.0.0 + 14.0.1 io.ebean ebean-sqlserver - 14.0.0 + 14.0.1 diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index d239a9c26..7fdfb41d0 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ebean-core-type @@ -16,7 +16,7 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 @@ -30,7 +30,7 @@ org.postgresql postgresql - 42.6.0 + 42.7.2 true diff --git a/ebean-core-type/src/main/java/io/ebean/core/type/DataBinder.java b/ebean-core-type/src/main/java/io/ebean/core/type/DataBinder.java index b08bb529a..d955445b9 100644 --- a/ebean-core-type/src/main/java/io/ebean/core/type/DataBinder.java +++ b/ebean-core-type/src/main/java/io/ebean/core/type/DataBinder.java @@ -174,4 +174,9 @@ public interface DataBinder { */ String popJson(); + /** + * Returns the last bound object (e.g. for BindValidation). Note for InputStreams you'll get an InputStreamInfo. + */ + Object popLastObject(); + } diff --git a/ebean-core-type/src/main/java/io/ebean/core/type/InputStreamInfo.java b/ebean-core-type/src/main/java/io/ebean/core/type/InputStreamInfo.java new file mode 100644 index 000000000..137ab4da6 --- /dev/null +++ b/ebean-core-type/src/main/java/io/ebean/core/type/InputStreamInfo.java @@ -0,0 +1,27 @@ +package io.ebean.core.type; + +import java.io.InputStream; + +/** + * Helper to transports length info of DataBind.setBinaryStream(stream, length) to BindValidation + * + * @author Roland Praml, FOCONIS AG + */ +public final class InputStreamInfo { + + private final InputStream stream; + private final long length; + + public InputStreamInfo(InputStream stream, long length) { + this.stream = stream; + this.length = length; + } + + public InputStream stream() { + return stream; + } + + public long length() { + return length; + } +} diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index 4c5d16349..7612cc9e2 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ebean-core @@ -22,7 +22,7 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 @@ -46,7 +46,7 @@ io.ebean ebean-core-type - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 provided @@ -47,7 +47,7 @@ org.postgresql postgresql - 42.6.0 + 42.7.2 provided @@ -62,7 +62,7 @@ io.ebean ebean-test - 14.0.0 + 14.0.1 test diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index 9e3c19402..d21e44808 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ebean querybean @@ -17,7 +17,7 @@ io.ebean ebean-core - 14.0.0 + 14.0.1 provided @@ -63,14 +63,14 @@ io.ebean ebean-ddl-generator - 14.0.0 + 14.0.1 test io.ebean ebean-test - 14.0.0 + 14.0.1 test @@ -84,7 +84,7 @@ io.ebean querybean-generator - 14.0.0 + 14.0.1 provided diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/TQAssocBean.java b/ebean-querybean/src/main/java/io/ebean/typequery/TQAssocBean.java index 0d87f3612..37324dfa3 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/TQAssocBean.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/TQAssocBean.java @@ -108,6 +108,18 @@ public abstract class TQAssocBean extends TQAssoc { return fetchWithProperties(FETCH_DEFAULT, properties); } + + /** + * Fetch this association with config for the type of fetch and the specified properties. + * + * @param config Fetch configuration to define the type of fetch to use + * @param properties The properties to fetch + */ + @SafeVarargs @SuppressWarnings("varargs") + public final R fetch(FetchConfig config, TQProperty... properties) { + return fetchWithProperties(config, properties); + } + /** * Eagerly fetch this association using a 'query join' loading the specified properties. */ diff --git a/ebean-querybean/src/test/java/org/example/domain/Alias.java b/ebean-querybean/src/test/java/org/example/domain/Alias.java new file mode 100644 index 000000000..9a5b38e24 --- /dev/null +++ b/ebean-querybean/src/test/java/org/example/domain/Alias.java @@ -0,0 +1,14 @@ +package org.example.domain; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Version; + +@Entity +public class Alias { + + @Id + long id; + @Version + long version; +} diff --git a/ebean-querybean/src/test/java/org/querytest/QOrderTest.java b/ebean-querybean/src/test/java/org/querytest/QOrderTest.java index bcfa451ec..44627581d 100644 --- a/ebean-querybean/src/test/java/org/querytest/QOrderTest.java +++ b/ebean-querybean/src/test/java/org/querytest/QOrderTest.java @@ -1,6 +1,7 @@ package org.querytest; import io.ebean.DB; +import io.ebean.FetchConfig; import io.ebean.FetchGroup; import io.ebean.Query; import io.ebean.test.LoggedSql; @@ -8,6 +9,7 @@ import org.example.domain.Customer; import org.example.domain.Order; import org.example.domain.OrderDetail; import org.example.domain.otherpackage.PhoneNumber; +import org.example.domain.query.QContact; import org.example.domain.query.QCustomer; import org.example.domain.query.QOrder; import org.example.domain.query.QOrderDetail; @@ -26,10 +28,17 @@ public class QOrderTest { private static final QOrder or = QOrder.alias(); + private static final QContact co = QContact.alias(); + private static final FetchGroup fgC = QCustomer.forFetchGroup() .select(cu.name, cu.phoneNumber) .buildFetchGroup(); + private static final FetchGroup fgCustomerWithContacts = QCustomer.forFetchGroup() + .select(cu.name, cu.phoneNumber) + .contacts.fetch(FetchConfig.ofQuery(1000), co.firstName, co.lastName, co.email) + .buildFetchGroup(); + private static final FetchGroup fgNested1 = QOrder.forFetchGroup() .select(or.status, or.shipDate) .customer.fetch(fgC) @@ -70,6 +79,20 @@ public class QOrderTest { DB.delete(customer); } + @Test + void fetchQueryWithBatch() { + LoggedSql.start(); + + new QCustomer() + .select(fgCustomerWithContacts) + .findList(); + + final List sql = LoggedSql.stop(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("select t0.id, t0.name, t0.phone_number from be_customer t0"); + assertThat(sql.get(1)).contains("select t0.customer_id, t0.id, t0.first_name, t0.last_name, t0.email from be_contact t0 where"); + } + @Test public void fetchCache() { diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index 350068c70..b3f711962 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ebean-redis @@ -22,28 +22,28 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 provided io.ebean ebean-core - 14.0.0 + 14.0.1 provided io.ebean ebean-querybean - 14.0.0 + 14.0.1 test io.ebean ebean-test - 14.0.0 + 14.0.1 test @@ -57,7 +57,7 @@ io.ebean querybean-generator - 14.0.0 + 14.0.1 provided diff --git a/ebean-spring-txn/pom.xml b/ebean-spring-txn/pom.xml index 6d2d9a2c8..6cb0cda91 100644 --- a/ebean-spring-txn/pom.xml +++ b/ebean-spring-txn/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ebean-spring-txn @@ -28,7 +28,7 @@ io.ebean ebean-core - 14.0.0 + 14.0.1 provided @@ -77,7 +77,7 @@ io.ebean ebean-test - 14.0.0 + 14.0.1 test diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 6cf4553db..192631849 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ebean test @@ -33,20 +33,20 @@ io.ebean ebean-platform-h2 - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 provided io.ebean ebean-ddl-generator - 14.0.0 + 14.0.1 @@ -135,28 +135,28 @@ io.ebean ebean-joda-time - 13.24.0 + 14.0.0 test io.ebean ebean-jackson-jsonnode - 13.24.0 + 14.0.0 test io.ebean ebean-jackson-mapper - 14.0.0 + 14.0.1 test io.ebean ebean-platform-all - 14.0.0 + 14.0.1 test @@ -213,7 +213,7 @@ org.postgresql postgresql - 42.6.0 + 42.7.2 org.checkerframework diff --git a/ebean-test/src/test/java/io/ebean/xtest/internal/server/text/json/WriteJsonDirtyTest.java b/ebean-test/src/test/java/io/ebean/xtest/internal/server/text/json/WriteJsonDirtyTest.java index 4918a243b..f18a5cb82 100644 --- a/ebean-test/src/test/java/io/ebean/xtest/internal/server/text/json/WriteJsonDirtyTest.java +++ b/ebean-test/src/test/java/io/ebean/xtest/internal/server/text/json/WriteJsonDirtyTest.java @@ -43,7 +43,7 @@ public class WriteJsonDirtyTest { JsonFactory jsonFactory = new JsonFactory(); JsonGenerator generator = jsonFactory.createGenerator(writer); - WriteJson writeJson = new WriteJson(server, generator, null, null, null, null); + WriteJson writeJson = new WriteJson(server, generator, null, null, null, null, true); descriptor.jsonWriteDirty(writeJson, entityBean, dirtyProperties); generator.flush(); diff --git a/ebean-test/src/test/java/org/tests/basic/TestLength.java b/ebean-test/src/test/java/org/tests/basic/TestLength.java new file mode 100644 index 000000000..fa30635f9 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/basic/TestLength.java @@ -0,0 +1,101 @@ +package org.tests.basic; + +import io.ebean.DB; +import io.ebean.DataIntegrityException; +import io.ebean.xtest.BaseTestCase; +import org.junit.jupiter.api.Test; +import org.tests.model.json.EBasicJsonList; +import org.tests.model.json.EBasicJsonMap; +import org.tests.model.types.SomeFileBean; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +/** + * @author Roland Praml, FOCONIS AG + */ +public class TestLength extends BaseTestCase { + + @Test + void testFileSize() throws IOException { + File f1 = File.createTempFile("testfile", "tmp"); + byte[] buf = new byte[1024]; + try (FileOutputStream fos = new FileOutputStream(f1)) { + for (int i = 0; i < 100; i++) { + fos.write(buf); + } + } + + SomeFileBean sfb1 = new SomeFileBean(); + sfb1.setContent(f1); + DB.save(sfb1); + + try (FileOutputStream fos = new FileOutputStream(f1)) { + for (int i = 0; i < 101; i++) { + fos.write(buf); + } + } + + SomeFileBean sfb2 = new SomeFileBean(); + sfb2.setContent(f1); + assertThatThrownBy(() -> DB.save(sfb2)).isInstanceOf(DataIntegrityException.class); + } + + + /** + * The property 'EBasicJsonMap.content' is annotated with @DbJson(length=5000). So we assume, that we cannot save Json-objects + * where the serialized form exceed that limit and we would expect an error on save. + * The length check works for platforms like h2, as H2 uses a 'varchar(5000)'. So it is impossible to save such long jsons, + * but it won't work for SqlServer, as here 'nvarchar(max)' is used. No validation happens at DB level and you might get very + * large Json objects in your database. This mostly happens unintentionally (programming error, misconfiguration) + * So they are in the database and they cannot be accessed by ebean any more, because there are new limits in Jackson: + * - Max 5 Meg per string in 2.15.0 + * - Max 20 Meg per string in 2.15.1 + * see https://github.com/FasterXML/jackson-core/issues/1014 + */ + @Test + void testLongString() { + // s is so big, that it could not be deserialized by jackson + String s = new String(new char[20_000_001]).replace('\0', 'x'); + + EBasicJsonMap bean = new EBasicJsonMap(); + bean.setName("b1"); + bean.setContent(Map.of("string", s)); + + assertThatThrownBy(() -> { + // we expect, that we can NOT save the bean, this is ensured by the bind validator. + DB.save(bean); + }).isInstanceOf(DataIntegrityException.class); + + } + + + /** + * Tests the UTF8 validation. + */ + @Test + void testUtf8() { + + String s = new String(new char[40]).replace('\0', '€'); + + EBasicJsonList bean = new EBasicJsonList(); + bean.setName("b1"); + bean.setTags(List.of(s)); + + if (isDb2() || isOracle()) { + // by default, DB2 && oracle uses bytes in varchar, so an '€' symbol needs 3 bytes + assertThatThrownBy(() -> { + // we expect, that we can NOT save the bean, this is ensured by the bind validator. + DB.save(bean); + }).isInstanceOf(DataIntegrityException.class); + } else { + DB.save(bean); + } + } + +} diff --git a/ebean-test/src/test/java/org/tests/json/TestDbJsonLength.java b/ebean-test/src/test/java/org/tests/json/TestDbJsonLength.java new file mode 100644 index 000000000..0fd9a3586 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/json/TestDbJsonLength.java @@ -0,0 +1,52 @@ +package org.tests.json; + +import io.ebean.DB; +import io.ebean.DataIntegrityException; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.Test; +import org.tests.model.json.EBasicJsonMap; + +import java.util.Map; + +class TestDbJsonLength { + + + /** + * The property 'EBasicJsonMap.content' is annotated with @DbJson(length=5000). So we assume, that we cannot save Json-objects + * where the serialized form exceed that limit and we would expect an error on save. + * The length check works for platforms like h2, as H2 uses a 'varchar(5000)'. So it is impossible to save such long jsons, + * but it won't work for SqlServer, as here 'nvarchar(max)' is used. No validation happens at DB level and you might get very + * large Json objects in your database. This mostly happens unintentionally (programming error, misconfiguration) + * So they are in the database and they cannot be accessed by ebean any more, because there are new limits in Jackson: + * - Max 5 Meg per string in 2.15.0 + * - Max 20 Meg per string in 2.15.1 + * see https://github.com/FasterXML/jackson-core/issues/1014 + */ + @Test + void testLongString() { + // s is so big, that it could not be deserialized by jackson + String s = new String(new char[20_000_001]).replace('\0', 'x'); + + EBasicJsonMap bean = new EBasicJsonMap(); + bean.setName("b1"); + bean.setContent(Map.of("string", s)); + + SoftAssertions softly = new SoftAssertions(); + + softly.assertThatThrownBy(() -> { + DB.save(bean); + }).isInstanceOf(DataIntegrityException.class); + + + if (bean.getId() != null) { + // we expect, that we could NOT save the bean, but this is not true for sqlServer. + // we will get a javax.persistence.PersistenceException: Error loading on org.tests.model.json.EBasicJsonMap.content + // when we try to load the bean back from DB + DB.find(EBasicJsonMap.class, bean.getId()); + } + + softly.assertAll(); + + } + +} diff --git a/ebean-test/src/test/java/org/tests/json/include/TestJsonImplicitLoaded.java b/ebean-test/src/test/java/org/tests/json/include/TestJsonImplicitLoaded.java new file mode 100644 index 000000000..f7bceef35 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/json/include/TestJsonImplicitLoaded.java @@ -0,0 +1,36 @@ +package org.tests.json.include; + +import io.ebean.DB; +import io.ebean.FetchPath; +import io.ebean.config.JsonConfig; +import io.ebean.text.PathProperties; +import io.ebean.text.json.JsonWriteOptions; +import org.junit.jupiter.api.Test; +import org.tests.model.basic.Contact; +import org.tests.model.basic.ResetBasicData; + +import static org.assertj.core.api.Assertions.assertThat; + +class TestJsonImplicitLoaded { + + @Test + void testToBeanToJson() { + ResetBasicData.reset(); + + FetchPath path = PathProperties.parse("*"); + Contact bean = DB.find(Contact.class).setId(1).apply(path).findOne(); + + JsonWriteOptions options = new JsonWriteOptions(); + options.setInclude(JsonConfig.Include.NON_NULL); + options.setPathProperties(path); + options.setIncludeLoadedImplicit(false); + + String asJson = DB.json().toJson(bean, options); + assertThat(asJson).contains("customer\":{\"id\":1}"); // hold only ID + + bean.getCustomer().getName(); // lazy-load bean; + asJson = DB.json().toJson(bean, options); + assertThat(asJson).contains("customer\":{\"id\":1}"); // expect the same result + } + +} diff --git a/ebean-test/src/test/java/org/tests/model/json/EBasicJsonMap.java b/ebean-test/src/test/java/org/tests/model/json/EBasicJsonMap.java index 351265f61..5feacf71c 100644 --- a/ebean-test/src/test/java/org/tests/model/json/EBasicJsonMap.java +++ b/ebean-test/src/test/java/org/tests/model/json/EBasicJsonMap.java @@ -18,7 +18,7 @@ public class EBasicJsonMap { String name; - @DbJson + @DbJson(length = 5000) Map content; @OneToMany(mappedBy = "owner", cascade = CascadeType.ALL) diff --git a/ebean-test/src/test/java/org/tests/model/types/SomeFileBean.java b/ebean-test/src/test/java/org/tests/model/types/SomeFileBean.java index eb5f8543b..fa6fa03be 100644 --- a/ebean-test/src/test/java/org/tests/model/types/SomeFileBean.java +++ b/ebean-test/src/test/java/org/tests/model/types/SomeFileBean.java @@ -1,9 +1,7 @@ package org.tests.model.types; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Lob; -import jakarta.persistence.Version; +import jakarta.persistence.*; + import java.io.File; @Entity @@ -18,6 +16,7 @@ public class SomeFileBean { String name; @Lob + @Column(length = 100 * 1024) // limit to 100kb File content; public Long getId() { diff --git a/ebean-test/src/test/resources/ebean.properties b/ebean-test/src/test/resources/ebean.properties index 9dec823ee..6bd984585 100644 --- a/ebean-test/src/test/resources/ebean.properties +++ b/ebean-test/src/test/resources/ebean.properties @@ -157,6 +157,7 @@ datasource.oracle.url=jdbc:oracle:thin:@localhost:1521:XE ## set this to use timestamp rather than timestamptz #ebean.postgres.timestamp=timestamp +ebean.pg.lengthCheck=on datasource.pg.username=unit datasource.pg.password=test datasource.pg.url=jdbc:postgresql://127.0.0.1:6432/unit diff --git a/ebean-test/testconfig/ebean-cockroach.properties b/ebean-test/testconfig/ebean-cockroach.properties index 604387b76..f088b3260 100644 --- a/ebean-test/testconfig/ebean-cockroach.properties +++ b/ebean-test/testconfig/ebean-cockroach.properties @@ -2,4 +2,4 @@ ebean.test.platform=cockroach ebean.test.dbName=unit datasource.default=cockroach #ebean.test.cockroach.version=v21.2.6 - +ebean.lengthCheck=on diff --git a/ebean-test/testconfig/ebean-db2.properties b/ebean-test/testconfig/ebean-db2.properties index 4ffab60f1..23006ac4b 100644 --- a/ebean-test/testconfig/ebean-db2.properties +++ b/ebean-test/testconfig/ebean-db2.properties @@ -5,3 +5,4 @@ ebean.test.username=admin ebean.test.password=admin datasource.default=db2-11 ebean.db2-11.databasePlatformName=db2luw +ebean.lengthCheck=utf8 diff --git a/ebean-test/testconfig/ebean-mariadb-10.3.properties b/ebean-test/testconfig/ebean-mariadb-10.3.properties index 082b4dbce..b7cac9c99 100644 --- a/ebean-test/testconfig/ebean-mariadb-10.3.properties +++ b/ebean-test/testconfig/ebean-mariadb-10.3.properties @@ -6,3 +6,4 @@ ebean.test.mariadb.version=10.3 ebean.test.mariadb.containerName=ut_mariadb-10-3 ebean.test.mariadb.port=14308 datasource.default=mariadb-103 +ebean.lengthCheck=on diff --git a/ebean-test/testconfig/ebean-mariadb.properties b/ebean-test/testconfig/ebean-mariadb.properties index a579e32bf..a56efb6dd 100644 --- a/ebean-test/testconfig/ebean-mariadb.properties +++ b/ebean-test/testconfig/ebean-mariadb.properties @@ -4,3 +4,4 @@ ebean.test.mariadb.version=10.6 ebean.test.mariadb.containerName=ut_mariadb-10-6 ebean.test.mariadb.port=14307 datasource.default=mariadb-106 +ebean.lengthCheck=on diff --git a/ebean-test/testconfig/ebean-mysql.properties b/ebean-test/testconfig/ebean-mysql.properties index 9539946a9..5da13cb2f 100644 --- a/ebean-test/testconfig/ebean-mysql.properties +++ b/ebean-test/testconfig/ebean-mysql.properties @@ -4,3 +4,4 @@ ebean.test.dbName=test_ebean # note: do not conflict with mariadb port #ebean.test.mysql.port=4306 datasource.default=mysql-docker +ebean.lengthCheck=on diff --git a/ebean-test/testconfig/ebean-oracle.properties b/ebean-test/testconfig/ebean-oracle.properties index 32b3af249..388c2ec82 100644 --- a/ebean-test/testconfig/ebean-oracle.properties +++ b/ebean-test/testconfig/ebean-oracle.properties @@ -1,3 +1,4 @@ ebean.test.platform=oracle ebean.test.dbName=test_eb datasource.default=oracle +ebean.lengthCheck=utf8 diff --git a/ebean-test/testconfig/ebean-postgres.properties b/ebean-test/testconfig/ebean-postgres.properties index 35a8bbbda..f87670982 100644 --- a/ebean-test/testconfig/ebean-postgres.properties +++ b/ebean-test/testconfig/ebean-postgres.properties @@ -2,4 +2,4 @@ ebean.test.platform=postgres datasource.default=postgres ebean.test.dbName=unit ebean.test.postgres.version=15 - +ebean.lengthCheck=on diff --git a/ebean-test/testconfig/ebean-sqlserver17.properties b/ebean-test/testconfig/ebean-sqlserver17.properties index 103b1fea2..25520ae8b 100644 --- a/ebean-test/testconfig/ebean-sqlserver17.properties +++ b/ebean-test/testconfig/ebean-sqlserver17.properties @@ -8,3 +8,4 @@ ebean.test.sqlserver.url=jdbc:sqlserver://localhost:9435;databaseName=test_ebean datasource.default=sqlserver2017 ebean.sqlserver2017.databasePlatformName=sqlserver17 +ebean.lengthCheck=on diff --git a/ebean-test/testconfig/ebean-sqlserver19.properties b/ebean-test/testconfig/ebean-sqlserver19.properties index 80ffe7320..478bff787 100644 --- a/ebean-test/testconfig/ebean-sqlserver19.properties +++ b/ebean-test/testconfig/ebean-sqlserver19.properties @@ -7,6 +7,7 @@ ebean.test.sqlserver.port=9434 ebean.test.sqlserver.url=jdbc:sqlserver://localhost:9434;databaseName=test_ebean;sendTimeAsDateTime=false;integratedSecurity=false;trustServerCertificate=true datasource.default=sqlserver2019 ebean.sqlserver2019.databasePlatformName=sqlserver17 +ebean.lengthCheck=on ## A case sensitive collation example: #ebean.test.sqlserver.collation=LATIN1_GENERAL_100_CI_AS_SC_UTF8 diff --git a/ebean-test/testconfig/ebean-yugabyte.properties b/ebean-test/testconfig/ebean-yugabyte.properties index 2b8e462cc..f5befb1ac 100644 --- a/ebean-test/testconfig/ebean-yugabyte.properties +++ b/ebean-test/testconfig/ebean-yugabyte.properties @@ -2,4 +2,4 @@ ebean.test.platform=yugabyte datasource.default=yugabyte ebean.test.dbName=unit ebean.test.yugabyte.version=2.18.0.0-b65 - +ebean.lengthCheck=on diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index 5e74ad518..23f0e470f 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 kotlin querybean generator @@ -21,7 +21,7 @@ io.ebean ebean-querybean - 14.0.0 + 14.0.1 test @@ -35,7 +35,7 @@ io.ebean ebean-core - 14.0.0 + 14.0.1 test @@ -56,14 +56,14 @@ io.ebean ebean-platform-h2 - 14.0.0 + 14.0.1 test io.ebean ebean-ddl-generator - 14.0.0 + 14.0.1 test diff --git a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/Constants.java b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/Constants.java index d1e536221..5d7938458 100644 --- a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/Constants.java +++ b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/Constants.java @@ -2,9 +2,8 @@ package io.ebean.querybean.generator; interface Constants { - String AT_GENERATED = "@Generated(\"io.ebean.querybean.kotlin-generator\")"; - String AT_TYPEQUERYBEAN = "@TypeQueryBean(\"v1\")"; - String GENERATED = "io.ebean.typequery.Generated"; + String AT_GENERATED = "@io.ebean.typequery.Generated(\"io.ebean.querybean.kotlin-generator\")"; + String AT_TYPEQUERYBEAN = "@io.ebean.typequery.TypeQueryBean(\"v1\")"; String MAPPED_SUPERCLASS = "jakarta.persistence.MappedSuperclass"; String DISCRIMINATOR_VALUE = "jakarta.persistence.DiscriminatorValue"; @@ -19,16 +18,9 @@ interface Constants { String DBJSONB = "io.ebean.annotation.DbJsonB"; String DBNAME = "io.ebean.annotation.DbName"; - String TQROOTBEAN = "io.ebean.typequery.TQRootBean"; String TQASSOC = "io.ebean.typequery.TQAssoc"; String TQASSOCBEAN = "io.ebean.typequery.TQAssocBean"; String TQPROPERTY = "io.ebean.typequery.TQProperty"; - String TYPEQUERYBEAN = "io.ebean.typequery.TypeQueryBean"; - String DATABASE = "io.ebean.Database"; - String DB = "io.ebean.DB"; - String FETCHGROUP = "io.ebean.FetchGroup"; - String QUERY = "io.ebean.Query"; - String TRANSACTION = "io.ebean.Transaction"; String MODULEINFO = "io.ebean.config.ModuleInfo"; String METAINF_MANIFEST = "META-INF/ebean-generated-info.mf"; diff --git a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/KotlinLangAdapter.java b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/KotlinLangAdapter.java index d92383e97..245a07ac8 100644 --- a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/KotlinLangAdapter.java +++ b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/KotlinLangAdapter.java @@ -3,17 +3,7 @@ package io.ebean.querybean.generator; class KotlinLangAdapter implements LangAdapter { @Override - public void beginClass(Append writer, String shortName) { - writer.append("class Q%s : TQRootBean<%1$s, Q%1$s> {", shortName).eol(); - } - - @Override - public void beginAssocClass(Append writer, String shortName, String origShortName) { -// writer.append("class Q%s : TQAssocBean<%s,R> {", shortName, origShortName).eol(); - } - - @Override - public void alias(Append writer, String shortName) { + public void alias(Append writer, String shortName, String fullName) { writer.append(" companion object {").eol(); writer.append(" /**").eol(); writer.append(" * shared 'Alias' instance used to provide").eol(); @@ -25,7 +15,7 @@ class KotlinLangAdapter implements LangAdapter { writer.append(" * Return a query bean used to build a FetchGroup.").eol(); writer.append(" */").eol(); writer.append(" fun forFetchGroup(): Q%s {", shortName).eol(); - writer.append(" return Q%s(FetchGroup.queryFor(%s::class.java));", shortName, shortName).eol(); + writer.append(" return Q%s(io.ebean.FetchGroup.queryFor(%s::class.java));", shortName, fullName).eol(); writer.append(" }").eol(); writer.append(" }").eol().eol(); } @@ -59,31 +49,31 @@ class KotlinLangAdapter implements LangAdapter { } @Override - public void rootBeanConstructor(Append writer, String shortName, String dbName) { + public void rootBeanConstructor(Append writer, String shortName, String dbName, String fullName) { String name = (dbName == null) ? "default" : dbName; writer.append(" /**").eol(); writer.append(" * Construct using the %s Database.", name).eol(); writer.append(" */").eol(); if (dbName == null) { - writer.append(" constructor() : super(%s::class.java)", shortName).eol().eol(); + writer.append(" constructor() : super(%s::class.java)", fullName).eol().eol(); } else { - writer.append(" constructor() : super(%s::class.java, DB.byName(\"%s\"))", shortName, dbName).eol().eol(); + writer.append(" constructor() : super(%s::class.java, io.ebean.DB.byName(\"%s\"))", fullName, dbName).eol().eol(); } writer.append(" /**").eol(); writer.append(" * Construct with a given Transaction.", name).eol(); writer.append(" */").eol(); if (dbName == null) { - writer.append(" constructor(transaction: Transaction) : super(%s::class.java, transaction)", shortName).eol().eol(); + writer.append(" constructor(transaction: io.ebean.Transaction) : super(%s::class.java, transaction)", fullName).eol().eol(); } else { - writer.append(" constructor(transaction: Transaction) : super(%s::class.java, DB.byName(\"%s\"), transaction)", shortName, dbName).eol().eol(); + writer.append(" constructor(transaction: io.ebean.Transaction) : super(%s::class.java, io.ebean.DB.byName(\"%s\"), transaction)", fullName, dbName).eol().eol(); } writer.eol(); writer.append(" /**").eol(); writer.append(" * Construct with a given Database.").eol(); writer.append(" */").eol(); - writer.append(" constructor(database: Database) : super(%s::class.java, database)", shortName).eol().eol(); + writer.append(" constructor(database: io.ebean.Database) : super(%s::class.java, database)", fullName).eol().eol(); writer.append(" /**").eol(); writer.append(" * Construct for Alias.").eol(); @@ -93,7 +83,7 @@ class KotlinLangAdapter implements LangAdapter { writer.append(" /**").eol(); writer.append(" * Private constructor for FetchGroup building.").eol(); writer.append(" */").eol(); - writer.append(" private constructor(fetchGroupQuery: Query<%s>) : super(fetchGroupQuery)", shortName).eol(); + writer.append(" private constructor(fetchGroupQuery: io.ebean.Query<%s>) : super(fetchGroupQuery)", fullName).eol(); writer.eol(); writer.append(" /** Return a copy of the query. */").eol(); diff --git a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/LangAdapter.java b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/LangAdapter.java index 3c7dba065..9bb48e39d 100644 --- a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/LangAdapter.java +++ b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/LangAdapter.java @@ -2,13 +2,10 @@ package io.ebean.querybean.generator; public interface LangAdapter { - void beginClass(Append writer, String shortName); - void beginAssocClass(Append writer, String shortName, String origShortName); + void alias(Append writer, String shortName, String beanFullName); - void alias(Append writer, String shortName); - - void rootBeanConstructor(Append writer, String shortName, String dbName); + void rootBeanConstructor(Append writer, String shortName, String dbName, String beanFullName); void assocBeanConstructor(Append writer, String shortName); diff --git a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleModuleInfoWriter.java b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleModuleInfoWriter.java index a3a68f74a..fd4f92438 100644 --- a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleModuleInfoWriter.java +++ b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleModuleInfoWriter.java @@ -91,7 +91,6 @@ class SimpleModuleInfoWriter { writer.append("import java.util.ArrayList;").eol(); writer.append("import java.util.Collections;").eol(); writer.append("import java.util.List;").eol(); - writer.append("import %s;", Constants.GENERATED).eol(); writer.eol(); writer.append("import io.ebean.config.ModuleInfo;").eol(); writer.append("import io.ebean.config.EntityClassRegister;").eol(); diff --git a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java index 01b398fe3..9bc4edbfa 100644 --- a/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java +++ b/kotlin-querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java @@ -123,22 +123,11 @@ class SimpleQueryBeanWriter { } private void gatherPropertyDetails() { - importTypes.add(Constants.GENERATED); - importTypes.add(beanFullName); - importTypes.add(Constants.TQROOTBEAN); - importTypes.add(Constants.TYPEQUERYBEAN); - importTypes.add(Constants.DATABASE); - importTypes.add(Constants.FETCHGROUP); - importTypes.add(Constants.QUERY); - importTypes.add(Constants.TRANSACTION); if (implementsInterface != null) { implementsInterfaceFullName = implementsInterface.getQualifiedName().toString(); boolean nested = implementsInterface.getNestingKind().isNested(); implementsInterfaceShortName = Util.shortName(nested, implementsInterfaceFullName); } - if (dbName != null) { - importTypes.add(Constants.DB); - } addClassProperties(); } @@ -230,12 +219,6 @@ class SimpleQueryBeanWriter { * Prepare the imports for writing assoc bean. */ private void prepareAssocBeanImports() { - - importTypes.remove(Constants.DB); - importTypes.remove(Constants.TQROOTBEAN); - importTypes.remove(Constants.DATABASE); - importTypes.remove(Constants.FETCHGROUP); - importTypes.remove(Constants.QUERY); if (embeddable) { importTypes.add(Constants.TQASSOC); } else { @@ -266,7 +249,6 @@ class SimpleQueryBeanWriter { * Write constructors. */ private void writeConstructors() { - if (writingAssocBean) { writeAssocBeanFetch(); writeAssocBeanConstructor(); @@ -279,7 +261,7 @@ class SimpleQueryBeanWriter { * Write the constructors for 'root' type query bean. */ private void writeRootBeanConstructor() { - lang().rootBeanConstructor(writer, shortName, dbName); + lang().rootBeanConstructor(writer, shortName, dbName, beanFullName); } private void writeAssocBeanFetch() { @@ -315,7 +297,6 @@ class SimpleQueryBeanWriter { * Write constructor for 'assoc' type query bean. */ private void writeAssocBeanConstructor() { - lang().assocBeanConstructor(writer, shortName); } @@ -344,11 +325,10 @@ class SimpleQueryBeanWriter { writer.append(Constants.AT_GENERATED).eol(); writer.append(Constants.AT_TYPEQUERYBEAN).eol(); if (embeddable) { - writer.append("class Q%s : TQAssoc<%s,R> {", shortName, shortInnerName).eol(); + writer.append("class Q%s : TQAssoc<%s,R> {", shortName, beanFullName).eol(); } else { - writer.append("class Q%s : TQAssocBean<%s,R,Q%s> {", shortName, shortInnerName, origShortName).eol(); + writer.append("class Q%s : TQAssocBean<%s,R,Q%s> {", shortName, beanFullName, origShortName).eol(); } - } else { writer.append("/**").eol(); writer.append(" * Query bean for %s.", shortName).eol(); @@ -357,7 +337,7 @@ class SimpleQueryBeanWriter { writer.append(" */").eol(); writer.append(Constants.AT_GENERATED).eol(); writer.append(Constants.AT_TYPEQUERYBEAN).eol(); - lang().beginClass(writer, shortName); + writer.append("class Q%s : io.ebean.typequery.TQRootBean<%s, Q%s> {", shortName, beanFullName, shortName).eol(); } writer.eol(); @@ -365,7 +345,7 @@ class SimpleQueryBeanWriter { private void writeAlias() { if (!writingAssocBean) { - lang().alias(writer, shortName); + lang().alias(writer, shortName, beanFullName); } } diff --git a/platforms/all/pom.xml b/platforms/all/pom.xml index 4b78c275d..ad48fd2d3 100644 --- a/platforms/all/pom.xml +++ b/platforms/all/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -15,67 +15,67 @@ io.ebean ebean-platform-h2 - 14.0.0 + 14.0.1 io.ebean ebean-platform-clickhouse - 14.0.0 + 14.0.1 io.ebean ebean-platform-db2 - 14.0.0 + 14.0.1 io.ebean ebean-platform-hana - 14.0.0 + 14.0.1 io.ebean ebean-platform-hsqldb - 14.0.0 + 14.0.1 io.ebean ebean-platform-mysql - 14.0.0 + 14.0.1 io.ebean ebean-platform-mariadb - 14.0.0 + 14.0.1 io.ebean ebean-platform-nuodb - 14.0.0 + 14.0.1 io.ebean ebean-platform-oracle - 14.0.0 + 14.0.1 io.ebean ebean-platform-postgres - 14.0.0 + 14.0.1 io.ebean ebean-platform-sqlanywhere - 14.0.0 + 14.0.1 io.ebean ebean-platform-sqlite - 14.0.0 + 14.0.1 io.ebean ebean-platform-sqlserver - 14.0.0 + 14.0.1 diff --git a/platforms/clickhouse/pom.xml b/platforms/clickhouse/pom.xml index ea6471ece..ad911aefc 100644 --- a/platforms/clickhouse/pom.xml +++ b/platforms/clickhouse/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -15,7 +15,7 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 diff --git a/platforms/db2/pom.xml b/platforms/db2/pom.xml index 195b5dc40..5cd12a9d3 100644 --- a/platforms/db2/pom.xml +++ b/platforms/db2/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -15,7 +15,7 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 diff --git a/platforms/h2/pom.xml b/platforms/h2/pom.xml index da4ce9fb5..9dccef1a2 100644 --- a/platforms/h2/pom.xml +++ b/platforms/h2/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ../.. @@ -15,7 +15,7 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 + 14.0.0