HHH-10399 - Add support for specifying TimeZone for ZonedDateTime type
This commit is contained in:
parent
d229534647
commit
553942d2f9
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
||||
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||
|
@ -174,4 +175,5 @@ public interface SessionBuilder<T extends SessionBuilder> {
|
|||
*/
|
||||
T clearEventListeners();
|
||||
|
||||
T jdbcTimeZone(TimeZone timeZone);
|
||||
}
|
||||
|
|
|
@ -6,12 +6,14 @@
|
|||
*/
|
||||
package org.hibernate.boot.internal;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.ConnectionAcquisitionMode;
|
||||
import org.hibernate.ConnectionReleaseMode;
|
||||
|
@ -77,6 +79,7 @@ import static org.hibernate.cfg.AvailableSettings.FLUSH_BEFORE_COMPLETION;
|
|||
import static org.hibernate.cfg.AvailableSettings.GENERATE_STATISTICS;
|
||||
import static org.hibernate.cfg.AvailableSettings.HQL_BULK_ID_STRATEGY;
|
||||
import static org.hibernate.cfg.AvailableSettings.INTERCEPTOR;
|
||||
import static org.hibernate.cfg.AvailableSettings.JDBC_TIME_ZONE;
|
||||
import static org.hibernate.cfg.AvailableSettings.JPAQL_STRICT_COMPLIANCE;
|
||||
import static org.hibernate.cfg.AvailableSettings.JTA_TRACK_BY_THREAD;
|
||||
import static org.hibernate.cfg.AvailableSettings.LOG_SESSION_METRICS;
|
||||
|
@ -591,6 +594,7 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
private boolean commentsEnabled;
|
||||
private PhysicalConnectionHandlingMode connectionHandlingMode;
|
||||
private boolean wrapResultSetsEnabled;
|
||||
private TimeZone jdbcTimeZone;
|
||||
|
||||
private Map<String, SQLFunction> sqlFunctions;
|
||||
|
||||
|
@ -767,6 +771,22 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
configurationSettings,
|
||||
false
|
||||
);
|
||||
Object jdbcTimeZoneValue = configurationSettings.get(
|
||||
JDBC_TIME_ZONE
|
||||
);
|
||||
|
||||
if ( jdbcTimeZoneValue instanceof TimeZone ) {
|
||||
this.jdbcTimeZone = (TimeZone) jdbcTimeZoneValue;
|
||||
}
|
||||
else if ( jdbcTimeZoneValue instanceof ZoneId ) {
|
||||
this.jdbcTimeZone = TimeZone.getTimeZone( (ZoneId) jdbcTimeZoneValue );
|
||||
}
|
||||
else if ( jdbcTimeZoneValue instanceof String ) {
|
||||
this.jdbcTimeZone = TimeZone.getTimeZone( ZoneId.of((String) jdbcTimeZoneValue) );
|
||||
}
|
||||
else if ( jdbcTimeZoneValue != null ) {
|
||||
throw new IllegalArgumentException( "Configuration property " + JDBC_TIME_ZONE + " value [" + jdbcTimeZoneValue + "] is not supported!" );
|
||||
}
|
||||
}
|
||||
|
||||
private static Interceptor determineInterceptor(Map configurationSettings, StrategySelector strategySelector) {
|
||||
|
@ -1180,6 +1200,11 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
public boolean isPreferUserTransaction() {
|
||||
return this.preferUserTransaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZone getJdbcTimeZone() {
|
||||
return this.jdbcTimeZone;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1480,4 +1505,9 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
public boolean isPreferUserTransaction() {
|
||||
return options.isPreferUserTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZone getJdbcTimeZone() {
|
||||
return options.getJdbcTimeZone();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.boot.internal;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.ConnectionReleaseMode;
|
||||
import org.hibernate.CustomEntityDirtinessStrategy;
|
||||
|
@ -118,6 +119,7 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
private final boolean commentsEnabled;
|
||||
private final PhysicalConnectionHandlingMode physicalConnectionHandlingMode;
|
||||
private final boolean wrapResultSetsEnabled;
|
||||
private final TimeZone jdbcTimeZone;
|
||||
|
||||
private final Map<String, SQLFunction> sqlFunctions;
|
||||
|
||||
|
@ -191,6 +193,8 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
this.commentsEnabled = state.isCommentsEnabled();
|
||||
|
||||
this.sqlFunctions = state.getCustomSqlFunctionMap();
|
||||
|
||||
this.jdbcTimeZone = state.getJdbcTimeZone();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -496,4 +500,9 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
public boolean isPreferUserTransaction() {
|
||||
return preferUserTransaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZone getJdbcTimeZone() {
|
||||
return jdbcTimeZone;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.boot.internal;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.ConnectionReleaseMode;
|
||||
import org.hibernate.CustomEntityDirtinessStrategy;
|
||||
|
@ -165,4 +166,6 @@ public interface SessionFactoryOptionsState {
|
|||
Map<String, SQLFunction> getCustomSqlFunctionMap();
|
||||
|
||||
boolean isPreferUserTransaction();
|
||||
|
||||
TimeZone getJdbcTimeZone();
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.boot.spi;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.ConnectionReleaseMode;
|
||||
import org.hibernate.CustomEntityDirtinessStrategy;
|
||||
|
@ -348,4 +349,9 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
|
|||
public Class<? extends Interceptor> getStatelessInterceptorImplementor() {
|
||||
return delegate.getStatelessInterceptorImplementor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZone getJdbcTimeZone() {
|
||||
return delegate.getJdbcTimeZone();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.boot.spi;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.ConnectionReleaseMode;
|
||||
import org.hibernate.CustomEntityDirtinessStrategy;
|
||||
|
@ -19,7 +20,6 @@ import org.hibernate.SessionFactoryObserver;
|
|||
import org.hibernate.boot.SchemaAutoTooling;
|
||||
import org.hibernate.boot.TempTableDdlTransactionHandling;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.cache.spi.CacheKeysFactory;
|
||||
import org.hibernate.cache.spi.QueryCacheFactory;
|
||||
import org.hibernate.cfg.BaselineSessionEventsListenerBuilder;
|
||||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
|
@ -205,4 +205,6 @@ public interface SessionFactoryOptions {
|
|||
boolean isAllowOutOfTransactionUpdateOperations();
|
||||
|
||||
boolean isReleaseResourcesOnCloseEnabled();
|
||||
|
||||
TimeZone getJdbcTimeZone();
|
||||
}
|
||||
|
|
|
@ -710,6 +710,11 @@ public interface AvailableSettings {
|
|||
*/
|
||||
String BATCH_VERSIONED_DATA = "hibernate.jdbc.batch_versioned_data";
|
||||
|
||||
/**
|
||||
* Default JDBC TimeZone.
|
||||
*/
|
||||
String JDBC_TIME_ZONE = "hibernate.jdbc.time_zone";
|
||||
|
||||
/**
|
||||
* Enable automatic session close at end of transaction
|
||||
*/
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.engine.spi;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.ConnectionReleaseMode;
|
||||
import org.hibernate.Interceptor;
|
||||
|
@ -99,4 +100,10 @@ public abstract class AbstractDelegatingSessionBuilder implements SessionBuilder
|
|||
delegate.clearEventListeners();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionBuilder jdbcTimeZone(TimeZone timeZone) {
|
||||
delegate.jdbcTimeZone(timeZone);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.EntityGraph;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
|
@ -1166,4 +1167,9 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
|
|||
public void setJdbcBatchSize(Integer jdbcBatchSize) {
|
||||
delegate.setJdbcBatchSize( jdbcBatchSize );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZone getJdbcTimeZone() {
|
||||
return delegate.getJdbcTimeZone();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.io.ObjectOutputStream;
|
|||
import java.io.Serializable;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.FlushModeType;
|
||||
import javax.persistence.Tuple;
|
||||
|
@ -109,6 +110,8 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
private final boolean isTransactionCoordinatorShared;
|
||||
private final Interceptor interceptor;
|
||||
|
||||
private final TimeZone jdbcTimeZone;
|
||||
|
||||
private FlushMode flushMode;
|
||||
private boolean autoJoinTransactions;
|
||||
|
||||
|
@ -152,6 +155,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
}
|
||||
|
||||
this.interceptor = interpret( options.getInterceptor() );
|
||||
this.jdbcTimeZone = options.getJdbcTimeZone();
|
||||
|
||||
final StatementInspector statementInspector = interpret( options.getStatementInspector() );
|
||||
this.jdbcSessionContext = new JdbcSessionContextImpl( this, statementInspector );
|
||||
|
@ -487,6 +491,11 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
return remapped == null ? sqlTypeDescriptor : remapped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZone getJdbcTimeZone() {
|
||||
return jdbcTimeZone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcServices getJdbcServices() {
|
||||
return getFactory().getJdbcServices();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.internal;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.Interceptor;
|
||||
|
@ -42,6 +43,7 @@ public interface SessionCreationOptions {
|
|||
|
||||
String getTenantIdentifier();
|
||||
|
||||
TimeZone getJdbcTimeZone();
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// deprecations
|
||||
|
@ -62,5 +64,4 @@ public interface SessionCreationOptions {
|
|||
AfterCompletionAction getAfterCompletionAction();
|
||||
|
||||
ManagedFlushChecker getManagedFlushChecker();
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import javax.naming.Reference;
|
||||
import javax.naming.StringRefAddr;
|
||||
import javax.persistence.EntityGraph;
|
||||
|
@ -1073,6 +1074,8 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
|
|||
private boolean autoClose;
|
||||
private boolean autoClear;
|
||||
private String tenantIdentifier;
|
||||
private TimeZone jdbcTimeZone;
|
||||
|
||||
private List<SessionEventListener> listeners;
|
||||
|
||||
//todo : expose setting
|
||||
|
@ -1094,6 +1097,7 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
|
|||
if ( sessionFactory.getCurrentTenantIdentifierResolver() != null ) {
|
||||
tenantIdentifier = sessionFactory.getCurrentTenantIdentifierResolver().resolveCurrentTenantIdentifier();
|
||||
}
|
||||
this.jdbcTimeZone = sessionFactory.getSessionFactoryOptions().getJdbcTimeZone();
|
||||
|
||||
listeners = sessionFactory.getSessionFactoryOptions().getBaselineSessionEventsListenerBuilder().buildBaselineList();
|
||||
}
|
||||
|
@ -1184,6 +1188,10 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
|
|||
return tenantIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZone getJdbcTimeZone() {
|
||||
return jdbcTimeZone;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// SessionBuilder
|
||||
|
@ -1304,6 +1312,12 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
|
|||
listeners.clear();
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T jdbcTimeZone(TimeZone timeZone) {
|
||||
jdbcTimeZone = timeZone;
|
||||
return (T) this;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StatelessSessionBuilderImpl implements StatelessSessionBuilder, SessionCreationOptions {
|
||||
|
@ -1382,6 +1396,11 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor {
|
|||
return tenantIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZone getJdbcTimeZone() {
|
||||
return sessionFactory.getSessionFactoryOptions().getJdbcTimeZone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionOwner getSessionOwner() {
|
||||
return null;
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
|
||||
|
@ -39,4 +43,14 @@ public interface WrapperOptions {
|
|||
* @return The remapped descriptor. May be the same as the known descriptor indicating no remapping.
|
||||
*/
|
||||
public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor);
|
||||
|
||||
/**
|
||||
* The JDBC {@link TimeZone} used when persisting Timestamp and DateTime properties into the database.
|
||||
* This setting is used when storing timestamps using the {@link java.sql.PreparedStatement#setTimestamp(int, Timestamp, Calendar)} method.
|
||||
*
|
||||
* This way, the storage {@link TimeZone} can differ from the default JVM TimeZone given by {@link TimeZone#getDefault()}.
|
||||
*
|
||||
* @return JDBC {@link TimeZone}
|
||||
*/
|
||||
public TimeZone getJdbcTimeZone();
|
||||
}
|
||||
|
|
|
@ -49,6 +49,9 @@ public class TimeTypeDescriptor implements SqlTypeDescriptor {
|
|||
if ( value instanceof Calendar ) {
|
||||
st.setTime( index, time, (Calendar) value );
|
||||
}
|
||||
else if (options.getJdbcTimeZone() != null) {
|
||||
st.setTime( index, time, Calendar.getInstance( options.getJdbcTimeZone() ) );
|
||||
}
|
||||
else {
|
||||
st.setTime( index, time );
|
||||
}
|
||||
|
@ -61,6 +64,9 @@ public class TimeTypeDescriptor implements SqlTypeDescriptor {
|
|||
if ( value instanceof Calendar ) {
|
||||
st.setTime( name, time, (Calendar) value );
|
||||
}
|
||||
else if (options.getJdbcTimeZone() != null) {
|
||||
st.setTime( name, time, Calendar.getInstance( options.getJdbcTimeZone() ) );
|
||||
}
|
||||
else {
|
||||
st.setTime( name, time );
|
||||
}
|
||||
|
@ -73,17 +79,23 @@ public class TimeTypeDescriptor implements SqlTypeDescriptor {
|
|||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getTime( name ), options );
|
||||
return options.getJdbcTimeZone() != null ?
|
||||
javaTypeDescriptor.wrap( rs.getTime( name, Calendar.getInstance( options.getJdbcTimeZone() ) ), options ) :
|
||||
javaTypeDescriptor.wrap( rs.getTime( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getTime( index ), options );
|
||||
return options.getJdbcTimeZone() != null ?
|
||||
javaTypeDescriptor.wrap( statement.getTime( index, Calendar.getInstance( options.getJdbcTimeZone() ) ), options ) :
|
||||
javaTypeDescriptor.wrap( statement.getTime( index ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getTime( name ), options );
|
||||
return options.getJdbcTimeZone() != null ?
|
||||
javaTypeDescriptor.wrap( statement.getTime( name, Calendar.getInstance( options.getJdbcTimeZone() ) ), options ) :
|
||||
javaTypeDescriptor.wrap( statement.getTime( name ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -49,6 +49,9 @@ public class TimestampTypeDescriptor implements SqlTypeDescriptor {
|
|||
if ( value instanceof Calendar ) {
|
||||
st.setTimestamp( index, timestamp, (Calendar) value );
|
||||
}
|
||||
else if (options.getJdbcTimeZone() != null) {
|
||||
st.setTimestamp( index, timestamp, Calendar.getInstance( options.getJdbcTimeZone() ) );
|
||||
}
|
||||
else {
|
||||
st.setTimestamp( index, timestamp );
|
||||
}
|
||||
|
@ -61,6 +64,9 @@ public class TimestampTypeDescriptor implements SqlTypeDescriptor {
|
|||
if ( value instanceof Calendar ) {
|
||||
st.setTimestamp( name, timestamp, (Calendar) value );
|
||||
}
|
||||
else if (options.getJdbcTimeZone() != null) {
|
||||
st.setTimestamp( name, timestamp, Calendar.getInstance( options.getJdbcTimeZone() ) );
|
||||
}
|
||||
else {
|
||||
st.setTimestamp( name, timestamp );
|
||||
}
|
||||
|
@ -73,17 +79,23 @@ public class TimestampTypeDescriptor implements SqlTypeDescriptor {
|
|||
return new BasicExtractor<X>( javaTypeDescriptor, this ) {
|
||||
@Override
|
||||
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( rs.getTimestamp( name ), options );
|
||||
return options.getJdbcTimeZone() != null ?
|
||||
javaTypeDescriptor.wrap( rs.getTimestamp( name, Calendar.getInstance( options.getJdbcTimeZone() ) ), options ) :
|
||||
javaTypeDescriptor.wrap( rs.getTimestamp( name ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getTimestamp( index ), options );
|
||||
return options.getJdbcTimeZone() != null ?
|
||||
javaTypeDescriptor.wrap( statement.getTimestamp( index, Calendar.getInstance( options.getJdbcTimeZone() ) ), options ) :
|
||||
javaTypeDescriptor.wrap( statement.getTimestamp( index ), options );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
|
||||
return javaTypeDescriptor.wrap( statement.getTimestamp( name ), options );
|
||||
return options.getJdbcTimeZone() != null ?
|
||||
javaTypeDescriptor.wrap( statement.getTimestamp( name, Calendar.getInstance( options.getJdbcTimeZone() ) ), options ) :
|
||||
javaTypeDescriptor.wrap( statement.getTimestamp( name ), options );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* 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.timestamp;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Time;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetTime;
|
||||
import java.util.Calendar;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.hibernate.test.util.jdbc.PreparedStatementSpyConnectionProvider;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class JdbcTimeCustomTimeZoneTest
|
||||
extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
|
||||
|
||||
private static final TimeZone TIME_ZONE = TimeZone.getTimeZone(
|
||||
"America/Los_Angeles" );
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Person.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSettings(Map settings) {
|
||||
settings.put(
|
||||
AvailableSettings.CONNECTION_PROVIDER,
|
||||
connectionProvider
|
||||
);
|
||||
settings.put(
|
||||
AvailableSettings.JDBC_TIME_ZONE,
|
||||
TIME_ZONE
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseResources() {
|
||||
super.releaseResources();
|
||||
connectionProvider.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeZone() {
|
||||
|
||||
connectionProvider.clear();
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Person person = new Person();
|
||||
person.id = 1L;
|
||||
s.persist( person );
|
||||
|
||||
} );
|
||||
|
||||
assertEquals( 1, connectionProvider.getPreparedStatements().size() );
|
||||
PreparedStatement ps = connectionProvider.getPreparedStatements()
|
||||
.get( 0 );
|
||||
try {
|
||||
ArgumentCaptor<Calendar> calendarArgumentCaptor = ArgumentCaptor.forClass(
|
||||
Calendar.class );
|
||||
verify( ps, times( 1 ) ).setTime(
|
||||
anyInt(),
|
||||
any( Time.class ),
|
||||
calendarArgumentCaptor.capture()
|
||||
);
|
||||
assertEquals(
|
||||
TIME_ZONE,
|
||||
calendarArgumentCaptor.getValue().getTimeZone()
|
||||
);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
fail( e.getMessage() );
|
||||
}
|
||||
|
||||
connectionProvider.clear();
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
s.doWork( connection -> {
|
||||
try (Statement st = connection.createStatement()) {
|
||||
try (ResultSet rs = st.executeQuery(
|
||||
"select createdOn from Person" )) {
|
||||
while ( rs.next() ) {
|
||||
Time time = rs.getTime( 1 );
|
||||
Time offsetTime = Time.valueOf( OffsetTime.ofInstant(
|
||||
Instant.ofEpochMilli( 0 ),
|
||||
TIME_ZONE.toZoneId()
|
||||
).toLocalTime() );
|
||||
assertEquals( offsetTime, time );
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
Person person = s.find( Person.class, 1L );
|
||||
assertEquals(
|
||||
0,
|
||||
person.createdOn.getTime() % TimeUnit.DAYS.toSeconds( 1 )
|
||||
);
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private Time createdOn = new Time( 0 );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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.timestamp;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Time;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.hibernate.test.util.jdbc.PreparedStatementSpyConnectionProvider;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class JdbcTimeDefaultTimeZoneTest
|
||||
extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Person.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSettings(Map settings) {
|
||||
settings.put(
|
||||
AvailableSettings.CONNECTION_PROVIDER,
|
||||
connectionProvider
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseResources() {
|
||||
super.releaseResources();
|
||||
connectionProvider.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeZone() {
|
||||
|
||||
connectionProvider.clear();
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Person person = new Person();
|
||||
person.id = 1L;
|
||||
s.persist( person );
|
||||
|
||||
} );
|
||||
|
||||
assertEquals( 1, connectionProvider.getPreparedStatements().size() );
|
||||
PreparedStatement ps = connectionProvider.getPreparedStatements()
|
||||
.get( 0 );
|
||||
try {
|
||||
verify( ps, times( 1 ) ).setTime( anyInt(), any( Time.class ) );
|
||||
}
|
||||
catch (SQLException e) {
|
||||
fail( e.getMessage() );
|
||||
}
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Person person = s.find( Person.class, 1L );
|
||||
assertEquals( 0, person.createdOn.getTime() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private Time createdOn = new Time( 0 );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* 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.timestamp;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.hibernate.test.util.jdbc.PreparedStatementSpyConnectionProvider;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernateSessionBuilder;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class JdbcTimestampCustomSessionLevelTimeZoneTest
|
||||
extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
|
||||
|
||||
private static final TimeZone TIME_ZONE = TimeZone.getTimeZone(
|
||||
"America/Los_Angeles" );
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Person.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSettings(Map settings) {
|
||||
settings.put(
|
||||
AvailableSettings.CONNECTION_PROVIDER,
|
||||
connectionProvider
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseResources() {
|
||||
super.releaseResources();
|
||||
connectionProvider.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeZone() {
|
||||
|
||||
connectionProvider.clear();
|
||||
doInHibernateSessionBuilder( () -> {return sessionFactory().withOptions().jdbcTimeZone( TIME_ZONE);}, s -> {
|
||||
Person person = new Person();
|
||||
person.id = 1L;
|
||||
s.persist( person );
|
||||
|
||||
} );
|
||||
|
||||
assertEquals( 1, connectionProvider.getPreparedStatements().size() );
|
||||
PreparedStatement ps = connectionProvider.getPreparedStatements()
|
||||
.get( 0 );
|
||||
try {
|
||||
ArgumentCaptor<Calendar> calendarArgumentCaptor = ArgumentCaptor.forClass(
|
||||
Calendar.class );
|
||||
verify( ps, times( 1 ) ).setTimestamp(
|
||||
anyInt(),
|
||||
any( Timestamp.class ),
|
||||
calendarArgumentCaptor.capture()
|
||||
);
|
||||
assertEquals(
|
||||
TIME_ZONE,
|
||||
calendarArgumentCaptor.getValue().getTimeZone()
|
||||
);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
fail( e.getMessage() );
|
||||
}
|
||||
|
||||
connectionProvider.clear();
|
||||
doInHibernateSessionBuilder( () -> {return sessionFactory().withOptions().jdbcTimeZone( TIME_ZONE);}, s -> {
|
||||
s.doWork( connection -> {
|
||||
try (Statement st = connection.createStatement()) {
|
||||
try (ResultSet rs = st.executeQuery(
|
||||
"select createdOn from Person" )) {
|
||||
while ( rs.next() ) {
|
||||
Timestamp timestamp = rs.getTimestamp( 1 );
|
||||
int offsetDiff = TimeZone.getDefault()
|
||||
.getOffset( 0 ) - TIME_ZONE.getOffset( 0 );
|
||||
assertEquals(
|
||||
Math.abs( Long.valueOf( offsetDiff )
|
||||
.longValue() ),
|
||||
Math.abs( timestamp.getTime() )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
Person person = s.find( Person.class, 1L );
|
||||
assertEquals( 0, person.createdOn.getTime() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private Timestamp createdOn = new Timestamp( 0 );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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.timestamp;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.hibernate.test.util.jdbc.PreparedStatementSpyConnectionProvider;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class JdbcTimestampCustomTimeZoneTest
|
||||
extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
|
||||
|
||||
private static final TimeZone TIME_ZONE = TimeZone.getTimeZone(
|
||||
"America/Los_Angeles" );
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Person.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSettings(Map settings) {
|
||||
settings.put(
|
||||
AvailableSettings.CONNECTION_PROVIDER,
|
||||
connectionProvider
|
||||
);
|
||||
settings.put(
|
||||
AvailableSettings.JDBC_TIME_ZONE,
|
||||
TIME_ZONE
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseResources() {
|
||||
super.releaseResources();
|
||||
connectionProvider.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeZone() {
|
||||
|
||||
connectionProvider.clear();
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Person person = new Person();
|
||||
person.id = 1L;
|
||||
s.persist( person );
|
||||
|
||||
} );
|
||||
|
||||
assertEquals( 1, connectionProvider.getPreparedStatements().size() );
|
||||
PreparedStatement ps = connectionProvider.getPreparedStatements()
|
||||
.get( 0 );
|
||||
try {
|
||||
ArgumentCaptor<Calendar> calendarArgumentCaptor = ArgumentCaptor.forClass(
|
||||
Calendar.class );
|
||||
verify( ps, times( 1 ) ).setTimestamp(
|
||||
anyInt(),
|
||||
any( Timestamp.class ),
|
||||
calendarArgumentCaptor.capture()
|
||||
);
|
||||
assertEquals(
|
||||
TIME_ZONE,
|
||||
calendarArgumentCaptor.getValue().getTimeZone()
|
||||
);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
fail( e.getMessage() );
|
||||
}
|
||||
|
||||
connectionProvider.clear();
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
s.doWork( connection -> {
|
||||
try (Statement st = connection.createStatement()) {
|
||||
try (ResultSet rs = st.executeQuery(
|
||||
"select createdOn from Person" )) {
|
||||
while ( rs.next() ) {
|
||||
Timestamp timestamp = rs.getTimestamp( 1 );
|
||||
int offsetDiff = TimeZone.getDefault()
|
||||
.getOffset( 0 ) - TIME_ZONE.getOffset( 0 );
|
||||
assertEquals(
|
||||
Math.abs( Long.valueOf( offsetDiff )
|
||||
.longValue() ),
|
||||
Math.abs( timestamp.getTime() )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
Person person = s.find( Person.class, 1L );
|
||||
assertEquals( 0, person.createdOn.getTime() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private Timestamp createdOn = new Timestamp( 0 );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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.timestamp;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.hibernate.test.util.jdbc.PreparedStatementSpyConnectionProvider;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class JdbcTimestampDefaultTimeZoneTest
|
||||
extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Person.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSettings(Map settings) {
|
||||
settings.put(
|
||||
AvailableSettings.CONNECTION_PROVIDER,
|
||||
connectionProvider
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseResources() {
|
||||
super.releaseResources();
|
||||
connectionProvider.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeZone() {
|
||||
|
||||
connectionProvider.clear();
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Person person = new Person();
|
||||
person.id = 1L;
|
||||
s.persist( person );
|
||||
|
||||
} );
|
||||
|
||||
assertEquals( 1, connectionProvider.getPreparedStatements().size() );
|
||||
PreparedStatement ps = connectionProvider.getPreparedStatements()
|
||||
.get( 0 );
|
||||
try {
|
||||
verify( ps, times( 1 ) ).setTimestamp(
|
||||
anyInt(),
|
||||
any( Timestamp.class )
|
||||
);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
fail( e.getMessage() );
|
||||
}
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Person person = s.find( Person.class, 1L );
|
||||
assertEquals( 0, person.createdOn.getTime() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private Timestamp createdOn = new Timestamp( 0 );
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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.timestamp;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.PostgreSQL82Dialect;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.hibernate.test.util.jdbc.PreparedStatementSpyConnectionProvider;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@RequiresDialect( value = PostgreSQL82Dialect.class)
|
||||
public class JdbcTimestampUTCTimeZoneTest
|
||||
extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider();
|
||||
|
||||
private static final TimeZone TIME_ZONE = TimeZone.getTimeZone( "UTC" );
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Person.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSettings(Map settings) {
|
||||
settings.put(
|
||||
AvailableSettings.CONNECTION_PROVIDER,
|
||||
connectionProvider
|
||||
);
|
||||
settings.put(
|
||||
AvailableSettings.JDBC_TIME_ZONE,
|
||||
TIME_ZONE
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseResources() {
|
||||
super.releaseResources();
|
||||
connectionProvider.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeZone() {
|
||||
|
||||
connectionProvider.clear();
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Person person = new Person();
|
||||
person.id = 1L;
|
||||
//Y2K
|
||||
person.createdOn = new Timestamp(946684800000L);
|
||||
s.persist( person );
|
||||
|
||||
} );
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Person person = s.find( Person.class, 1L );
|
||||
assertEquals( 946684800000L, person.createdOn.getTime() );
|
||||
s.doWork( connection -> {
|
||||
try (Statement st = connection.createStatement()) {
|
||||
try (ResultSet rs = st.executeQuery(
|
||||
"SELECT " +
|
||||
" to_char(createdon, 'YYYY-MM-DD HH24:MI:SS.US') " +
|
||||
"FROM person" )) {
|
||||
while ( rs.next() ) {
|
||||
String timestamp = rs.getString( 1 );
|
||||
assertEquals("2000-01-01 00:00:00.000000", timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private Timestamp createdOn;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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.timestamp;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.PostgreSQL82Dialect;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.hibernate.test.util.jdbc.TimeZoneConnectionProvider;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@RequiresDialect( value = PostgreSQL82Dialect.class)
|
||||
public class JdbcTimestampWithoutUTCTimeZoneTest
|
||||
extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
private TimeZoneConnectionProvider connectionProvider = new TimeZoneConnectionProvider( "America/Los_Angeles" );
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Person.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSettings(Map settings) {
|
||||
settings.put(
|
||||
AvailableSettings.CONNECTION_PROVIDER,
|
||||
connectionProvider
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseResources() {
|
||||
super.releaseResources();
|
||||
connectionProvider.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeZone() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Person person = new Person();
|
||||
person.id = 1L;
|
||||
//Y2K
|
||||
person.createdOn = new Timestamp(946684800000L);
|
||||
s.persist( person );
|
||||
|
||||
} );
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
s.doWork( connection -> {
|
||||
try (Statement st = connection.createStatement()) {
|
||||
try (ResultSet rs = st.executeQuery(
|
||||
"SELECT " +
|
||||
" to_char(createdon, 'YYYY-MM-DD HH24:MI:SS.US') " +
|
||||
"FROM person" )) {
|
||||
while ( rs.next() ) {
|
||||
String timestamp = rs.getString( 1 );
|
||||
assertEquals("1999-12-31 16:00:00.000000", timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private Timestamp createdOn;
|
||||
}
|
||||
}
|
||||
|
|
@ -8,13 +8,13 @@ package org.hibernate.test.timestamp;
|
|||
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
|
|
|
@ -9,12 +9,10 @@ import java.sql.Clob;
|
|||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.junit.Test;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.engine.jdbc.NonContextualLobCreator;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
|
@ -23,6 +21,9 @@ import org.hibernate.type.descriptor.sql.ClobTypeDescriptor;
|
|||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
|
@ -47,6 +48,11 @@ public class StringValueMappingTest extends BaseUnitTestCase {
|
|||
public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
|
||||
return sqlTypeDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZone getJdbcTimeZone() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public static final String COLUMN_NAME = "n/a";
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package org.hibernate.test.util;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
|
@ -24,6 +27,26 @@ public class ReflectionUtil {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field value from a given object
|
||||
* @param target Object whose field is being read
|
||||
* @param name field name
|
||||
* @return field object
|
||||
*/
|
||||
public static <T> T getFieldValue(Object target, String name) {
|
||||
try {
|
||||
Field field = target.getClass().getDeclaredField( name );
|
||||
field.setAccessible( true );
|
||||
return (T) field.get( target );
|
||||
}
|
||||
catch ( NoSuchFieldException e ) {
|
||||
throw new IllegalArgumentException( "Class " + target.getClass() + " does not contain a " + name + " field", e);
|
||||
}
|
||||
catch ( IllegalAccessException e ) {
|
||||
throw new IllegalArgumentException( "Cannot set field " + name, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set target Object field to a certain value
|
||||
* @param target Object whose field is being set
|
||||
|
@ -38,4 +61,37 @@ public class ReflectionUtil {
|
|||
throw new IllegalArgumentException("Field " + field + " could not be set", e );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* New target Object instance using the given arguments
|
||||
* @param constructorSupplier constructor supplier
|
||||
* @param args Constructor arguments
|
||||
* @return new Object instance
|
||||
*/
|
||||
public static <T> T newInstance(Supplier<Constructor<T>> constructorSupplier, Object... args) {
|
||||
try {
|
||||
Constructor constructor = constructorSupplier.get();
|
||||
constructor.setAccessible( true );
|
||||
return (T) constructor.newInstance( args );
|
||||
}
|
||||
catch ( IllegalAccessException | InstantiationException | InvocationTargetException e ) {
|
||||
throw new IllegalArgumentException("Constructor could not be called", e );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set target Object field to a certain value
|
||||
* @param target Object whose field is being set
|
||||
* @param fieldName Object field naem to set
|
||||
* @param value the new value for the given field
|
||||
*/
|
||||
public static void setField(Object target, String fieldName, Object value) {
|
||||
try {
|
||||
Field field = getField(target.getClass(), fieldName);
|
||||
field.set( target, value );
|
||||
}
|
||||
catch ( IllegalAccessException e ) {
|
||||
throw new IllegalArgumentException("Field " + fieldName + " could not be set", e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.util.jdbc;
|
||||
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
||||
|
||||
/**
|
||||
* This {@link ConnectionProvider} extends any other ConnectionProvider that would be used by default taken the current configuration properties, and it
|
||||
* just sets a default TimeZone which is different than the current default one.
|
||||
*
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class TimeZoneConnectionProvider
|
||||
extends ConnectionProviderDelegate {
|
||||
|
||||
private final String defaultTimeZone;
|
||||
private final String customTimeZone;
|
||||
|
||||
public TimeZoneConnectionProvider(String customTimeZone) {
|
||||
this.customTimeZone = customTimeZone;
|
||||
this.defaultTimeZone = System.setProperty( "user.timezone", customTimeZone);
|
||||
TimeZone.setDefault(TimeZone.getTimeZone( customTimeZone ));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
super.stop();
|
||||
System.setProperty( "user.timezone", defaultTimeZone);
|
||||
TimeZone.setDefault(TimeZone.getTimeZone( defaultTimeZone ));
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ import javax.persistence.EntityManagerFactory;
|
|||
import javax.persistence.EntityTransaction;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionBuilder;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.Transaction;
|
||||
|
||||
|
@ -183,7 +184,7 @@ public class TransactionUtil {
|
|||
/**
|
||||
* Execute function in a Hibernate transaction
|
||||
*
|
||||
* @param factorySupplier EntityManagerFactory supplier
|
||||
* @param factorySupplier SessionFactory supplier
|
||||
* @param function function
|
||||
* @param <T> result type
|
||||
*
|
||||
|
@ -219,9 +220,9 @@ public class TransactionUtil {
|
|||
}
|
||||
|
||||
/**
|
||||
* Execute function in a JPA transaction without return value
|
||||
* Execute function in a Hibernate transaction without return value
|
||||
*
|
||||
* @param factorySupplier EntityManagerFactory supplier
|
||||
* @param factorySupplier SessionFactory supplier
|
||||
* @param function function
|
||||
*/
|
||||
public static void doInHibernate(
|
||||
|
@ -250,4 +251,75 @@ public class TransactionUtil {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute function in a Hibernate transaction
|
||||
*
|
||||
* @param sessionBuilderSupplier SessionFactory supplier
|
||||
* @param function function
|
||||
* @param <T> result type
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
public static <T> T doInHibernateSessionBuilder(
|
||||
Supplier<SessionBuilder> sessionBuilderSupplier,
|
||||
HibernateTransactionFunction<T> function) {
|
||||
T result = null;
|
||||
Session session = null;
|
||||
Transaction txn = null;
|
||||
try {
|
||||
session = sessionBuilderSupplier.get().openSession();
|
||||
function.beforeTransactionCompletion();
|
||||
txn = session.beginTransaction();
|
||||
|
||||
result = function.apply( session );
|
||||
txn.commit();
|
||||
}
|
||||
catch ( Throwable e ) {
|
||||
if ( txn != null ) {
|
||||
txn.rollback();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
function.afterTransactionCompletion();
|
||||
if ( session != null ) {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute function in a Hibernate transaction without return value
|
||||
*
|
||||
* @param sessionBuilderSupplier SessionFactory supplier
|
||||
* @param function function
|
||||
*/
|
||||
public static void doInHibernateSessionBuilder(
|
||||
Supplier<SessionBuilder> sessionBuilderSupplier,
|
||||
HibernateTransactionConsumer function) {
|
||||
Session session = null;
|
||||
Transaction txn = null;
|
||||
try {
|
||||
session = sessionBuilderSupplier.get().openSession();
|
||||
function.beforeTransactionCompletion();
|
||||
txn = session.beginTransaction();
|
||||
|
||||
function.accept( session );
|
||||
txn.commit();
|
||||
}
|
||||
catch ( Throwable e ) {
|
||||
if ( txn != null ) {
|
||||
txn.rollback();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
function.afterTransactionCompletion();
|
||||
if ( session != null ) {
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue