From bb9cfe9d0ff259d4109c383f65e0c96f63717683 Mon Sep 17 00:00:00 2001 From: Noemi Praml Date: Tue, 24 May 2022 11:09:56 +0200 Subject: [PATCH 1/7] add support for findSingleAttributeSet --- .../main/java/io/ebean/ExpressionList.java | 9 +++++ .../main/java/io/ebean/ExtendedServer.java | 5 +++ ebean-api/src/main/java/io/ebean/Query.java | 5 +++ .../autotune/service/BaseQueryTuner.java | 1 + .../java/io/ebeaninternal/api/SpiQuery.java | 5 +++ .../api/TxnProfileEventCodes.java | 1 + .../server/core/DefaultServer.java | 18 +++++++++- .../server/core/OrmQueryEngine.java | 5 +-- .../server/core/OrmQueryRequest.java | 4 +-- .../server/core/SpiOrmQueryRequest.java | 3 +- .../expression/DefaultExpressionList.java | 5 +++ .../server/expression/JunctionExpression.java | 5 +++ .../server/query/CQueryEngine.java | 34 +++++++++++-------- .../query/CQueryFetchSingleAttribute.java | 5 ++- .../server/query/DefaultFetchGroupQuery.java | 5 +++ .../server/query/DefaultOrmQueryEngine.java | 5 +-- .../server/querydefn/DefaultOrmQuery.java | 4 +++ .../xtest/internal/api/TDSpiEbeanServer.java | 5 +++ .../java/org/tests/cache/TestQueryCache.java | 30 ++++++++++++++-- 19 files changed, 126 insertions(+), 28 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/ExpressionList.java b/ebean-api/src/main/java/io/ebean/ExpressionList.java index 8f2ebe0d0..bd3016a60 100644 --- a/ebean-api/src/main/java/io/ebean/ExpressionList.java +++ b/ebean-api/src/main/java/io/ebean/ExpressionList.java @@ -383,6 +383,15 @@ public interface ExpressionList { */ List findSingleAttributeList(); + /** + * Executes the query returning a set of values for a single property. + * + * This can be used to cache sets. + * + * @return a HashSet of values for the selegted property + */ + Set findSingleAttributeSet(); + /** * Execute a query returning a single value of a single property/column. *
{@code
diff --git a/ebean-api/src/main/java/io/ebean/ExtendedServer.java b/ebean-api/src/main/java/io/ebean/ExtendedServer.java
index 0088e9c2b..d6dc9af97 100644
--- a/ebean-api/src/main/java/io/ebean/ExtendedServer.java
+++ b/ebean-api/src/main/java/io/ebean/ExtendedServer.java
@@ -368,6 +368,11 @@ public interface ExtendedServer {
    */
    List findSingleAttributeList(Query query, Transaction transaction);
 
+  /**
+   * Execute the query returning a hashset of values for a single property.
+   */
+   Set findSingleAttributeSet(Query query, Transaction transaction);
+
   /**
    * Execute the query returning at most one entity bean or null (if no matching
    * bean is found).
diff --git a/ebean-api/src/main/java/io/ebean/Query.java b/ebean-api/src/main/java/io/ebean/Query.java
index 400c9775e..dafabe37f 100644
--- a/ebean-api/src/main/java/io/ebean/Query.java
+++ b/ebean-api/src/main/java/io/ebean/Query.java
@@ -925,6 +925,11 @@ public interface Query extends CancelableQuery {
    */
    List findSingleAttributeList();
 
+  /**
+   * Execute the query returning a hashset of values for a single property.
+   */
+   Set findSingleAttributeSet();
+
   /**
    * Execute a query returning a single value of a single property/column.
    * 

diff --git a/ebean-autotune/src/main/java/io/ebeaninternal/server/autotune/service/BaseQueryTuner.java b/ebean-autotune/src/main/java/io/ebeaninternal/server/autotune/service/BaseQueryTuner.java index b93be5cc8..b2282b468 100644 --- a/ebean-autotune/src/main/java/io/ebeaninternal/server/autotune/service/BaseQueryTuner.java +++ b/ebean-autotune/src/main/java/io/ebeaninternal/server/autotune/service/BaseQueryTuner.java @@ -143,6 +143,7 @@ public class BaseQueryTuner { switch (type) { case COUNT: case ATTRIBUTE: + case ATTRIBUTE_SET: case ID_LIST: case UPDATE: case DELETE: diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiQuery.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiQuery.java index ef939a8f5..4c5c35abd 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiQuery.java @@ -92,6 +92,11 @@ public interface SpiQuery extends Query, SpiQueryFetch, TxnProfileEventCod */ ATTRIBUTE(FIND_ATTRIBUTE, "findAttribute", false, false), + /** + * Find single attribute set. + */ + ATTRIBUTE_SET(FIND_ATTRIBUTE_SET, "findAttributeSet", false, false), + /** * Find rowCount. */ diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/TxnProfileEventCodes.java b/ebean-core/src/main/java/io/ebeaninternal/api/TxnProfileEventCodes.java index c4d1ea0be..8c492d77b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/TxnProfileEventCodes.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/TxnProfileEventCodes.java @@ -28,6 +28,7 @@ public interface TxnProfileEventCodes { String FIND_ID_LIST = "fi"; String FIND_EXISTS = "ex"; String FIND_ATTRIBUTE = "fa"; + String FIND_ATTRIBUTE_SET = "fas"; String FIND_COUNT = "fc"; String FIND_SUBQUERY = "fs"; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index 5fa876883..13e4365fa 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -1193,7 +1193,23 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } try { request.initTransIfRequired(); - return request.findSingleAttributeList(); + return request.findSingleAttributeCollection(new ArrayList<>()); + } finally { + request.endTransIfRequired(); + } + } + + @Override + @SuppressWarnings("unchecked") + public Set findSingleAttributeSet(Query query, Transaction transaction) { + SpiOrmQueryRequest request = createQueryRequest(Type.ATTRIBUTE_SET, query, transaction); + Object result = request.getFromQueryCache(); + if (result != null) { + return (Set) result; + } + try { + request.initTransIfRequired(); + return request.findSingleAttributeCollection(new LinkedHashSet<>()); } finally { request.endTransIfRequired(); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryEngine.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryEngine.java index b080e4a29..d3ca32b6d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryEngine.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryEngine.java @@ -6,6 +6,7 @@ import io.ebean.bean.BeanCollection; import javax.persistence.PersistenceException; import java.sql.SQLException; +import java.util.Collection; import java.util.List; /** @@ -29,9 +30,9 @@ public interface OrmQueryEngine { BeanCollection findMany(OrmQueryRequest request); /** - * Execute the findSingleAttributeList query. + * Execute the findSingleAttributeCollection query. */ - List findSingleAttributeList(OrmQueryRequest request); + > A findSingleAttributeCollection(OrmQueryRequest request, A collection); /** * Execute the findVersions query. diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java index 834ec2a04..ebe0ca971 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java @@ -431,8 +431,8 @@ public final class OrmQueryRequest extends BeanRequest implements SpiOrmQuery } @Override - public List findSingleAttributeList() { - return queryEngine.findSingleAttributeList(this); + public > A findSingleAttributeCollection(A collection) { + return queryEngine.findSingleAttributeCollection(this, collection); } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/SpiOrmQueryRequest.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/SpiOrmQueryRequest.java index 3c7139476..c3f98854b 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/SpiOrmQueryRequest.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/SpiOrmQueryRequest.java @@ -7,6 +7,7 @@ import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeanservice.docstore.api.DocQueryRequest; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @@ -122,7 +123,7 @@ public interface SpiOrmQueryRequest extends BeanQueryRequest, DocQueryRequ /** * Execute the findSingleAttributeList query. */ - List findSingleAttributeList(); + > A findSingleAttributeCollection(A collection); /** * Execute returning the ResultSet. diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java index 4bf66743b..c3abfef86 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java @@ -467,6 +467,11 @@ public class DefaultExpressionList implements SpiExpressionList { return query.findSingleAttributeList(); } + @Override + public Set findSingleAttributeSet() { + return query.findSingleAttributeSet(); + } + @Override public boolean exists() { return query.exists(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java index ee9245356..6984e5c9a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java @@ -464,6 +464,11 @@ final class JunctionExpression implements SpiJunction, SpiExpression, Expr return exprList.findSingleAttributeList(); } + @Override + public Set findSingleAttributeSet() { + return exprList.findSingleAttributeSet(); + } + @Override public PagedList findPagedList() { return exprList.findPagedList(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java index 6cc408c35..416da3c31 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java @@ -24,11 +24,7 @@ import org.slf4j.Logger; import javax.persistence.PersistenceException; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * Handles the Object Relational fetching. @@ -91,16 +87,16 @@ public final class CQueryEngine { /** * Build and execute the findSingleAttributeList query. */ - public List findSingleAttributeList(OrmQueryRequest request) { + public > A findSingleAttributeList(OrmQueryRequest request, A collection) { CQueryFetchSingleAttribute rcQuery = queryBuilder.buildFetchAttributeQuery(request); request.setCancelableQuery(rcQuery); - return findAttributeList(request, rcQuery); + return findAttributeCollection(request, rcQuery, collection); } @SuppressWarnings("unchecked") - private List findAttributeList(OrmQueryRequest request, CQueryFetchSingleAttribute rcQuery) { + private > A findAttributeCollection(OrmQueryRequest request, CQueryFetchSingleAttribute rcQuery, A collection) { try { - List list = (List) rcQuery.findList(); + rcQuery.findCollection(collection); if (request.logSql()) { logGeneratedSql(request, rcQuery.getGeneratedSql(), rcQuery.getBindLog(), rcQuery.micros()); } @@ -109,13 +105,21 @@ public final class CQueryEngine { } if (request.isQueryCachePut()) { request.addDependentTables(rcQuery.getDependentTables()); - list = Collections.unmodifiableList(list); - request.putToQueryCache(list); - if (Boolean.FALSE.equals(request.query().isReadOnly())) { - list = new ArrayList<>(list); + if (collection instanceof List) { + collection = (A) Collections.unmodifiableList((List) collection); + request.putToQueryCache(collection); + if (Boolean.FALSE.equals(request.query().isReadOnly())) { + collection = (A) new ArrayList<>(collection); + } + } else if (collection instanceof Set) { + collection = (A) Collections.unmodifiableSet((Set) collection); + request.putToQueryCache(collection); + if (Boolean.FALSE.equals(request.query().isReadOnly())) { + collection = (A) new LinkedHashSet<>(collection); + } } } - return list; + return collection; } catch (SQLException e) { throw translate(request, rcQuery.getBindLog(), rcQuery.getGeneratedSql(), e); } @@ -144,7 +148,7 @@ public final class CQueryEngine { public List findIds(OrmQueryRequest request) { CQueryFetchSingleAttribute rcQuery = queryBuilder.buildFetchIdsQuery(request); request.setCancelableQuery(rcQuery); - return findAttributeList(request, rcQuery); + return findAttributeCollection(request, rcQuery, new ArrayList<>()); } private void logGeneratedSql(OrmQueryRequest request, String sql, String bindLog, long micros) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryFetchSingleAttribute.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryFetchSingleAttribute.java index 7e7586d46..747793e85 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryFetchSingleAttribute.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryFetchSingleAttribute.java @@ -16,6 +16,7 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Set; import java.util.concurrent.locks.ReentrantLock; @@ -76,11 +77,10 @@ final class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent, Ca /** * Execute the query returning the row count. */ - List findList() throws SQLException { + void findCollection(Collection result) throws SQLException { long startNano = System.nanoTime(); try { prepareExecute(); - List result = new ArrayList<>(); while (dataReader.next()) { Object value = reader.read(dataReader); if (containsCounts) { @@ -95,7 +95,6 @@ final class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent, Ca queryPlan.captureBindForQueryPlan(predicates, executionTimeMicros); } getTransaction().profileEvent(this); - return result; } finally { close(); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java index fbc791937..71e13330e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java @@ -286,6 +286,11 @@ final class DefaultFetchGroupQuery implements SpiFetchGroupQuery, SpiQuery throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup"); } + @Override + public Set findSingleAttributeSet() { + throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup"); + } + @Override public A findSingleAttribute() { throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup"); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java index 86076b379..95c5dbe7e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java @@ -17,6 +17,7 @@ import javax.persistence.PersistenceException; import java.sql.SQLException; import java.util.Collection; import java.util.List; +import java.util.Set; /** * Main Finder implementation. @@ -97,9 +98,9 @@ public final class DefaultOrmQueryEngine implements OrmQueryEngine { } @Override - public List findSingleAttributeList(OrmQueryRequest request) { + public > A findSingleAttributeCollection(OrmQueryRequest request, A collection) { flushJdbcBatchOnQuery(request); - return queryEngine.findSingleAttributeList(request); + return queryEngine.findSingleAttributeList(request, collection); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index df2e1a2aa..7fbdbb5a5 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -1498,6 +1498,10 @@ public class DefaultOrmQuery extends AbstractQuery implements SpiQuery { return (List) server.findSingleAttributeList(this, transaction); } + @Override + public final Set findSingleAttributeSet() { + return (Set) server.findSingleAttributeSet(this, transaction); + } @Override public final A findSingleAttribute() { List list = findSingleAttributeList(); diff --git a/ebean-test/src/test/java/io/ebean/xtest/internal/api/TDSpiEbeanServer.java b/ebean-test/src/test/java/io/ebean/xtest/internal/api/TDSpiEbeanServer.java index 909ddcbb3..34309393c 100644 --- a/ebean-test/src/test/java/io/ebean/xtest/internal/api/TDSpiEbeanServer.java +++ b/ebean-test/src/test/java/io/ebean/xtest/internal/api/TDSpiEbeanServer.java @@ -695,6 +695,11 @@ public class TDSpiEbeanServer extends TDSpiServer implements SpiEbeanServer { return null; } + @Override + public Set findSingleAttributeSet(Query query, Transaction transaction) { + return null; + } + @Override public T findOne(Query query, Transaction transaction) { return null; diff --git a/ebean-test/src/test/java/org/tests/cache/TestQueryCache.java b/ebean-test/src/test/java/org/tests/cache/TestQueryCache.java index 7b0949b42..feff29a68 100644 --- a/ebean-test/src/test/java/org/tests/cache/TestQueryCache.java +++ b/ebean-test/src/test/java/org/tests/cache/TestQueryCache.java @@ -1,21 +1,23 @@ package org.tests.cache; -import io.ebean.xtest.BaseTestCase; import io.ebean.CacheMode; import io.ebean.DB; import io.ebean.ExpressionList; import io.ebean.bean.BeanCollection; import io.ebean.cache.ServerCache; import io.ebean.test.LoggedSql; +import io.ebean.xtest.BaseTestCase; import org.junit.jupiter.api.Test; import org.tests.model.basic.Customer; import org.tests.model.basic.ResetBasicData; import org.tests.model.cache.EColAB; import java.util.List; +import java.util.Set; import java.util.function.Consumer; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.*; public class TestQueryCache extends BaseTestCase { @@ -50,7 +52,7 @@ public class TestQueryCache extends BaseTestCase { } @Test - public void findSingleAttribute() { + public void findSingleAttributeList() { DB.find(EColAB.class).delete(); new EColAB("03", "SingleAttribute").save(); @@ -98,6 +100,30 @@ public class TestQueryCache extends BaseTestCase { assertThat(count).isEqualTo(2); } + @Test + public void findSingleAttributeSet() { + + DB.find(EColAB.class).delete(); + new EColAB("03", "SingleAttribute").save(); + new EColAB("03", "SingleAttribute").save(); + ExpressionList query = DB + .find(EColAB.class) + .setUseQueryCache(true) + .select("columnA") + .where() + .eq("columnB", "SingleAttribute"); + Set colA_first = query.findSingleAttributeSet(); + + Set colA_Second = query.findSingleAttributeSet(); + + assertThat(colA_Second).isSameAs(colA_first).hasSize(1); + assertThatThrownBy(colA_first::clear).isInstanceOf(UnsupportedOperationException.class); + // ensure, that we do not have cache collisions on same query + query.findSingleAttributeList(); + query.findSingleAttribute(); + query.findCount(); + } + @Test public void findCount() { From d1a40b4739dc2c2408b1936b4afedaed12ca0ac5 Mon Sep 17 00:00:00 2001 From: Noemi Praml Date: Tue, 31 May 2022 10:47:08 +0200 Subject: [PATCH 2/7] failing test --- .../org/tests/timezone/LocalTimeTest.java | 69 +++++++++++++++++++ .../java/org/tests/timezone/MLocalTime.java | 28 ++++++++ 2 files changed, 97 insertions(+) create mode 100644 ebean-test/src/test/java/org/tests/timezone/LocalTimeTest.java create mode 100644 ebean-test/src/test/java/org/tests/timezone/MLocalTime.java diff --git a/ebean-test/src/test/java/org/tests/timezone/LocalTimeTest.java b/ebean-test/src/test/java/org/tests/timezone/LocalTimeTest.java new file mode 100644 index 000000000..6f5b7e0f9 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/timezone/LocalTimeTest.java @@ -0,0 +1,69 @@ +package org.tests.timezone; + +import io.ebean.Database; +import io.ebean.DatabaseFactory; +import io.ebean.config.DatabaseConfig; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +import java.time.LocalTime; + +import static org.assertj.core.api.Assertions.assertThat; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class LocalTimeTest { + + protected String platform="h2"; + protected Database db; + + @BeforeAll + public void startTest() { + db = createServer("GMT"); // test uses GMT database + } + + @AfterAll + public void shutdown() { + if (db != null) { + db.find(MLocalTime.class).delete(); + db.shutdown(); + } + } + + /** + * The test checks the write and read of LocalTime values. The database is in GMT time zone. + * In order to verify the test in different java time zones (where the application runs), + * use the -Duser.timezone as JVM argument, + * e.g. -Duser.timezone="America/New_York" or -Duser.timezone="PST"> + * or any other timezone: https://garygregory.wordpress.com/2013/06/18/what-are-the-java-timezone-ids/. + */ + @Test + public void testLocalTime() { + LocalTime lt = LocalTime.of(5, 15, 15); + assertThat(db.find(MLocalTime.class).findCount()).isEqualTo(0); + db.sqlUpdate("insert into mlocal_time (id, local_time) values (1, '05:15:15')").execute(); + + int count = db.find(MLocalTime.class).where().eq("local_time", lt).findCount(); + assertThat(count).isEqualTo(1); + + MLocalTime dbModel = db.find(MLocalTime.class).where().eq("local_time", lt).findOne(); + assertThat(dbModel.getLocalTime().toString()).isEqualTo(lt.toString()); + } + + private Database createServer(String dbTimeZone) { + DatabaseConfig config = new DatabaseConfig(); + config.setName(platform); + config.loadFromProperties(); + config.setDdlExtra(false); + config.setDefaultServer(false); + config.setRegister(false); + config.setChangeLogAsync(false); + config.addClass(MLocalTime.class); + + config.setDumpMetricsOnShutdown(false); + config.setDataTimeZone(dbTimeZone); + + return DatabaseFactory.create(config); + } +} diff --git a/ebean-test/src/test/java/org/tests/timezone/MLocalTime.java b/ebean-test/src/test/java/org/tests/timezone/MLocalTime.java new file mode 100644 index 000000000..4a2d30313 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/timezone/MLocalTime.java @@ -0,0 +1,28 @@ +package org.tests.timezone; + +import javax.annotation.Nullable; +import javax.persistence.Entity; +import javax.persistence.Id; +import java.time.LocalTime; + +@Entity +public class MLocalTime { + + @Id + private Integer id; + + @Nullable + private LocalTime localTime; + + @Nullable + public LocalTime getLocalTime() { + return localTime; + } + public Integer getId() { + return id; + } + public void setId(Integer id) { + this.id = id; + } + +} From c8be59fd9553bd1ae14a9eb27357261ae8b0de45 Mon Sep 17 00:00:00 2001 From: Noemi Praml Date: Wed, 25 May 2022 10:20:46 +0200 Subject: [PATCH 3/7] it fixes the test (cherry picked from commit d2e21aa3dcbd4ae59dd8d1ff5404d94c298f087b) --- .../src/main/java/io/ebeaninternal/server/type/DataBind.java | 2 +- .../main/java/io/ebeaninternal/server/type/RsetDataReader.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/DataBind.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/DataBind.java index 04492de5c..2ef0c6db3 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/DataBind.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/DataBind.java @@ -178,7 +178,7 @@ public class DataBind implements DataBinder { @Override public final void setTime(Time v) throws SQLException { - Calendar timeZone = dataTimeZone.getTimeZone(); + Calendar timeZone = dataTimeZone.getDateTimeZone(); if (timeZone != null) { pstmt.setTime(++pos, v, timeZone); } else { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/RsetDataReader.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/RsetDataReader.java index 6469f8346..4bb1be3ae 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/RsetDataReader.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/RsetDataReader.java @@ -156,7 +156,7 @@ public class RsetDataReader implements DataReader { @Override public final Time getTime() throws SQLException { - Calendar cal = dataTimeZone.getTimeZone(); + Calendar cal = dataTimeZone.getDateTimeZone(); if (cal != null) { return rset.getTime(pos(), cal); } else { From 9c354919e5c64e1787b6f335601aafcde059570f Mon Sep 17 00:00:00 2001 From: Noemi Praml Date: Wed, 25 May 2022 10:36:52 +0200 Subject: [PATCH 4/7] refactoring (cherry picked from commit 43e28c4f5c747cdda2e3547a8db593eab490ceec) --- .../ebeaninternal/server/core/timezone/DataTimeZone.java | 7 +++---- .../server/core/timezone/MySqlDataTimeZone.java | 2 +- .../main/java/io/ebeaninternal/server/type/DataBind.java | 4 ++-- .../java/io/ebeaninternal/server/type/RsetDataReader.java | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/timezone/DataTimeZone.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/timezone/DataTimeZone.java index 775e826d1..ff9366802 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/timezone/DataTimeZone.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/timezone/DataTimeZone.java @@ -13,11 +13,10 @@ public interface DataTimeZone { Calendar getTimeZone(); /** - * Return the Calendar to use for Timezone information when reading/writing date. - * A 'date' only value has normally no timezone information, but some platforms (like MySQL) - * reqire this. + * Return the Calendar to use for Timezone information when reading/writing a time component (date only/time only). + * A time component has normally no timezone information, but some platforms (like MySQL) reqire this. */ - default Calendar getDateTimeZone() { + default Calendar getTimeComponentTimeZone() { return null; } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/timezone/MySqlDataTimeZone.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/timezone/MySqlDataTimeZone.java index 85ceab500..102fcd88f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/timezone/MySqlDataTimeZone.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/timezone/MySqlDataTimeZone.java @@ -19,7 +19,7 @@ public class MySqlDataTimeZone implements DataTimeZone { } @Override - public Calendar getDateTimeZone() { + public Calendar getTimeComponentTimeZone() { return zone; } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/DataBind.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/DataBind.java index 2ef0c6db3..ab17244e4 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/DataBind.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/DataBind.java @@ -158,7 +158,7 @@ public class DataBind implements DataBinder { @Override public final void setDate(java.sql.Date v) throws SQLException { - Calendar timeZone = dataTimeZone.getDateTimeZone(); + Calendar timeZone = dataTimeZone.getTimeComponentTimeZone(); if (timeZone != null) { pstmt.setDate(++pos, v, timeZone); } else { @@ -178,7 +178,7 @@ public class DataBind implements DataBinder { @Override public final void setTime(Time v) throws SQLException { - Calendar timeZone = dataTimeZone.getDateTimeZone(); + Calendar timeZone = dataTimeZone.getTimeComponentTimeZone(); if (timeZone != null) { pstmt.setTime(++pos, v, timeZone); } else { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/RsetDataReader.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/RsetDataReader.java index 4bb1be3ae..5bf529d77 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/RsetDataReader.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/RsetDataReader.java @@ -107,7 +107,7 @@ public class RsetDataReader implements DataReader { @Override public final Date getDate() throws SQLException { - Calendar cal = dataTimeZone.getDateTimeZone(); + Calendar cal = dataTimeZone.getTimeComponentTimeZone(); if (cal != null) { return rset.getDate(pos(), cal); } else { @@ -156,7 +156,7 @@ public class RsetDataReader implements DataReader { @Override public final Time getTime() throws SQLException { - Calendar cal = dataTimeZone.getDateTimeZone(); + Calendar cal = dataTimeZone.getTimeComponentTimeZone(); if (cal != null) { return rset.getTime(pos(), cal); } else { From 1ee18a182330bf3aedeeeec9cff5f0b1dfe64262 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 9 Jun 2022 12:26:36 +1200 Subject: [PATCH 5/7] #2711 - Gradle: Change querybean generator from isolating to aggregating --- .../resources/META-INF/gradle/incremental.annotation.processors | 1 + .../resources/META-INF/gradle/incremental.annotation.processors | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 kotlin-querybean-generator/src/main/resources/META-INF/gradle/incremental.annotation.processors diff --git a/kotlin-querybean-generator/src/main/resources/META-INF/gradle/incremental.annotation.processors b/kotlin-querybean-generator/src/main/resources/META-INF/gradle/incremental.annotation.processors new file mode 100644 index 000000000..2403f535e --- /dev/null +++ b/kotlin-querybean-generator/src/main/resources/META-INF/gradle/incremental.annotation.processors @@ -0,0 +1 @@ +io.ebean.querybean.generator.Processor,aggregating diff --git a/querybean-generator/src/main/resources/META-INF/gradle/incremental.annotation.processors b/querybean-generator/src/main/resources/META-INF/gradle/incremental.annotation.processors index 678105220..2403f535e 100644 --- a/querybean-generator/src/main/resources/META-INF/gradle/incremental.annotation.processors +++ b/querybean-generator/src/main/resources/META-INF/gradle/incremental.annotation.processors @@ -1 +1 @@ -io.ebean.querybean.generator.Processor,isolating +io.ebean.querybean.generator.Processor,aggregating From 168c940b79a694699542801872e61b1cd00623d3 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 9 Jun 2022 12:29:52 +1200 Subject: [PATCH 6/7] #2712 - Bump jedis to 4.2.3 (from 4.2.2) --- ebean-redis/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index 7b849a27f..3aa9d2e97 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -16,7 +16,7 @@ redis.clients jedis - 4.2.2 + 4.2.3 From 9aa7ae79e255cc0241215e1871f3e1a2e48d64f2 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 9 Jun 2022 13:26:48 +1200 Subject: [PATCH 7/7] #2713 - Improve javadoc of Finder, BeanFinder, BeanRepository - deprecate use of BeanFinder server field (migrate to database) --- .../src/main/java/io/ebean/BeanFinder.java | 23 +++++++++++++------ .../main/java/io/ebean/BeanRepository.java | 18 +++++++++------ ebean-api/src/main/java/io/ebean/Finder.java | 5 ++++ .../tests/repository/CustomerRepository.java | 3 --- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/BeanFinder.java b/ebean-api/src/main/java/io/ebean/BeanFinder.java index 1f5c0a12c..62a9bd6f9 100644 --- a/ebean-api/src/main/java/io/ebean/BeanFinder.java +++ b/ebean-api/src/main/java/io/ebean/BeanFinder.java @@ -12,6 +12,7 @@ import java.util.Optional; *

*
{@code
  *
+ * @Component
  * public class CustomerFinder extends BeanFinder {
  *
  *   @Inject
@@ -26,29 +27,37 @@ import java.util.Optional;
  *
  * @param  The ID type
  * @param  The Bean type
+ *
+ * @see BeanRepository
  */
 @NonNullApi
 public abstract class BeanFinder {
 
+  /**
+   * Migrate to using database rather than server.
+   */
+  @Deprecated
   protected final Database server;
+  protected final Database database;
   protected final Class type;
 
   /**
    * Create with the given bean type and Database instance.
    *
    * @param type The bean type
-   * @param server The Database instance typically created via Spring factory or equivalent.
+   * @param database The Database instance typically created via Spring factory or equivalent.
    */
-  protected BeanFinder(Class type, Database server) {
+  protected BeanFinder(Class type, Database database) {
     this.type = type;
-    this.server = server;
+    this.database = database;
+    this.server = database;
   }
 
   /**
    * Return the Database to use.
    */
   public Database db() {
-    return server;
+    return database;
   }
 
   /**
@@ -70,10 +79,10 @@ public abstract class BeanFinder {
    * 

* This is equivalent to {@link DB#byName(String)} * - * @param server The name of the Database. If this is null then the default Database is returned. + * @param name The name of the Database. If this is null then the default Database is returned. */ - public Database db(String server) { - return DB.byName(server); + public Database db(String name) { + return DB.byName(name); } /** diff --git a/ebean-api/src/main/java/io/ebean/BeanRepository.java b/ebean-api/src/main/java/io/ebean/BeanRepository.java index ad973e261..f5ca84500 100644 --- a/ebean-api/src/main/java/io/ebean/BeanRepository.java +++ b/ebean-api/src/main/java/io/ebean/BeanRepository.java @@ -6,11 +6,15 @@ import io.ebean.bean.EntityBean; import java.util.Collection; /** - * Provides finder functionality for use with "Dependency Injection style" use of Ebean. + * Provides find and persist functionality for use with "Dependency Injection style" use of Ebean. *

+ * Extend the BeanRepository with additional finder and persisting methods as needed by the + * application. The intention is to keep all the related logic together, for example, all the + * persisting and finding logic for Customer would be in CustomerRepository. + * *

{@code
  *
- * @Repository
+ * @Component
  * public class CustomerRepository extends BeanRepository {
  *
  *   @Inject
@@ -50,10 +54,10 @@ public abstract class BeanRepository extends BeanFinder {
    * }
* * @param type The bean type - * @param server The Database instance typically created via Spring factory or equivalent + * @param database The Database instance typically created via Spring factory or equivalent */ - protected BeanRepository(Class type, Database server) { - super(type, server); + protected BeanRepository(Class type, Database database) { + super(type, database); } /** @@ -122,8 +126,8 @@ public abstract class BeanRepository extends BeanFinder { /** * Save all the beans in the collection. */ - public int saveAll(Collection bean) { - return db().saveAll(bean); + public int saveAll(Collection beans) { + return db().saveAll(beans); } /** diff --git a/ebean-api/src/main/java/io/ebean/Finder.java b/ebean-api/src/main/java/io/ebean/Finder.java index 2bb927640..8dd4088fb 100644 --- a/ebean-api/src/main/java/io/ebean/Finder.java +++ b/ebean-api/src/main/java/io/ebean/Finder.java @@ -8,6 +8,9 @@ import java.util.List; * Intended to be used as a base class for 'Finder' implementations that can then * be injected or used as public static fields on the associated entity bean. *

+ * When using dependency injection {@link BeanRepository} and {@link BeanFinder} + * are expected to be used rather than this Finder. + *

* These 'finders' are a place to organise all the finder methods for that bean type * and specific finder methods are expected to be added (find by unique properties etc). *

@@ -54,6 +57,8 @@ import java.util.List; * * }
* + * @see BeanRepository + * @see BeanFinder */ @NonNullApi public class Finder { diff --git a/ebean-test/src/test/java/org/tests/repository/CustomerRepository.java b/ebean-test/src/test/java/org/tests/repository/CustomerRepository.java index f9fc7f59b..97179c38a 100644 --- a/ebean-test/src/test/java/org/tests/repository/CustomerRepository.java +++ b/ebean-test/src/test/java/org/tests/repository/CustomerRepository.java @@ -6,8 +6,6 @@ import org.tests.model.basic.Customer; import java.util.List; -//import javax.inject.Inject; - public class CustomerRepository extends BeanRepository { //@Inject @@ -28,7 +26,6 @@ public class CustomerRepository extends BeanRepository { } public int updateNotes(String blah, String whot) { - return updateQuery() .set("smallnote", whot) .where().eq("name", blah)