diff --git a/hibernate-java8/src/main/java/org/hibernate/type/DurationType.java b/hibernate-java8/src/main/java/org/hibernate/type/DurationType.java new file mode 100644 index 0000000000..9f48975a68 --- /dev/null +++ b/hibernate-java8/src/main/java/org/hibernate/type/DurationType.java @@ -0,0 +1,61 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2015, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.type; + +import java.time.Duration; + +import org.hibernate.dialect.Dialect; +import org.hibernate.type.descriptor.java.DurationJavaDescriptor; +import org.hibernate.type.descriptor.sql.BigIntTypeDescriptor; + +/** + * @author Steve Ebersole + */ +public class DurationType + extends AbstractSingleColumnStandardBasicType + implements LiteralType { + /** + * Singleton access + */ + public static final DurationType INSTANCE = new DurationType(); + + public DurationType() { + super( BigIntTypeDescriptor.INSTANCE, DurationJavaDescriptor.INSTANCE ); + } + + @Override + public String objectToSQLString(Duration value, Dialect dialect) throws Exception { + return String.valueOf( value.toNanos() ); + } + + @Override + public String getName() { + return Duration.class.getSimpleName(); + } + + @Override + protected boolean registerUnderJavaType() { + return true; + } +} diff --git a/hibernate-java8/src/main/java/org/hibernate/type/InstantType.java b/hibernate-java8/src/main/java/org/hibernate/type/InstantType.java index d1b130b5ce..0d6c51be19 100644 --- a/hibernate-java8/src/main/java/org/hibernate/type/InstantType.java +++ b/hibernate-java8/src/main/java/org/hibernate/type/InstantType.java @@ -78,7 +78,7 @@ public class InstantType @Override public String getName() { - return "Instant"; + return Instant.class.getSimpleName(); } @Override diff --git a/hibernate-java8/src/main/java/org/hibernate/type/Java8DateTimeTypeContributor.java b/hibernate-java8/src/main/java/org/hibernate/type/Java8DateTimeTypeContributor.java index 79525572f8..f639183e82 100644 --- a/hibernate-java8/src/main/java/org/hibernate/type/Java8DateTimeTypeContributor.java +++ b/hibernate-java8/src/main/java/org/hibernate/type/Java8DateTimeTypeContributor.java @@ -44,5 +44,7 @@ public class Java8DateTimeTypeContributor implements TypeContributor { typeContributions.contributeType( ZonedDateTimeType.INSTANCE ); typeContributions.contributeType( OffsetDateTimeType.INSTANCE ); typeContributions.contributeType( OffsetTimeType.INSTANCE ); + + typeContributions.contributeType( DurationType.INSTANCE ); } } \ No newline at end of file diff --git a/hibernate-java8/src/main/java/org/hibernate/type/LocalDateTimeType.java b/hibernate-java8/src/main/java/org/hibernate/type/LocalDateTimeType.java index 517fd0853d..29b8a41d7c 100644 --- a/hibernate-java8/src/main/java/org/hibernate/type/LocalDateTimeType.java +++ b/hibernate-java8/src/main/java/org/hibernate/type/LocalDateTimeType.java @@ -55,7 +55,7 @@ public class LocalDateTimeType @Override public String getName() { - return "LocalDateTime"; + return LocalDateTime.class.getSimpleName(); } @Override diff --git a/hibernate-java8/src/main/java/org/hibernate/type/LocalDateType.java b/hibernate-java8/src/main/java/org/hibernate/type/LocalDateType.java index cedaa1617b..12062bad78 100644 --- a/hibernate-java8/src/main/java/org/hibernate/type/LocalDateType.java +++ b/hibernate-java8/src/main/java/org/hibernate/type/LocalDateType.java @@ -32,7 +32,7 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.internal.util.compare.ComparableComparator; import org.hibernate.type.descriptor.java.LocalDateJavaDescriptor; -import org.hibernate.type.descriptor.sql.TimestampTypeDescriptor; +import org.hibernate.type.descriptor.sql.DateTypeDescriptor; /** * @author Steve Ebersole @@ -49,12 +49,12 @@ public class LocalDateType public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern( "yyyy-MM-dd", Locale.ENGLISH ); public LocalDateType() { - super( TimestampTypeDescriptor.INSTANCE, LocalDateJavaDescriptor.INSTANCE ); + super( DateTypeDescriptor.INSTANCE, LocalDateJavaDescriptor.INSTANCE ); } @Override public String getName() { - return "LocalDate"; + return LocalDate.class.getSimpleName(); } @Override diff --git a/hibernate-java8/src/main/java/org/hibernate/type/LocalTimeType.java b/hibernate-java8/src/main/java/org/hibernate/type/LocalTimeType.java index 1e8636c01c..ae891051bc 100644 --- a/hibernate-java8/src/main/java/org/hibernate/type/LocalTimeType.java +++ b/hibernate-java8/src/main/java/org/hibernate/type/LocalTimeType.java @@ -32,7 +32,7 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.internal.util.compare.ComparableComparator; import org.hibernate.type.descriptor.java.LocalTimeJavaDescriptor; -import org.hibernate.type.descriptor.sql.TimestampTypeDescriptor; +import org.hibernate.type.descriptor.sql.TimeTypeDescriptor; /** * A type that maps between {@link java.sql.Types#TIMESTAMP TIMESTAMP} and {@link java.time.LocalDateTime}. @@ -50,12 +50,12 @@ public class LocalTimeType public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern( "HH:mm:ss", Locale.ENGLISH ); public LocalTimeType() { - super( TimestampTypeDescriptor.INSTANCE, LocalTimeJavaDescriptor.INSTANCE ); + super( TimeTypeDescriptor.INSTANCE, LocalTimeJavaDescriptor.INSTANCE ); } @Override public String getName() { - return "LocalTime"; + return LocalTime.class.getSimpleName(); } @Override diff --git a/hibernate-java8/src/main/java/org/hibernate/type/OffsetTimeType.java b/hibernate-java8/src/main/java/org/hibernate/type/OffsetTimeType.java index a348e3a8c2..e2e1e7bdbb 100644 --- a/hibernate-java8/src/main/java/org/hibernate/type/OffsetTimeType.java +++ b/hibernate-java8/src/main/java/org/hibernate/type/OffsetTimeType.java @@ -32,7 +32,7 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.internal.util.compare.ComparableComparator; import org.hibernate.type.descriptor.java.OffsetTimeJavaDescriptor; -import org.hibernate.type.descriptor.sql.TimestampTypeDescriptor; +import org.hibernate.type.descriptor.sql.TimeTypeDescriptor; /** * @author Steve Ebersole @@ -49,12 +49,12 @@ public class OffsetTimeType public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern( "HH:mm:ss.S xxxxx", Locale.ENGLISH ); public OffsetTimeType() { - super( TimestampTypeDescriptor.INSTANCE, OffsetTimeJavaDescriptor.INSTANCE ); + super( TimeTypeDescriptor.INSTANCE, OffsetTimeJavaDescriptor.INSTANCE ); } @Override public String objectToSQLString(OffsetTime value, Dialect dialect) throws Exception { - return "{ts '" + FORMATTER.format( value ) + "'}"; + return "{t '" + FORMATTER.format( value ) + "'}"; } @Override diff --git a/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/DurationJavaDescriptor.java b/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/DurationJavaDescriptor.java new file mode 100644 index 0000000000..aa5dc2a652 --- /dev/null +++ b/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/DurationJavaDescriptor.java @@ -0,0 +1,102 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2015, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.type.descriptor.java; + +import java.time.Duration; + +import org.hibernate.type.descriptor.WrapperOptions; + +/** + * @author Steve Ebersole + */ +public class DurationJavaDescriptor extends AbstractTypeDescriptor { + /** + * Singleton access + */ + public static final DurationJavaDescriptor INSTANCE = new DurationJavaDescriptor(); + + @SuppressWarnings("unchecked") + public DurationJavaDescriptor() { + super( Duration.class, ImmutableMutabilityPlan.INSTANCE ); + } + + @Override + public String toString(Duration value) { + if ( value == null ) { + return null; + } + return String.valueOf( value.toNanos() ); + } + + @Override + public Duration fromString(String string) { + if ( string == null ) { + return null; + } + return Duration.ofNanos( Long.valueOf( string ) ); + } + + @Override + @SuppressWarnings("unchecked") + public X unwrap(Duration duration, Class type, WrapperOptions options) { + if ( duration == null ) { + return null; + } + + if ( Duration.class.isAssignableFrom( type ) ) { + return (X) duration; + } + + if ( String.class.isAssignableFrom( type ) ) { + return (X) duration.toString(); + } + + if ( Long.class.isAssignableFrom( type ) ) { + return (X) Long.valueOf( duration.toNanos() ); + } + + throw unknownUnwrap( type ); + } + + @Override + public Duration wrap(X value, WrapperOptions options) { + if ( value == null ) { + return null; + } + + if ( Duration.class.isInstance( value ) ) { + return (Duration) value; + } + + if ( Long.class.isInstance( value ) ) { + return Duration.ofNanos( (Long) value ); + } + + if ( String.class.isInstance( value ) ) { + return Duration.parse( (String) value ); + } + + throw unknownWrap( value.getClass() ); + } +} diff --git a/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/InstantJavaDescriptor.java b/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/InstantJavaDescriptor.java index 9a8835a825..9af5de53b5 100644 --- a/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/InstantJavaDescriptor.java +++ b/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/InstantJavaDescriptor.java @@ -25,8 +25,6 @@ package org.hibernate.type.descriptor.java; import java.sql.Timestamp; import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; @@ -35,7 +33,6 @@ import java.util.Date; import java.util.GregorianCalendar; import org.hibernate.type.InstantType; -import org.hibernate.type.LocalDateType; import org.hibernate.type.descriptor.WrapperOptions; /** diff --git a/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/LocalDateJavaDescriptor.java b/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/LocalDateJavaDescriptor.java index 3c17194395..6887266816 100644 --- a/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/LocalDateJavaDescriptor.java +++ b/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/LocalDateJavaDescriptor.java @@ -73,7 +73,17 @@ public class LocalDateJavaDescriptor extends AbstractTypeDescriptor { return (X) value; } - final ZonedDateTime zonedDateTime = value.atStartOfDay().atZone( ZoneId.systemDefault() ); + if ( java.sql.Date.class.isAssignableFrom( type ) ) { + return (X) java.sql.Date.valueOf( value ); + } + + final LocalDateTime localDateTime = value.atStartOfDay(); + + if ( Timestamp.class.isAssignableFrom( type ) ) { + return (X) Timestamp.valueOf( localDateTime ); + } + + final ZonedDateTime zonedDateTime = localDateTime.atZone( ZoneId.systemDefault() ); if ( Calendar.class.isAssignableFrom( type ) ) { return (X) GregorianCalendar.from( zonedDateTime ); @@ -81,19 +91,7 @@ public class LocalDateJavaDescriptor extends AbstractTypeDescriptor { final Instant instant = zonedDateTime.toInstant(); - if ( Timestamp.class.isAssignableFrom( type ) ) { - return (X) Timestamp.from( instant ); - } - - if ( java.sql.Date.class.isAssignableFrom( type ) ) { - return (X) java.sql.Date.from( instant ); - } - - if ( java.sql.Time.class.isAssignableFrom( type ) ) { - return (X) java.sql.Time.from( instant ); - } - - if ( Date.class.isAssignableFrom( type ) ) { + if ( Date.class.equals( type ) ) { return (X) Date.from( instant ); } @@ -130,7 +128,7 @@ public class LocalDateJavaDescriptor extends AbstractTypeDescriptor { } if ( Date.class.isInstance( value ) ) { - final Timestamp ts = (Timestamp) value; + final Date ts = (Date) value; final Instant instant = Instant.ofEpochMilli( ts.getTime() ); return LocalDateTime.ofInstant( instant, ZoneId.systemDefault() ).toLocalDate(); } diff --git a/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/LocalTimeJavaDescriptor.java b/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/LocalTimeJavaDescriptor.java index 92bd864704..0b6fbc0938 100644 --- a/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/LocalTimeJavaDescriptor.java +++ b/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/LocalTimeJavaDescriptor.java @@ -23,6 +23,7 @@ */ package org.hibernate.type.descriptor.java; +import java.sql.Time; import java.sql.Timestamp; import java.time.Instant; import java.time.LocalDate; @@ -74,10 +75,15 @@ public class LocalTimeJavaDescriptor extends AbstractTypeDescriptor { return (X) value; } + if ( Time.class.isAssignableFrom( type ) ) { + return (X) Time.valueOf( value ); + } + // Oracle documentation says to set the Date to January 1, 1970 when convert from // a LocalTime to a Calendar. IMO the same should hold true for converting to all // the legacy Date/Time types... + final ZonedDateTime zonedDateTime = value.atDate( LocalDate.of( 1970, 1, 1 ) ).atZone( ZoneId.systemDefault() ); if ( Calendar.class.isAssignableFrom( type ) ) { @@ -90,15 +96,7 @@ public class LocalTimeJavaDescriptor extends AbstractTypeDescriptor { return (X) Timestamp.from( instant ); } - if ( java.sql.Date.class.isAssignableFrom( type ) ) { - return (X) java.sql.Date.from( instant ); - } - - if ( java.sql.Time.class.isAssignableFrom( type ) ) { - return (X) java.sql.Time.from( instant ); - } - - if ( Date.class.isAssignableFrom( type ) ) { + if ( Date.class.equals( type ) ) { return (X) Date.from( instant ); } @@ -135,7 +133,7 @@ public class LocalTimeJavaDescriptor extends AbstractTypeDescriptor { } if ( Date.class.isInstance( value ) ) { - final Timestamp ts = (Timestamp) value; + final Date ts = (Date) value; final Instant instant = Instant.ofEpochMilli( ts.getTime() ); return LocalDateTime.ofInstant( instant, ZoneId.systemDefault() ).toLocalTime(); } diff --git a/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/OffsetTimeJavaDescriptor.java b/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/OffsetTimeJavaDescriptor.java index ab85e19d24..804cbaa217 100644 --- a/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/OffsetTimeJavaDescriptor.java +++ b/hibernate-java8/src/main/java/org/hibernate/type/descriptor/java/OffsetTimeJavaDescriptor.java @@ -23,9 +23,11 @@ */ package org.hibernate.type.descriptor.java; +import java.sql.Time; import java.sql.Timestamp; import java.time.Instant; import java.time.LocalDate; +import java.time.OffsetDateTime; import java.time.OffsetTime; import java.time.ZoneId; import java.time.ZonedDateTime; @@ -73,34 +75,30 @@ public class OffsetTimeJavaDescriptor extends AbstractTypeDescriptor return (X) offsetTime; } + if ( java.sql.Time.class.isAssignableFrom( type ) ) { + return (X) java.sql.Time.valueOf( offsetTime.toLocalTime() ); + } + final ZonedDateTime zonedDateTime = offsetTime.atDate( LocalDate.of( 1970, 1, 1 ) ).toZonedDateTime(); + if ( Timestamp.class.isAssignableFrom( type ) ) { + return (X) Timestamp.valueOf( zonedDateTime.toLocalDateTime() ); + } + if ( Calendar.class.isAssignableFrom( type ) ) { return (X) GregorianCalendar.from( zonedDateTime ); } final Instant instant = zonedDateTime.toInstant(); - if ( Timestamp.class.isAssignableFrom( type ) ) { - return (X) Timestamp.from( instant ); - } - - if ( java.sql.Date.class.isAssignableFrom( type ) ) { - return (X) java.sql.Date.from( instant ); - } - - if ( java.sql.Time.class.isAssignableFrom( type ) ) { - return (X) java.sql.Time.from( instant ); - } - - if ( Date.class.isAssignableFrom( type ) ) { - return (X) Date.from( instant ); - } - if ( Long.class.isAssignableFrom( type ) ) { return (X) Long.valueOf( instant.toEpochMilli() ); } + if ( java.util.Date.class.isAssignableFrom( type ) ) { + return (X) java.util.Date.from( instant ); + } + throw unknownUnwrap( type ); } @@ -114,6 +112,10 @@ public class OffsetTimeJavaDescriptor extends AbstractTypeDescriptor return (OffsetTime) value; } + if ( Time.class.isInstance( value ) ) { + return ( (Time) value ).toLocalTime().atOffset( OffsetDateTime.now().getOffset() ); + } + if ( Timestamp.class.isInstance( value ) ) { final Timestamp ts = (Timestamp) value; return OffsetTime.ofInstant( ts.toInstant(), ZoneId.systemDefault() ); diff --git a/hibernate-java8/src/test/java/org/hibernate/test/type/Java8DateTimeTests.java b/hibernate-java8/src/test/java/org/hibernate/test/type/Java8DateTimeTests.java index 25bf7addeb..c3fc7cb51f 100644 --- a/hibernate-java8/src/test/java/org/hibernate/test/type/Java8DateTimeTests.java +++ b/hibernate-java8/src/test/java/org/hibernate/test/type/Java8DateTimeTests.java @@ -23,6 +23,7 @@ */ package org.hibernate.test.type; +import java.time.Duration; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; @@ -30,6 +31,7 @@ import java.time.LocalTime; import java.time.OffsetDateTime; import java.time.OffsetTime; import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.Iterator; import javax.persistence.Entity; import javax.persistence.Id; @@ -115,6 +117,7 @@ public class Java8DateTimeTests extends BaseNonConfigCoreFunctionalTestCase { private ZonedDateTime zonedDateTime = ZonedDateTime.now(); private OffsetDateTime offsetDateTime = OffsetDateTime.now(); private OffsetTime offsetTime = OffsetTime.now(); + private Duration duration = Duration.of( 20, ChronoUnit.DAYS ); public TheEntity() { } @@ -187,5 +190,13 @@ public class Java8DateTimeTests extends BaseNonConfigCoreFunctionalTestCase { public void setOffsetTime(OffsetTime offsetTime) { this.offsetTime = offsetTime; } + + public Duration getDuration() { + return duration; + } + + public void setDuration(Duration duration) { + this.duration = duration; + } } } diff --git a/release/release.gradle b/release/release.gradle index 8c5420899a..ee0c4dd868 100644 --- a/release/release.gradle +++ b/release/release.gradle @@ -4,13 +4,13 @@ apply plugin: 'distribution' buildDir = "target" -//project.tasks*.each { -// it.doFirst { +project.tasks*.each { + it.doFirst { if ( !JavaVersion.current().java8Compatible ) { throw new GradleException( "Release must use Java 8 or greater" ) } -// } -//} + } +} idea.module { }