HHH-13266 Add an abstract class for all java.time tests for this ticket

So that we can hopefully factorize the upcoming additions.
This commit is contained in:
Yoann Rodière 2019-03-11 16:32:44 +01:00 committed by gbadner
parent a17e9fc494
commit ece5f1a180
6 changed files with 547 additions and 844 deletions

View File

@ -0,0 +1,222 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.type;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.testing.junit4.CustomParameterized;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
/**
* Tests for storage of Instant properties.
*
* @param <T> The time type being tested.
* @param <E> The entity type used in tests.
*/
@RunWith(CustomParameterized.class)
abstract class AbstractJavaTimeTypeTest<T, E> extends BaseCoreFunctionalTestCase {
private static Dialect determineDialect() {
try {
return Dialect.getDialect();
}
catch (Exception e) {
return new Dialect() {
};
}
}
protected static final String ENTITY_NAME = "theentity";
protected static final String ID_COLUMN_NAME = "theid";
protected static final String PROPERTY_COLUMN_NAME = "thevalue";
protected static final ZoneId ZONE_UTC_MINUS_8 = ZoneId.of( "UTC-8" );
protected static final ZoneId ZONE_PARIS = ZoneId.of( "Europe/Paris" );
protected static final ZoneId ZONE_GMT = ZoneId.of( "GMT" );
protected static final ZoneId ZONE_OSLO = ZoneId.of( "Europe/Oslo" );
protected static final ZoneId ZONE_AMSTERDAM = ZoneId.of( "Europe/Amsterdam" );
private final EnvironmentParameters env;
public AbstractJavaTimeTypeTest(EnvironmentParameters env) {
this.env = env;
}
@Override
protected final Class<?>[] getAnnotatedClasses() {
return new Class[] { getEntityType() };
}
protected abstract Class<E> getEntityType();
protected abstract E createEntity(int id);
protected abstract T getExpectedPropertyValue();
protected abstract T getActualPropertyValue(E entity);
protected abstract Object getExpectedJdbcValue();
protected abstract Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws SQLException;
@Before
public void cleanup() {
inTransaction( session -> {
session.createNativeQuery( "DELETE FROM " + ENTITY_NAME ).executeUpdate();
} );
}
@Test
@TestForIssue(jiraKey = "HHH-13266")
public void writeThenRead() {
withDefaultTimeZone( () -> {
inTransaction( session -> {
session.persist( createEntity( 1 ) );
} );
inTransaction( session -> {
T read = getActualPropertyValue( session.find( getEntityType(), 1 ) );
assertEquals(
"Writing then reading a value should return the original value",
getExpectedPropertyValue(), read
);
} );
} );
}
@Test
@TestForIssue(jiraKey = "HHH-13266")
public void writeThenNativeRead() {
withDefaultTimeZone( () -> {
inTransaction( session -> {
session.persist( createEntity( 1 ) );
} );
inTransaction( session -> {
session.doWork( connection -> {
final PreparedStatement statement = connection.prepareStatement(
"SELECT " + PROPERTY_COLUMN_NAME + " FROM " + ENTITY_NAME + " WHERE " + ID_COLUMN_NAME + " = ?"
);
statement.setInt( 1, 1 );
statement.execute();
final ResultSet resultSet = statement.getResultSet();
resultSet.next();
Object nativeRead = getActualJdbcValue( resultSet, 1 );
assertEquals(
"Values written by Hibernate ORM should match the original value (same day, hour, ...)",
getExpectedJdbcValue(),
nativeRead
);
} );
} );
} );
}
protected final void withDefaultTimeZone(Runnable runnable) {
TimeZone timeZoneBefore = TimeZone.getDefault();
TimeZone.setDefault( TimeZone.getTimeZone( env.defaultJvmTimeZone ) );
/*
* Run the code in a new thread, because some libraries (looking at you, h2 JDBC driver)
* cache data dependent on the default timezone in thread local variables,
* and we want this data to be reinitialized with the new default time zone.
*/
try {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit( runnable );
executor.shutdown();
future.get();
}
catch (InterruptedException e) {
throw new IllegalStateException( "Interrupted while testing", e );
}
catch (ExecutionException e) {
Throwable cause = e.getCause();
if ( cause instanceof RuntimeException ) {
throw (RuntimeException) cause;
}
else if ( cause instanceof Error ) {
throw (Error) cause;
}
else {
throw new IllegalStateException( "Unexpected exception while testing", cause );
}
}
finally {
TimeZone.setDefault( timeZoneBefore );
}
}
protected static abstract class AbstractParametersBuilder<S extends AbstractParametersBuilder<S>> {
private final Dialect dialect;
private final List<Object[]> result = new ArrayList<>();
protected AbstractParametersBuilder() {
dialect = determineDialect();
}
protected final boolean isNanosecondPrecisionSupported() {
// PostgreSQL apparently doesn't support nanosecond precision correctly
return !( dialect instanceof PostgreSQL81Dialect );
}
protected final S add(ZoneId defaultJvmTimeZone, Object ... subClassParameters) {
List<Object> parameters = new ArrayList<>();
parameters.add( new EnvironmentParameters( defaultJvmTimeZone ) );
Collections.addAll( parameters, subClassParameters );
result.add( parameters.toArray() );
return thisAsS();
}
private S thisAsS() {
return (S) this;
}
public List<Object[]> build() {
return result;
}
}
protected final static class EnvironmentParameters {
/*
* The default timezone affects conversions done using java.util,
* which is why we take it into account even with timezone-independent types such as Instant.
*/
private final ZoneId defaultJvmTimeZone;
private EnvironmentParameters(ZoneId defaultJvmTimeZone) {
this.defaultJvmTimeZone = defaultJvmTimeZone;
}
@Override
public String toString() {
return String.format( "[JVM TZ: %s]", defaultJvmTimeZone );
}
}
}

View File

@ -6,91 +6,57 @@
*/
package org.hibernate.test.type;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.testing.junit4.CustomParameterized;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import static org.junit.Assert.assertEquals;
/**
* Tests for storage of Instant properties.
*/
@RunWith(CustomParameterized.class)
public class InstantTest extends BaseCoreFunctionalTestCase {
public class InstantTest extends AbstractJavaTimeTypeTest<Instant, InstantTest.EntityWithInstant> {
private static Dialect DIALECT;
private static Dialect determineDialect() {
try {
return Dialect.getDialect();
}
catch (Exception e) {
return new Dialect() {
};
private static class ParametersBuilder extends AbstractParametersBuilder<ParametersBuilder> {
public ParametersBuilder add(int year, int month, int day,
int hour, int minute, int second, int nanosecond, ZoneId defaultTimeZone) {
if ( !isNanosecondPrecisionSupported() ) {
nanosecond = 0;
}
return add( defaultTimeZone, year, month, day, hour, minute, second, nanosecond );
}
}
/*
* The default timezone affects conversions done using java.util,
* which is why we take it into account even when testing Instant.
*/
@Parameterized.Parameters(name = "{0}-{1}-{2}T{3}:{4}:{5}.{6}Z [JVM TZ: {7}]")
@Parameterized.Parameters(name = "{1}-{2}-{3}T{4}:{5}:{6}.{7}Z {0}")
public static List<Object[]> data() {
DIALECT = determineDialect();
return Arrays.asList(
return new ParametersBuilder()
// Not affected by HHH-13266 (JDK-8061577)
data( 2017, 11, 6, 19, 19, 1, 0, ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 500, ZoneId.of( "Europe/Paris" ) ),
data( 1970, 1, 1, 0, 0, 0, 0, ZoneId.of( "GMT" ) ),
data( 1900, 1, 1, 0, 0, 0, 0, ZoneId.of( "GMT" ) ),
data( 1900, 1, 1, 0, 0, 0, 0, ZoneId.of( "Europe/Oslo" ) ),
data( 1900, 1, 1, 0, 0, 0, 0, ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 2, 0, 9, 21, 0, ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 1, 0, 0, 0, 0, ZoneId.of( "Europe/Amsterdam" ) ),
data( 1900, 1, 2, 0, 19, 32, 0, ZoneId.of( "Europe/Amsterdam" ) ),
.add( 2017, 11, 6, 19, 19, 1, 0, ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 500, ZONE_PARIS )
.add( 1970, 1, 1, 0, 0, 0, 0, ZONE_GMT )
.add( 1900, 1, 1, 0, 0, 0, 0, ZONE_GMT )
.add( 1900, 1, 1, 0, 0, 0, 0, ZONE_OSLO )
.add( 1900, 1, 1, 0, 0, 0, 0, ZONE_PARIS )
.add( 1900, 1, 2, 0, 9, 21, 0, ZONE_PARIS )
.add( 1900, 1, 1, 0, 0, 0, 0, ZONE_AMSTERDAM )
.add( 1900, 1, 2, 0, 19, 32, 0, ZONE_AMSTERDAM )
// Affected by HHH-13266 (JDK-8061577)
data( 1892, 1, 1, 0, 0, 0, 0, ZoneId.of( "Europe/Oslo" ) ),
data( 1899, 12, 31, 23, 59, 59, 999_999_999, ZoneId.of( "Europe/Paris" ) ),
data( 1899, 12, 31, 23, 59, 59, 999_999_999, ZoneId.of( "Europe/Amsterdam" ) ),
data( 1600, 1, 1, 0, 0, 0, 0, ZoneId.of( "Europe/Amsterdam" ) )
);
}
private static Object[] data(int year, int month, int day,
int hour, int minute, int second, int nanosecond, ZoneId defaultTimeZone) {
if ( DIALECT instanceof PostgreSQL81Dialect ) {
// PostgreSQL apparently doesn't support nanosecond precision correctly
nanosecond = 0;
}
return new Object[] { year, month, day, hour, minute, second, nanosecond, defaultTimeZone };
.add( 1892, 1, 1, 0, 0, 0, 0, ZONE_OSLO )
.add( 1899, 12, 31, 23, 59, 59, 999_999_999, ZONE_PARIS )
.add( 1899, 12, 31, 23, 59, 59, 999_999_999, ZONE_AMSTERDAM )
.add( 1600, 1, 1, 0, 0, 0, 0, ZONE_AMSTERDAM )
.build();
}
private final int year;
@ -100,10 +66,10 @@ public class InstantTest extends BaseCoreFunctionalTestCase {
private final int minute;
private final int second;
private final int nanosecond;
private final ZoneId defaultTimeZone;
public InstantTest(int year, int month, int day,
int hour, int minute, int second, int nanosecond, ZoneId defaultTimeZone) {
public InstantTest(EnvironmentParameters env, int year, int month, int day,
int hour, int minute, int second, int nanosecond) {
super( env );
this.year = year;
this.month = month;
this.day = day;
@ -111,15 +77,31 @@ public class InstantTest extends BaseCoreFunctionalTestCase {
this.minute = minute;
this.second = second;
this.nanosecond = nanosecond;
this.defaultTimeZone = defaultTimeZone;
}
private Instant getExpectedInstant() {
@Override
protected Class<EntityWithInstant> getEntityType() {
return EntityWithInstant.class;
}
@Override
protected EntityWithInstant createEntity(int id) {
return new EntityWithInstant( id, getExpectedPropertyValue() );
}
@Override
protected Instant getExpectedPropertyValue() {
return OffsetDateTime.of( year, month, day, hour, minute, second, nanosecond, ZoneOffset.UTC ).toInstant();
}
private Timestamp getExpectedTimestamp() {
LocalDateTime dateTimeInDefaultTimeZone = getExpectedInstant().atZone( ZoneId.systemDefault() )
@Override
protected Instant getActualPropertyValue(EntityWithInstant entity) {
return entity.value;
}
@Override
protected Object getExpectedJdbcValue() {
LocalDateTime dateTimeInDefaultTimeZone = getExpectedPropertyValue().atZone( ZoneId.systemDefault() )
.toLocalDateTime();
return new Timestamp(
dateTimeInDefaultTimeZone.getYear() - 1900, dateTimeInDefaultTimeZone.getMonthValue() - 1,
@ -131,104 +113,18 @@ public class InstantTest extends BaseCoreFunctionalTestCase {
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { EntityWithInstant.class };
protected Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws SQLException {
return resultSet.getTimestamp( columnIndex );
}
@Before
public void cleanup() {
inTransaction( session -> {
session.createNativeQuery( "DELETE FROM theentity" ).executeUpdate();
} );
}
@Test
@TestForIssue(jiraKey = "HHH-13266")
public void writeThenRead() {
withDefaultTimeZone( defaultTimeZone, () -> {
inTransaction( session -> {
session.persist( new EntityWithInstant( 1, getExpectedInstant() ) );
} );
inTransaction( session -> {
Instant read = session.find( EntityWithInstant.class, 1 ).value;
assertEquals(
"Writing then reading a value should return the original value",
getExpectedInstant(), read
);
} );
} );
}
@Test
@TestForIssue(jiraKey = "HHH-13266")
public void writeThenNativeRead() {
withDefaultTimeZone( defaultTimeZone, () -> {
inTransaction( session -> {
session.persist( new EntityWithInstant( 1, getExpectedInstant() ) );
} );
inTransaction( session -> {
session.doWork( connection -> {
final PreparedStatement statement = connection.prepareStatement(
"SELECT thevalue FROM theentity WHERE theid = ?"
);
statement.setInt( 1, 1 );
statement.execute();
final ResultSet resultSet = statement.getResultSet();
resultSet.next();
Timestamp nativeRead = resultSet.getTimestamp( 1 );
assertEquals(
"Raw values written in database should match the original value (same day, hour, ...)",
getExpectedTimestamp(),
nativeRead
);
} );
} );
} );
}
private static void withDefaultTimeZone(ZoneId zoneId, Runnable runnable) {
TimeZone timeZoneBefore = TimeZone.getDefault();
TimeZone.setDefault( TimeZone.getTimeZone( zoneId ) );
/*
* Run the code in a new thread, because some libraries (looking at you, h2 JDBC driver)
* cache data dependent on the default timezone in thread local variables,
* and we want this data to be reinitialized with the new default time zone.
*/
try {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit( runnable );
executor.shutdown();
future.get();
}
catch (InterruptedException e) {
throw new IllegalStateException( "Interrupted while testing", e );
}
catch (ExecutionException e) {
Throwable cause = e.getCause();
if ( cause instanceof RuntimeException ) {
throw (RuntimeException) cause;
}
else if ( cause instanceof Error ) {
throw (Error) cause;
}
else {
throw new IllegalStateException( "Unexpected exception while testing", cause );
}
}
finally {
TimeZone.setDefault( timeZoneBefore );
}
}
@Entity
@Table(name = "theentity")
private static final class EntityWithInstant {
@Entity(name = ENTITY_NAME)
static final class EntityWithInstant {
@Id
@Column(name = "theid")
@Column(name = ID_COLUMN_NAME)
private Integer id;
@Basic
@Column(name = "thevalue")
@Column(name = PROPERTY_COLUMN_NAME)
private Instant value;
protected EntityWithInstant() {

View File

@ -7,186 +7,99 @@
package org.hibernate.test.type;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.testing.junit4.CustomParameterized;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import static org.junit.Assert.assertEquals;
/**
* Tests for storage of LocalDate properties.
*/
@RunWith(CustomParameterized.class)
@TestForIssue(jiraKey = "HHH-10371")
public class LocalDateTest extends BaseCoreFunctionalTestCase {
public class LocalDateTest extends AbstractJavaTimeTypeTest<LocalDate, LocalDateTest.EntityWithLocalDate> {
/*
* The default timezone affects conversions done using java.util,
* which is why we take it into account even when testing LocalDateTime.
*/
@Parameterized.Parameters(name = "{0}-{1}-{2} [JVM TZ: {3}]")
public static List<Object[]> data() {
return Arrays.asList(
// Not affected by HHH-13266 (JDK-8061577)
data( 2017, 11, 6, ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, ZoneId.of( "Europe/Paris" ) ),
data( 1970, 1, 1, ZoneId.of( "GMT" ) ),
data( 1900, 1, 1, ZoneId.of( "GMT" ) ),
data( 1900, 1, 1, ZoneId.of( "Europe/Oslo" ) ),
data( 1900, 1, 2, ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 2, ZoneId.of( "Europe/Amsterdam" ) ),
// Could have been affected by HHH-13266 (JDK-8061577), but was not
data( 1892, 1, 1, ZoneId.of( "Europe/Oslo" ) ),
data( 1900, 1, 1, ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 1, ZoneId.of( "Europe/Amsterdam" ) ),
data( 1600, 1, 1, ZoneId.of( "Europe/Amsterdam" ) )
);
private static class ParametersBuilder extends AbstractParametersBuilder<ParametersBuilder> {
public ParametersBuilder add(int year, int month, int day, ZoneId defaultTimeZone) {
return add( defaultTimeZone, year, month, day );
}
}
private static Object[] data(int year, int month, int day, ZoneId defaultTimeZone) {
return new Object[] { year, month, day, defaultTimeZone };
@Parameterized.Parameters(name = "{1}-{2}-{3} {0}")
public static List<Object[]> data() {
return new ParametersBuilder()
// Not affected by HHH-13266 (JDK-8061577)
.add( 2017, 11, 6, ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, ZONE_PARIS )
.add( 1970, 1, 1, ZONE_GMT )
.add( 1900, 1, 1, ZONE_GMT )
.add( 1900, 1, 1, ZONE_OSLO )
.add( 1900, 1, 2, ZONE_PARIS )
.add( 1900, 1, 2, ZONE_AMSTERDAM )
// Could have been affected by HHH-13266 (JDK-8061577), but was not
.add( 1892, 1, 1, ZONE_OSLO )
.add( 1900, 1, 1, ZONE_PARIS )
.add( 1900, 1, 1, ZONE_AMSTERDAM )
.add( 1600, 1, 1, ZONE_AMSTERDAM )
.build();
}
private final int year;
private final int month;
private final int day;
private final ZoneId defaultTimeZone;
public LocalDateTest(int year, int month, int day, ZoneId defaultTimeZone) {
public LocalDateTest(EnvironmentParameters env, int year, int month, int day) {
super( env );
this.year = year;
this.month = month;
this.day = day;
this.defaultTimeZone = defaultTimeZone;
}
private LocalDate getExpectedLocalDate() {
@Override
protected Class<EntityWithLocalDate> getEntityType() {
return EntityWithLocalDate.class;
}
@Override
protected EntityWithLocalDate createEntity(int id) {
return new EntityWithLocalDate( id, getExpectedPropertyValue() );
}
@Override
protected LocalDate getExpectedPropertyValue() {
return LocalDate.of( year, month, day );
}
private Date getExpectedSqlDate() {
@Override
protected LocalDate getActualPropertyValue(EntityWithLocalDate entity) {
return entity.value;
}
@Override
protected Object getExpectedJdbcValue() {
return new Date( year - 1900, month - 1, day );
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { EntityWithLocalDate.class };
protected Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws SQLException {
return resultSet.getDate( columnIndex );
}
@Before
public void cleanup() {
inTransaction( session -> {
session.createNativeQuery( "DELETE FROM theentity" ).executeUpdate();
} );
}
@Test
@TestForIssue(jiraKey = "HHH-13266")
public void writeThenRead() {
withDefaultTimeZone( defaultTimeZone, () -> {
inTransaction( session -> {
session.persist( new EntityWithLocalDate( 1, getExpectedLocalDate() ) );
} );
inTransaction( session -> {
LocalDate read = session.find( EntityWithLocalDate.class, 1 ).value;
assertEquals(
"Writing then reading a value should return the original value",
getExpectedLocalDate(), read
);
} );
} );
}
@Test
@TestForIssue(jiraKey = "HHH-13266")
public void writeThenNativeRead() {
withDefaultTimeZone( defaultTimeZone, () -> {
inTransaction( session -> {
session.persist( new EntityWithLocalDate( 1, getExpectedLocalDate() ) );
} );
inTransaction( session -> {
session.doWork( connection -> {
final PreparedStatement statement = connection.prepareStatement(
"SELECT thevalue FROM theentity WHERE theid = ?"
);
statement.setInt( 1, 1 );
statement.execute();
final ResultSet resultSet = statement.getResultSet();
resultSet.next();
Date nativeRead = resultSet.getDate( 1 );
assertEquals(
"Raw values written in database should match the original value (same day, hour, ...)",
getExpectedSqlDate(),
nativeRead
);
} );
} );
} );
}
private static void withDefaultTimeZone(ZoneId zoneId, Runnable runnable) {
TimeZone timeZoneBefore = TimeZone.getDefault();
TimeZone.setDefault( TimeZone.getTimeZone( zoneId ) );
/*
* Run the code in a new thread, because some libraries (looking at you, h2 JDBC driver)
* cache data dependent on the default timezone in thread local variables,
* and we want this data to be reinitialized with the new default time zone.
*/
try {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit( runnable );
executor.shutdown();
future.get();
}
catch (InterruptedException e) {
throw new IllegalStateException( "Interrupted while testing", e );
}
catch (ExecutionException e) {
Throwable cause = e.getCause();
if ( cause instanceof RuntimeException ) {
throw (RuntimeException) cause;
}
else if ( cause instanceof Error ) {
throw (Error) cause;
}
else {
throw new IllegalStateException( "Unexpected exception while testing", cause );
}
}
finally {
TimeZone.setDefault( timeZoneBefore );
}
}
@Entity
@Table(name = "theentity")
private static final class EntityWithLocalDate {
@Entity(name = ENTITY_NAME)
static final class EntityWithLocalDate {
@Id
@Column(name = "theid")
@Column(name = ID_COLUMN_NAME)
private Integer id;
@Basic
@Column(name = "thevalue")
@Column(name = PROPERTY_COLUMN_NAME)
private LocalDate value;
protected EntityWithLocalDate() {

View File

@ -6,86 +6,52 @@
*/
package org.hibernate.test.type;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.hibernate.testing.junit4.CustomParameterized;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import static org.junit.Assert.assertEquals;
/**
* Tests for storage of LocalDateTime properties.
*/
@RunWith(CustomParameterized.class)
public class LocalDateTimeTest extends BaseCoreFunctionalTestCase {
public class LocalDateTimeTest extends AbstractJavaTimeTypeTest<LocalDateTime, LocalDateTimeTest.EntityWithLocalDateTime> {
private static Dialect DIALECT;
private static Dialect determineDialect() {
try {
return Dialect.getDialect();
}
catch (Exception e) {
return new Dialect() {
};
private static class ParametersBuilder extends AbstractParametersBuilder<ParametersBuilder> {
public ParametersBuilder add(int year, int month, int day,
int hour, int minute, int second, int nanosecond, ZoneId defaultTimeZone) {
if ( !isNanosecondPrecisionSupported() ) {
nanosecond = 0;
}
return add( defaultTimeZone, year, month, day, hour, minute, second, nanosecond );
}
}
/*
* The default timezone affects conversions done using java.util,
* which is why we take it into account even when testing LocalDateTime.
*/
@Parameterized.Parameters(name = "{0}-{1}-{2}T{3}:{4}:{5}.{6} [JVM TZ: {7}]")
@Parameterized.Parameters(name = "{1}-{2}-{3}T{4}:{5}:{6}.{7} {0}")
public static List<Object[]> data() {
DIALECT = determineDialect();
return Arrays.asList(
return new ParametersBuilder()
// Not affected by HHH-13266 (JDK-8061577)
data( 2017, 11, 6, 19, 19, 1, 0, ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 500, ZoneId.of( "Europe/Paris" ) ),
data( 1970, 1, 1, 0, 0, 0, 0, ZoneId.of( "GMT" ) ),
data( 1900, 1, 1, 0, 0, 0, 0, ZoneId.of( "GMT" ) ),
data( 1900, 1, 1, 0, 0, 0, 0, ZoneId.of( "Europe/Oslo" ) ),
data( 1900, 1, 2, 0, 9, 21, 0, ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 2, 0, 19, 32, 0, ZoneId.of( "Europe/Amsterdam" ) ),
.add( 2017, 11, 6, 19, 19, 1, 0, ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 500, ZONE_PARIS )
.add( 1970, 1, 1, 0, 0, 0, 0, ZONE_GMT )
.add( 1900, 1, 1, 0, 0, 0, 0, ZONE_GMT )
.add( 1900, 1, 1, 0, 0, 0, 0, ZONE_OSLO )
.add( 1900, 1, 2, 0, 9, 21, 0, ZONE_PARIS )
.add( 1900, 1, 2, 0, 19, 32, 0, ZONE_AMSTERDAM )
// Affected by HHH-13266 (JDK-8061577)
data( 1892, 1, 1, 0, 0, 0, 0, ZoneId.of( "Europe/Oslo" ) ),
data( 1900, 1, 1, 0, 9, 20, 0, ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 1, 0, 19, 31, 0, ZoneId.of( "Europe/Amsterdam" ) ),
data( 1600, 1, 1, 0, 0, 0, 0, ZoneId.of( "Europe/Amsterdam" ) )
);
}
private static Object[] data(int year, int month, int day,
int hour, int minute, int second, int nanosecond, ZoneId defaultTimeZone) {
if ( DIALECT instanceof PostgreSQL81Dialect ) {
// PostgreSQL apparently doesn't support nanosecond precision correctly
nanosecond = 0;
}
return new Object[] { year, month, day, hour, minute, second, nanosecond, defaultTimeZone };
.add( 1892, 1, 1, 0, 0, 0, 0, ZONE_OSLO )
.add( 1900, 1, 1, 0, 9, 20, 0, ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 31, 0, ZONE_AMSTERDAM )
.add( 1600, 1, 1, 0, 0, 0, 0, ZONE_AMSTERDAM )
.build();
}
private final int year;
@ -95,10 +61,10 @@ public class LocalDateTimeTest extends BaseCoreFunctionalTestCase {
private final int minute;
private final int second;
private final int nanosecond;
private final ZoneId defaultTimeZone;
public LocalDateTimeTest(int year, int month, int day,
int hour, int minute, int second, int nanosecond, ZoneId defaultTimeZone) {
public LocalDateTimeTest(EnvironmentParameters env, int year, int month, int day,
int hour, int minute, int second, int nanosecond) {
super( env );
this.year = year;
this.month = month;
this.day = day;
@ -106,14 +72,30 @@ public class LocalDateTimeTest extends BaseCoreFunctionalTestCase {
this.minute = minute;
this.second = second;
this.nanosecond = nanosecond;
this.defaultTimeZone = defaultTimeZone;
}
private LocalDateTime getExpectedLocalDateTime() {
@Override
protected Class<EntityWithLocalDateTime> getEntityType() {
return EntityWithLocalDateTime.class;
}
@Override
protected EntityWithLocalDateTime createEntity(int id) {
return new EntityWithLocalDateTime( id, getExpectedPropertyValue() );
}
@Override
protected LocalDateTime getExpectedPropertyValue() {
return LocalDateTime.of( year, month, day, hour, minute, second, nanosecond );
}
private Timestamp getExpectedTimestamp() {
@Override
protected LocalDateTime getActualPropertyValue(EntityWithLocalDateTime entity) {
return entity.value;
}
@Override
protected Object getExpectedJdbcValue() {
return new Timestamp(
year - 1900, month - 1, day,
hour, minute, second, nanosecond
@ -121,104 +103,18 @@ public class LocalDateTimeTest extends BaseCoreFunctionalTestCase {
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { EntityWithLocalDateTime.class };
protected Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws SQLException {
return resultSet.getTimestamp( columnIndex );
}
@Before
public void cleanup() {
inTransaction( session -> {
session.createNativeQuery( "DELETE FROM theentity" ).executeUpdate();
} );
}
@Test
@TestForIssue(jiraKey = "HHH-13266")
public void writeThenRead() {
withDefaultTimeZone( defaultTimeZone, () -> {
inTransaction( session -> {
session.persist( new EntityWithLocalDateTime( 1, getExpectedLocalDateTime() ) );
} );
inTransaction( session -> {
LocalDateTime read = session.find( EntityWithLocalDateTime.class, 1 ).value;
assertEquals(
"Writing then reading a value should return the original value",
getExpectedLocalDateTime(), read
);
} );
} );
}
@Test
@TestForIssue(jiraKey = "HHH-13266")
public void writeThenNativeRead() {
withDefaultTimeZone( defaultTimeZone, () -> {
inTransaction( session -> {
session.persist( new EntityWithLocalDateTime( 1, getExpectedLocalDateTime() ) );
} );
inTransaction( session -> {
session.doWork( connection -> {
final PreparedStatement statement = connection.prepareStatement(
"SELECT thevalue FROM theentity WHERE theid = ?"
);
statement.setInt( 1, 1 );
statement.execute();
final ResultSet resultSet = statement.getResultSet();
resultSet.next();
Timestamp nativeRead = resultSet.getTimestamp( 1 );
assertEquals(
"Raw values written in database should match the original value (same day, hour, ...)",
getExpectedTimestamp(),
nativeRead
);
} );
} );
} );
}
private static void withDefaultTimeZone(ZoneId zoneId, Runnable runnable) {
TimeZone timeZoneBefore = TimeZone.getDefault();
TimeZone.setDefault( TimeZone.getTimeZone( zoneId ) );
/*
* Run the code in a new thread, because some libraries (looking at you, h2 JDBC driver)
* cache data dependent on the default timezone in thread local variables,
* and we want this data to be reinitialized with the new default time zone.
*/
try {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit( runnable );
executor.shutdown();
future.get();
}
catch (InterruptedException e) {
throw new IllegalStateException( "Interrupted while testing", e );
}
catch (ExecutionException e) {
Throwable cause = e.getCause();
if ( cause instanceof RuntimeException ) {
throw (RuntimeException) cause;
}
else if ( cause instanceof Error ) {
throw (Error) cause;
}
else {
throw new IllegalStateException( "Unexpected exception while testing", cause );
}
}
finally {
TimeZone.setDefault( timeZoneBefore );
}
}
@Entity
@Table(name = "theentity")
private static final class EntityWithLocalDateTime {
@Entity(name = ENTITY_NAME)
static final class EntityWithLocalDateTime {
@Id
@Column(name = "theid")
@Column(name = ID_COLUMN_NAME)
private Integer id;
@Basic
@Column(name = "thevalue")
@Column(name = PROPERTY_COLUMN_NAME)
private LocalDateTime value;
protected EntityWithLocalDateTime() {

View File

@ -6,116 +6,84 @@
*/
package org.hibernate.test.type;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.function.Consumer;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.Query;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.type.OffsetDateTimeType;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.hibernate.testing.junit4.CustomParameterized;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
* @author Andrea Boriero
*/
@RunWith(CustomParameterized.class)
@TestForIssue(jiraKey = "HHH-10372")
public class OffsetDateTimeTest extends BaseNonConfigCoreFunctionalTestCase {
public class OffsetDateTimeTest extends AbstractJavaTimeTypeTest<OffsetDateTime, OffsetDateTimeTest.EntityWithOffsetDateTime> {
private static Dialect DIALECT;
private static Dialect determineDialect() {
try {
return Dialect.getDialect();
}
catch (Exception e) {
return new Dialect() {
};
private static class ParametersBuilder extends AbstractParametersBuilder<ParametersBuilder> {
public ParametersBuilder add(int year, int month, int day,
int hour, int minute, int second, int nanosecond, String offset, ZoneId defaultTimeZone) {
if ( !isNanosecondPrecisionSupported() ) {
nanosecond = 0;
}
return add( defaultTimeZone, year, month, day, hour, minute, second, nanosecond, offset );
}
}
/*
* The default timezone affects conversions done using java.util,
* which is why we take it into account even when testing OffsetDateTime.
*/
@Parameterized.Parameters(name = "{0}-{1}-{2}T{3}:{4}:{5}.{6}[{7}] [JVM TZ: {8}]")
@Parameterized.Parameters(name = "{1}-{2}-{3}T{4}:{5}:{6}.{7}[{8}] {0}")
public static List<Object[]> data() {
DIALECT = determineDialect();
return Arrays.asList(
return new ParametersBuilder()
// Not affected by HHH-13266
data( 2017, 11, 6, 19, 19, 1, 0, "+10:00", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "+07:00", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "+01:30", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "+01:00", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "+00:30", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "-02:00", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "-06:00", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "-08:00", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "+10:00", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "+07:00", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "+01:30", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 500, "+01:00", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "+01:00", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "+00:30", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "-02:00", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "-06:00", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "-08:00", ZoneId.of( "Europe/Paris" ) ),
data( 1970, 1, 1, 0, 0, 0, 0, "+01:00", ZoneId.of( "GMT" ) ),
data( 1970, 1, 1, 0, 0, 0, 0, "+00:00", ZoneId.of( "GMT" ) ),
data( 1970, 1, 1, 0, 0, 0, 0, "-01:00", ZoneId.of( "GMT" ) ),
data( 1900, 1, 1, 0, 0, 0, 0, "+01:00", ZoneId.of( "GMT" ) ),
data( 1900, 1, 1, 0, 0, 0, 0, "+00:00", ZoneId.of( "GMT" ) ),
data( 1900, 1, 1, 0, 0, 0, 0, "-01:00", ZoneId.of( "GMT" ) ),
data( 1900, 1, 1, 0, 0, 0, 0, "+00:00", ZoneId.of( "Europe/Oslo" ) ),
data( 1900, 1, 1, 0, 9, 21, 0, "+00:09:21", ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 1, 0, 19, 32, 0, "+00:19:32", ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 1, 0, 19, 32, 0, "+00:19:32", ZoneId.of( "Europe/Amsterdam" ) ),
.add( 2017, 11, 6, 19, 19, 1, 0, "+10:00", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "+07:00", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "+01:30", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "+01:00", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "+00:30", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "-02:00", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "-06:00", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "-08:00", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "+10:00", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "+07:00", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "+01:30", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 500, "+01:00", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "+01:00", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "+00:30", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "-02:00", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "-06:00", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "-08:00", ZONE_PARIS )
.add( 1970, 1, 1, 0, 0, 0, 0, "+01:00", ZONE_GMT )
.add( 1970, 1, 1, 0, 0, 0, 0, "+00:00", ZONE_GMT )
.add( 1970, 1, 1, 0, 0, 0, 0, "-01:00", ZONE_GMT )
.add( 1900, 1, 1, 0, 0, 0, 0, "+01:00", ZONE_GMT )
.add( 1900, 1, 1, 0, 0, 0, 0, "+00:00", ZONE_GMT )
.add( 1900, 1, 1, 0, 0, 0, 0, "-01:00", ZONE_GMT )
.add( 1900, 1, 1, 0, 0, 0, 0, "+00:00", ZONE_OSLO )
.add( 1900, 1, 1, 0, 9, 21, 0, "+00:09:21", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 32, 0, "+00:19:32", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 32, 0, "+00:19:32", ZONE_AMSTERDAM )
// Affected by HHH-13266
data( 1892, 1, 1, 0, 0, 0, 0, "+00:00", ZoneId.of( "Europe/Oslo" ) ),
data( 1900, 1, 1, 0, 9, 20, 0, "+00:09:21", ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 1, 0, 19, 31, 0, "+00:19:32", ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 1, 0, 19, 31, 0, "+00:19:32", ZoneId.of( "Europe/Amsterdam" ) ),
data( 1600, 1, 1, 0, 0, 0, 0, "+00:19:32", ZoneId.of( "Europe/Amsterdam" ) )
);
}
private static Object[] data(int year, int month, int day,
int hour, int minute, int second, int nanosecond, String offset, ZoneId defaultTimeZone) {
if ( DIALECT instanceof PostgreSQL81Dialect ) {
// PostgreSQL apparently doesn't support nanosecond precision correctly
nanosecond = 0;
}
return new Object[] { year, month, day, hour, minute, second, nanosecond, offset, defaultTimeZone };
.add( 1892, 1, 1, 0, 0, 0, 0, "+00:00", ZONE_OSLO )
.add( 1900, 1, 1, 0, 9, 20, 0, "+00:09:21", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 31, 0, "+00:19:32", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 31, 0, "+00:19:32", ZONE_AMSTERDAM )
.add( 1600, 1, 1, 0, 0, 0, 0, "+00:19:32", ZONE_AMSTERDAM )
.build();
}
private final int year;
@ -126,10 +94,10 @@ public class OffsetDateTimeTest extends BaseNonConfigCoreFunctionalTestCase {
private final int second;
private final int nanosecond;
private final String offset;
private final ZoneId defaultTimeZone;
public OffsetDateTimeTest(int year, int month, int day,
int hour, int minute, int second, int nanosecond, String offset, ZoneId defaultTimeZone) {
public OffsetDateTimeTest(EnvironmentParameters env, int year, int month, int day,
int hour, int minute, int second, int nanosecond, String offset) {
super( env );
this.year = year;
this.month = month;
this.day = day;
@ -138,18 +106,34 @@ public class OffsetDateTimeTest extends BaseNonConfigCoreFunctionalTestCase {
this.second = second;
this.nanosecond = nanosecond;
this.offset = offset;
this.defaultTimeZone = defaultTimeZone;
}
@Override
protected Class<EntityWithOffsetDateTime> getEntityType() {
return EntityWithOffsetDateTime.class;
}
@Override
protected EntityWithOffsetDateTime createEntity(int id) {
return new EntityWithOffsetDateTime( id, getOriginalOffsetDateTime() );
}
private OffsetDateTime getOriginalOffsetDateTime() {
return OffsetDateTime.of( year, month, day, hour, minute, second, nanosecond, ZoneOffset.of( offset ) );
}
private OffsetDateTime getExpectedOffsetDateTime() {
@Override
protected OffsetDateTime getExpectedPropertyValue() {
return getOriginalOffsetDateTime().atZoneSameInstant( ZoneId.systemDefault() ).toOffsetDateTime();
}
private Timestamp getExpectedTimestamp() {
@Override
protected OffsetDateTime getActualPropertyValue(EntityWithOffsetDateTime entity) {
return entity.value;
}
@Override
protected Object getExpectedJdbcValue() {
LocalDateTime dateTimeInDefaultTimeZone = getOriginalOffsetDateTime().atZoneSameInstant( ZoneId.systemDefault() )
.toLocalDateTime();
return new Timestamp(
@ -162,129 +146,36 @@ public class OffsetDateTimeTest extends BaseNonConfigCoreFunctionalTestCase {
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { EntityWithOffsetDateTime.class };
}
@Before
public void cleanup() {
inTransaction( session -> {
session.createNativeQuery( "DELETE FROM theentity" ).executeUpdate();
} );
}
@Test
@TestForIssue(jiraKey = "HHH-13266")
public void writeThenRead() {
withDefaultTimeZone( defaultTimeZone, () -> {
inTransaction( session -> {
session.persist( new EntityWithOffsetDateTime( 1, getOriginalOffsetDateTime() ) );
} );
inTransaction( session -> {
OffsetDateTime read = session.find( org.hibernate.test.type.OffsetDateTimeTest.EntityWithOffsetDateTime.class, 1 ).value;
assertEquals(
"Writing then reading a value should return the original value",
getExpectedOffsetDateTime(), read
);
assertTrue(
getExpectedOffsetDateTime().isEqual( read )
);
assertEquals(
0,
OffsetDateTimeType.INSTANCE.getComparator().compare( getExpectedOffsetDateTime(), read )
);
} );
} );
}
@Test
@TestForIssue(jiraKey = "HHH-13266")
public void writeThenNativeRead() {
withDefaultTimeZone( defaultTimeZone, () -> {
inTransaction( session -> {
session.persist( new EntityWithOffsetDateTime( 1, getOriginalOffsetDateTime() ) );
} );
inTransaction( session -> {
session.doWork( connection -> {
final PreparedStatement statement = connection.prepareStatement(
"SELECT thevalue FROM theentity WHERE theid = ?"
);
statement.setInt( 1, 1 );
statement.execute();
final ResultSet resultSet = statement.getResultSet();
resultSet.next();
Timestamp nativeRead = resultSet.getTimestamp( 1 );
assertEquals(
"Raw values written in database should match the original value (same instant)",
getExpectedTimestamp(),
nativeRead
);
} );
} );
} );
protected Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws SQLException {
return resultSet.getTimestamp( columnIndex );
}
@Test
public void testRetrievingEntityByOffsetDateTime() {
withDefaultTimeZone( defaultTimeZone, () -> {
withDefaultTimeZone( () -> {
inTransaction( session -> {
session.persist( new EntityWithOffsetDateTime( 1, getOriginalOffsetDateTime() ) );
} );
Consumer<OffsetDateTime> checkOneMatch = expected -> inSession( s -> {
Query query = s.createQuery( "from EntityWithOffsetDateTime o where o.value = :date" );
Query query = s.createQuery( "from " + ENTITY_NAME + " o where o.value = :date" );
query.setParameter( "date", expected, OffsetDateTimeType.INSTANCE );
List<EntityWithOffsetDateTime> list = query.list();
assertThat( list.size(), is( 1 ) );
} );
checkOneMatch.accept( getOriginalOffsetDateTime() );
checkOneMatch.accept( getExpectedOffsetDateTime() );
checkOneMatch.accept( getExpectedOffsetDateTime().withOffsetSameInstant( ZoneOffset.UTC ) );
checkOneMatch.accept( getExpectedPropertyValue() );
checkOneMatch.accept( getExpectedPropertyValue().withOffsetSameInstant( ZoneOffset.UTC ) );
} );
}
private static void withDefaultTimeZone(ZoneId zoneId, Runnable runnable) {
TimeZone timeZoneBefore = TimeZone.getDefault();
TimeZone.setDefault( TimeZone.getTimeZone( zoneId ) );
/*
* Run the code in a new thread, because some libraries (looking at you, h2 JDBC driver)
* cache data dependent on the default timezone in thread local variables,
* and we want this data to be reinitialized with the new default time zone.
*/
try {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit( runnable );
executor.shutdown();
future.get();
}
catch (InterruptedException e) {
throw new IllegalStateException( "Interrupted while testing", e );
}
catch (ExecutionException e) {
Throwable cause = e.getCause();
if ( cause instanceof RuntimeException ) {
throw (RuntimeException) cause;
}
else if ( cause instanceof Error ) {
throw (Error) cause;
}
else {
throw new IllegalStateException( "Unexpected exception while testing", cause );
}
}
finally {
TimeZone.setDefault( timeZoneBefore );
}
}
@Entity(name = "EntityWithOffsetDateTime")
@Table(name = "theentity")
private static final class EntityWithOffsetDateTime {
@Entity(name = ENTITY_NAME)
static final class EntityWithOffsetDateTime {
@Id
@Column(name = "theid")
@Column(name = ID_COLUMN_NAME)
private Integer id;
@Basic
@Column(name = "thevalue")
@Column(name = PROPERTY_COLUMN_NAME)
private OffsetDateTime value;
protected EntityWithOffsetDateTime() {
@ -295,9 +186,4 @@ public class OffsetDateTimeTest extends BaseNonConfigCoreFunctionalTestCase {
this.value = value;
}
}
@Override
protected boolean isCleanupTestDataRequired() {
return true;
}
}

View File

@ -6,127 +6,96 @@
*/
package org.hibernate.test.type;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.function.Consumer;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.Query;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.type.ZonedDateTimeType;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.hibernate.testing.junit4.CustomParameterized;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
* @author Andrea Boriero
*/
@RunWith(CustomParameterized.class)
@TestForIssue(jiraKey = "HHH-10372")
public class ZonedDateTimeTest extends BaseNonConfigCoreFunctionalTestCase {
public class ZonedDateTimeTest extends AbstractJavaTimeTypeTest<ZonedDateTime, ZonedDateTimeTest.EntityWithZonedDateTime> {
private static Dialect DIALECT;
private static Dialect determineDialect() {
try {
return Dialect.getDialect();
}
catch (Exception e) {
return new Dialect() {
};
private static class ParametersBuilder extends AbstractParametersBuilder<ParametersBuilder> {
public ParametersBuilder add(int year, int month, int day,
int hour, int minute, int second, int nanosecond, String zone, ZoneId defaultTimeZone) {
if ( !isNanosecondPrecisionSupported() ) {
nanosecond = 0;
}
return add( defaultTimeZone, year, month, day, hour, minute, second, nanosecond, zone );
}
}
/*
* The default timezone affects conversions done using java.util,
* which is why we take it into account even when testing ZonedDateTime.
*/
@Parameterized.Parameters(name = "{0}-{1}-{2}T{3}:{4}:{5}.{6}[{7}] [JVM TZ: {8}]")
@Parameterized.Parameters(name = "{1}-{2}-{3}T{4}:{5}:{6}.{7}[{8}] {0}")
public static List<Object[]> data() {
DIALECT = determineDialect();
return Arrays.asList(
return new ParametersBuilder()
// Not affected by HHH-13266
data( 2017, 11, 6, 19, 19, 1, 0, "GMT+10:00", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "GMT+07:00", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "GMT+01:30", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "GMT+01:00", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "Europe/Paris", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "Europe/London", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "GMT+00:30", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "GMT-02:00", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "GMT-06:00", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "GMT-08:00", ZoneId.of( "UTC-8" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "GMT+10:00", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "GMT+07:00", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "GMT+01:30", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "GMT+01:00", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 500, "GMT+01:00", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "Europe/Paris", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "Europe/London", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "GMT+00:30", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "GMT-02:00", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "GMT-06:00", ZoneId.of( "Europe/Paris" ) ),
data( 2017, 11, 6, 19, 19, 1, 0, "GMT-08:00", ZoneId.of( "Europe/Paris" ) ),
data( 1970, 1, 1, 0, 0, 0, 0, "GMT+01:00", ZoneId.of( "GMT" ) ),
data( 1970, 1, 1, 0, 0, 0, 0, "GMT+00:00", ZoneId.of( "GMT" ) ),
data( 1970, 1, 1, 0, 0, 0, 0, "GMT-01:00", ZoneId.of( "GMT" ) ),
data( 1900, 1, 1, 0, 0, 0, 0, "GMT+01:00", ZoneId.of( "GMT" ) ),
data( 1900, 1, 1, 0, 0, 0, 0, "GMT+00:00", ZoneId.of( "GMT" ) ),
data( 1900, 1, 1, 0, 0, 0, 0, "GMT-01:00", ZoneId.of( "GMT" ) ),
data( 1900, 1, 1, 0, 0, 0, 0, "GMT+00:00", ZoneId.of( "Europe/Oslo" ) ),
data( 1900, 1, 1, 0, 9, 21, 0, "GMT+00:09:21", ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 1, 0, 9, 21, 0, "Europe/Paris", ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 1, 0, 19, 31, 0, "Europe/Paris", ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 1, 0, 19, 32, 0, "GMT+00:19:32", ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 1, 0, 19, 32, 0, "Europe/Amsterdam", ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 1, 0, 19, 32, 0, "GMT+00:19:32", ZoneId.of( "Europe/Amsterdam" ) ),
data( 1900, 1, 1, 0, 19, 32, 0, "Europe/Amsterdam", ZoneId.of( "Europe/Amsterdam" ) ),
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT+10:00", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT+07:00", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT+01:30", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT+01:00", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "Europe/Paris", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "Europe/London", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT+00:30", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT-02:00", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT-06:00", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT-08:00", ZONE_UTC_MINUS_8 )
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT+10:00", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT+07:00", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT+01:30", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT+01:00", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 500, "GMT+01:00", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "Europe/Paris", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "Europe/London", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT+00:30", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT-02:00", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT-06:00", ZONE_PARIS )
.add( 2017, 11, 6, 19, 19, 1, 0, "GMT-08:00", ZONE_PARIS )
.add( 1970, 1, 1, 0, 0, 0, 0, "GMT+01:00", ZONE_GMT )
.add( 1970, 1, 1, 0, 0, 0, 0, "GMT+00:00", ZONE_GMT )
.add( 1970, 1, 1, 0, 0, 0, 0, "GMT-01:00", ZONE_GMT )
.add( 1900, 1, 1, 0, 0, 0, 0, "GMT+01:00", ZONE_GMT )
.add( 1900, 1, 1, 0, 0, 0, 0, "GMT+00:00", ZONE_GMT )
.add( 1900, 1, 1, 0, 0, 0, 0, "GMT-01:00", ZONE_GMT )
.add( 1900, 1, 1, 0, 0, 0, 0, "GMT+00:00", ZONE_OSLO )
.add( 1900, 1, 1, 0, 9, 21, 0, "GMT+00:09:21", ZONE_PARIS )
.add( 1900, 1, 1, 0, 9, 21, 0, "Europe/Paris", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 31, 0, "Europe/Paris", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 32, 0, "GMT+00:19:32", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 32, 0, "Europe/Amsterdam", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 32, 0, "GMT+00:19:32", ZONE_AMSTERDAM )
.add( 1900, 1, 1, 0, 19, 32, 0, "Europe/Amsterdam", ZONE_AMSTERDAM )
// Affected by HHH-13266
data( 1892, 1, 1, 0, 0, 0, 0, "GMT+00:00", ZoneId.of( "Europe/Oslo" ) ),
data( 1892, 1, 1, 0, 0, 0, 0, "Europe/Oslo", ZoneId.of( "Europe/Oslo" ) ),
data( 1900, 1, 1, 0, 9, 20, 0, "GMT+00:09:21", ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 1, 0, 9, 20, 0, "Europe/Paris", ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 1, 0, 19, 31, 0, "GMT+00:19:32", ZoneId.of( "Europe/Paris" ) ),
data( 1900, 1, 1, 0, 19, 31, 0, "GMT+00:19:32", ZoneId.of( "Europe/Amsterdam" ) ),
data( 1900, 1, 1, 0, 19, 31, 0, "Europe/Amsterdam", ZoneId.of( "Europe/Amsterdam" ) ),
data( 1600, 1, 1, 0, 0, 0, 0, "GMT+00:19:32", ZoneId.of( "Europe/Amsterdam" ) ),
data( 1600, 1, 1, 0, 0, 0, 0, "Europe/Amsterdam", ZoneId.of( "Europe/Amsterdam" ) )
);
}
private static Object[] data(int year, int month, int day,
int hour, int minute, int second, int nanosecond, String zone, ZoneId defaultTimeZone) {
if ( DIALECT instanceof PostgreSQL81Dialect ) {
// PostgreSQL apparently doesn't support nanosecond precision correctly
nanosecond = 0;
}
return new Object[] { year, month, day, hour, minute, second, nanosecond, zone, defaultTimeZone };
.add( 1892, 1, 1, 0, 0, 0, 0, "GMT+00:00", ZONE_OSLO )
.add( 1892, 1, 1, 0, 0, 0, 0, "Europe/Oslo", ZONE_OSLO )
.add( 1900, 1, 1, 0, 9, 20, 0, "GMT+00:09:21", ZONE_PARIS )
.add( 1900, 1, 1, 0, 9, 20, 0, "Europe/Paris", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 31, 0, "GMT+00:19:32", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 31, 0, "GMT+00:19:32", ZONE_AMSTERDAM )
.add( 1900, 1, 1, 0, 19, 31, 0, "Europe/Amsterdam", ZONE_AMSTERDAM )
.add( 1600, 1, 1, 0, 0, 0, 0, "GMT+00:19:32", ZONE_AMSTERDAM )
.add( 1600, 1, 1, 0, 0, 0, 0, "Europe/Amsterdam", ZONE_AMSTERDAM )
.build();
}
private final int year;
@ -137,10 +106,10 @@ public class ZonedDateTimeTest extends BaseNonConfigCoreFunctionalTestCase {
private final int second;
private final int nanosecond;
private final String zone;
private final ZoneId defaultTimeZone;
public ZonedDateTimeTest(int year, int month, int day,
int hour, int minute, int second, int nanosecond, String zone, ZoneId defaultTimeZone) {
public ZonedDateTimeTest(EnvironmentParameters env, int year, int month, int day,
int hour, int minute, int second, int nanosecond, String zone) {
super( env );
this.year = year;
this.month = month;
this.day = day;
@ -149,18 +118,37 @@ public class ZonedDateTimeTest extends BaseNonConfigCoreFunctionalTestCase {
this.second = second;
this.nanosecond = nanosecond;
this.zone = zone;
this.defaultTimeZone = defaultTimeZone;
}
@Override
protected Class<EntityWithZonedDateTime> getEntityType() {
return EntityWithZonedDateTime.class;
}
@Override
protected EntityWithZonedDateTime createEntity(int id) {
return new EntityWithZonedDateTime(
id,
getOriginalZonedDateTime()
);
}
private ZonedDateTime getOriginalZonedDateTime() {
return ZonedDateTime.of( year, month, day, hour, minute, second, nanosecond, ZoneId.of( zone ) );
}
private ZonedDateTime getExpectedZonedDateTime() {
@Override
protected ZonedDateTime getExpectedPropertyValue() {
return getOriginalZonedDateTime().withZoneSameInstant( ZoneId.systemDefault() );
}
private Timestamp getExpectedTimestamp() {
@Override
protected ZonedDateTime getActualPropertyValue(EntityWithZonedDateTime entity) {
return entity.value;
}
@Override
protected Object getExpectedJdbcValue() {
LocalDateTime dateTimeInDefaultTimeZone = getOriginalZonedDateTime().withZoneSameInstant( ZoneId.systemDefault() )
.toLocalDateTime();
return new Timestamp(
@ -173,129 +161,36 @@ public class ZonedDateTimeTest extends BaseNonConfigCoreFunctionalTestCase {
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { EntityWithZonedDateTime.class };
}
@Before
public void cleanup() {
inTransaction( session -> {
session.createNativeQuery( "DELETE FROM theentity" ).executeUpdate();
} );
}
@Test
@TestForIssue(jiraKey = "HHH-13266")
public void writeThenRead() {
withDefaultTimeZone( defaultTimeZone, () -> {
inTransaction( session -> {
session.persist( new EntityWithZonedDateTime( 1, getOriginalZonedDateTime() ) );
} );
inTransaction( session -> {
ZonedDateTime read = session.find( ZonedDateTimeTest.EntityWithZonedDateTime.class, 1 ).value;
assertEquals(
"Writing then reading a value should return the original value",
getExpectedZonedDateTime(), read
);
assertTrue(
getExpectedZonedDateTime().isEqual( read )
);
assertEquals(
0,
ZonedDateTimeType.INSTANCE.getComparator().compare( getExpectedZonedDateTime(), read )
);
} );
} );
}
@Test
@TestForIssue(jiraKey = "HHH-13266")
public void writeThenNativeRead() {
withDefaultTimeZone( defaultTimeZone, () -> {
inTransaction( session -> {
session.persist( new EntityWithZonedDateTime( 1, getOriginalZonedDateTime() ) );
} );
inTransaction( session -> {
session.doWork( connection -> {
final PreparedStatement statement = connection.prepareStatement(
"SELECT thevalue FROM theentity WHERE theid = ?"
);
statement.setInt( 1, 1 );
statement.execute();
final ResultSet resultSet = statement.getResultSet();
resultSet.next();
Timestamp nativeRead = resultSet.getTimestamp( 1 );
assertEquals(
"Raw values written in database should match the original value (same instant)",
getExpectedTimestamp(),
nativeRead
);
} );
} );
} );
protected Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws SQLException {
return resultSet.getTimestamp( columnIndex );
}
@Test
public void testRetrievingEntityByZonedDateTime() {
withDefaultTimeZone( defaultTimeZone, () -> {
withDefaultTimeZone( () -> {
inTransaction( session -> {
session.persist( new EntityWithZonedDateTime( 1, getOriginalZonedDateTime() ) );
} );
Consumer<ZonedDateTime> checkOneMatch = expected -> inSession( s -> {
Query query = s.createQuery( "from EntityWithZonedDateTime o where o.value = :date" );
Query query = s.createQuery( "from " + ENTITY_NAME + " o where o.value = :date" );
query.setParameter( "date", expected, ZonedDateTimeType.INSTANCE );
List<EntityWithZonedDateTime> list = query.list();
assertThat( list.size(), is( 1 ) );
} );
checkOneMatch.accept( getOriginalZonedDateTime() );
checkOneMatch.accept( getExpectedZonedDateTime() );
checkOneMatch.accept( getExpectedZonedDateTime().withZoneSameInstant( ZoneOffset.UTC ) );
checkOneMatch.accept( getExpectedPropertyValue() );
checkOneMatch.accept( getExpectedPropertyValue().withZoneSameInstant( ZoneOffset.UTC ) );
} );
}
private static void withDefaultTimeZone(ZoneId zoneId, Runnable runnable) {
TimeZone timeZoneBefore = TimeZone.getDefault();
TimeZone.setDefault( TimeZone.getTimeZone( zoneId ) );
/*
* Run the code in a new thread, because some libraries (looking at you, h2 JDBC driver)
* cache data dependent on the default timezone in thread local variables,
* and we want this data to be reinitialized with the new default time zone.
*/
try {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit( runnable );
executor.shutdown();
future.get();
}
catch (InterruptedException e) {
throw new IllegalStateException( "Interrupted while testing", e );
}
catch (ExecutionException e) {
Throwable cause = e.getCause();
if ( cause instanceof RuntimeException ) {
throw (RuntimeException) cause;
}
else if ( cause instanceof Error ) {
throw (Error) cause;
}
else {
throw new IllegalStateException( "Unexpected exception while testing", cause );
}
}
finally {
TimeZone.setDefault( timeZoneBefore );
}
}
@Entity(name = "EntityWithZonedDateTime")
@Table(name = "theentity")
private static final class EntityWithZonedDateTime {
@Entity(name = ENTITY_NAME)
static final class EntityWithZonedDateTime {
@Id
@Column(name = "theid")
@Column(name = ID_COLUMN_NAME)
private Integer id;
@Basic
@Column(name = "thevalue")
@Column(name = PROPERTY_COLUMN_NAME)
private ZonedDateTime value;
protected EntityWithZonedDateTime() {
@ -306,9 +201,4 @@ public class ZonedDateTimeTest extends BaseNonConfigCoreFunctionalTestCase {
this.value = value;
}
}
@Override
protected boolean isCleanupTestDataRequired() {
return true;
}
}