Skip to content

Commit f50223b

Browse files
committed
more work on coercion, casting, and isInstance()
1 parent 907decd commit f50223b

File tree

7 files changed

+53
-26
lines changed

7 files changed

+53
-26
lines changed

hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ private boolean handleIdType(EntityPersister persister, LoadEvent event, LoadTyp
114114
parentIdTargetIdMapping instanceof CompositeIdentifierMapping compositeMapping
115115
? compositeMapping.getMappedIdEmbeddableTypeDescriptor()
116116
: parentIdTargetIdMapping.getMappedType();
117-
if ( parentIdType.getMappedJavaType().getJavaTypeClass().isInstance( event.getEntityId() ) ) {
117+
if ( parentIdType.getMappedJavaType().isInstance( event.getEntityId() ) ) {
118118
// yep that's what we have...
119119
loadByDerivedIdentitySimplePkValue(
120120
event,

hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleNaturalIdMapping.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public void validateInternalForm(Object naturalIdValue) {
115115
}
116116
}
117117

118-
if ( !getJavaType().getJavaTypeClass().isInstance( naturalIdValue ) ) {
118+
if ( !getJavaType().isInstance( naturalIdValue ) ) {
119119
throw new IllegalArgumentException(
120120
String.format(
121121
Locale.ROOT,

hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,22 +1650,17 @@ public SelectStatement visitSelectStatement(SqmSelectStatement<?> statement) {
16501650
@Override
16511651
public DynamicInstantiation<?> visitDynamicInstantiation(SqmDynamicInstantiation<?> sqmDynamicInstantiation) {
16521652
final var instantiationTarget = sqmDynamicInstantiation.getInstantiationTarget();
1653-
final var instantiationNature = instantiationTarget.getNature();
1654-
final var targetTypeDescriptor = interpretInstantiationTarget( instantiationTarget );
1655-
1656-
final var dynamicInstantiation = new DynamicInstantiation<>( instantiationNature, targetTypeDescriptor );
1657-
1653+
final var dynamicInstantiation =
1654+
new DynamicInstantiation<>( instantiationTarget.getNature(),
1655+
interpretInstantiationTarget( instantiationTarget ) );
16581656
for ( var sqmArgument : sqmDynamicInstantiation.getArguments() ) {
16591657
if ( sqmArgument.getSelectableNode() instanceof SqmPath<?> sqmPath ) {
16601658
prepareForSelection( sqmPath );
16611659
}
1662-
final var argumentResultProducer = (DomainResultProducer<?>) sqmArgument.accept( this );
1663-
1664-
dynamicInstantiation.addArgument( sqmArgument.getAlias(), argumentResultProducer, this );
1660+
dynamicInstantiation.addArgument( sqmArgument.getAlias(),
1661+
(DomainResultProducer<?>) sqmArgument.accept( this ) );
16651662
}
1666-
16671663
dynamicInstantiation.complete();
1668-
16691664
return dynamicInstantiation;
16701665
}
16711666

hibernate-core/src/main/java/org/hibernate/sql/results/graph/basic/BasicResultAssembler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public J assemble(
6060
if ( valueConverter != null ) {
6161
if ( jdbcValue != null ) {
6262
// the raw value type should be the converter's relational-JTD
63-
if ( ! valueConverter.getRelationalJavaType().getJavaTypeClass().isInstance( jdbcValue ) ) {
63+
if ( ! valueConverter.getRelationalJavaType().isInstance( jdbcValue ) ) {
6464
throw new HibernateException(
6565
String.format(
6666
Locale.ROOT,

hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerImpl.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,8 @@ private void resolveEntity(EntityInitializerData data, Object proxy) {
11541154
public void resolveInstance(EntityInitializerData data) {
11551155
if ( data.getState() == State.KEY_RESOLVED ) {
11561156
final var rowProcessingState = data.getRowProcessingState();
1157+
final var session = rowProcessingState.getSession();
1158+
final var persistenceContext = session.getPersistenceContextInternal();
11571159
data.setState( State.RESOLVED );
11581160
if ( data.entityKey == null ) {
11591161
assert identifierAssembler != null;
@@ -1165,7 +1167,7 @@ public void resolveInstance(EntityInitializerData data) {
11651167
resolveEntityKey( data, id );
11661168
}
11671169
data.entityHolder =
1168-
rowProcessingState.getSession().getPersistenceContextInternal()
1170+
persistenceContext
11691171
.claimEntityHolderIfPossible(
11701172
data.entityKey,
11711173
null,
@@ -1179,7 +1181,6 @@ public void resolveInstance(EntityInitializerData data) {
11791181
else {
11801182
resolveEntityInstance1( data );
11811183
if ( data.uniqueKeyAttributePath != null ) {
1182-
final var session = rowProcessingState.getSession();
11831184
final var concreteDescriptor = getConcreteDescriptor( data );
11841185
final var entityUniqueKey = new EntityUniqueKey(
11851186
concreteDescriptor.getEntityName(),
@@ -1188,8 +1189,7 @@ public void resolveInstance(EntityInitializerData data) {
11881189
data.uniqueKeyPropertyTypes[concreteDescriptor.getSubclassId()],
11891190
session.getFactory()
11901191
);
1191-
session.getPersistenceContextInternal()
1192-
.addEntity( entityUniqueKey, data.getInstance() );
1192+
persistenceContext.addEntity( entityUniqueKey, data.getInstance() );
11931193
}
11941194
}
11951195

@@ -1346,7 +1346,10 @@ protected void upgradeLockMode(EntityInitializerData data) {
13461346
protected boolean isProxyInstance(Object proxy) {
13471347
return proxy != null
13481348
&& ( proxy instanceof MapProxy
1349-
|| entityDescriptor.getJavaType().getJavaTypeClass().isInstance( proxy ) );
1349+
// do NOT use JavaType.isInstance() here; we're testing if the
1350+
// proxy itself is an instance of the given entity type, not if
1351+
// the underlying entity implementation is an instance
1352+
|| entityDescriptor.getJavaType().getJavaTypeClass().isInstance( proxy ) );
13501353
}
13511354

13521355
private boolean isExistingEntityInitialized(Object existingEntity) {

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

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,27 @@ default String getTypeName() {
100100
* but some descriptors need specialized semantics, for example, the descriptors for
101101
* {@link JdbcDateJavaType java.sql.Date}, {@link JdbcTimeJavaType java.sql.Time}, and
102102
* {@link JdbcTimestampJavaType java.sql.Timestamp}.
103+
* <p>
104+
* For {@link org.hibernate.type.descriptor.java.spi.EntityJavaType}, this method
105+
* handles proxies in a semantically correct way, by checking the entity instance
106+
* underlying the proxy object.
103107
*/
104108
default boolean isInstance(Object value) {
105109
return getJavaTypeClass().isInstance( value );
106110
}
107111

112+
/**
113+
* Apply a simple type cast to the given value, without attempting any sort of
114+
* {@linkplain #coerce(Object) coercion} or {@linkplain #wrap wrapping}. This
115+
* method is provided as a convenient way to avoid an unchecked cast to a type
116+
* variable. Use {@code javaType.cast(value)} instead of {@code (T) value}
117+
* wherever possible.
118+
* <p>
119+
* Usually just {@link #getJavaTypeClass() getJavaTypeClass().}{@link Class#cast cast(value)},
120+
* but overridden in some cases as an "optimization". This optimization is
121+
* almost certainly unnecessary, and might even indeed be harmful, since
122+
* {@code Class.cast()} is an intrinsic.
123+
*/
108124
default T cast(Object value) {
109125
return getJavaTypeClass().cast( value );
110126
}
@@ -322,10 +338,28 @@ interface CoercionContext {
322338

323339
/**
324340
* Coerce the given value to this type, if possible.
341+
* <p>
342+
* This method differs from {@link #wrap wrap()} in that it allows
343+
* simple, basic, implicit type conversions, and does not require
344+
* {@link WrapperOptions}. The {@code wrap()} method may be thought
345+
* of as offering explicitly requested type conversions driven by a
346+
* choice of {@link JdbcType}.
347+
* <p>
348+
* An implementation of this method reports failure in one of two
349+
* ways, by:
350+
* <ul>
351+
* <li>throwing {@link CoercionException}, or
352+
* <li>simply returning the given uncoerced value.
353+
* </ul>
354+
* <p>
355+
* Therefore, this method is declared to return {@link Object}.
356+
* In case immediate coercion is required, the following idiom
357+
* may be used:
358+
* <pre>javaType.cast(javaType.coerce(value))</pre>
325359
*
326360
* @param value The value to coerce
327-
* @return The coerced value, or the given value
328-
* if no coercion was possible
361+
* @return The coerced value, or the given value if no coercion was
362+
* possible
329363
* @throws CoercionException if coercion fails
330364
*/
331365
@Incubating

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,6 @@ private static <T> MutabilityPlan<T> createMutabilityPlan(Class<T> type) {
5858
: (MutabilityPlan<T>) SerializableMutabilityPlan.INSTANCE;
5959
}
6060

61-
@Override
62-
public boolean isInstance(Object value) {
63-
return value instanceof Serializable;
64-
}
65-
6661
@Override
6762
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators indicators) {
6863
final int typeCode = indicators.isLob() ? Types.BLOB : Types.VARBINARY;
@@ -137,7 +132,7 @@ else if (value instanceof Blob blob) {
137132
throw new HibernateException( e );
138133
}
139134
}
140-
else if ( getJavaTypeClass().isInstance( value ) ) {
135+
else if ( isInstance( value ) ) {
141136
return cast( value );
142137
}
143138
throw unknownWrap( value.getClass() );

0 commit comments

Comments
 (0)