Skip to content

Commit

Permalink
HHH-17575 - Add a new @FractionalSeconds annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
sebersole committed Dec 22, 2023
1 parent 53dbc95 commit 480072d
Show file tree
Hide file tree
Showing 11 changed files with 430 additions and 24 deletions.
@@ -0,0 +1,51 @@
/*
* 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.annotations;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import org.hibernate.Incubating;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
* Indicates that the associated temporal value should be stored with fractional seconds.
* Only valid for values which contain seconds.
*
* @apiNote The presence or absence of this annotation implies different semantics for time
* versus timestamp based values. By default, time values are stored without fractional seconds
* whereas timestamp values are stored with a precision based on the
* {@linkplain org.hibernate.dialect.Dialect#getDefaultTimestampPrecision Dialect default}
*
* @see java.time.Instant
* @see java.time.LocalDateTime
* @see java.time.LocalTime
* @see java.time.OffsetDateTime
* @see java.time.OffsetTime
* @see java.time.ZonedDateTime
* @see java.sql.Time
* @see java.sql.Timestamp
* @see java.util.Calendar
*
* @author Steve Ebersole
*/
@Target({METHOD, FIELD})
@Retention( RUNTIME)
@Incubating
public @interface FractionalSeconds {
/**
* The fractional precision for the associated seconds. Generally this will be one of<ul>
* <li>3 (milliseconds)</li>
* <li>6 (microseconds)</li>
* <li>9 (nanoseconds)</li>
* </ul>
*/
int value();
}
Expand Up @@ -17,6 +17,7 @@
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.ColumnTransformer;
import org.hibernate.annotations.ColumnTransformers;
import org.hibernate.annotations.FractionalSeconds;
import org.hibernate.annotations.GeneratedColumn;
import org.hibernate.annotations.Index;
import org.hibernate.annotations.common.reflection.XProperty;
Expand Down Expand Up @@ -77,6 +78,7 @@ public class AnnotatedColumn {
private Long length;
private Integer precision;
private Integer scale;
private Integer temporalPrecision; // technically scale, but most dbs call it precision so...
private Integer arrayLength;
private String logicalColumnName;
private boolean unique;
Expand Down Expand Up @@ -183,6 +185,10 @@ public void setScale(Integer scale) {
this.scale = scale;
}

public void setTemporalPrecision(Integer temporalPrecision) {
this.temporalPrecision = temporalPrecision;
}

public void setLogicalColumnName(String logicalColumnName) {
this.logicalColumnName = logicalColumnName;
}
Expand Down Expand Up @@ -239,6 +245,7 @@ public void bind() {
length,
precision,
scale,
temporalPrecision,
arrayLength,
nullable,
sqlType,
Expand Down Expand Up @@ -269,6 +276,7 @@ protected void initMappingColumn(
Long length,
Integer precision,
Integer scale,
Integer temporalPrecision,
Integer arrayLength,
boolean nullable,
String sqlType,
Expand All @@ -287,6 +295,9 @@ protected void initMappingColumn(
mappingColumn.setPrecision( precision );
mappingColumn.setScale( scale );
}
if ( temporalPrecision != null ) {
mappingColumn.setTemporalPrecision( temporalPrecision );
}
mappingColumn.setArrayLength( arrayLength );
mappingColumn.setNullable( nullable );
mappingColumn.setSqlType( sqlType );
Expand Down Expand Up @@ -488,6 +499,7 @@ public static AnnotatedColumns buildFormulaFromAnnotation(
return buildColumnOrFormulaFromAnnotation(
null,
formulaAnn,
null,
// commentAnn,
nullability,
propertyHolder,
Expand All @@ -498,6 +510,7 @@ public static AnnotatedColumns buildFormulaFromAnnotation(
}

public static AnnotatedColumns buildColumnFromNoAnnotation(
FractionalSeconds fractionalSeconds,
// Comment commentAnn,
Nullability nullability,
PropertyHolder propertyHolder,
Expand All @@ -506,6 +519,7 @@ public static AnnotatedColumns buildColumnFromNoAnnotation(
MetadataBuildingContext context) {
return buildColumnsFromAnnotations(
null,
fractionalSeconds,
// commentAnn,
nullability,
propertyHolder,
Expand All @@ -517,6 +531,7 @@ public static AnnotatedColumns buildColumnFromNoAnnotation(

public static AnnotatedColumns buildColumnFromAnnotation(
jakarta.persistence.Column column,
org.hibernate.annotations.FractionalSeconds fractionalSeconds,
// Comment commentAnn,
Nullability nullability,
PropertyHolder propertyHolder,
Expand All @@ -526,6 +541,7 @@ public static AnnotatedColumns buildColumnFromAnnotation(
return buildColumnOrFormulaFromAnnotation(
column,
null,
fractionalSeconds,
// commentAnn,
nullability,
propertyHolder,
Expand All @@ -537,6 +553,7 @@ public static AnnotatedColumns buildColumnFromAnnotation(

public static AnnotatedColumns buildColumnsFromAnnotations(
jakarta.persistence.Column[] columns,
FractionalSeconds fractionalSeconds,
// Comment commentAnn,
Nullability nullability,
PropertyHolder propertyHolder,
Expand All @@ -546,6 +563,7 @@ public static AnnotatedColumns buildColumnsFromAnnotations(
return buildColumnsOrFormulaFromAnnotation(
columns,
null,
fractionalSeconds,
// commentAnn,
nullability,
propertyHolder,
Expand All @@ -568,6 +586,7 @@ public static AnnotatedColumns buildColumnsFromAnnotations(
return buildColumnsOrFormulaFromAnnotation(
columns,
null,
null,
// commentAnn,
nullability,
propertyHolder,
Expand All @@ -581,6 +600,7 @@ public static AnnotatedColumns buildColumnsFromAnnotations(
public static AnnotatedColumns buildColumnOrFormulaFromAnnotation(
jakarta.persistence.Column column,
org.hibernate.annotations.Formula formulaAnn,
org.hibernate.annotations.FractionalSeconds fractionalSeconds,
// Comment commentAnn,
Nullability nullability,
PropertyHolder propertyHolder,
Expand All @@ -590,6 +610,7 @@ public static AnnotatedColumns buildColumnOrFormulaFromAnnotation(
return buildColumnsOrFormulaFromAnnotation(
column==null ? null : new jakarta.persistence.Column[] { column },
formulaAnn,
fractionalSeconds,
// commentAnn,
nullability,
propertyHolder,
Expand All @@ -603,6 +624,7 @@ public static AnnotatedColumns buildColumnOrFormulaFromAnnotation(
public static AnnotatedColumns buildColumnsOrFormulaFromAnnotation(
jakarta.persistence.Column[] columns,
org.hibernate.annotations.Formula formulaAnn,
org.hibernate.annotations.FractionalSeconds fractionalSeconds,
// Comment comment,
Nullability nullability,
PropertyHolder propertyHolder,
Expand Down Expand Up @@ -630,6 +652,7 @@ public static AnnotatedColumns buildColumnsOrFormulaFromAnnotation(
final jakarta.persistence.Column[] actualColumns = overrideColumns( columns, propertyHolder, inferredData );
if ( actualColumns == null ) {
return buildImplicitColumn(
fractionalSeconds,
inferredData,
suffixForDefaultColumnName,
secondaryTables,
Expand All @@ -647,7 +670,8 @@ public static AnnotatedColumns buildColumnsOrFormulaFromAnnotation(
suffixForDefaultColumnName,
secondaryTables,
context,
actualColumns
actualColumns,
fractionalSeconds
);
}
}
Expand Down Expand Up @@ -684,7 +708,8 @@ private static AnnotatedColumns buildExplicitColumns(
String suffixForDefaultColumnName,
Map<String, Join> secondaryTables,
MetadataBuildingContext context,
jakarta.persistence.Column[] actualCols) {
jakarta.persistence.Column[] actualCols,
FractionalSeconds fractionalSeconds) {
final AnnotatedColumns parent = new AnnotatedColumns();
parent.setPropertyHolder( propertyHolder );
parent.setPropertyName( getRelativePath( propertyHolder, inferredData.getPropertyName() ) );
Expand All @@ -708,6 +733,7 @@ private static AnnotatedColumns buildExplicitColumns(
actualCols.length,
database,
column,
fractionalSeconds,
sqlType,
tableName
);
Expand All @@ -734,6 +760,7 @@ private static AnnotatedColumn buildColumn(
int numberOfColumns,
Database database,
jakarta.persistence.Column column,
FractionalSeconds fractionalSeconds,
String sqlType,
String tableName) {
final String columnName = logicalColumnName( inferredData, suffixForDefaultColumnName, database, column );
Expand All @@ -742,7 +769,12 @@ private static AnnotatedColumn buildColumn(
annotatedColumn.setImplicit( false );
annotatedColumn.setSqlType( sqlType );
annotatedColumn.setLength( (long) column.length() );
annotatedColumn.setPrecision( column.precision() );
if ( fractionalSeconds != null ) {
annotatedColumn.setTemporalPrecision( fractionalSeconds.value() );
}
else {
annotatedColumn.setPrecision( column.precision() );
}
annotatedColumn.setScale( column.scale() );
annotatedColumn.handleArrayLength( inferredData );
// annotatedColumn.setPropertyHolder( propertyHolder );
Expand Down Expand Up @@ -881,6 +913,7 @@ private void processColumnTransformerExpressions(ColumnTransformer annotation) {
}

private static AnnotatedColumns buildImplicitColumn(
FractionalSeconds fractionalSeconds,
PropertyData inferredData,
String suffixForDefaultColumnName,
Map<String, Join> secondaryTables,
Expand Down Expand Up @@ -920,6 +953,9 @@ private static AnnotatedColumns buildImplicitColumn(
column.applyCheckConstraint( inferredData, 1 );
column.extractDataFromPropertyData( propertyHolder, inferredData );
column.handleArrayLength( inferredData );
if ( fractionalSeconds != null ) {
column.setTemporalPrecision( fractionalSeconds.value() );
}
column.bind();
return columns;
}
Expand Down
Expand Up @@ -325,6 +325,7 @@ public void linkValueUsingDefaultColumnNaming(
referencedColumn.getLength(),
referencedColumn.getPrecision(),
referencedColumn.getScale(),
referencedColumn.getTemporalPrecision(),
referencedColumn.getArrayLength(),
mappingColumn != null && mappingColumn.isNullable(),
referencedColumn.getSqlType(),
Expand Down Expand Up @@ -375,6 +376,7 @@ public void linkValueUsingAColumnCopy(Column column, SimpleValue value) {
column.getLength(),
column.getPrecision(),
column.getScale(),
column.getTemporalPrecision(),
column.getArrayLength(),
getMappingColumn().isNullable(),
column.getSqlType(),
Expand Down
Expand Up @@ -761,6 +761,7 @@ public static Any buildAnyValue(
final AnnotatedColumns discriminatorColumns = buildColumnOrFormulaFromAnnotation(
discriminatorColumn,
discriminatorFormula,
null,
// null,
nullability,
propertyHolder,
Expand Down
Expand Up @@ -570,6 +570,7 @@ private static AnnotatedColumns elementColumns(
if ( property.isAnnotationPresent( jakarta.persistence.Column.class ) ) {
return buildColumnFromAnnotation(
property.getAnnotation( jakarta.persistence.Column.class ),
null,
// comment,
nullability,
propertyHolder,
Expand All @@ -592,6 +593,7 @@ else if ( property.isAnnotationPresent( Formula.class ) ) {
else if ( property.isAnnotationPresent( Columns.class ) ) {
return buildColumnsFromAnnotations(
property.getAnnotation( Columns.class ).columns(),
null,
// comment,
nullability,
propertyHolder,
Expand All @@ -602,6 +604,7 @@ else if ( property.isAnnotationPresent( Columns.class ) ) {
}
else {
return buildColumnFromNoAnnotation(
null,
// comment,
nullability,
propertyHolder,
Expand Down
Expand Up @@ -9,6 +9,7 @@
import org.hibernate.AnnotationException;
import org.hibernate.annotations.Columns;
import org.hibernate.annotations.Formula;
import org.hibernate.annotations.FractionalSeconds;
import org.hibernate.annotations.JoinColumnOrFormula;
import org.hibernate.annotations.JoinColumnsOrFormulas;
import org.hibernate.annotations.JoinFormula;
Expand Down Expand Up @@ -85,6 +86,7 @@ public ColumnsBuilder extractMetadata() {
if ( property.isAnnotationPresent( Column.class ) ) {
columns = buildColumnFromAnnotation(
property.getAnnotation( Column.class ),
property.getAnnotation( FractionalSeconds.class ),
// comment,
nullability,
propertyHolder,
Expand All @@ -107,6 +109,7 @@ else if ( property.isAnnotationPresent( Formula.class ) ) {
else if ( property.isAnnotationPresent( Columns.class ) ) {
columns = buildColumnsFromAnnotations(
property.getAnnotation( Columns.class ).columns(),
null,
// comment,
nullability,
propertyHolder,
Expand Down Expand Up @@ -144,6 +147,7 @@ else if ( joinColumns == null
if ( columns == null && !property.isAnnotationPresent( ManyToMany.class ) ) {
//useful for collection of embedded elements
columns = buildColumnFromNoAnnotation(
property.getAnnotation( FractionalSeconds.class ),
// comment,
nullability,
propertyHolder,
Expand Down
Expand Up @@ -70,6 +70,7 @@ protected boolean bindStarToManySecondPass(Map<String, PersistentClass> persiste
final AnnotatedColumns idColumns = AnnotatedColumn.buildColumnsFromAnnotations(
new Column[] { collectionIdAnn.column() },
// null,
null,
Nullability.FORCED_NOT_NULL,
propertyHolder,
propertyData,
Expand Down

0 comments on commit 480072d

Please sign in to comment.