mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Merge branch 'master' of github.com:ebean-orm/ebean
This commit is contained in:
@@ -6,6 +6,10 @@ import java.util.concurrent.Callable;
|
||||
* BackgroundExecutorWrapper that can be used to wrap tasks that are sent to background (i.e. another thread).
|
||||
* It should copy all necessary thread-local variables. See {@link MdcBackgroundExecutorWrapper} for implementation details.
|
||||
*
|
||||
* Note: only tasks that are executed immediately (submit, execute) are wrapped. Periodic or scheduled tasks are not wrapped,
|
||||
* as these may keep copied variables in memory either forever or until the scheduled task is finished.
|
||||
* The caller is responsible to handle these cases.
|
||||
*
|
||||
* @author Roland Praml, FOCONIS AG
|
||||
*/
|
||||
public interface BackgroundExecutorWrapper {
|
||||
|
||||
@@ -121,7 +121,7 @@ public interface SpiOrmQueryRequest<T> extends BeanQueryRequest<T>, DocQueryRequ
|
||||
<K> Map<K, T> findMap();
|
||||
|
||||
/**
|
||||
* Execute the findSingleAttributeList query.
|
||||
* Execute the findSingleAttributeCollection query.
|
||||
*/
|
||||
<A extends Collection<?>> A findSingleAttributeCollection(A collection);
|
||||
|
||||
|
||||
+4
-4
@@ -106,23 +106,23 @@ public final class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit) {
|
||||
return schedulePool.scheduleWithFixedDelay(wrap(logExceptions(task)), initialDelay, delay, unit);
|
||||
return schedulePool.scheduleWithFixedDelay(logExceptions(task), initialDelay, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long delay, TimeUnit unit) {
|
||||
return schedulePool.scheduleAtFixedRate(wrap(logExceptions(task)), initialDelay, delay, unit);
|
||||
return schedulePool.scheduleAtFixedRate(logExceptions(task), initialDelay, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> schedule(Runnable task, long delay, TimeUnit unit) {
|
||||
return schedulePool.schedule(wrap(logExceptions(task)), delay, unit);
|
||||
return schedulePool.schedule(logExceptions(task), delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> ScheduledFuture<V> schedule(Callable<V> task, long delay, TimeUnit unit) {
|
||||
// Note: No "logExceptions" as we expect Future.get() by the invoker
|
||||
return schedulePool.schedule(wrap(task), delay, unit);
|
||||
return schedulePool.schedule(task, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -106,7 +106,7 @@ public class UuidV1RndIdGenerator implements PlatformIdGenerator {
|
||||
|
||||
delta = current - last;
|
||||
if (delta < -10000 * 20000) {
|
||||
log.log(INFO, "Clock skew of {} ms detected", delta / -10000);
|
||||
log.log(INFO, "Clock skew of {0} ms detected", delta / -10000);
|
||||
// The clock was adjusted back about 2 seconds, or we were generating a lot of ids too fast
|
||||
// if so, we try to set the current as last and also increment the clockSeq.
|
||||
lock.lock();
|
||||
|
||||
@@ -885,6 +885,9 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
|
||||
public final void preCommit() {
|
||||
internalBatchFlush();
|
||||
firePreCommit();
|
||||
// we must flush the batch queue again, because the callback can
|
||||
// modify current transaction
|
||||
internalBatchFlush();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,7 +61,7 @@ final class ScalarTypeCalendar extends ScalarTypeBaseDateTime<Calendar> {
|
||||
|
||||
@Override
|
||||
protected String toJsonNanos(Calendar value) {
|
||||
return String.valueOf(value.getTime());
|
||||
return String.valueOf(value.getTime().getTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeParseException;
|
||||
|
||||
/**
|
||||
* ScalarType for java.sql.Timestamp.
|
||||
@@ -48,7 +49,7 @@ final class ScalarTypeLocalDateTime extends ScalarTypeBaseDateTime<LocalDateTime
|
||||
|
||||
@Override
|
||||
public LocalDateTime jsonRead(JsonParser parser) throws IOException {
|
||||
return LocalDateTime.parse(parser.getText());
|
||||
return parse(parser.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,7 +64,11 @@ final class ScalarTypeLocalDateTime extends ScalarTypeBaseDateTime<LocalDateTime
|
||||
|
||||
@Override
|
||||
public LocalDateTime parse(String value) {
|
||||
return LocalDateTime.parse(value);
|
||||
try {
|
||||
return LocalDateTime.parse(value);
|
||||
} catch (DateTimeParseException pe) {
|
||||
return super.parse(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+37
-1
@@ -2,15 +2,20 @@ package io.ebeaninternal.server.type;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import io.ebean.config.JsonConfig;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class ScalarTypeLocalDateTimeTest {
|
||||
|
||||
@@ -123,4 +128,35 @@ public class ScalarTypeLocalDateTimeTest {
|
||||
LocalDateTime value = typeIso.fromJsonISO8601(asJson);
|
||||
assertThat(localDateTime).isEqualToIgnoringNanos(value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseEbean11() throws IOException {
|
||||
ScalarTypeLocalDateTime type = new ScalarTypeLocalDateTime(JsonConfig.DateTime.ISO8601);
|
||||
JsonFactory factory = new JsonFactory();
|
||||
JsonParser parser11 = factory.createParser("1517627106000"); // its a number!
|
||||
JsonParser parser13 = factory.createParser("\"2022-01-01T01:00:00\"");
|
||||
|
||||
// test parsing an ebean 11/13 timestamp, we do not expect an exception
|
||||
LocalDateTime p = type.parse("1517627106000");
|
||||
parser11.nextToken();
|
||||
LocalDateTime q = type.jsonRead(parser11);
|
||||
assertThat(p).isEqualTo(q);
|
||||
|
||||
p = type.parse("2022-01-01T01:00:00");
|
||||
parser13.nextToken();
|
||||
q = type.jsonRead(parser13);
|
||||
assertThat(p).isEqualTo(q);
|
||||
TimeZone tz = TimeZone.getDefault();
|
||||
try {
|
||||
// Adjust Timezone to run on build server
|
||||
// Note Millis and Iso have a time offset according to TZ
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin"));
|
||||
LocalDateTime fromMillis = type.parse("0");
|
||||
LocalDateTime fromIso = type.parse("1970-01-01T01:00");
|
||||
|
||||
assertThat(fromMillis).isEqualToIgnoringNanos(fromIso);
|
||||
} finally {
|
||||
TimeZone.setDefault(tz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,11 @@ import java.io.Reader;
|
||||
import java.net.URL;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
|
||||
class CsvReaderTest {
|
||||
|
||||
final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy");
|
||||
final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy", Locale.ENGLISH);
|
||||
|
||||
@Test
|
||||
void test() throws Exception {
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ public class ExtraDdlXmlReader {
|
||||
StringBuilder sb = new StringBuilder(300);
|
||||
for (DdlScript script : read.getDdlScript()) {
|
||||
if (script.isDrop() == drops && matchPlatform(platform, script.getPlatforms())) {
|
||||
logger.log(DEBUG, "include script {}", script.getName());
|
||||
logger.log(DEBUG, "include script {0}", script.getName());
|
||||
String value = script.getValue();
|
||||
sb.append(value);
|
||||
if (value.lastIndexOf(';') == -1) {
|
||||
|
||||
+21
@@ -105,4 +105,25 @@ public class JdbcTransactionTest {
|
||||
assertThat(postCommitCallCount.get()).isEqualTo(2); // postcommit executed twice
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlushInCallback() {
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setBatchMode(true);
|
||||
DB.currentTransaction().register(
|
||||
new TransactionCallbackAdapter() {
|
||||
|
||||
@Override
|
||||
public void preCommit() {
|
||||
EBasic basic = new EBasic("binner1");
|
||||
DB.save(basic);
|
||||
}
|
||||
}
|
||||
);
|
||||
EBasic basic = new EBasic("bouter1");
|
||||
DB.save(basic);
|
||||
transaction.commit(); // transaction will fail if recursive post-commit is failing
|
||||
}
|
||||
assertThat(DB.find(EBasic.class).where().eq("name", "binner1").exists()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
+17
-17
@@ -91,12 +91,12 @@ public class TestQueryCache extends BaseTestCase {
|
||||
// ensure that findCount & findSingleAttribute use different
|
||||
// slots in cache. If not a "Cannot cast List to int" should happen.
|
||||
int count = DB
|
||||
.find(EColAB.class)
|
||||
.setUseQueryCache(true)
|
||||
.select("columnA")
|
||||
.where()
|
||||
.eq("columnB", "SingleAttribute")
|
||||
.findCount();
|
||||
.find(EColAB.class)
|
||||
.setUseQueryCache(true)
|
||||
.select("columnA")
|
||||
.where()
|
||||
.eq("columnB", "SingleAttribute")
|
||||
.findCount();
|
||||
assertThat(count).isEqualTo(2);
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ public class TestQueryCache extends BaseTestCase {
|
||||
assertSame(list, list2B);
|
||||
|
||||
List<Customer> list3 = DB.find(Customer.class).setUseQueryCache(true).setReadOnly(false).where()
|
||||
.ilike("name", "Rob").findList();
|
||||
.ilike("name", "Rob").findList();
|
||||
|
||||
assertNotSame(list, list3);
|
||||
BeanCollection<Customer> bc3 = (BeanCollection<Customer>) list3;
|
||||
@@ -349,10 +349,10 @@ public class TestQueryCache extends BaseTestCase {
|
||||
// and now, ensure that we hit the database
|
||||
LoggedSql.start();
|
||||
colA_second = DB.find(EColAB.class)
|
||||
.setUseQueryCache(CacheMode.PUT)
|
||||
.where()
|
||||
.eq("columnB", "someId")
|
||||
.findIds();
|
||||
.setUseQueryCache(CacheMode.PUT)
|
||||
.where()
|
||||
.eq("columnB", "someId")
|
||||
.findIds();
|
||||
sql = LoggedSql.stop();
|
||||
|
||||
assertThat(sql).hasSize(1);
|
||||
@@ -361,15 +361,15 @@ public class TestQueryCache extends BaseTestCase {
|
||||
@Test
|
||||
public void findCountDifferentQueriesBit() {
|
||||
DB.getDefault().pluginApi().cacheManager().clearAll();
|
||||
differentFindCount(q->q.bitwiseAny("id",1), q->q.bitwiseAny("id",0));
|
||||
differentFindCount(q->q.bitwiseAll("id",1), q->q.bitwiseAll("id",0));
|
||||
differentFindCount(q -> q.bitwiseAny("id", 1), q -> q.bitwiseAny("id", 0));
|
||||
differentFindCount(q -> q.bitwiseAll("id", 1), q -> q.bitwiseAll("id", 0));
|
||||
// differentFindCount(q->q.bitwiseNot("id",1), q->q.bitwiseNot("id",0)); NOT 1 == AND 1 = 0
|
||||
differentFindCount(q->q.bitwiseAnd("id",1, 0), q->q.bitwiseAnd("id",1, 1));
|
||||
differentFindCount(q -> q.bitwiseAnd("id", 1, 0), q -> q.bitwiseAnd("id", 1, 1));
|
||||
|
||||
differentFindCount(q->q.bitwiseAnd("id",2, 0), q->q.bitwiseAnd("id",4, 0));
|
||||
differentFindCount(q->q.bitwiseAnd("id",2, 1), q->q.bitwiseAnd("id",4, 1));
|
||||
differentFindCount(q -> q.bitwiseAnd("id", 2, 0), q -> q.bitwiseAnd("id", 4, 0));
|
||||
differentFindCount(q -> q.bitwiseAnd("id", 2, 1), q -> q.bitwiseAnd("id", 4, 1));
|
||||
// Will produce hash collision
|
||||
differentFindCount(q->q.bitwiseAnd("id",10, 0), q->q.bitwiseAnd("id",0, 928210));
|
||||
differentFindCount(q -> q.bitwiseAnd("id", 10, 0), q -> q.bitwiseAnd("id", 0, 928210));
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user