From ed8d4b5fc41ea8f0054e889e3f26b7f75aa2c82f Mon Sep 17 00:00:00 2001 From: "robin.bygrave" Date: Wed, 21 Feb 2024 16:05:13 +1300 Subject: [PATCH 01/24] Bump postgresql dependency to 42.7.2 --- composites/ebean-postgis/pom.xml | 2 +- ebean-core-type/pom.xml | 2 +- ebean-core/pom.xml | 2 +- ebean-postgis-types/pom.xml | 2 +- ebean-test/pom.xml | 2 +- platforms/postgres/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/composites/ebean-postgis/pom.xml b/composites/ebean-postgis/pom.xml index 98b667668..4d328f4c9 100644 --- a/composites/ebean-postgis/pom.xml +++ b/composites/ebean-postgis/pom.xml @@ -14,7 +14,7 @@ 2.5.1 - 42.6.0 + 42.7.2 diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index d239a9c26..9985732d9 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -30,7 +30,7 @@ org.postgresql postgresql - 42.6.0 + 42.7.2 true diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index 882d126b3..da4ac868e 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -151,7 +151,7 @@ org.postgresql postgresql - 42.6.0 + 42.7.2 true diff --git a/ebean-postgis-types/pom.xml b/ebean-postgis-types/pom.xml index 25cb90a4f..39e5a6c20 100644 --- a/ebean-postgis-types/pom.xml +++ b/ebean-postgis-types/pom.xml @@ -47,7 +47,7 @@ org.postgresql postgresql - 42.6.0 + 42.7.2 provided diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 6cf4553db..cc640add1 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -213,7 +213,7 @@ org.postgresql postgresql - 42.6.0 + 42.7.2 org.checkerframework diff --git a/platforms/postgres/pom.xml b/platforms/postgres/pom.xml index abc5d77b5..d48db4da7 100644 --- a/platforms/postgres/pom.xml +++ b/platforms/postgres/pom.xml @@ -28,7 +28,7 @@ org.postgresql postgresql - 42.6.0 + 42.7.2 test From 7322030e9035661039e24242b121b5c04885517d Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 26 Feb 2024 08:32:44 +1300 Subject: [PATCH 02/24] Fix for #3338 Potential shutdown hang with SpringContextShutdownHook and ebean ShutdownHook --- .../java/io/ebean/event/ShutdownManager.java | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) 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 { From 11c9bdfc6f987aef48e6b9712106fa17161854bb Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 27 Feb 2024 21:04:06 +1300 Subject: [PATCH 03/24] Squashed commit of the following: commit 20152e16891582f8ff466a93ec2cf01871824d6d Author: Rob Bygrave Date: Tue Feb 27 20:59:51 2024 +1300 #3341 Update DatabaseConfig for fluid style + javadoc commit 1c495a738493946376cad3ff75cae05edea4f882 Author: Roland Praml Date: Mon Feb 26 10:25:42 2024 +0100 Fix: Compile errors commit 574876b758791a9b66abd11e0195a0107e6b1b6d Merge: df7b04877 77634fc3e Author: Roland Praml Date: Fri Feb 23 16:16:39 2024 +0100 Merge branch 'master-rob' into FOCONIS-string-length-validation commit df7b04877d949d8a0f9fdb615fa34963712e52df Author: Rob Bygrave Date: Mon Jun 26 21:16:32 2023 +1200 #3121 BindMaxLength validation At deploy time derive a BindMaxLength property to use per BeanProperty commit 4683877e0b76e71d7f1c4562e0bf37487f8ee641 Merge: 9a4b9d4be d0020ab8c Author: Rob Bygrave Date: Fri Jun 23 16:51:34 2023 +1200 Merge branch 'string-length-validation' of github.com:FOCONIS/ebean into FOCONIS-string-length-validation commit d0020ab8ce2e5094f7f4dada24648a1730ac7bc3 Author: Roland Praml Date: Tue Jun 20 14:47:20 2023 +0200 Length validation less invasive commit 9b3b8ad46aef9dba0704173e63bc1b63e67a32da Author: Roland Praml Date: Tue Jun 20 13:03:04 2023 +0200 extended DataBind, so that it could return the last bound object commit ca3c02bc1cce66e1176b9b7bcf414ac074a25e6e Author: Roland Praml Date: Mon Jun 19 09:52:52 2023 +0200 Failing test for SqlServer --- .../java/io/ebean/DataIntegrityException.java | 9 +- .../main/java/io/ebean/DatabaseBuilder.java | 10 ++ .../java/io/ebean/config/DatabaseConfig.java | 15 +++ .../java/io/ebean/config/LengthCheck.java | 22 ++++ .../io/ebean/config/DatabaseConfigTest.java | 11 +- .../java/io/ebean/core/type/DataBinder.java | 5 + .../io/ebean/core/type/InputStreamInfo.java | 27 +++++ .../ebeaninternal/server/bind/DataBind.java | 37 ++++++- .../server/deploy/BeanDescriptorManager.java | 18 ++++ .../server/deploy/BeanProperty.java | 20 ++++ .../server/deploy/BindMaxLength.java | 77 +++++++++++++ .../deploy/meta/DeployBeanDescriptor.java | 7 +- .../deploy/meta/DeployBeanProperty.java | 19 ++++ .../test/java/org/tests/basic/TestLength.java | 101 ++++++++++++++++++ .../java/org/tests/json/TestDbJsonLength.java | 52 +++++++++ .../org/tests/model/json/EBasicJsonMap.java | 2 +- .../org/tests/model/types/SomeFileBean.java | 7 +- ebean-test/testconfig/ebean-db2.properties | 1 + ebean-test/testconfig/ebean-oracle.properties | 1 + .../testconfig/ebean-sqlserver19.properties | 1 + 20 files changed, 430 insertions(+), 12 deletions(-) create mode 100644 ebean-api/src/main/java/io/ebean/config/LengthCheck.java create mode 100644 ebean-core-type/src/main/java/io/ebean/core/type/InputStreamInfo.java create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/deploy/BindMaxLength.java create mode 100644 ebean-test/src/test/java/org/tests/basic/TestLength.java create mode 100644 ebean-test/src/test/java/org/tests/json/TestDbJsonLength.java 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/DatabaseBuilder.java b/ebean-api/src/main/java/io/ebean/DatabaseBuilder.java index bbe3afdc9..5c1c04581 100644 --- a/ebean-api/src/main/java/io/ebean/DatabaseBuilder.java +++ b/ebean-api/src/main/java/io/ebean/DatabaseBuilder.java @@ -87,6 +87,7 @@ public interface DatabaseBuilder { } return this; } + /** * Set the name of the Database. */ @@ -2221,6 +2222,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. @@ -3103,5 +3109,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 b3ad2ef43..9fc3ee31f 100644 --- a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java +++ b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java @@ -545,6 +545,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings { private String dumpMetricsOptions; + private LengthCheck lengthCheck = LengthCheck.OFF; private Function metricNaming = MetricNamingMatch.INSTANCE; /** @@ -2195,6 +2196,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); @@ -2571,6 +2573,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/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-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/src/main/java/io/ebeaninternal/server/bind/DataBind.java b/ebean-core/src/main/java/io/ebeaninternal/server/bind/DataBind.java index 3c4c1aedb..3b65b788f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/bind/DataBind.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/bind/DataBind.java @@ -1,10 +1,14 @@ package io.ebeaninternal.server.bind; import io.ebean.core.type.DataBinder; +import io.ebean.core.type.InputStreamInfo; import io.ebeaninternal.api.CoreLog; import io.ebeaninternal.server.core.timezone.DataTimeZone; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; import java.math.BigDecimal; import java.sql.*; import java.util.ArrayList; @@ -23,6 +27,8 @@ public class DataBind implements DataBinder { protected int pos; private String json; + private Object lastObject = null; + public DataBind(DataTimeZone dataTimeZone, PreparedStatement pstmt, Connection connection) { this.dataTimeZone = dataTimeZone; this.pstmt = pstmt; @@ -65,16 +71,19 @@ public class DataBind implements DataBinder { @Override public void setObject(Object value) throws SQLException { pstmt.setObject(++pos, value); + lastObject = value; } @Override public final void setObject(Object value, int sqlType) throws SQLException { pstmt.setObject(++pos, value, sqlType); + lastObject = value; } @Override public void setNull(int jdbcType) throws SQLException { pstmt.setNull(++pos, jdbcType); + lastObject = null; } @Override @@ -96,7 +105,7 @@ public class DataBind implements DataBinder { } } - private void closeInputStreams() { + public void closeInputStreams() { if (inputStreams != null) { for (InputStream inputStream : inputStreams) { try { @@ -117,36 +126,43 @@ public class DataBind implements DataBinder { @Override public void setString(String value) throws SQLException { pstmt.setString(++pos, value); + lastObject = value; } @Override public final void setInt(int value) throws SQLException { pstmt.setInt(++pos, value); + lastObject = null; } @Override public final void setLong(long value) throws SQLException { pstmt.setLong(++pos, value); + lastObject = null; } @Override public final void setShort(short value) throws SQLException { pstmt.setShort(++pos, value); + lastObject = null; } @Override public final void setFloat(float value) throws SQLException { pstmt.setFloat(++pos, value); + lastObject = null; } @Override public final void setDouble(double value) throws SQLException { pstmt.setDouble(++pos, value); + lastObject = null; } @Override public final void setBigDecimal(BigDecimal value) throws SQLException { pstmt.setBigDecimal(++pos, value); + lastObject = null; } @Override @@ -157,6 +173,7 @@ public class DataBind implements DataBinder { } else { pstmt.setDate(++pos, value); } + lastObject = null; } @Override @@ -167,6 +184,7 @@ public class DataBind implements DataBinder { } else { pstmt.setTimestamp(++pos, value); } + lastObject = null; } @Override @@ -177,26 +195,31 @@ public class DataBind implements DataBinder { } else { pstmt.setTime(++pos, value); } + lastObject = null; } @Override public void setBoolean(boolean value) throws SQLException { pstmt.setBoolean(++pos, value); + lastObject = null; } @Override public void setBytes(byte[] value) throws SQLException { pstmt.setBytes(++pos, value); + lastObject = value; } @Override public void setByte(byte value) throws SQLException { pstmt.setByte(++pos, value); + lastObject = null; } @Override public void setChar(char value) throws SQLException { pstmt.setString(++pos, String.valueOf(value)); + lastObject = null; } @Override @@ -211,21 +234,31 @@ public class DataBind implements DataBinder { } inputStreams.add(inputStream); pstmt.setBinaryStream(++pos, inputStream, length); + lastObject = new InputStreamInfo(inputStream, length); } @Override public void setBlob(byte[] bytes) throws SQLException { pstmt.setBinaryStream(++pos, new ByteArrayInputStream(bytes), bytes.length); + lastObject = bytes; } @Override public void setClob(String content) throws SQLException { pstmt.setCharacterStream(++pos, new StringReader(content), content.length()); + lastObject = content; } @Override public void setArray(String arrayType, Object[] elements) throws SQLException { pstmt.setArray(++pos, connection.createArrayOf(arrayType, elements)); + lastObject = null; } + @Override + public Object popLastObject() { + Object ret = lastObject; + lastObject = null; + return ret; + } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index c4d179e6d..2cee48646 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -106,6 +106,7 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy private final String asOfViewSuffix; private final boolean jacksonCorePresent; private final int queryPlanTTLSeconds; + private final BindMaxLength bindMaxLength; private int entityBeanCount; private List> immutableDescriptorList; /** @@ -160,6 +161,19 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy this.changeLogListener = config.changeLogListener(bootupClasses.getChangeLogListener()); this.changeLogRegister = config.changeLogRegister(bootupClasses.getChangeLogRegister()); this.jacksonCorePresent = config.isJacksonCorePresent(); + this.bindMaxLength = initMaxLength(); + } + + BindMaxLength initMaxLength() { + LengthCheck lengthCheck = this.config.getLengthCheck(); + switch (lengthCheck) { + case OFF: + return null; + case UTF8: + return BindMaxLength.ofUtf8(); + default: + return BindMaxLength.ofStandard(); + } } @Override @@ -1501,6 +1515,10 @@ public final class BeanDescriptorManager implements BeanDescriptorMap, SpiBeanTy return list; } + public BindMaxLength bindMaxLength() { + return bindMaxLength; + } + /** * Comparator to sort the BeanDescriptors by name. */ diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java index 4cac21ef2..7dd2e9a33 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java @@ -1,16 +1,20 @@ package io.ebeaninternal.server.deploy; import com.fasterxml.jackson.core.JsonToken; +import io.ebean.DataIntegrityException; import io.ebean.ValuePair; import io.ebean.bean.EntityBean; import io.ebean.bean.EntityBeanIntercept; import io.ebean.bean.MutableValueInfo; import io.ebean.bean.PersistenceContext; import io.ebean.config.EncryptKey; +import io.ebean.config.LengthCheck; import io.ebean.config.dbplatform.DbEncryptFunction; import io.ebean.config.dbplatform.DbPlatformType; +import io.ebean.config.dbplatform.ExtraDbTypes; import io.ebean.core.type.DataReader; import io.ebean.core.type.DocPropertyType; +import io.ebean.core.type.InputStreamInfo; import io.ebean.core.type.ScalarType; import io.ebean.plugin.Property; import io.ebean.text.StringParser; @@ -46,6 +50,7 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.lang.reflect.Field; +import java.nio.charset.StandardCharsets; import java.sql.SQLException; import java.sql.Types; import java.util.List; @@ -166,6 +171,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { */ private final String dbComment; private final DbEncryptFunction dbEncryptFunction; + private final BindMaxLength bindMaxLength; private int deployOrder; final boolean jsonSerialize; final boolean jsonDeserialize; @@ -258,6 +264,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { } this.jsonSerialize = deploy.isJsonSerialize(); this.jsonDeserialize = deploy.isJsonDeserialize(); + this.bindMaxLength = deploy.bindMaxLength(); } private String tableAliasIntern(BeanDescriptor descriptor, String s, boolean dbEncrypted, String dbColumn) { @@ -345,6 +352,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { this.elPlaceHolderEncrypted = override.replace(source.elPlaceHolderEncrypted, source.dbColumn); this.jsonSerialize = source.jsonSerialize; this.jsonDeserialize = source.jsonDeserialize; + this.bindMaxLength = source.bindMaxLength; } /** @@ -555,6 +563,18 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { @SuppressWarnings("unchecked") public void bind(DataBind b, Object value) throws SQLException { scalarType.bind(b, value); + if (bindMaxLength != null) { + Object obj = b.popLastObject(); + long length = bindMaxLength.length(dbLength, obj); + if (length > dbLength) { + b.closeInputStreams(); + String s = String.valueOf(value); // take original bind value here. + if (s.length() > 50) { + s = s.substring(0, 47) + "..."; + } + throw new DataIntegrityException("Cannot bind value '" + s + "' (effective length=" + length + ") to column '" + dbColumn + "' (length=" + dbLength + ")"); + } + } } @SuppressWarnings(value = "unchecked") diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BindMaxLength.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BindMaxLength.java new file mode 100644 index 000000000..51bdcfa1a --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BindMaxLength.java @@ -0,0 +1,77 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.core.type.InputStreamInfo; + +import java.nio.charset.StandardCharsets; + +/** + * The max length check on bind values. + */ +public interface BindMaxLength { + + /** + * Return a UTF8 based implementation. + */ + static BindMaxLength ofUtf8() { + return new UTF8(); + } + + /** + * Return a standard implementation. + */ + static BindMaxLength ofStandard() { + return new Standard(); + } + + /** + * Return the length of the object. + */ + long length(int dbLength, Object obj); + + /** + * Length check based on UTF8 bytes. + */ + final class UTF8 implements BindMaxLength { + + @Override + public long length(int dbLength, Object obj) { + if (obj instanceof String) { + String s = (String) obj; + int stringLength = s.length(); + if (stringLength > dbLength) { + return stringLength; + } else if (stringLength * 4 <= dbLength) { + return -1; + } else { + return s.getBytes(StandardCharsets.UTF_8).length; + } + + } else if (obj instanceof byte[]) { + return ((byte[]) obj).length; + } else if (obj instanceof InputStreamInfo) { + return ((InputStreamInfo) obj).length(); + } else { + return -1; + } + } + } + + /** + * Standard string length implementation. + */ + final class Standard implements BindMaxLength { + + @Override + public long length(int dbLength, Object obj) { + if (obj instanceof String) { + return ((String) obj).length(); + } else if (obj instanceof byte[]) { + return ((byte[]) obj).length; + } else if (obj instanceof InputStreamInfo) { + return ((InputStreamInfo) obj).length(); + } else { + return -1; + } + } + } +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index 1f56614d1..f96cabb46 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -1,10 +1,10 @@ package io.ebeaninternal.server.deploy.meta; +import io.ebean.DatabaseBuilder; import io.ebean.annotation.Cache; import io.ebean.annotation.DocStore; import io.ebean.annotation.DocStoreMode; import io.ebean.annotation.Identity; -import io.ebean.DatabaseBuilder; import io.ebean.config.TableName; import io.ebean.config.dbplatform.IdType; import io.ebean.config.dbplatform.PlatformIdGenerator; @@ -21,7 +21,6 @@ import io.ebeaninternal.server.idgen.UuidV1IdGenerator; import io.ebeaninternal.server.idgen.UuidV1RndIdGenerator; import io.ebeaninternal.server.idgen.UuidV4IdGenerator; import io.ebeaninternal.server.rawsql.SpiRawSql; - import jakarta.persistence.Entity; import jakarta.persistence.MappedSuperclass; @@ -139,6 +138,10 @@ public class DeployBeanDescriptor { this.beanType = beanType; } + public BindMaxLength bindMaxLength() { + return manager.bindMaxLength(); + } + private String[] readPropertyNames() { try { Field field = beanType.getField("_ebean_props"); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java index 190e0b220..b8a010204 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java @@ -1,14 +1,17 @@ package io.ebeaninternal.server.deploy.meta; +import io.avaje.lang.Nullable; import io.ebean.annotation.*; import io.ebean.config.ScalarTypeConverter; import io.ebean.config.dbplatform.DbDefaultValue; import io.ebean.config.dbplatform.DbEncrypt; import io.ebean.config.dbplatform.DbEncryptFunction; +import io.ebean.config.dbplatform.ExtraDbTypes; import io.ebean.core.type.ScalarType; import io.ebean.util.AnnotationUtil; import io.ebeaninternal.server.core.InternString; import io.ebeaninternal.server.deploy.BeanProperty; +import io.ebeaninternal.server.deploy.BindMaxLength; import io.ebeaninternal.server.deploy.DbMigrationInfo; import io.ebeaninternal.server.deploy.DeployDocPropertyOptions; import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty; @@ -1133,4 +1136,20 @@ public class DeployBeanProperty { boolean isJsonType() { return mutationDetection != null; } + + @Nullable + public BindMaxLength bindMaxLength() { + if (dbLength == 0) { + return null; + } + switch (dbType) { + case Types.VARCHAR: + case Types.BLOB: + case ExtraDbTypes.JSON: + return desc.bindMaxLength(); + default: + return null; + } + + } } 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..0e35e1f56 --- /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/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/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-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-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 From feb2bd1e157d552444748492956c7a1d441ee800 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 27 Feb 2024 21:04:19 +1300 Subject: [PATCH 04/24] String length validation tidy up --- ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java | 1 + .../java/io/ebeaninternal/server/deploy/BeanProperty.java | 4 ---- ebean-test/src/test/java/org/tests/json/TestDbJsonLength.java | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) 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 9fc3ee31f..4c69d7aec 100644 --- a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java +++ b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java @@ -546,6 +546,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings { private String dumpMetricsOptions; private LengthCheck lengthCheck = LengthCheck.OFF; + private Function metricNaming = MetricNamingMatch.INSTANCE; /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java index 7dd2e9a33..5f592a540 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java @@ -8,13 +8,10 @@ import io.ebean.bean.EntityBeanIntercept; import io.ebean.bean.MutableValueInfo; import io.ebean.bean.PersistenceContext; import io.ebean.config.EncryptKey; -import io.ebean.config.LengthCheck; import io.ebean.config.dbplatform.DbEncryptFunction; import io.ebean.config.dbplatform.DbPlatformType; -import io.ebean.config.dbplatform.ExtraDbTypes; import io.ebean.core.type.DataReader; import io.ebean.core.type.DocPropertyType; -import io.ebean.core.type.InputStreamInfo; import io.ebean.core.type.ScalarType; import io.ebean.plugin.Property; import io.ebean.text.StringParser; @@ -50,7 +47,6 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.lang.reflect.Field; -import java.nio.charset.StandardCharsets; import java.sql.SQLException; import java.sql.Types; import java.util.List; diff --git a/ebean-test/src/test/java/org/tests/json/TestDbJsonLength.java b/ebean-test/src/test/java/org/tests/json/TestDbJsonLength.java index 0e35e1f56..0fd9a3586 100644 --- a/ebean-test/src/test/java/org/tests/json/TestDbJsonLength.java +++ b/ebean-test/src/test/java/org/tests/json/TestDbJsonLength.java @@ -11,7 +11,7 @@ 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, From 2352df309cc9179d421658a062a34cef0e084bc0 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 27 Feb 2024 21:21:58 +1300 Subject: [PATCH 05/24] Bump avaje-config to 3.11 --- ebean-api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index 93960d07d..2f3c5d954 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -39,7 +39,7 @@ io.avaje avaje-config - 3.10 + 3.11 From eed487ad26d6b0dd37875f312de32b48f813e9ed Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Thu, 29 Feb 2024 13:25:50 +0100 Subject: [PATCH 06/24] NEW: Allow control of jsonwrite-loadedprops --- .../io/ebean/text/json/JsonWriteOptions.java | 16 ++++++++ .../server/json/DJsonContext.java | 9 +++- .../ebeaninternal/server/json/WriteJson.java | 19 ++++++--- .../server/text/json/WriteJsonDirtyTest.java | 2 +- .../json/include/TestJsonImplicitLoaded.java | 41 +++++++++++++++++++ 5 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 ebean-test/src/test/java/org/tests/json/include/TestJsonImplicitLoaded.java 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-core/src/main/java/io/ebeaninternal/server/json/DJsonContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/json/DJsonContext.java index 340f978e1..39b80344b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/json/DJsonContext.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/json/DJsonContext.java @@ -402,7 +402,13 @@ public final class DJsonContext implements SpiJsonContext { private WriteJson createWriteJson(JsonGenerator gen, JsonWriteOptions options) { FetchPath pathProps = (options == null) ? null : options.getPathProperties(); Map> visitors = (options == null) ? null : options.getVisitorMap(); - return new WriteJson(server, gen, pathProps, visitors, determineObjectMapper(options), determineInclude(options)); + return new WriteJson(server, + gen, + pathProps, + visitors, + determineObjectMapper(options), + determineInclude(options), + options == null || options.isIncludeLoadedImplicit()); } private void toJsonFromCollection(Collection collection, String key, JsonGenerator gen, JsonWriteOptions options) throws IOException { @@ -490,4 +496,5 @@ public final class DJsonContext implements SpiJsonContext { JsonConfig.Include include = options.getInclude(); return (include != null) ? include : defaultInclude; } + } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/json/WriteJson.java b/ebean-core/src/main/java/io/ebeaninternal/server/json/WriteJson.java index 39e03eb95..f5b583822 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/json/WriteJson.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/json/WriteJson.java @@ -31,12 +31,15 @@ public final class WriteJson implements SpiJsonWriter { private final ArrayStack parentBeans; private final Object objectMapper; private final JsonConfig.Include include; + private final boolean includeLoadedImplicit; + /** * Construct for full bean use (normal). */ public WriteJson(SpiEbeanServer server, JsonGenerator generator, FetchPath fetchPath, - Map> visitors, Object objectMapper, JsonConfig.Include include) { + Map> visitors, Object objectMapper, JsonConfig.Include include, + boolean includeLoadedImplicit) { this.server = server; this.generator = generator; @@ -44,6 +47,7 @@ public final class WriteJson implements SpiJsonWriter { this.visitors = visitors; this.objectMapper = objectMapper; this.include = include; + this.includeLoadedImplicit = includeLoadedImplicit; this.parentBeans = new ArrayStack<>(); this.pathStack = new PathStack(); } @@ -54,6 +58,7 @@ public final class WriteJson implements SpiJsonWriter { public WriteJson(JsonGenerator generator, JsonConfig.Include include) { this.generator = generator; this.include = include; + this.includeLoadedImplicit = true; this.visitors = null; this.server = null; this.fetchPath = null; @@ -443,7 +448,7 @@ public final class WriteJson implements SpiJsonWriter { currentIncludeProps = null; } } - return new WriteBean(desc, explicitAllProps, currentIncludeProps, bean, visitor); + return new WriteBean(desc, explicitAllProps, includeLoadedImplicit, currentIncludeProps, bean, visitor); } @Override @@ -477,6 +482,7 @@ public final class WriteJson implements SpiJsonWriter { public static class WriteBean { final boolean explicitAllProps; + final boolean includeLoadedImplicit; final Set currentIncludeProps; final BeanDescriptor desc; final EntityBean currentBean; @@ -485,14 +491,15 @@ public final class WriteJson implements SpiJsonWriter { final JsonWriteBeanVisitor visitor; WriteBean(BeanDescriptor desc, EntityBean currentBean, JsonWriteBeanVisitor visitor) { - this(desc, false, null, currentBean, visitor); + this(desc, false, true, null, currentBean, visitor); } - WriteBean(BeanDescriptor desc, boolean explicitAllProps, Set currentIncludeProps, EntityBean currentBean, JsonWriteBeanVisitor visitor) { + WriteBean(BeanDescriptor desc, boolean explicitAllProps, boolean includeLoadedImplicit, Set currentIncludeProps, EntityBean currentBean, JsonWriteBeanVisitor visitor) { super(); this.desc = desc; this.currentBean = currentBean; this.explicitAllProps = explicitAllProps; + this.includeLoadedImplicit = includeLoadedImplicit; this.currentIncludeProps = currentIncludeProps; this.visitor = visitor; } @@ -507,9 +514,11 @@ public final class WriteJson implements SpiJsonWriter { if (currentIncludeProps != null) { // explicitly controlled by pathProperties return currentIncludeProps.contains(prop.name()); - } else { + } else if (includeLoadedImplicit){ // include only loaded properties return currentBean._ebean_getIntercept().isLoadedProperty(prop.propertyIndex()); + } else { + return prop.isId(); } } 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/json/include/TestJsonImplicitLoaded.java b/ebean-test/src/test/java/org/tests/json/include/TestJsonImplicitLoaded.java new file mode 100644 index 000000000..ca930df30 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/json/include/TestJsonImplicitLoaded.java @@ -0,0 +1,41 @@ +package org.tests.json.include; + +import io.ebean.DB; +import io.ebean.FetchPath; +import io.ebean.annotation.Transactional; +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; + +public class TestJsonImplicitLoaded { + + @Test + @Transactional + public void testToBeanToJson() throws Exception { + 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 + + + } + +} From 9b18d46b78b041569fc24f894de7af75c5405a16 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 2 Mar 2024 09:27:05 +1300 Subject: [PATCH 07/24] Add ebean.lengthCheck for mysql test run --- ebean-test/testconfig/ebean-mysql.properties | 1 + 1 file changed, 1 insertion(+) 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 From 26abe27e42591e66bd992526c283127787a96df9 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 2 Mar 2024 09:38:33 +1300 Subject: [PATCH 08/24] Add ebean.lengthCheck for sqlserver17 test run --- ebean-test/testconfig/ebean-sqlserver17.properties | 1 + 1 file changed, 1 insertion(+) 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 From 6babb2e6f54c92fc511dbc82c74f5de1be1e5eb3 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 2 Mar 2024 09:39:25 +1300 Subject: [PATCH 09/24] Add ebean.lengthCheck for mariadb test run --- ebean-test/testconfig/ebean-mariadb-10.3.properties | 1 + ebean-test/testconfig/ebean-mariadb.properties | 1 + 2 files changed, 2 insertions(+) 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 From 5fa09a6f908b3803e6c809a0e45556279e515f2e Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 2 Mar 2024 09:52:04 +1300 Subject: [PATCH 10/24] #3341 String length validation with Postgres PGobject (JSON/JSONB) --- .../server/deploy/BindMaxLength.java | 27 ++++++++++++------- .../src/test/resources/ebean.properties | 1 + .../testconfig/ebean-cockroach.properties | 2 +- .../testconfig/ebean-postgres.properties | 2 +- .../testconfig/ebean-yugabyte.properties | 2 +- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BindMaxLength.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BindMaxLength.java index 51bdcfa1a..dcc4e4428 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BindMaxLength.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BindMaxLength.java @@ -37,23 +37,29 @@ public interface BindMaxLength { public long length(int dbLength, Object obj) { if (obj instanceof String) { String s = (String) obj; - int stringLength = s.length(); - if (stringLength > dbLength) { - return stringLength; - } else if (stringLength * 4 <= dbLength) { - return -1; - } else { - return s.getBytes(StandardCharsets.UTF_8).length; - } - + return utf8String(dbLength, s); } else if (obj instanceof byte[]) { return ((byte[]) obj).length; } else if (obj instanceof InputStreamInfo) { return ((InputStreamInfo) obj).length(); + } else if ("org.postgresql.util.PGobject".equals(obj.getClass().getCanonicalName())) { + String value = ((org.postgresql.util.PGobject) obj).getValue(); + return value == null ? -1 : utf8String(dbLength, value); } else { return -1; } } + + private static int utf8String(int dbLength, String s) { + int stringLength = s.length(); + if (stringLength > dbLength) { + return stringLength; + } else if (stringLength * 4 <= dbLength) { + return -1; + } else { + return s.getBytes(StandardCharsets.UTF_8).length; + } + } } /** @@ -69,6 +75,9 @@ public interface BindMaxLength { return ((byte[]) obj).length; } else if (obj instanceof InputStreamInfo) { return ((InputStreamInfo) obj).length(); + } else if ("org.postgresql.util.PGobject".equals(obj.getClass().getCanonicalName())) { + String value = ((org.postgresql.util.PGobject) obj).getValue(); + return value == null ? -1 : value.length(); } else { return -1; } 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-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-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 From 9e461e47089d986e296900efdef432debd68ad67 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 2 Mar 2024 10:06:22 +1300 Subject: [PATCH 11/24] #3341 String length validation with Postgres PGobject (JSON/JSONB) --- .../io/ebeaninternal/server/deploy/BindMaxLength.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BindMaxLength.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BindMaxLength.java index dcc4e4428..bee29ad4a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BindMaxLength.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BindMaxLength.java @@ -35,7 +35,9 @@ public interface BindMaxLength { @Override public long length(int dbLength, Object obj) { - if (obj instanceof String) { + if (obj == null) { + return -1; + } else if (obj instanceof String) { String s = (String) obj; return utf8String(dbLength, s); } else if (obj instanceof byte[]) { @@ -69,7 +71,9 @@ public interface BindMaxLength { @Override public long length(int dbLength, Object obj) { - if (obj instanceof String) { + if (obj == null) { + return -1; + } else if (obj instanceof String) { return ((String) obj).length(); } else if (obj instanceof byte[]) { return ((byte[]) obj).length; From cd780208e530e7882a4c65589e6c7743c82fb333 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sun, 3 Mar 2024 11:45:36 +1300 Subject: [PATCH 12/24] Javadoc format only for io.ebean.Database --- .../src/main/java/io/ebean/Database.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/Database.java b/ebean-api/src/main/java/io/ebean/Database.java index 5c3ca8265..6bd7ebe2b 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(); From a2cdea24edbfb63411d6e6e3a480c015914d984b Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sun, 3 Mar 2024 12:13:49 +1300 Subject: [PATCH 13/24] #3337 Fix querybean-generation to not import the entity bean type Use the full canonical name of the entity bean in the generated code. --- .../test/java/org/example/domain/Alias.java | 14 +++++++++ .../ebean/querybean/generator/Constants.java | 12 ++------ .../generator/KotlinLangAdapter.java | 28 ++++++----------- .../querybean/generator/LangAdapter.java | 7 ++--- .../generator/SimpleModuleInfoWriter.java | 1 - .../generator/SimpleQueryBeanWriter.java | 30 ++++--------------- .../generator/SimpleQueryBeanWriter.java | 23 +++++++------- tests/test-kotlin/pom.xml | 11 +++---- 8 files changed, 49 insertions(+), 77 deletions(-) create mode 100644 ebean-querybean/src/test/java/org/example/domain/Alias.java 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/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/querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java b/querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java index 0cb6be142..de9315afd 100644 --- a/querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java +++ b/querybean-generator/src/main/java/io/ebean/querybean/generator/SimpleQueryBeanWriter.java @@ -70,7 +70,6 @@ class SimpleQueryBeanWriter { } private void gatherPropertyDetails() { - importTypes.add(beanFullName); if (implementsInterface != null) { String implementsInterfaceFullName = implementsInterface.getQualifiedName().toString(); boolean nested = implementsInterface.getNestingKind().isNested(); @@ -146,7 +145,7 @@ class SimpleQueryBeanWriter { writer.append(" * }").eol(); writer.append(" */").eol(); writer.append(" public static Q%s forFetchGroup() {", shortName).eol(); - writer.append(" return new Q%s(io.ebean.FetchGroup.queryFor(%s.class));", shortName, shortName).eol(); + writer.append(" return new Q%s(io.ebean.FetchGroup.queryFor(%s.class));", shortName, beanFullName).eol(); writer.append(" }").eol(); writer.eol(); @@ -154,9 +153,9 @@ class SimpleQueryBeanWriter { writer.append(" /** Construct using the %s Database */", name).eol(); writer.append(" public Q%s() {", shortName).eol(); if (dbName == null) { - writer.append(" super(%s.class);", shortName).eol(); + writer.append(" super(%s.class);", beanFullName).eol(); } else { - writer.append(" super(%s.class, io.ebean.DB.byName(\"%s\"));", shortName, dbName).eol(); + writer.append(" super(%s.class, io.ebean.DB.byName(\"%s\"));", beanFullName, dbName).eol(); } writer.append(" }").eol(); writer.eol(); @@ -164,16 +163,16 @@ class SimpleQueryBeanWriter { writer.append(" /** Construct with a given transaction */").eol(); writer.append(" public Q%s(io.ebean.Transaction transaction) {", shortName).eol(); if (dbName == null) { - writer.append(" super(%s.class, transaction);", shortName).eol(); + writer.append(" super(%s.class, transaction);", beanFullName).eol(); } else { - writer.append(" super(%s.class, io.ebean.DB.byName(\"%s\"), transaction);", shortName, dbName).eol(); + writer.append(" super(%s.class, io.ebean.DB.byName(\"%s\"), transaction);", beanFullName, dbName).eol(); } writer.append(" }").eol(); writer.eol(); writer.append(" /** Construct with a given Database */").eol(); writer.append(" public Q%s(io.ebean.Database database) {", shortName).eol(); - writer.append(" super(%s.class, database);", shortName).eol(); + writer.append(" super(%s.class, database);", beanFullName).eol(); writer.append(" }").eol(); writer.eol(); @@ -185,13 +184,13 @@ class SimpleQueryBeanWriter { writer.eol(); writer.append(" /** Private constructor for FetchGroup building */").eol(); - writer.append(" private Q%s(io.ebean.Query<%s> fetchGroupQuery) {", shortName, shortName).eol(); + writer.append(" private Q%s(io.ebean.Query<%s> fetchGroupQuery) {", shortName, beanFullName).eol(); writer.append(" super(fetchGroupQuery);").eol(); writer.append(" }").eol(); writer.eol(); writer.append(" /** Private constructor for filterMany */").eol(); - writer.append(" private Q%s(io.ebean.ExpressionList<%s> filter) {", shortName, shortName).eol(); + writer.append(" private Q%s(io.ebean.ExpressionList<%s> filter) {", shortName, beanFullName).eol(); writer.append(" super(filter);").eol(); writer.append(" }").eol(); @@ -224,7 +223,7 @@ class SimpleQueryBeanWriter { writer.append("public final class Q%s {", shortName).eol(); } else { writer.append(Constants.AT_TYPEQUERYBEAN).eol(); - writer.append("public final class Q%s extends io.ebean.typequery.TQRootBean<%1$s,Q%1$s> {", shortName).eol(); + writer.append("public final class Q%s extends io.ebean.typequery.TQRootBean<%s,Q%s> {", shortName, beanFullName, shortName).eol(); } writer.eol(); } @@ -263,9 +262,9 @@ class SimpleQueryBeanWriter { writer.append(" ").append(Constants.AT_GENERATED).eol(); writer.append(" ").append(Constants.AT_TYPEQUERYBEAN).eol(); if (embeddable) { - writer.append(" public static final class Assoc extends io.ebean.typequery.TQAssoc<%s,R> {", shortInnerName).eol(); + writer.append(" public static final class Assoc extends io.ebean.typequery.TQAssoc<%s,R> {", beanFullName).eol(); } else { - writer.append(" public static final class Assoc extends io.ebean.typequery.TQAssocBean<%s,R,Q%s> {", shortName, shortInnerName).eol(); + writer.append(" public static final class Assoc extends io.ebean.typequery.TQAssocBean<%s,R,Q%s> {", beanFullName, shortInnerName).eol(); } for (PropertyMeta property : properties) { writer.append(" "); diff --git a/tests/test-kotlin/pom.xml b/tests/test-kotlin/pom.xml index 2f1dc4d50..df3ea04eb 100644 --- a/tests/test-kotlin/pom.xml +++ b/tests/test-kotlin/pom.xml @@ -15,9 +15,9 @@ 11 11 - 13.13.0 - 1.8.10 - 2.12.1 + 14.0.0 + 1.9.22 + 2.16.1 @@ -29,7 +29,7 @@ ch.qos.logback logback-classic - 1.3.12 + 1.5.0 javax.validation @@ -91,7 +91,8 @@ io.ebean kotlin-querybean-generator - 13.14.0 + + 14.0.0 From 6091f7b6831e157c6f33945c90994f3c135a5be3 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sun, 3 Mar 2024 12:25:25 +1300 Subject: [PATCH 14/24] No effective change - tidy test TestJsonImplicitLoaded --- .../org/tests/json/include/TestJsonImplicitLoaded.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) 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 index ca930df30..f7bceef35 100644 --- a/ebean-test/src/test/java/org/tests/json/include/TestJsonImplicitLoaded.java +++ b/ebean-test/src/test/java/org/tests/json/include/TestJsonImplicitLoaded.java @@ -2,7 +2,6 @@ package org.tests.json.include; import io.ebean.DB; import io.ebean.FetchPath; -import io.ebean.annotation.Transactional; import io.ebean.config.JsonConfig; import io.ebean.text.PathProperties; import io.ebean.text.json.JsonWriteOptions; @@ -12,14 +11,12 @@ import org.tests.model.basic.ResetBasicData; import static org.assertj.core.api.Assertions.assertThat; -public class TestJsonImplicitLoaded { +class TestJsonImplicitLoaded { @Test - @Transactional - public void testToBeanToJson() throws Exception { + void testToBeanToJson() { ResetBasicData.reset(); - FetchPath path = PathProperties.parse("*"); Contact bean = DB.find(Contact.class).setId(1).apply(path).findOne(); @@ -34,8 +31,6 @@ public class TestJsonImplicitLoaded { bean.getCustomer().getName(); // lazy-load bean; asJson = DB.json().toJson(bean, options); assertThat(asJson).contains("customer\":{\"id\":1}"); // expect the same result - - } } From b2de333dcc022b86a704debb1079b78331c34927 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sun, 3 Mar 2024 13:47:49 +1300 Subject: [PATCH 15/24] #3313 Ability to configure fetch batch size when using FetchGroups and query beans We can do this currently using string paths and properties, this adds support for doing this when using query beans and strong types --- .../java/io/ebean/typequery/TQAssocBean.java | 12 ++++++++++ .../test/java/org/querytest/QOrderTest.java | 23 +++++++++++++++++++ 2 files changed, 35 insertions(+) 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 e14a78d06..36758bee3 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/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() { From 334793667e3bb9d5adfff033f27a8e1d40497f4c Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sun, 3 Mar 2024 14:14:23 +1300 Subject: [PATCH 16/24] Add deployment error message for ManyToMany with one of the related beans missing an @Id property --- .../io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 1c2f3aa9b..423f5415c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -379,6 +379,9 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST for (ExportedProperty exportedProperty : exportedProperties) { row.addColumn(exportedProperty.getForeignDbColumn()); } + if (importedId == null) { + throw new PersistenceException("Missing @Id property on bean related to ManyToMany " + fullName()); + } importedId.buildImport(row); return row.build(); } From ed9113efe63aa37c6ae6ffbb90a098c3beb89312 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sun, 3 Mar 2024 15:24:44 +1300 Subject: [PATCH 17/24] dep: Bump ebean-datasource to 8.12 This adds the option to register a JVM shutdown hook (which we generally will not use with ebean as the ebean io.ebean.Database shutdown wants to shutdown the DataSource after any background tasks have completed). This also adds an experimental feature for use with AWS Lambda to check for old idle connections due to lambda suspension. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0519d362f..4e9dd8f3c 100644 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,7 @@ 1.2 13.11.1 7.3 - 8.11 + 8.12 14.0.0 14.0.0 false From 03edfb54544cc5b40720063fe6ba8d0f3d7446df Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sun, 3 Mar 2024 15:33:39 +1300 Subject: [PATCH 18/24] git workflow trigger on push to master and pull_request --- .github/workflows/build.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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: From a0b04cceda6435208f32c592f627b8c6aee3face Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sun, 3 Mar 2024 15:38:14 +1300 Subject: [PATCH 19/24] dep: Bump avaje-config to 3.12 - supports AWS AppConfig & Dynamic Logback This version of avaje-config supports using AWS AppConfig as a configuration source (via avaje-aws-appconfig). It also supports dynamic changing Logback logging levels (via avaje-dynamic-logback). --- ebean-api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index 2f3c5d954..20f3ed2d9 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -39,7 +39,7 @@ io.avaje avaje-config - 3.11 + 3.12 From 0738316f15c3314622ca0a48d03375e8eeffde5d Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sun, 3 Mar 2024 16:54:22 +1300 Subject: [PATCH 20/24] Bump test dependencies only - logback and ebean-test-containers --- platforms/postgres/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platforms/postgres/pom.xml b/platforms/postgres/pom.xml index d48db4da7..adea430b8 100644 --- a/platforms/postgres/pom.xml +++ b/platforms/postgres/pom.xml @@ -21,7 +21,7 @@ io.ebean ebean-test-containers - 6.3 + ${ebean-test-containers.version} test diff --git a/pom.xml b/pom.xml index 4e9dd8f3c..89dd0e85b 100644 --- a/pom.xml +++ b/pom.xml @@ -70,7 +70,7 @@ ch.qos.logback logback-classic - 1.3.12 + 1.5.0 test From 61cfc7a9798555749731432d9834f0bcdc26bb70 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sun, 3 Mar 2024 17:01:36 +1300 Subject: [PATCH 21/24] dep: Update the common components to 14.0.0 ebean-joda-types, ebean-jackson-jsonnode --- composites/ebean/pom.xml | 4 ++-- ebean-bom/pom.xml | 10 +++++----- ebean-core/pom.xml | 2 +- ebean-test/pom.xml | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/composites/ebean/pom.xml b/composites/ebean/pom.xml index e54b6ea9d..db87c7233 100644 --- a/composites/ebean/pom.xml +++ b/composites/ebean/pom.xml @@ -29,13 +29,13 @@ io.ebean ebean-joda-time - 13.24.0 + 14.0.0 io.ebean ebean-jackson-jsonnode - 13.24.0 + 14.0.0 diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index 001501f40..c8f141861 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -113,13 +113,13 @@ io.ebean ebean-joda-time - 13.24.0 + 14.0.0 io.ebean ebean-jackson-jsonnode - 13.24.0 + 14.0.0 @@ -137,19 +137,19 @@ 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 diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index da4ac868e..fd98a9cfe 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -52,7 +52,7 @@ io.ebean ebean-externalmapping-api - 13.18.0 + 14.0.0 diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index cc640add1..b47a10ace 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -135,14 +135,14 @@ io.ebean ebean-joda-time - 13.24.0 + 14.0.0 test io.ebean ebean-jackson-jsonnode - 13.24.0 + 14.0.0 test From d84485546207f2b46750b76288a1e7f9aa0f7a0e Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sun, 3 Mar 2024 18:32:14 +1300 Subject: [PATCH 22/24] Bump ebean-agent to 14.0.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 89dd0e85b..13810a634 100644 --- a/pom.xml +++ b/pom.xml @@ -53,8 +53,8 @@ 13.11.1 7.3 8.12 - 14.0.0 - 14.0.0 + 14.0.1 + 14.0.1 false From dd377621a4f913774a78db077eea1ed17111a8d3 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sun, 3 Mar 2024 20:19:17 +1300 Subject: [PATCH 23/24] dep: Bump ebean-migration to 14.0.0, no effective change No effective change in that ebean-migration 14.0.0 has no change, it was released to align version numbers with 14.x --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 13810a634..b0f21eea6 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,7 @@ 8.4 2.3 1.2 - 13.11.1 + 14.0.0 7.3 8.12 14.0.1 From 6ce42b1ca33fa1b6bfcb27aab096808d7d81c57d Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sun, 3 Mar 2024 20:24:26 +1300 Subject: [PATCH 24/24] Version 14.0.1 --- composites/ebean-clickhouse/pom.xml | 10 +++--- composites/ebean-cockroach/pom.xml | 10 +++--- composites/ebean-db2/pom.xml | 10 +++--- composites/ebean-h2/pom.xml | 10 +++--- composites/ebean-hana/pom.xml | 10 +++--- composites/ebean-mariadb/pom.xml | 10 +++--- composites/ebean-mysql/pom.xml | 10 +++--- composites/ebean-nuodb/pom.xml | 10 +++--- composites/ebean-oracle/pom.xml | 10 +++--- composites/ebean-postgis/pom.xml | 12 +++---- composites/ebean-postgres/pom.xml | 10 +++--- composites/ebean-sqlite/pom.xml | 10 +++--- composites/ebean-sqlserver/pom.xml | 10 +++--- composites/ebean-yugabyte/pom.xml | 10 +++--- composites/ebean/pom.xml | 12 +++---- composites/pom.xml | 2 +- ebean-api/pom.xml | 2 +- ebean-bom/pom.xml | 52 ++++++++++++++--------------- ebean-core-type/pom.xml | 4 +-- ebean-core/pom.xml | 12 +++---- ebean-ddl-generator/pom.xml | 8 ++--- ebean-jackson-mapper/pom.xml | 4 +-- ebean-postgis-types/pom.xml | 8 ++--- ebean-querybean/pom.xml | 10 +++--- ebean-redis/pom.xml | 12 +++---- ebean-spring-txn/pom.xml | 6 ++-- ebean-test/pom.xml | 12 +++---- kotlin-querybean-generator/pom.xml | 10 +++--- platforms/all/pom.xml | 28 ++++++++-------- platforms/clickhouse/pom.xml | 4 +-- platforms/db2/pom.xml | 4 +-- platforms/h2/pom.xml | 4 +-- platforms/hana/pom.xml | 4 +-- platforms/hsqldb/pom.xml | 4 +-- platforms/mariadb/pom.xml | 6 ++-- platforms/mysql/pom.xml | 4 +-- platforms/nuodb/pom.xml | 4 +-- platforms/oracle/pom.xml | 4 +-- platforms/pom.xml | 2 +- platforms/postgres/pom.xml | 4 +-- platforms/sqlanywhere/pom.xml | 4 +-- platforms/sqlite/pom.xml | 4 +-- platforms/sqlserver/pom.xml | 4 +-- pom.xml | 2 +- querybean-generator/pom.xml | 2 +- tests/pom.xml | 2 +- tests/test-java16/pom.xml | 8 ++--- tests/test-kotlin/pom.xml | 6 ++-- 48 files changed, 200 insertions(+), 200 deletions(-) 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 4d328f4c9..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 ../.. @@ -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 db87c7233..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,13 +17,13 @@ io.ebean ebean-api - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 @@ -41,7 +41,7 @@ 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 20f3ed2d9..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 diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index c8f141861..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,25 +89,25 @@ 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 @@ -125,13 +125,13 @@ io.ebean ebean-jackson-mapper - 14.0.0 + 14.0.1 io.ebean ebean-ddl-generator - 14.0.0 + 14.0.1 @@ -155,37 +155,37 @@ 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 9985732d9..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 diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index fd98a9cfe..be3df0dea 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 @@ -159,21 +159,21 @@ io.ebean ebean-platform-h2 - 14.0.0 + 14.0.1 test io.ebean ebean-platform-postgres - 14.0.0 + 14.0.1 test io.ebean ebean-platform-sqlserver - 14.0.0 + 14.0.1 test diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index bfd4d95e2..add4d7720 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ebean ddl generation @@ -28,14 +28,14 @@ io.ebean ebean-core-type - 14.0.0 + 14.0.1 provided io.ebean ebean-core - 14.0.0 + 14.0.1 provided @@ -65,7 +65,7 @@ io.ebean ebean-platform-all - 14.0.0 + 14.0.1 test diff --git a/ebean-jackson-mapper/pom.xml b/ebean-jackson-mapper/pom.xml index 40726807b..898933704 100644 --- a/ebean-jackson-mapper/pom.xml +++ b/ebean-jackson-mapper/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 4.0.0 @@ -14,7 +14,7 @@ io.ebean ebean-core-type - 14.0.0 + 14.0.1 provided diff --git a/ebean-postgis-types/pom.xml b/ebean-postgis-types/pom.xml index 39e5a6c20..5b1e733a6 100644 --- a/ebean-postgis-types/pom.xml +++ b/ebean-postgis-types/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.0 + 14.0.1 ebean postgis types @@ -19,14 +19,14 @@ io.ebean ebean-platform-postgres - 14.0.0 + 14.0.1 io.ebean ebean-core - 14.0.0 + 14.0.1 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-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 b47a10ace..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 @@ -149,14 +149,14 @@ io.ebean ebean-jackson-mapper - 14.0.0 + 14.0.1 test io.ebean ebean-platform-all - 14.0.0 + 14.0.1 test 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/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