Skip to content

Commit 95a31e6

Browse files
committed
Use DateJavaType instead of JdbcXxxxJavaTypes to represent fields of type Date
This fixes bugs in the metamodel where getJavaType() would return the wrong class even in the Persistence-standard metamodel. It's also a first step to fixing a bunch of other unsound things we do in the codebase.
1 parent 0722f2c commit 95a31e6

File tree

14 files changed

+371
-251
lines changed

14 files changed

+371
-251
lines changed

hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/InferredBasicValueResolver.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ public static <T> BasicValue.Resolution<T> fromTemporal(
537537
? reflectedJtd.resolveTypeForPrecision( requestedTemporalPrecision, typeConfiguration )
538538
// Avoid using the DateJavaType and prefer the JdbcTimestampJavaType
539539
: reflectedJtd.resolveTypeForPrecision( reflectedJtd.getPrecision(), typeConfiguration );
540-
final BasicType<T> jdbcMapping = basicTypeRegistry.resolve( temporalJavaType, explicitJdbcType );
540+
final var jdbcMapping = basicTypeRegistry.resolve( temporalJavaType, explicitJdbcType );
541541
return new InferredBasicValueResolution<>(
542542
jdbcMapping,
543543
temporalJavaType,
@@ -564,7 +564,6 @@ public static <T> BasicValue.Resolution<T> fromTemporal(
564564
}
565565
else {
566566
basicType = basicTypeRegistry.resolve(
567-
// Avoid using the DateJavaType and prefer the JdbcTimestampJavaType
568567
reflectedJtd.resolveTypeForPrecision( reflectedJtd.getPrecision(), typeConfiguration ),
569568
reflectedJtd.getRecommendedJdbcType( stdIndicators )
570569
);

hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractAttribute.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,11 @@ public String getName() {
6363

6464
@Override
6565
public Class<J> getJavaType() {
66-
return valueType instanceof BasicTypeImpl basicType
67-
? basicType.getJavaType()
66+
// TODO: create a new method to abstract this logic
67+
return valueType instanceof BasicTypeImpl<?> basicType
68+
// handles primitives in basic types
69+
? (Class<J>) basicType.getJavaType()
70+
// good for everything else
6871
: attributeJtd.getJavaTypeClass();
6972
}
7073

hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmDynamicInstantiation.java

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
package org.hibernate.query.sqm.tree.select;
66

77
import java.util.ArrayList;
8-
import java.util.Collections;
98
import java.util.List;
109
import java.util.Map;
1110
import java.util.Objects;
@@ -23,11 +22,15 @@
2322
import org.hibernate.query.sqm.tree.domain.SqmDomainType;
2423
import org.hibernate.query.sqm.tree.expression.SqmExpression;
2524
import org.hibernate.query.sqm.tree.jpa.AbstractJpaSelection;
25+
import org.hibernate.type.descriptor.java.DateJavaType;
2626
import org.hibernate.type.descriptor.java.JavaType;
2727

28+
import org.hibernate.type.descriptor.java.TemporalJavaType;
2829
import org.hibernate.type.spi.TypeConfiguration;
2930
import org.jboss.logging.Logger;
3031

32+
import static java.util.Collections.emptyList;
33+
import static java.util.Collections.unmodifiableList;
3134
import static java.util.stream.Collectors.toList;
3235
import static org.hibernate.internal.util.NullnessUtil.castNonNull;
3336
import static org.hibernate.query.sqm.DynamicInstantiationNature.CLASS;
@@ -157,7 +160,7 @@ public boolean checkInstantiation(TypeConfiguration typeConfiguration) {
157160
if ( isConstructorCompatible( javaType, argTypes, typeConfiguration ) ) {
158161
return true;
159162
}
160-
final List<SqmDynamicInstantiationArgument<?>> arguments = getArguments();
163+
final var arguments = getArguments();
161164
final List<String> aliases = new ArrayList<>( arguments.size() );
162165
for ( var argument : arguments ) {
163166
final String alias = argument.getAlias();
@@ -182,9 +185,18 @@ private List<Class<?>> argumentTypes() {
182185
return getArguments().stream()
183186
.map( arg -> {
184187
final var expressible = arg.getExpressible();
185-
return expressible != null && expressible.getExpressibleJavaType() != null ?
186-
expressible.getExpressibleJavaType().getJavaTypeClass() :
187-
Void.class;
188+
if ( expressible != null ) {
189+
final var expressibleJavaType = expressible.getExpressibleJavaType();
190+
if ( expressibleJavaType != null ) {
191+
return expressibleJavaType instanceof DateJavaType temporalJavaType
192+
// Hack to accommodate a constructor with java.sql parameter
193+
// types when the entity has java.util.Date as its field types.
194+
// (This was requested in HHH-4179 and we fixed it by accident.)
195+
? TemporalJavaType.resolveJavaTypeClass( temporalJavaType.getPrecision() )
196+
: expressibleJavaType.getJavaTypeClass();
197+
}
198+
}
199+
return Void.class;
188200
} ).collect( toList() );
189201
}
190202

@@ -227,7 +239,7 @@ public SqmDynamicInstantiationTarget<T> getInstantiationTarget() {
227239
}
228240

229241
public List<SqmDynamicInstantiationArgument<?>> getArguments() {
230-
return arguments == null ? Collections.emptyList() : Collections.unmodifiableList( arguments );
242+
return arguments == null ? emptyList() : unmodifiableList( arguments );
231243
}
232244

233245
@Override

hibernate-core/src/main/java/org/hibernate/sql/results/graph/instantiation/internal/DynamicInstantiationResultImpl.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
import org.hibernate.sql.results.graph.DomainResultAssembler;
1818
import org.hibernate.sql.results.graph.InitializerParent;
1919
import org.hibernate.sql.results.graph.instantiation.DynamicInstantiationResult;
20+
import org.hibernate.type.descriptor.java.DateJavaType;
2021
import org.hibernate.type.descriptor.java.JavaType;
2122

23+
import org.hibernate.type.descriptor.java.TemporalJavaType;
2224
import org.jboss.logging.Logger;
2325

2426
import static java.util.stream.Collectors.toList;
@@ -157,7 +159,7 @@ private DomainResultAssembler<R> assembler(
157159
final var constructor = findMatchingConstructor(
158160
javaType.getJavaTypeClass(),
159161
argumentReaders.stream()
160-
.map( reader -> reader.getAssembledJavaType().getJavaTypeClass() )
162+
.map( reader -> argumentClass( reader ) )
161163
.collect( toList() ),
162164
creationState.getSqlAstCreationContext()
163165
.getMappingMetamodel()
@@ -194,6 +196,16 @@ private DomainResultAssembler<R> assembler(
194196
return new DynamicInstantiationAssemblerInjectionImpl<>( javaType, argumentReaders );
195197
}
196198

199+
private static Class<?> argumentClass(ArgumentReader<?> reader) {
200+
final var assembledJavaType = reader.getAssembledJavaType();
201+
return assembledJavaType instanceof DateJavaType temporalJavaType
202+
// Hack to accommodate a constructor with java.sql parameter
203+
// types when the entity has java.util.Date as its field types.
204+
// (This was requested in HHH-4179 and we fixed it by accident.)
205+
? TemporalJavaType.resolveJavaTypeClass( temporalJavaType.getPrecision() )
206+
: assembledJavaType.getJavaTypeClass();
207+
}
208+
197209
private List<String> signature() {
198210
return argumentResults.stream()
199211
.map( adt -> adt.getResultJavaType().getTypeName() )

hibernate-core/src/main/java/org/hibernate/type/StandardBasicTypes.java

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
import java.sql.Blob;
1212
import java.sql.Clob;
1313
import java.sql.NClob;
14-
import java.sql.Time;
15-
import java.sql.Timestamp;
1614
import java.time.Duration;
1715
import java.time.Instant;
1816
import java.time.LocalDate;
@@ -494,7 +492,7 @@ private StandardBasicTypes() {
494492
*/
495493
public static final BasicTypeReference<Date> TIME = new BasicTypeReference<>(
496494
"time",
497-
Time.class,
495+
java.util.Date.class,
498496
SqlTypes.TIME
499497
);
500498

@@ -504,7 +502,7 @@ private StandardBasicTypes() {
504502
*/
505503
public static final BasicTypeReference<Date> DATE = new BasicTypeReference<>(
506504
"date",
507-
java.sql.Date.class,
505+
java.util.Date.class,
508506
SqlTypes.DATE
509507
);
510508

@@ -514,7 +512,37 @@ private StandardBasicTypes() {
514512
*/
515513
public static final BasicTypeReference<Date> TIMESTAMP = new BasicTypeReference<>(
516514
"timestamp",
517-
Timestamp.class,
515+
java.util.Date.class,
516+
SqlTypes.TIMESTAMP
517+
);
518+
519+
/**
520+
* The standard Hibernate type for mapping {@link java.sql.Time} to JDBC
521+
* {@link org.hibernate.type.SqlTypes#TIMESTAMP TIMESTAMP}.
522+
*/
523+
public static final BasicTypeReference<java.sql.Time> SQL_TIME = new BasicTypeReference<>(
524+
"sql_time",
525+
java.sql.Time.class,
526+
SqlTypes.TIME
527+
);
528+
529+
/**
530+
* The standard Hibernate type for mapping {@link java.sql.Date} to JDBC
531+
* {@link org.hibernate.type.SqlTypes#DATE DATE}.
532+
*/
533+
public static final BasicTypeReference<java.sql.Date> SQL_DATE = new BasicTypeReference<>(
534+
"sql_date",
535+
java.sql.Date.class,
536+
SqlTypes.DATE
537+
);
538+
539+
/**
540+
* The standard Hibernate type for mapping {@link java.sql.Timestamp} to JDBC
541+
* {@link org.hibernate.type.SqlTypes#TIMESTAMP TIMESTAMP}.
542+
*/
543+
public static final BasicTypeReference<java.sql.Timestamp> SQL_TIMESTAMP = new BasicTypeReference<>(
544+
"sql_timestamp",
545+
java.sql.Timestamp.class,
518546
SqlTypes.TIMESTAMP
519547
);
520548

@@ -1174,21 +1202,42 @@ public static void prime(TypeConfiguration typeConfiguration) {
11741202
DATE,
11751203
"org.hibernate.type.DateType",
11761204
basicTypeRegistry,
1177-
"date", java.sql.Date.class.getName()
1205+
"date"
11781206
);
11791207

11801208
handle(
11811209
TIME,
11821210
"org.hibernate.type.TimeType",
11831211
basicTypeRegistry,
1184-
"time", java.sql.Time.class.getName()
1212+
"time"
11851213
);
11861214

11871215
handle(
11881216
TIMESTAMP,
11891217
"org.hibernate.type.TimestampType",
11901218
basicTypeRegistry,
1191-
"timestamp", java.sql.Timestamp.class.getName(), Date.class.getName()
1219+
"timestamp", Date.class.getName()
1220+
);
1221+
1222+
handle(
1223+
SQL_DATE,
1224+
null,
1225+
basicTypeRegistry,
1226+
"sql_date", java.sql.Date.class.getName()
1227+
);
1228+
1229+
handle(
1230+
SQL_TIME,
1231+
null,
1232+
basicTypeRegistry,
1233+
"sql_time", java.sql.Time.class.getName()
1234+
);
1235+
1236+
handle(
1237+
SQL_TIMESTAMP,
1238+
null,
1239+
basicTypeRegistry,
1240+
"sql_timestamp", java.sql.Timestamp.class.getName()
11921241
);
11931242

11941243
handle(

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/AbstractTemporalJavaType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public AbstractTemporalJavaType(
3333
}
3434

3535
@Override
36-
public final <X> TemporalJavaType<X> resolveTypeForPrecision(
36+
public <X> TemporalJavaType<X> resolveTypeForPrecision(
3737
TemporalType precision,
3838
TypeConfiguration typeConfiguration) {
3939
if ( precision == null ) {

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarDateJavaType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ protected <X> TemporalJavaType<X> forTimePrecision(TypeConfiguration typeConfigu
5656
}
5757

5858
public String toString(Calendar value) {
59-
return JdbcDateJavaType.INSTANCE.toString( value.getTime() );
59+
return JdbcDateJavaType.INSTANCE.toString(
60+
new java.sql.Date( value.getTime().getTime() ) );
6061
}
6162

6263
public Calendar fromString(CharSequence string) {

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/CalendarTimeJavaType.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
package org.hibernate.type.descriptor.java;
66

7+
import java.sql.Time;
78
import java.sql.Types;
89
import java.util.Calendar;
910
import java.util.Date;
@@ -56,7 +57,8 @@ protected <X> TemporalJavaType<X> forDatePrecision(TypeConfiguration typeConfigu
5657
}
5758

5859
public String toString(Calendar value) {
59-
return JdbcTimeJavaType.INSTANCE.toString( value.getTime() );
60+
return JdbcTimeJavaType.INSTANCE.toString(
61+
new Time( value.getTime().getTime() ) );
6062
}
6163

6264
public Calendar fromString(CharSequence string) {

0 commit comments

Comments
 (0)