diff --git a/CONFIGURATION.md b/CONFIGURATION.md index 16fa6d698..46be98f0b 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -293,6 +293,6 @@ ebean.tenant.schemaProvider ebean.updateAllPropertiesInBatch ebean.updateChangesOnly ebean.updatesDeleteMissingChildren -ebean.useJavaxValidationNotNull +ebean.useValidationNotNull ebean.useJtaTransactionManager diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index 0d8e67b00..c073c2699 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -4,18 +4,13 @@ ebean-parent io.ebean - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT ebean api ebean api ebean-api - - 2.11.3 - 2.11.3 - - - - javax.validation - validation-api - 1.1.0.Final - true - - javax.servlet javax.servlet-api diff --git a/ebean-api/src/main/java/io/ebean/BeanFinder.java b/ebean-api/src/main/java/io/ebean/BeanFinder.java index 00aec8de5..2c8e04eec 100644 --- a/ebean-api/src/main/java/io/ebean/BeanFinder.java +++ b/ebean-api/src/main/java/io/ebean/BeanFinder.java @@ -14,7 +14,7 @@ import java.util.Optional; * * public class CustomerFinder extends BeanFinder { * - * @Inject + * @Inject * public CustomerFinder(Database database) { * super(Customer.class, database); * } diff --git a/ebean-api/src/main/java/io/ebean/BeanRepository.java b/ebean-api/src/main/java/io/ebean/BeanRepository.java index 19f390582..b89a49b39 100644 --- a/ebean-api/src/main/java/io/ebean/BeanRepository.java +++ b/ebean-api/src/main/java/io/ebean/BeanRepository.java @@ -9,10 +9,10 @@ import java.util.Collection; *

*

{@code
  *
- * @Repository
+ * @Repository
  * public class CustomerRepository extends BeanRepository {
  *
- *   @Inject
+ *   @Inject
  *   public CustomerRepository(Database server) {
  *     super(Customer.class, server);
  *   }
diff --git a/ebean-api/src/main/java/io/ebean/Database.java b/ebean-api/src/main/java/io/ebean/Database.java
index 5bbf29ad3..bd38253de 100644
--- a/ebean-api/src/main/java/io/ebean/Database.java
+++ b/ebean-api/src/main/java/io/ebean/Database.java
@@ -897,7 +897,7 @@ public interface Database {
    * 
{@code
    *   public class Order { ...
    *
-   *     @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
+   *     @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
    * 	   List details;
    * 	   ...
    *   }
diff --git a/ebean-api/src/main/java/io/ebean/DocumentStore.java b/ebean-api/src/main/java/io/ebean/DocumentStore.java
index a4f75132d..0a2353ff0 100644
--- a/ebean-api/src/main/java/io/ebean/DocumentStore.java
+++ b/ebean-api/src/main/java/io/ebean/DocumentStore.java
@@ -149,7 +149,7 @@ public interface DocumentStore {
    *    .setUseDocStore(true)
    *    .where()... // perhaps add predicates
    *    .findEachWhile(new Predicate() {
-   *      @Override
+   *      @Override
    *      public void accept(Order bean) {
    *        // process the bean
    *
diff --git a/ebean-api/src/main/java/io/ebean/Ebean.java b/ebean-api/src/main/java/io/ebean/Ebean.java
index f68a0666b..fb0e34db3 100644
--- a/ebean-api/src/main/java/io/ebean/Ebean.java
+++ b/ebean-api/src/main/java/io/ebean/Ebean.java
@@ -346,7 +346,7 @@ public final class Ebean {
    * 
{@code
    *   public class Order { ...
    *
-   *     @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
+   *     @OneToMany(cascade=CascadeType.ALL, mappedBy="order")
    * 	   List details;
    * 	   ...
    *   }
diff --git a/ebean-api/src/main/java/io/ebean/ExpressionFactory.java b/ebean-api/src/main/java/io/ebean/ExpressionFactory.java
index 1e5c4ebf5..3bcd5cb39 100644
--- a/ebean-api/src/main/java/io/ebean/ExpressionFactory.java
+++ b/ebean-api/src/main/java/io/ebean/ExpressionFactory.java
@@ -200,7 +200,7 @@ public interface ExpressionFactory {
   Expression gtOrNull(String propertyName, Object value);
 
   /**
-   * Greater than or Equal to OR Null  >= or null 
+   * Greater than or Equal to OR Null ({@code >= or null })
    * 

* A convenient expression combining GE and Is Null. Most often useful for range * expressions where the top range value is nullable. @@ -227,7 +227,7 @@ public interface ExpressionFactory { Expression ltOrNull(String propertyName, Object value); /** - * Less Than or Equal to OR Null <= or null + * Less Than or Equal to OR Null ({@code <= or null }) *

* A convenient expression combining LE and Is Null. Most often useful for range * expressions where the bottom range value is nullable. diff --git a/ebean-api/src/main/java/io/ebean/ExpressionList.java b/ebean-api/src/main/java/io/ebean/ExpressionList.java index e137f64ba..7e4e0f164 100644 --- a/ebean-api/src/main/java/io/ebean/ExpressionList.java +++ b/ebean-api/src/main/java/io/ebean/ExpressionList.java @@ -909,7 +909,7 @@ public interface ExpressionList { ExpressionList gtOrNull(String propertyName, Object value); /** - * Greater Than or Equal to OR Null - >= or null . + * Greater Than or Equal to OR Null - ({@code >= or null }). */ ExpressionList geOrNull(String propertyName, Object value); @@ -930,7 +930,7 @@ public interface ExpressionList { ExpressionList ltOrNull(String propertyName, Object value); /** - * Less Than or Equal to OR Null - <= or null . + * Less Than or Equal to OR Null - ({@code <= or null }). */ ExpressionList leOrNull(String propertyName, Object value); diff --git a/ebean-api/src/main/java/io/ebean/Finder.java b/ebean-api/src/main/java/io/ebean/Finder.java index e91238344..3c9318e7d 100644 --- a/ebean-api/src/main/java/io/ebean/Finder.java +++ b/ebean-api/src/main/java/io/ebean/Finder.java @@ -37,7 +37,7 @@ import java.util.List; * } * } * - * @Entity + * @Entity * public class Customer extends BaseModel { * * public static final CustomerFinder find = new CustomerFinder(); @@ -80,7 +80,7 @@ public class Finder { * // ... add extra customer specific finder methods * } * - * @Entity + * @Entity * public class Customer extends BaseModel { * * public static final CustomerFinder find = new CustomerFinder(); diff --git a/ebean-api/src/main/java/io/ebean/Model.java b/ebean-api/src/main/java/io/ebean/Model.java index 5fe2205e1..ac2f11ea7 100644 --- a/ebean-api/src/main/java/io/ebean/Model.java +++ b/ebean-api/src/main/java/io/ebean/Model.java @@ -32,16 +32,16 @@ import io.ebean.bean.EntityBean; * // Typically there is a common base model that has some * // common properties like the ones below * - * @MappedSuperclass + * @MappedSuperclass * public class BaseModel extends Model { * - * @Id Long id; + * @Id Long id; * - * @Version Long version; + * @Version Long version; * - * @WhenCreated Timestamp whenCreated; + * @WhenCreated Timestamp whenCreated; * - * @WhenUpdated Timestamp whenUpdated; + * @WhenUpdated Timestamp whenUpdated; * * ... * } @@ -52,7 +52,7 @@ import io.ebean.bean.EntityBean; * * // Extend the mappedSuperclass * - * @Entity @Table(name="o_account") + * @Entity @Table(name="o_account") * public class Customer extends BaseModel { * * String name; diff --git a/ebean-api/src/main/java/io/ebean/Pairs.java b/ebean-api/src/main/java/io/ebean/Pairs.java index 4f609f95a..bd5ee5137 100644 --- a/ebean-api/src/main/java/io/ebean/Pairs.java +++ b/ebean-api/src/main/java/io/ebean/Pairs.java @@ -18,7 +18,7 @@ import java.util.List; * * // where a bean is annotated with a complex * // natural key made of several properties - * @Cache(naturalKey = {"store","code","sku"}) + * @Cache(naturalKey = {"store","code","sku"}) * * * Pairs pairs = new Pairs("sku", "code"); diff --git a/ebean-api/src/main/java/io/ebean/RawSql.java b/ebean-api/src/main/java/io/ebean/RawSql.java index e0e20714b..901f1a43c 100644 --- a/ebean-api/src/main/java/io/ebean/RawSql.java +++ b/ebean-api/src/main/java/io/ebean/RawSql.java @@ -41,14 +41,14 @@ package io.ebean; *

Example OrderAggregate

*
{@code
  *  ...
- *   // @Sql indicates to that this bean
+ *   // @Sql indicates to that this bean
  *   // is based on RawSql rather than a table
  *
- *   @Entity
- *   @Sql
+ *   @Entity
+ *   @Sql
  *   public class OrderAggregate {
  *
- *    @OneToOne
+ *    @OneToOne
  *    Order order;
  *
  *    Double totalAmount;
diff --git a/ebean-api/src/main/java/io/ebean/RowMapper.java b/ebean-api/src/main/java/io/ebean/RowMapper.java
index 47e96498d..b1d59c984 100644
--- a/ebean-api/src/main/java/io/ebean/RowMapper.java
+++ b/ebean-api/src/main/java/io/ebean/RowMapper.java
@@ -22,7 +22,7 @@ import java.sql.SQLException;
  *    //
  *    class CustomerMapper implements RowMapper {
  *
- *     @Override
+ *     @Override
  *     public CustomerDto map(ResultSet rset, int rowNum) throws SQLException {
  *
  *       long id = rset.getLong(1);
diff --git a/ebean-api/src/main/java/io/ebean/Update.java b/ebean-api/src/main/java/io/ebean/Update.java
index 25aed9315..ece973392 100644
--- a/ebean-api/src/main/java/io/ebean/Update.java
+++ b/ebean-api/src/main/java/io/ebean/Update.java
@@ -13,23 +13,23 @@ package io.ebean;
  * 

*
{@code
  *    ...
- *   @NamedUpdates(value = {
- *     @NamedUpdate(
+ *   @NamedUpdates(value = {
+ *     @NamedUpdate(
  *       name = "setTitle",
  *       notifyCache = false,
  *       update = "update topic set title = :title, postCount = :count where id = :id"),
- *    @NamedUpdate(
+ *    @NamedUpdate(
  *       name = "setPostCount",
  *       notifyCache = false,
  *       update = "update f_topic set post_count = :postCount where id = :id"),
- *    @NamedUpdate(
+ *    @NamedUpdate(
  *       name = "incrementPostCount",
  *       notifyCache = false,
  *       update = "update Topic set postCount = postCount + 1 where id = :id")
  *       //update = "update f_topic set post_count = post_count + 1 where id = :id")
  *   })
- *   @Entity
- *   @Table(name = "f_topic")
+ *   @Entity
+ *   @Table(name = "f_topic")
  *   public class Topic {
  *     ...
  *   }
diff --git a/ebean-api/src/main/java/io/ebean/common/BeanList.java b/ebean-api/src/main/java/io/ebean/common/BeanList.java
index 0aee7f211..0aa774a81 100644
--- a/ebean-api/src/main/java/io/ebean/common/BeanList.java
+++ b/ebean-api/src/main/java/io/ebean/common/BeanList.java
@@ -87,7 +87,7 @@ public final class BeanList extends AbstractBeanCollection implements List
 
   @Override
   public void internalAddWithCheck(Object bean) {
-    if (list == null || !containsInstance(bean)) {
+    if (list == null || bean == null || !containsInstance(bean)) {
       internalAdd(bean);
     }
   }
diff --git a/ebean-api/src/main/java/io/ebean/common/BeanMap.java b/ebean-api/src/main/java/io/ebean/common/BeanMap.java
index b2ded02c9..09b37d38a 100644
--- a/ebean-api/src/main/java/io/ebean/common/BeanMap.java
+++ b/ebean-api/src/main/java/io/ebean/common/BeanMap.java
@@ -77,7 +77,7 @@ public final class BeanMap extends AbstractBeanCollection implements Ma
   }
 
   public void internalPutWithCheck(Object key, Object bean) {
-    if (map == null || !map.containsKey(key)) {
+    if (map == null || key == null || !map.containsKey(key)) {
       internalPut(key, bean);
     }
   }
diff --git a/ebean-api/src/main/java/io/ebean/common/BeanSet.java b/ebean-api/src/main/java/io/ebean/common/BeanSet.java
index ec4dc3829..880ece106 100644
--- a/ebean-api/src/main/java/io/ebean/common/BeanSet.java
+++ b/ebean-api/src/main/java/io/ebean/common/BeanSet.java
@@ -70,9 +70,8 @@ public final class BeanSet extends AbstractBeanCollection implements Set&x64;javax.validation.contstraints.NotNull
+   * Controls if Ebean should ignore &x64;javax.validation.contstraints.NotNull or
+   * &x64;jakarta.validation.contstraints.NotNull
    * with respect to generating a NOT NULL column.
    * 

* Normally when Ebean sees javax NotNull annotation it means that column is defined as NOT NULL. * Set this to false and the javax NotNull annotation is effectively ignored (and * we instead use Ebean's own NotNull annotation or JPA Column(nullable=false) annotation. */ - public void setUseJavaxValidationNotNull(boolean useJavaxValidationNotNull) { - this.useJavaxValidationNotNull = useJavaxValidationNotNull; + public void setUseValidationNotNull(boolean useValidationNotNull) { + this.useValidationNotNull = useValidationNotNull; } /** diff --git a/ebean-api/src/main/java/io/ebean/config/DatabaseConfigProvider.java b/ebean-api/src/main/java/io/ebean/config/DatabaseConfigProvider.java index 0a1f3e768..066af5fc4 100644 --- a/ebean-api/src/main/java/io/ebean/config/DatabaseConfigProvider.java +++ b/ebean-api/src/main/java/io/ebean/config/DatabaseConfigProvider.java @@ -15,7 +15,7 @@ package io.ebean.config; * * public class EbeanConfigProvider implements DatabaseConfigProvider { * - * @Override + * @Override * public void apply(DatabaseConfig config) { * * // register the entity bean classes explicitly diff --git a/ebean-api/src/main/java/io/ebean/config/ServerConfigProvider.java b/ebean-api/src/main/java/io/ebean/config/ServerConfigProvider.java index f992b004d..1ba45907d 100644 --- a/ebean-api/src/main/java/io/ebean/config/ServerConfigProvider.java +++ b/ebean-api/src/main/java/io/ebean/config/ServerConfigProvider.java @@ -16,7 +16,7 @@ package io.ebean.config; * * public class EbeanConfigProvider implements ServerConfigProvider { * - * @Override + * @Override * public void apply(ServerConfig config) { * * // register the entity bean classes explicitly diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/DbDefaultValue.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/DbDefaultValue.java index b74465f35..851fc2707 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/DbDefaultValue.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/DbDefaultValue.java @@ -79,7 +79,7 @@ public class DbDefaultValue { } /** - * This method checks & convert the {@link DbDefault#value()} to a valid SQL literal. + * This method checks and converts the {@link DbDefault#value()} to a valid SQL literal. * * This is mainly to quote string literals and verify integer/dates for correctness. *

diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/Oracle11Platform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/Oracle11Platform.java index e13155f3f..cb32a7470 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/Oracle11Platform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/Oracle11Platform.java @@ -13,6 +13,7 @@ public class Oracle11Platform extends OraclePlatform { this.platform = Platform.ORACLE11; this.columnAliasPrefix = "c"; this.sqlLimiter = new OracleRownumSqlLimiter(); + this.basicSqlLimiter = new OracleRownumBasicLimiter(); dbIdentity.setIdType(IdType.SEQUENCE); } } diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/OracleRownumBasicLimiter.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/OracleRownumBasicLimiter.java new file mode 100644 index 000000000..e51df98cb --- /dev/null +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/OracleRownumBasicLimiter.java @@ -0,0 +1,35 @@ +package io.ebean.config.dbplatform.oracle; + +import io.ebean.config.dbplatform.BasicSqlLimiter; + +/** + * Row limiter for Oracle 9,10,11 using rownum. + */ +public class OracleRownumBasicLimiter implements BasicSqlLimiter { + + @Override + public String limit(String dbSql, int firstRow, int maxRows) { + if (firstRow < 1 && maxRows < 1) { + return dbSql; + } + StringBuilder sb = new StringBuilder(60 + dbSql.length()); + int lastRow = maxRows; + if (lastRow > 0) { + lastRow += firstRow; + } + sb.append("select * from (select "); + if (maxRows > 0) { + sb.append("/*+ FIRST_ROWS(").append(maxRows).append(") */ "); + } + sb.append("a.*, rownum rn_ from ("); + sb.append(dbSql).append(") a "); + if (lastRow > 0) { + sb.append(" where rownum <= ").append(lastRow); + } + sb.append(") "); + if (firstRow > 0) { + sb.append(" where rn_ > ").append(firstRow); + } + return sb.toString(); + } +} diff --git a/ebean-autotune/pom.xml b/ebean-autotune/pom.xml index 7b0dabb3b..4ced5a224 100644 --- a/ebean-autotune/pom.xml +++ b/ebean-autotune/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT @@ -26,7 +26,7 @@ io.ebean ebean-core - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT provided diff --git a/ebean-autotune/src/test/java/io/ebeaninternal/server/autotune/service/ProfileOriginTest.java b/ebean-autotune/src/test/java/io/ebeaninternal/server/autotune/service/ProfileOriginTest.java index ec0a09596..c3995d215 100644 --- a/ebean-autotune/src/test/java/io/ebeaninternal/server/autotune/service/ProfileOriginTest.java +++ b/ebean-autotune/src/test/java/io/ebeaninternal/server/autotune/service/ProfileOriginTest.java @@ -11,12 +11,9 @@ import org.tests.model.basic.Order; import static org.assertj.core.api.Assertions.assertThat; -//import org.tests.model.basic.ResetBasicData; - public class ProfileOriginTest extends BaseTestCase { - - private BeanDescriptor desc = getBeanDescriptor(Order.class); + private final BeanDescriptor desc = getBeanDescriptor(Order.class); @Test public void buildDetail() { diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index c6219cfea..2293b2db9 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT ebean bom @@ -81,88 +81,88 @@ io.ebean ebean - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT io.ebean ebean-api - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT io.ebean ebean-core - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT io.ebean ebean-core-type - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT io.ebean ebean-ddl-generator - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT io.ebean ebean-externalmapping-api - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT io.ebean ebean-externalmapping-xml - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT io.ebean ebean-autotune - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT io.ebean ebean-querybean - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT io.ebean querybean-generator - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT provided io.ebean kotlin-querybean-generator - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT provided io.ebean ebean-test - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT test io.ebean ebean-postgis - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT io.ebean ebean-redis - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index 56aebbb2c..9e7a3c6eb 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -4,30 +4,25 @@ ebean-parent io.ebean - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT ebean-core-type ebean core type ebean scalar types api - - 2.11.3 - 2.11.3 - - io.ebean ebean-api - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT com.fasterxml.jackson.core jackson-core - ${jackson-core.version} + ${jackson.version} true diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index 20d9cfe6c..b493318d1 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT ebean-core @@ -18,11 +18,6 @@ ebean-parent-12.6.5 - - 2.11.3 - 2.11.3 - - @@ -33,7 +33,7 @@ io.ebean ebean-externalmapping-api - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT @@ -59,14 +59,14 @@ io.ebean ebean-core - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT test io.ebean ebean-ddl-generator - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT test diff --git a/ebean-postgis/pom.xml b/ebean-postgis/pom.xml index 0e6936d14..99fe84dca 100644 --- a/ebean-postgis/pom.xml +++ b/ebean-postgis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT ebean postgis @@ -15,7 +15,6 @@ 2.2.1 - 2.11.3 @@ -24,14 +23,14 @@ io.ebean ebean-core - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT provided com.fasterxml.jackson.core jackson-core - ${jackson-core.version} + ${jackson.version} true @@ -75,7 +74,7 @@ io.ebean ebean-test - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT test diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index 2fe2570a4..132ef56e2 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -4,18 +4,8 @@ ebean-parent io.ebean - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT - - - - - - - - scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.6.5 - ebean querybean Ebean querybean support @@ -27,7 +17,7 @@ io.ebean ebean-core - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT provided @@ -67,14 +57,21 @@ io.ebean ebean-ddl-generator - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT test io.ebean querybean-generator - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT + test + + + + io.ebean + ebean-test + 12.7.3-SNAPSHOT test diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/PBaseCompareable.java b/ebean-querybean/src/main/java/io/ebean/typequery/PBaseCompareable.java index c9488f63c..4e0ba7c1d 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/PBaseCompareable.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/PBaseCompareable.java @@ -121,12 +121,12 @@ public class PBaseCompareable extends PBaseValueEqual { * Greater or equal to lower value and strictly less than upper value. *

* This is generally preferable over Between for date and datetime types - * as SQL Between is inclusive on the upper bound (<=) and generally we - * need the upper bound to be exclusive (<). + * as SQL Between is inclusive on the upper bound ({@code <= }) and generally + * we need the upper bound to be exclusive ({@code < }). *

* - * @param lower the lower bind value (>=) - * @param upper the upper bind value (<) + * @param lower the lower bind value ({@code >= }) + * @param upper the upper bind value ({@code < }) * @return the root query bean instance */ public final R inRange(T lower, T upper) { diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/PBaseValueEqual.java b/ebean-querybean/src/main/java/io/ebean/typequery/PBaseValueEqual.java index c102d9991..3883afe66 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/PBaseValueEqual.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/PBaseValueEqual.java @@ -1,5 +1,7 @@ package io.ebean.typequery; +import io.ebean.Query; + import java.util.Collection; /** @@ -224,4 +226,25 @@ public abstract class PBaseValueEqual extends TQPropertyBase { expr().in(_name, values); return _root; } + + /** + * Is in the result of a subquery. + * + * @param subQuery values provided by a subQuery + * @return the root query bean instance + */ + public final R in(Query subQuery) { + expr().in(_name, subQuery); + return _root; + } + + /** + * Is in the result of a subquery. Synonym for in(). + * + * @param subQuery values provided by a subQuery + * @return the root query bean instance + */ + public final R isIn(Query subQuery) { + return in(subQuery); + } } 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 9f56b6b13..c54862151 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/TQAssocBean.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/TQAssocBean.java @@ -1,6 +1,11 @@ package io.ebean.typequery; import io.ebean.ExpressionList; +import io.ebean.FetchConfig; +import io.ebeaninternal.api.SpiQueryFetch; + +import java.util.LinkedHashSet; +import java.util.Set; /** * Base type for associated beans. @@ -11,6 +16,11 @@ import io.ebean.ExpressionList; @SuppressWarnings("rawtypes") public abstract class TQAssocBean extends TQProperty { + private static final FetchConfig FETCH_DEFAULT = FetchConfig.ofDefault(); + private static final FetchConfig FETCH_QUERY = FetchConfig.ofQuery(); + private static final FetchConfig FETCH_LAZY = FetchConfig.ofLazy(); + private static final FetchConfig FETCH_CACHE = FetchConfig.ofCache(); + /** * Construct with a property name and root instance. * @@ -88,9 +98,8 @@ public abstract class TQAssocBean extends TQProperty { /** * Deprecated in favor of fetch(). - * - * @deprecated */ + @Deprecated public R fetchAll() { return fetch(); } @@ -100,8 +109,7 @@ public abstract class TQAssocBean extends TQProperty { */ @SafeVarargs protected final R fetchProperties(TQProperty... props) { - ((TQRootBean) _root).query().fetch(_name, properties(props)); - return _root; + return fetchWithProperties(FETCH_DEFAULT, props); } /** @@ -109,8 +117,7 @@ public abstract class TQAssocBean extends TQProperty { */ @SafeVarargs protected final R fetchQueryProperties(TQProperty... props) { - ((TQRootBean) _root).query().fetchQuery(_name, properties(props)); - return _root; + return fetchWithProperties(FETCH_QUERY, props); } /** @@ -118,8 +125,7 @@ public abstract class TQAssocBean extends TQProperty { */ @SafeVarargs protected final R fetchCacheProperties(TQProperty... props) { - ((TQRootBean) _root).query().fetchCache(_name, properties(props)); - return _root; + return fetchWithProperties(FETCH_CACHE, props); } /** @@ -127,23 +133,26 @@ public abstract class TQAssocBean extends TQProperty { */ @SafeVarargs protected final R fetchLazyProperties(TQProperty... props) { - ((TQRootBean) _root).query().fetchLazy(_name, properties(props)); + return fetchWithProperties(FETCH_LAZY, props); + } + + @SafeVarargs + private final R fetchWithProperties(FetchConfig config, TQProperty... props) { + spiQuery().fetchProperties(_name, properties(props), config); return _root; } - /** - * Append the properties as a comma delimited string. - */ + private final SpiQueryFetch spiQuery() { + return (SpiQueryFetch)((TQRootBean) _root).query(); + } + @SafeVarargs - protected final String properties(TQProperty... props) { - StringBuilder selectProps = new StringBuilder(50); - for (int i = 0; i < props.length; i++) { - if (i > 0) { - selectProps.append(","); - } - selectProps.append(props[i].propertyName()); + private final Set properties(TQProperty... props) { + Set set = new LinkedHashSet<>(); + for (TQProperty prop : props) { + set.add(prop.propertyName()); } - return selectProps.toString(); + return set; } /** diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java b/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java index 72876a00d..4deab6037 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java @@ -25,6 +25,7 @@ import io.ebean.search.TextQueryString; import io.ebean.search.TextSimple; import io.ebean.service.SpiFetchGroupQuery; import io.ebean.text.PathProperties; +import io.ebeaninternal.api.SpiQueryFetch; import io.ebeaninternal.server.util.ArrayStack; import javax.annotation.Nonnull; @@ -32,6 +33,7 @@ import javax.annotation.Nullable; import java.sql.Connection; import java.sql.Timestamp; import java.util.Collection; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; @@ -41,55 +43,39 @@ import java.util.function.Predicate; import java.util.stream.Stream; /** - * Base root query bean. + * Base root query bean providing common features for all root query beans. *

- * With code generation for each entity bean type a query bean is created that extends this. + * For each entity bean querybean-generator generates a query bean that extends TQRootBean. *

- * Provides common features for all root query beans + * *

- *

- *

Example - QCustomer extends TQRootBean

- *

- * These 'query beans' like QCustomer are generated using the avaje-ebeanorm-typequery-generator. - *

- *
{@code
- *
- *   public class QCustomer extends TQRootBean {
- *
- *     // properties
- *     public PLong id;
- *
- *     public PString name;
- *     ...
- *
- * }
- *

*

Example - usage of QCustomer

*
{@code
  *
- *    Date fiveDaysAgo = ...
+ *  Date fiveDaysAgo = ...
  *
- *    List customers =
- *        new QCustomer()
- *          .name.ilike("rob")
- *          .status.equalTo(Customer.Status.GOOD)
- *          .registered.after(fiveDaysAgo)
- *          .contacts.email.endsWith("@foo.com")
- *          .orderBy()
- *            .name.asc()
- *            .registered.desc()
- *          .findList();
+ *  List customers =
+ *      new QCustomer()
+ *        .name.ilike("rob")
+ *        .status.equalTo(Customer.Status.GOOD)
+ *        .registered.after(fiveDaysAgo)
+ *        .contacts.email.endsWith("@foo.com")
+ *        .orderBy()
+ *          .name.asc()
+ *          .registered.desc()
+ *        .findList();
  *
  * }
*

*

Resulting SQL where

*

- *

{@code sql
+ * 
{@code
  *
- *     where lower(t0.name) like ?  and t0.status = ?  and t0.registered > ?  and u1.email like ?
- *     order by t0.name, t0.registered desc;
+ *   where lower(t0.name) like ?  and t0.status = ?  and t0.registered > ?  and u1.email like ?
+ *   order by t0.name, t0.registered desc;
+ *
+ *   --bind(rob,GOOD,Mon Jul 27 12:05:37 NZST 2015,%@foo.com)
  *
- *     --bind(rob,GOOD,Mon Jul 27 12:05:37 NZST 2015,%@foo.com)
  * }
* * @param the entity bean type (normal entity bean type e.g. Customer) @@ -278,22 +264,21 @@ public abstract class TQRootBean { */ @SafeVarargs public final R select(TQProperty... properties) { - StringBuilder selectProps = new StringBuilder(50); - for (int i = 0; i < properties.length; i++) { - if (i > 0) { - selectProps.append(","); - } - selectProps.append(properties[i].propertyName()); - } - query.select(selectProps.toString()); + ((SpiQueryFetch) query).selectProperties(properties(properties)); return root; } + private Set properties(TQProperty[] properties) { + Set props = new LinkedHashSet<>(); + for (TQProperty property : properties) { + props.add(property.propertyName()); + } + return props; + } + /** * Specify a path to load including all its properties. - *

- * The same as {@link #fetch(String, String)} with the fetchProperties as "*". - *

+ * *
{@code
    *
    * List customers =
diff --git a/ebean-querybean/src/test/java/org/example/domain/Product.java b/ebean-querybean/src/test/java/org/example/domain/Product.java
index e41d4fc34..ed58daa05 100644
--- a/ebean-querybean/src/test/java/org/example/domain/Product.java
+++ b/ebean-querybean/src/test/java/org/example/domain/Product.java
@@ -8,7 +8,7 @@ import javax.validation.constraints.Size;
  * Product entity bean.
  */
 @Entity
-@Table(name = "o_product")
+@Table(name = "o_product", schema = "foo")
 public class Product extends BaseModel {
 
   @Size(max = 20)
diff --git a/ebean-querybean/src/test/java/org/querytest/FindNative_withSchema.java b/ebean-querybean/src/test/java/org/querytest/FindNative_withSchema.java
new file mode 100644
index 000000000..59146648d
--- /dev/null
+++ b/ebean-querybean/src/test/java/org/querytest/FindNative_withSchema.java
@@ -0,0 +1,78 @@
+package org.querytest;
+
+import io.ebean.DB;
+import org.example.domain.Customer;
+import org.example.domain.Order;
+import org.example.domain.OrderDetail;
+import org.example.domain.Product;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class FindNative_withSchema {
+
+  @Test
+  public void test_rootLevelUsesSchema() {
+
+    Product p = new Product();
+    p.setName("prod1");
+    p.setSku("p1");
+    p.save();
+
+    String sql = "select * from foo.o_product p where p.sku = ?";
+
+    Product product = DB.findNative(Product.class, sql)
+      .setParameter("p1")
+      .findOne();
+
+    assertThat(product).isNotNull();
+    assertThat(product.getName()).isEqualTo("prod1");
+  }
+
+  @Test
+  public void test_joinToSchema() {
+
+    Order order = setupData();
+
+    String sql = "select l.*, p.* " +
+      " from o_order_detail l " +
+      " join foo.o_product p on p.id = l.product_id " +
+      " where l.order_id = ?";
+
+    List lines = DB.findNative(OrderDetail.class, sql)
+      .setParameter(order.getId())
+      .findList();
+
+    assertThat(lines).hasSize(1);
+    OrderDetail line = lines.get(0);
+    Product product = line.getProduct();
+
+    // check normal bean population
+    assertThat(line.getOrderQty()).isEqualTo(10);
+    assertThat(line.getOrder().getId()).isEqualTo(order.getId());
+    // check associated bean with schema is populated
+    assertThat(product).isNotNull();
+    assertThat(product.getName()).isEqualTo("prod2");
+  }
+
+  private Order setupData() {
+    Product p = new Product();
+    p.setName("prod2");
+    p.setSku("p2");
+    p.save();
+
+    Customer customer = new Customer();
+    customer.setName("junk");
+    customer.save();
+    Order order = new Order();
+    order.setCustomer(customer);
+
+    OrderDetail line = new OrderDetail(p, 10, 10.0);
+    order.getDetails().add(line);
+
+    order.save();
+    return order;
+  }
+}
diff --git a/ebean-querybean/src/test/java/org/querytest/QOrderTest.java b/ebean-querybean/src/test/java/org/querytest/QOrderTest.java
index ab98f0e67..2f470fdb5 100644
--- a/ebean-querybean/src/test/java/org/querytest/QOrderTest.java
+++ b/ebean-querybean/src/test/java/org/querytest/QOrderTest.java
@@ -1,11 +1,17 @@
 package org.querytest;
 
+import io.ebean.DB;
 import io.ebean.FetchGroup;
+import io.ebean.test.LoggedSql;
 import org.example.domain.Order;
 import org.example.domain.query.QCustomer;
 import org.example.domain.query.QOrder;
 import org.junit.Test;
 
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
 public class QOrderTest {
 
   private static final QCustomer cu = QCustomer.alias();
@@ -17,10 +23,14 @@ public class QOrderTest {
     .customer.fetchCache(cu.name, cu.status, cu.registered, cu.comments)
     .buildFetchGroup();
 
+  private static final FetchGroup fg2 = QOrder.forFetchGroup()
+    .select(or.status)
+    .customer.fetch(cu.name)
+    .buildFetchGroup();
+
   @Test
   public void fetchCache() {
 
-
     new QOrder()
       .status.eq(Order.Status.NEW)
       .customer.fetchCache(cu.name, cu.registered)
@@ -35,10 +45,72 @@ public class QOrderTest {
   @Test
   public void viaFetchGraph() {
 
+    DB.getDefault();
+    LoggedSql.start();
+
     new QOrder()
       .status.eq(Order.Status.NEW)
       .select(fg)
       .findList();
+
+
+    final List sql = LoggedSql.stop();
+    assertThat(sql).hasSize(1);
+    assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.ship_date, t0.customer_id from o_order t0 where");
+  }
+
+  @Test
+  public void viaFetchGraph_withJoin() {
+
+    DB.getDefault();
+    LoggedSql.start();
+
+    new QOrder()
+      .status.eq(Order.Status.NEW)
+      .select(fg2)
+      .findList();
+
+
+    final List sql = LoggedSql.stop();
+    assertThat(sql).hasSize(1);
+    assertThat(sql.get(0)).contains("select t0.id, t0.status, t1.id, t1.name from o_order t0 join be_customer t1 on t1.id = t0.customer_id where");
+  }
+
+  @Test
+  public void select_partial() {
+
+    DB.getDefault();
+    LoggedSql.start();
+
+    final QOrder o = QOrder.alias();
+
+    new QOrder()
+      .select(o.status, o.orderDate)
+      .findList();
+
+    final List sql = LoggedSql.stop();
+    assertThat(sql).hasSize(1);
+    assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.order_date from o_order t0");
+  }
+
+  @Test
+  public void fetch_partial() {
+
+    DB.getDefault();
+    LoggedSql.start();
+
+    final QOrder o = QOrder.alias();
+    final QCustomer c = QCustomer.alias();
+
+    new QOrder()
+      .select(o.status)
+      .customer.fetch(c.email, c.name)
+      .findList();
+
+    final List sql = LoggedSql.stop();
+    assertThat(sql).hasSize(1);
+    assertThat(sql.get(0)).contains("select t0.id, t0.status, t1.id, t1.email, t1.name from o_order t0 join be_customer t1 on t1.id = t0.customer_id");
+
   }
 
 }
diff --git a/ebean-querybean/src/test/resources/application-test.properties b/ebean-querybean/src/test/resources/application-test.properties
index 68e06a3f9..76f2d661f 100644
--- a/ebean-querybean/src/test/resources/application-test.properties
+++ b/ebean-querybean/src/test/resources/application-test.properties
@@ -1,5 +1,6 @@
 ebean.ddl.generate=true
 ebean.ddl.run=true
+ebean.ddl.initSql=init-db.sql
 
 datasource.default=h2
 
diff --git a/ebean-querybean/src/test/resources/init-db.sql b/ebean-querybean/src/test/resources/init-db.sql
new file mode 100644
index 000000000..fde39032e
--- /dev/null
+++ b/ebean-querybean/src/test/resources/init-db.sql
@@ -0,0 +1 @@
+create schema foo;
diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml
index 98186aa7f..476ee7c2a 100644
--- a/ebean-redis/pom.xml
+++ b/ebean-redis/pom.xml
@@ -4,7 +4,7 @@
   
     ebean-parent
     io.ebean
-    12.7.1-SNAPSHOT
+    12.7.3-SNAPSHOT
   
 
   ebean-redis
@@ -22,35 +22,35 @@
     
       io.ebean
       ebean-api
-      12.7.1-SNAPSHOT
+      12.7.3-SNAPSHOT
       provided
     
 
     
       io.ebean
       ebean-core
-      12.7.1-SNAPSHOT
+      12.7.3-SNAPSHOT
       provided
     
 
     
       io.ebean
       ebean-querybean
-      12.7.1-SNAPSHOT
+      12.7.3-SNAPSHOT
       test
     
 
     
       io.ebean
       querybean-generator
-      12.7.1-SNAPSHOT
+      12.7.3-SNAPSHOT
       test
     
 
     
       io.ebean
       ebean-test
-      12.7.1-SNAPSHOT
+      12.7.3-SNAPSHOT
       test
     
 
diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml
index d880773a8..4b5e47899 100644
--- a/ebean-test/pom.xml
+++ b/ebean-test/pom.xml
@@ -4,27 +4,13 @@
   
     ebean-parent
     io.ebean
-    12.7.1-SNAPSHOT
+    12.7.3-SNAPSHOT
   
-
-
-
-
-
-
-  
-    scm:git:git@github.com:ebean-orm/ebean.git
-    ebean-parent-12.6.5
-  
 
   ebean test
   Testing support for Ebean
   ebean-test
 
-  
-    2.11.3
-  
-
   
 
     
@@ -43,27 +29,34 @@
     
       io.ebean
       ebean-core
-      12.7.1-SNAPSHOT
+      12.7.3-SNAPSHOT
       provided
     
 
     
       io.ebean
       ebean-ddl-generator
-      12.7.1-SNAPSHOT
+      12.7.3-SNAPSHOT
     
 
     
       com.fasterxml.jackson.core
       jackson-databind
-      ${jackson-databind.version}
+      ${jackson.version}
+      true
+    
+
+    
+      com.fasterxml.jackson.datatype
+      jackson-datatype-jsr310
+      ${jackson.version}
       true
     
 
     
       io.ebean
       ebean-test-docker
-      4.1
+      4.2
     
 
     
diff --git a/ebean-test/src/main/java/io/ebean/test/DbJson.java b/ebean-test/src/main/java/io/ebean/test/DbJson.java
index 79de39099..3675063c1 100644
--- a/ebean-test/src/main/java/io/ebean/test/DbJson.java
+++ b/ebean-test/src/main/java/io/ebean/test/DbJson.java
@@ -2,34 +2,63 @@ package io.ebean.test;
 
 import io.ebean.DB;
 
-import java.io.IOException;
-import java.io.InputStream;
-
 import static org.assertj.core.api.Assertions.assertThat;
 
 /**
  * Helper for testing to assert that the JSON form of an entity
- * or list of entities match a String / typically test resource.
+ * or list of entities is as expected.
+ * 

+ * Using assertContains() we can match the JSON form of an entity + * against a subset of JSON content. Typically the subset of JSON + * excludes generated properties like id, when created and + * when modified properties. + *

+ * + *

Assert contains

+ *
{@code
+ *
+ *    DbJson.of(order)
+ *      .assertContains("/order-partial.json");
+ *
+ * }
+ * + * + *

Assert content matches

+ *

+ * Using assertContentMatches() we are doing an exact content match. + * We typically need to replace generated property values. This assert + * will start to fail if the model changes like adding a property to + * the entity so we should use it less widely due to the maintenance + * burden we have with it. + *

* *
{@code
  *
- *    DbJson.of(timedEntries)
- *      .replace("id", "eventTime")
- *      .assertContentMatches("/assertJson/full-1-timed.json");
+ *    DbJson.of(order)
+ *      .replace("id", "whenCreated", "whenModified)
+ *      .assertContentMatches("/order-full.json");
  *
  * }
*/ public class DbJson { /** - * Create a PrettyJson object that has the JSON form of the - * entity bean or beans. + * Create a PrettyJson object that has the JSON form of the entity bean or beans. * + *

Assert contains

*
{@code
    *
-   *    DbJson.of(timedEntries)
-   *      .replace("id", "eventTime")
-   *      .assertContentMatches("/assertJson/full-1-timed.json");
+   *    DbJson.of(order)
+   *      .assertContains("/order-partial.json");
+   *
+   * }
+ * + *

Assert content matches

+ *
{@code
+   *
+   *    DbJson.of(order)
+   *      .replace("id", "whenCreated", "whenModified)
+   *      .assertContentMatches("/order-full.json");
    *
    * }
*/ @@ -41,12 +70,7 @@ public class DbJson { * Read the content for the given resource path. */ public static String readResource(String resourcePath) { - InputStream is = DbJson.class.getResourceAsStream(resourcePath); - try { - return IOUtils.readUtf8(is).trim(); - } catch (IOException e) { - throw new IllegalArgumentException(e); - } + return IOUtils.readResource(resourcePath); } /** @@ -92,7 +116,7 @@ public class DbJson { } /** - * Assert the json matches the content at the given resource path. + * Assert the json exactly matches the content at the given resource path. * *
{@code
      *
@@ -103,7 +127,44 @@ public class DbJson {
      * }
*/ public void assertContentMatches(String resourcePath) { - assertThat(rawJson).isEqualTo(readResource(resourcePath)); + assertThat(lineEnd(rawJson)).isEqualTo(lineEnd(readResource(resourcePath))); + } + + /** + * Normalise line ending characters to just use new line. + */ + private String lineEnd(String content) { + return content.replace("\r\n", "\n"); + } + + /** + * Assert the DB json contains the given json content. + *

+ * With this "contains" check the DB Json can contain more content than what + * it is checked against. Typically the DB json can contain generated properties + * like id values, when created, when modified etc and we leave these out of the + * json content we are checking against. + *

+ * + * @param json The subset json content that should be contained by the DB json. + */ + public void assertContains(String json) { + Json.assertContains(rawJson, json); + } + + /** + * Assert the DB Json contains the Json at the given resource path. + *

+ * With this "contains" check the DB Json can contain more content than what + * it is checked against. Typically the DB json can contain generated properties + * like id values, when created, when modified etc and we leave these out of the + * json content we are checking against. + *

+ * + * @param resourcePath The resource path of the JSON content we are checking against. + */ + public void assertContainsResource(String resourcePath) { + assertContains(readResource(resourcePath)); } } } diff --git a/ebean-test/src/main/java/io/ebean/test/IOUtils.java b/ebean-test/src/main/java/io/ebean/test/IOUtils.java index 79b706706..a9b98086b 100644 --- a/ebean-test/src/main/java/io/ebean/test/IOUtils.java +++ b/ebean-test/src/main/java/io/ebean/test/IOUtils.java @@ -11,6 +11,18 @@ import java.nio.charset.StandardCharsets; */ class IOUtils { + /** + * Read the content for the given resource path. + */ + static String readResource(String resourcePath) { + try { + InputStream is = IOUtils.class.getResourceAsStream(resourcePath); + return IOUtils.readUtf8(is).trim(); + } catch (IOException e) { + throw new IllegalArgumentException("Error reading resource " + resourcePath, e); + } + } + /** * Reads the entire contents of the specified input stream and return them as UTF-8 string. */ diff --git a/ebean-test/src/main/java/io/ebean/test/Json.java b/ebean-test/src/main/java/io/ebean/test/Json.java new file mode 100644 index 000000000..7612757e3 --- /dev/null +++ b/ebean-test/src/main/java/io/ebean/test/Json.java @@ -0,0 +1,168 @@ +package io.ebean.test; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.type.CollectionType; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; + +import java.io.IOException; +import java.util.List; + +/** + * Helper to convert to and from json using Jackson object mapper and + * perform some useful asserts based on json content. + */ +public class Json { + + /** + * For reading resource json content into a bean, list or jsonNode in a fluid style. + */ + public static class Resource { + private final String resourcePath; + + private Resource(String resourcePath) { + this.resourcePath = resourcePath; + } + + /** + * Return as a plain bean. + */ + T asBean(Class cls) { + return Json.read(cls, readResource(resourcePath)); + } + + /** + * Return as a list of beans. + */ + List asList(Class cls) { + return Json.readList(cls, readResource(resourcePath)); + } + + /** + * Return as a JsonNode. + */ + JsonNode asNode() { + return Json.readNodeFromResource(resourcePath); + } + } + + private static final ObjectMapper MAPPER = initMapper(); + + /** + * For fluid style reading resource json content and return as a + * bean, list of bean or JsonNode. + *
{@code
+   *
+   *   PlainBean bean =
+   *     Json.resource("/example/plain-list.json").asBean(PlainBean.class);
+   *
+   *   List list =
+   *     Json.resource("/example/plain-list.json").asList(PlainBean.class);
+   *
+   *   JsonNode jsonNode =
+   *     Json.resource("/example/plain-list.json").asJsonNode();
+   *
+   * }
+ * + * @param resourcePath The resource path where the json content is read from + * @return The resource to convert to a bean or jsonNode etc + */ + public static Resource resource(String resourcePath) { + return new Resource(resourcePath); + } + + /** + * Assert all the fields in the expectedJson are present in actualJson and values match. + */ + public static void assertContains(String actualJson, String expectedJson) { + assertContains(readNode(actualJson), readNode(expectedJson)); + } + + /** + * Assert all the fields in the expectedJson are present in actualJson and values match. + */ + public static void assertContains(JsonNode actualJsonNode, JsonNode expectedJsonNode) { + JsonAssertContains.assertContains(actualJsonNode, expectedJsonNode); + } + + /** + * Read the content for the given resource path. + */ + public static String readResource(String resourcePath) { + return IOUtils.readResource(resourcePath); + } + + /** + * Return a bean from json content of a resource path. + */ + public static T readFromResource(Class type, String resourcePath) { + return read(type, readResource(resourcePath)); + } + + /** + * Return a typed object from json content. + */ + public static T read(Class type, String json) { + try { + return MAPPER.readValue(json, type); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Return a list of a given type from json content. + */ + public static List readList(Class type, String json) { + final CollectionType collectionType = MAPPER.getTypeFactory().constructCollectionType(List.class, type); + try { + return MAPPER.readValue(json, collectionType); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Parse json into a generic JsonNode structure from resource. + */ + public static JsonNode readNodeFromResource(String resourcePath) { + return readNode(IOUtils.readResource(resourcePath)); + } + + /** + * Parse json into a generic JsonNode structure. + */ + public static JsonNode readNode(String json) { + try { + return MAPPER.readTree(json); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Serialize object to string + */ + public static String toJsonString(Object bean) { + try { + return MAPPER.writeValueAsString(bean); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static ObjectMapper initMapper() { + return new ObjectMapper() + .registerModule(new JavaTimeModule()) + .configure(SerializationFeature.INDENT_OUTPUT, true) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) + .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false) + .configure(SerializationFeature.INDENT_OUTPUT, true) + .setSerializationInclusion(JsonInclude.Include.NON_NULL); + } + +} diff --git a/ebean-test/src/main/java/io/ebean/test/JsonAssertContains.java b/ebean-test/src/main/java/io/ebean/test/JsonAssertContains.java new file mode 100644 index 000000000..25e1e065a --- /dev/null +++ b/ebean-test/src/main/java/io/ebean/test/JsonAssertContains.java @@ -0,0 +1,118 @@ +package io.ebean.test; + +import com.fasterxml.jackson.databind.JsonNode; +import org.assertj.core.api.Assertions; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.Stack; + +/** + * Perform traversal of JsonNodes comparing against an expected JsonNode that + * typically contains a subset of the data (typically excludes any generated properties + * like when modified timestamps etc). + */ +class JsonAssertContains { + + private final Stack path = new Stack<>(); + private final LinkedList errors = new LinkedList<>(); + + static void assertContains(JsonNode actualJsonNode, JsonNode expectedJsonNode) { + new JsonAssertContains().contains(actualJsonNode, expectedJsonNode); + } + + private void contains(JsonNode actualJsonNode, JsonNode expectedJsonNode) { + checkRecursive(null, actualJsonNode, expectedJsonNode); + if (!errors.isEmpty()) { + String errorsString = String.join("\n", errors); + errorsString += "\nExpected JSON fields: " + expectedJsonNode; + errorsString += "\nActual JSON: " + actualJsonNode; + Assertions.fail(errorsString); + } + } + + private void checkRecursive(String name, JsonNode actualJsonNode, JsonNode expectedJsonNode) { + if (name != null) { + path.push(name); + } + if (checkNull(actualJsonNode, expectedJsonNode)) { + if (checkType(actualJsonNode, expectedJsonNode)) { + if (checkArray(actualJsonNode, expectedJsonNode)) { + if (checkObject(actualJsonNode, expectedJsonNode)) { + checkValue(actualJsonNode, expectedJsonNode); + } + } + } + } + if (name != null) { + path.pop(); + } + } + + private boolean checkNull(JsonNode actualJsonNode, JsonNode expectedJsonNode) { + if (actualJsonNode == null) { + errors.add(String.format("Expected field '%s' to be '%s' but was null", path(), expectedJsonNode)); + return false; + } + return true; + } + + private boolean checkType(JsonNode actualJsonNode, JsonNode expectedJsonNode) { + if (!expectedJsonNode.getNodeType().equals(actualJsonNode.getNodeType())) { + errors.add(String.format("Expected field '%s' to be of type '%s' but was '%s'", path(), expectedJsonNode.getNodeType(), actualJsonNode.getNodeType())); + return false; + } + return true; + } + + private boolean checkArray(JsonNode actualJsonNode, JsonNode expectedJsonNode) { + if (!expectedJsonNode.isArray()) { + return true; + } + for (int i = 0; i < expectedJsonNode.size(); i++) { + checkRecursive("[" + i + "]", actualJsonNode.get(i), expectedJsonNode.get(i)); + } + // do not continue (object or scalar type check) + return false; + } + + private boolean checkObject(JsonNode actualJsonNode, JsonNode expectedJsonNode) { + if (!expectedJsonNode.isObject()) { + return true; + } + Iterator> expectedFields = expectedJsonNode.fields(); + while (expectedFields.hasNext()) { + Map.Entry expectedField = expectedFields.next(); + String expectedKey = expectedField.getKey(); + JsonNode actualNode = actualJsonNode.get(expectedKey); + if (actualNode == null) { + errors.add(String.format("Expected field '%s' to be present", path(expectedKey))); + } else { + checkRecursive(expectedKey, actualNode, expectedField.getValue()); + } + } + // do not continue (scalar type check) + return false; + } + + private void checkValue(JsonNode actualJsonNode, JsonNode expectedJsonNode) { + if (!expectedJsonNode.equals(actualJsonNode)) { + errors.add(String.format("Expected field '%s' to be equal to '%s' but was '%s'", path(), expectedJsonNode, actualJsonNode)); + } + } + + String path(String expectedKey) { + if (path.isEmpty()) { + return expectedKey; + } + return path() + "." + expectedKey; + } + + String path() { + if (path.isEmpty()) { + return ""; + } + return String.join(".", path).replace(".[", "["); + } +} diff --git a/ebean-test/src/test/java/io/ebean/test/DbJsonTest.java b/ebean-test/src/test/java/io/ebean/test/DbJsonTest.java index dc841c88f..365c019cd 100644 --- a/ebean-test/src/test/java/io/ebean/test/DbJsonTest.java +++ b/ebean-test/src/test/java/io/ebean/test/DbJsonTest.java @@ -1,11 +1,13 @@ package io.ebean.test; +import com.fasterxml.jackson.databind.JsonNode; import io.ebean.DB; import org.junit.Test; import org.test.BSimpleWithGen; import java.util.List; +import static io.ebean.test.DbJson.readResource; import static org.assertj.core.api.Assertions.assertThat; @@ -36,6 +38,37 @@ public class DbJsonTest { //.withPlaceholder("_") .replace("id", "whenModified") .assertContentMatches("/bean/example-list.json"); + } + @Test + public void assertContains_pass() { + + BSimpleWithGen bean = new BSimpleWithGen("something-contains-me", "YeahNah"); + DB.save(bean); + + BSimpleWithGen found = DB.find(BSimpleWithGen.class, bean.getId()); + + DbJson.of(found).assertContainsResource("/bean/contains-minimal.json"); + DbJson.of(found).assertContains(readResource("/bean/contains-with-version.json")); + + DB.delete(bean); + } + + @Test + public void asJson() { + + BSimpleWithGen bean = new BSimpleWithGen("other"); + DB.save(bean); + + String asJson = DbJson.of(bean) + .withPlaceholder("\"*Replaced*\"") + .replace("id") + .asJson(); + + JsonNode node = Json.readNode(asJson); + assertThat(node.get("id").asText()).isEqualTo("*Replaced*"); + assertThat(node.get("name").asText()).isEqualTo("other"); + + DB.delete(bean); } } diff --git a/ebean-test/src/test/java/io/ebean/test/JsonAssertContainsTest.java b/ebean-test/src/test/java/io/ebean/test/JsonAssertContainsTest.java new file mode 100644 index 000000000..2c25776f9 --- /dev/null +++ b/ebean-test/src/test/java/io/ebean/test/JsonAssertContainsTest.java @@ -0,0 +1,86 @@ +package io.ebean.test; + +import com.fasterxml.jackson.databind.JsonNode; +import org.junit.Test; + +import java.util.stream.Stream; + +import static io.ebean.test.Json.readNodeFromResource; +import static org.assertj.core.api.Assertions.assertThat; + + +public class JsonAssertContainsTest { + + @Test + public void assertContains_itself() { + JsonNode original = readNodeFromResource("/contains/original.json"); + JsonAssertContains.assertContains(original, original); + } + + @Test + public void assertContains_subset() { + JsonNode original = readNodeFromResource("/contains/original.json"); + JsonNode expected = readNodeFromResource("/contains/original-subset.json"); + JsonAssertContains.assertContains(original, expected); + } + + + @Test + public void testContainsFails() { + JsonNode original = readNodeFromResource("/contains/original.json"); + JsonNode expected = readNodeFromResource("/contains/original-subset-modified.json"); + try { + JsonAssertContains.assertContains(original, expected); + } catch (AssertionError e) { + String exceptionMessage = e.getMessage(); + Stream.of("Expected field 'someString1' to be equal to '\"aaaa\"' but was '\"string1\"", + "Expected field 'someValue1' to be equal to '99' but was '1'", + "Expected field 'someArray1[0]' to be of type 'STRING' but was 'NUMBER", + "Expected field 'someArray2[0].value1' to be of type 'ARRAY' but was 'NUMBER'", + "Expected field 'someArray2[0].value2' to be of type 'OBJECT' but was 'STRING'", + "Expected field 'someArray2[0].array1[0]' to be '\"1\"' but was null", + "Expected field 'someArray2[0].object1.val5' to be present", + "Expected field 'someArray2[0].object1.val6' to be present", + "Expected field 'someArray2[0].object2' to be of type 'NULL' but was 'OBJECT'", + "Expected field 'someArray2[0].objectNull' to be of type 'OBJECT' but was 'NULL'") + .forEach(assertionError -> assertThat(exceptionMessage).contains(assertionError)); + } + } + + + @Test + public void assertContains_checkNull() { + JsonNode original = readNodeFromResource("/contains/check-null-actual.json"); + JsonNode expected = readNodeFromResource("/contains/check-null-expected.json"); + try { + JsonAssertContains.assertContains(original, expected); + } catch (AssertionError e) { + String exceptionMessage = e.getMessage(); + Stream.of("Expected field 'someNull' to be of type 'NULL' but was 'STRING'", + "Expected field 'extra' to be present") + .forEach(assertionError -> assertThat(exceptionMessage).contains(assertionError)); + } + } + + @Test + public void assertContains_checkType() { + JsonNode original = readNodeFromResource("/contains/check-type-actual.json"); + JsonNode expected = readNodeFromResource("/contains/check-type-expected.json"); + try { + JsonAssertContains.assertContains(original, expected); + } catch (AssertionError e) { + String exceptionMessage = e.getMessage(); + Stream.of("Expected field 'some' to be of type 'NUMBER' but was 'STRING'") + .forEach(assertionError -> assertThat(exceptionMessage).contains(assertionError)); + } + } + + @Test + public void path_when_empty() { + JsonAssertContains contains = new JsonAssertContains(); + + assertThat(contains.path()).isEqualTo(""); + assertThat(contains.path("a")).isEqualTo("a"); + assertThat(contains.path("b")).isEqualTo("b"); + } +} diff --git a/ebean-test/src/test/java/io/ebean/test/JsonTest.java b/ebean-test/src/test/java/io/ebean/test/JsonTest.java new file mode 100644 index 000000000..baf7a1563 --- /dev/null +++ b/ebean-test/src/test/java/io/ebean/test/JsonTest.java @@ -0,0 +1,75 @@ +package io.ebean.test; + +import com.fasterxml.jackson.databind.JsonNode; +import org.junit.Test; +import org.test.PlainBean; + +import java.util.List; + +import static io.ebean.test.Json.readNodeFromResource; +import static io.ebean.test.Json.readResource; +import static org.assertj.core.api.Assertions.assertThat; + +public class JsonTest { + + @Test + public void assertContains_subset() { + JsonNode original = readNodeFromResource("/contains/original.json"); + JsonNode expected = readNodeFromResource("/contains/original-subset.json"); + Json.assertContains(original, expected); + } + + @Test + public void readNode() { + JsonNode original = Json.readNode(readResource("/contains/original.json")); + Json.assertContains(original, original); + } + + @Test + public void resource_asNode() { + JsonNode original = Json.resource("/contains/original.json").asNode(); + JsonNode nonFluid = Json.readNode(readResource("/contains/original.json")); + assertThat(original).isEqualTo(nonFluid); + } + + @Test + public void readBean_resource_asBean() { + // traditional style from resource + PlainBean bean1 = Json.readFromResource(PlainBean.class, "/example/plain.json"); + assertThat(bean1.id).isEqualTo(42); + assertThat(bean1.name).isEqualTo("foo"); + + // traditional style given json content + PlainBean bean2 = Json.read(PlainBean.class, readResource("/example/plain.json")); + assertThat(bean2.id).isEqualTo(42); + assertThat(bean2.name).isEqualTo("foo"); + + // fluid style - resource asBean() + PlainBean bean3 = Json.resource("/example/plain.json").asBean(PlainBean.class); + assertThat(bean3.id).isEqualTo(42); + assertThat(bean3.name).isEqualTo("foo"); + } + + @Test + public void readList() { + List list = Json.readList(PlainBean.class, readResource("/example/plain-list.json")); + + String asJson = Json.toJsonString(list); + assertThat(list).hasSize(2); + assertThat(list.get(0).name).isEqualTo("foo"); + assertThat(list.get(1).name).isEqualTo("bar"); + + assertThat(asJson).contains("\"name\" : \"foo\""); + } + + @Test + public void resourceAsList() { + // fluid style - resource asList() + List list = Json.resource("/example/plain-list.json").asList(PlainBean.class); + + // traditional style + List list2 = Json.readList(PlainBean.class, readResource("/example/plain-list.json")); + assertThat(list).isEqualTo(list2); + } + +} diff --git a/ebean-test/src/test/java/org/test/BSimpleWithGen.java b/ebean-test/src/test/java/org/test/BSimpleWithGen.java index cf3c7f2f6..5ee189229 100644 --- a/ebean-test/src/test/java/org/test/BSimpleWithGen.java +++ b/ebean-test/src/test/java/org/test/BSimpleWithGen.java @@ -18,6 +18,8 @@ public class BSimpleWithGen { private String name; + private String other; + @Transient private Map> someMap; @@ -31,6 +33,11 @@ public class BSimpleWithGen { this.name = name; } + public BSimpleWithGen(String name, String other) { + this.name = name; + this.other = other; + } + public Integer getId() { return id; } diff --git a/ebean-test/src/test/java/org/test/PlainBean.java b/ebean-test/src/test/java/org/test/PlainBean.java new file mode 100644 index 000000000..103e67425 --- /dev/null +++ b/ebean-test/src/test/java/org/test/PlainBean.java @@ -0,0 +1,22 @@ +package org.test; + +import java.util.Objects; + +public class PlainBean { + + public int id; + public String name; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PlainBean plainBean = (PlainBean) o; + return id == plainBean.id && name.equals(plainBean.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } +} diff --git a/ebean-test/src/test/resources/bean/contains-minimal.json b/ebean-test/src/test/resources/bean/contains-minimal.json new file mode 100644 index 000000000..564060eec --- /dev/null +++ b/ebean-test/src/test/resources/bean/contains-minimal.json @@ -0,0 +1,4 @@ +{ + "name": "something-contains-me", + "version": 1 +} diff --git a/ebean-test/src/test/resources/bean/contains-with-version.json b/ebean-test/src/test/resources/bean/contains-with-version.json new file mode 100644 index 000000000..894b0bf14 --- /dev/null +++ b/ebean-test/src/test/resources/bean/contains-with-version.json @@ -0,0 +1,5 @@ +{ + "name": "something-contains-me", + "other": "YeahNah", + "version": 1 +} diff --git a/ebean-test/src/test/resources/bean/example-bean.json b/ebean-test/src/test/resources/bean/example-bean.json index 593babff3..e9a935767 100644 --- a/ebean-test/src/test/resources/bean/example-bean.json +++ b/ebean-test/src/test/resources/bean/example-bean.json @@ -1,6 +1,7 @@ { "id": _, "name": "something", + "other": null, "whenModified": _, "version": 1 } diff --git a/ebean-test/src/test/resources/bean/example-list.json b/ebean-test/src/test/resources/bean/example-list.json index 21264b0a7..8c7b8b681 100644 --- a/ebean-test/src/test/resources/bean/example-list.json +++ b/ebean-test/src/test/resources/bean/example-list.json @@ -1,11 +1,13 @@ [ { "id": "*", "name": "something", + "other": null, "whenModified": "*", "version": 1 }, { "id": "*", "name": "other", + "other": null, "whenModified": "*", "version": 1 } ] diff --git a/ebean-test/src/test/resources/contains/check-null-actual.json b/ebean-test/src/test/resources/contains/check-null-actual.json new file mode 100644 index 000000000..992d2aef4 --- /dev/null +++ b/ebean-test/src/test/resources/contains/check-null-actual.json @@ -0,0 +1,9 @@ +{ + "some": "val", + "someNull": "actualNotNull", + "matchNull": null, + "nullObject": { + "id": 42 + } + +} diff --git a/ebean-test/src/test/resources/contains/check-null-expected.json b/ebean-test/src/test/resources/contains/check-null-expected.json new file mode 100644 index 000000000..ce4163032 --- /dev/null +++ b/ebean-test/src/test/resources/contains/check-null-expected.json @@ -0,0 +1,7 @@ +{ + "some": "val", + "someNull": null, + "extra": "notThere", + "matchNull": null, + "nullObject": null +} diff --git a/ebean-test/src/test/resources/contains/check-type-actual.json b/ebean-test/src/test/resources/contains/check-type-actual.json new file mode 100644 index 000000000..6b240843c --- /dev/null +++ b/ebean-test/src/test/resources/contains/check-type-actual.json @@ -0,0 +1,3 @@ +{ + "some": "val" +} diff --git a/ebean-test/src/test/resources/contains/check-type-expected.json b/ebean-test/src/test/resources/contains/check-type-expected.json new file mode 100644 index 000000000..5b0cf6957 --- /dev/null +++ b/ebean-test/src/test/resources/contains/check-type-expected.json @@ -0,0 +1,3 @@ +{ + "some": 42 +} diff --git a/ebean-test/src/test/resources/contains/original-subset-modified.json b/ebean-test/src/test/resources/contains/original-subset-modified.json new file mode 100644 index 000000000..107d557d2 --- /dev/null +++ b/ebean-test/src/test/resources/contains/original-subset-modified.json @@ -0,0 +1,26 @@ +{ + "someString1": "aaaa", + "someString2": "string2", + "someValue1": 99, + "someValue2": 2, + "someArray1": [ + "a" + ], + "someArray2": [ + { + "value1": [], + "value2": {}, + "array1": [ + "1" + ], + "object1": { + "val5": "a", + "val6": 1 + }, + "object2": null, + "objectNull": { + "val": [] + } + } + ] +} diff --git a/ebean-test/src/test/resources/contains/original-subset.json b/ebean-test/src/test/resources/contains/original-subset.json new file mode 100644 index 000000000..e5823e2a4 --- /dev/null +++ b/ebean-test/src/test/resources/contains/original-subset.json @@ -0,0 +1,15 @@ +{ + "someString1": "string1", + "someValue1": 1, + "someArray2": [ + { + "value1": 11, + "array1": [], + "object2": { + "v1": "v1", + "v4": [] + }, + "objectNull": null + } + ] +} diff --git a/ebean-test/src/test/resources/contains/original.json b/ebean-test/src/test/resources/contains/original.json new file mode 100644 index 000000000..063affac4 --- /dev/null +++ b/ebean-test/src/test/resources/contains/original.json @@ -0,0 +1,27 @@ +{ + "someString1": "string1", + "someString2": "string2", + "someValue1": 1, + "someValue2": 2, + "someArray1": [ + 1, + 2, + 3, + 4 + ], + "someArray2": [ + { + "value1": 11, + "value2": "22", + "array1": [], + "object1": {}, + "object2": { + "v1": "v1", + "v2": 1, + "v3": {}, + "v4": [] + }, + "objectNull": null + } + ] +} diff --git a/ebean-test/src/test/resources/example/plain-list.json b/ebean-test/src/test/resources/example/plain-list.json new file mode 100644 index 000000000..49bc4c34d --- /dev/null +++ b/ebean-test/src/test/resources/example/plain-list.json @@ -0,0 +1,10 @@ +[ + { + "id": 42, + "name": "foo" + }, + { + "id": 55, + "name": "bar" + } +] diff --git a/ebean-test/src/test/resources/example/plain.json b/ebean-test/src/test/resources/example/plain.json new file mode 100644 index 000000000..63632de85 --- /dev/null +++ b/ebean-test/src/test/resources/example/plain.json @@ -0,0 +1,4 @@ +{ + "id": 42, + "name": "foo" +} diff --git a/ebean/pom.xml b/ebean/pom.xml index 337b3deba..7356b26ff 100644 --- a/ebean/pom.xml +++ b/ebean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT ebean composite @@ -22,20 +22,20 @@ io.ebean ebean-api - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT io.ebean ebean-core - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT io.ebean ebean-querybean - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT
diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index 07993d49e..8e4df4f39 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT kotlin querybean generator @@ -29,7 +29,7 @@ io.ebean ebean-querybean - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT test @@ -43,7 +43,7 @@ io.ebean ebean-core - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT test @@ -64,7 +64,7 @@ io.ebean ebean-ddl-generator - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT test @@ -106,7 +106,7 @@ io.ebean kotlin-querybean-generator - 12.6.1 + 12.7.1 diff --git a/pom.xml b/pom.xml index 88954f378..8e06ae121 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean-parent - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT pom ebean parent @@ -40,6 +40,7 @@ false 7.0 + 2.12.1 diff --git a/querybean-generator/pom.xml b/querybean-generator/pom.xml index 90140df71..bc6fc7019 100644 --- a/querybean-generator/pom.xml +++ b/querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.7.1-SNAPSHOT + 12.7.3-SNAPSHOT querybean generator