Skip to content

Commit b6748cd

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 67d35af commit b6748cd

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
@@ -541,7 +541,7 @@ public static <T> BasicValue.Resolution<T> fromTemporal(
541541
? reflectedJtd.resolveTypeForPrecision( requestedTemporalPrecision, typeConfiguration )
542542
// Avoid using the DateJavaType and prefer the JdbcTimestampJavaType
543543
: reflectedJtd.resolveTypeForPrecision( reflectedJtd.getPrecision(), typeConfiguration );
544-
final BasicType<T> jdbcMapping = basicTypeRegistry.resolve( temporalJavaType, explicitJdbcType );
544+
final var jdbcMapping = basicTypeRegistry.resolve( temporalJavaType, explicitJdbcType );
545545
return new InferredBasicValueResolution<>(
546546
jdbcMapping,
547547
temporalJavaType,
@@ -568,7 +568,6 @@ public static <T> BasicValue.Resolution<T> fromTemporal(
568568
}
569569
else {
570570
basicType = basicTypeRegistry.resolve(
571-
// Avoid using the DateJavaType and prefer the JdbcTimestampJavaType
572571
reflectedJtd.resolveTypeForPrecision( reflectedJtd.getPrecision(), typeConfiguration ),
573572
reflectedJtd.getRecommendedJdbcType( stdIndicators )
574573
);

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;
@@ -493,7 +491,7 @@ private StandardBasicTypes() {
493491
*/
494492
public static final BasicTypeReference<Date> TIME = new BasicTypeReference<>(
495493
"time",
496-
Time.class,
494+
java.util.Date.class,
497495
SqlTypes.TIME
498496
);
499497

@@ -503,7 +501,7 @@ private StandardBasicTypes() {
503501
*/
504502
public static final BasicTypeReference<Date> DATE = new BasicTypeReference<>(
505503
"date",
506-
java.sql.Date.class,
504+
java.util.Date.class,
507505
SqlTypes.DATE
508506
);
509507

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

@@ -1173,21 +1201,42 @@ public static void prime(TypeConfiguration typeConfiguration) {
11731201
DATE,
11741202
"org.hibernate.type.DateType",
11751203
basicTypeRegistry,
1176-
"date", java.sql.Date.class.getName()
1204+
"date"
11771205
);
11781206

11791207
handle(
11801208
TIME,
11811209
"org.hibernate.type.TimeType",
11821210
basicTypeRegistry,
1183-
"time", java.sql.Time.class.getName()
1211+
"time"
11841212
);
11851213

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

11931242
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)