Skip to content

Commit ccf42f0

Browse files
committed
actually fix up the unsafe methods of JpaMetamodel
this change exposed multiple bugs! 1. generic attributes declared by a mapped superclass where not being handled properly in HQL path expressions 2. getSubTypes() on EntityTypeImpl was broken (due, again, to use of unchecked cast!) causing problems in HQL
1 parent 0cdbc4d commit ccf42f0

File tree

18 files changed

+177
-151
lines changed

18 files changed

+177
-151
lines changed

hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1767,7 +1767,7 @@ private void processValueResolvers(MetadataBuildingContext buildingContext) {
17671767

17681768
private void processSecondPasses(ArrayList<? extends SecondPass> secondPasses) {
17691769
if ( secondPasses != null ) {
1770-
for ( SecondPass secondPass : secondPasses ) {
1770+
for ( var secondPass : secondPasses ) {
17711771
secondPass.doSecondPass( getEntityBindingMap() );
17721772
}
17731773
secondPasses.clear();

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

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import org.hibernate.AssertionFailure;
1313
import org.hibernate.PropertyNotFoundException;
1414
import org.hibernate.boot.spi.MetadataBuildingContext;
15-
import org.hibernate.boot.spi.SecondPass;
1615
import org.hibernate.mapping.Collection;
1716
import org.hibernate.mapping.Component;
1817
import org.hibernate.mapping.IndexedCollection;
@@ -312,29 +311,25 @@ static void prepareActualProperty(
312311
if ( !allowCollections ) {
313312
throw new AssertionFailure( "Collections are not allowed as identifier properties" );
314313
}
315-
// The owner is a MappedSuperclass which is not a PersistentClass, so set it to null
316-
// collection.setOwner( null );
314+
// The owner is a MappedSuperclass, not a PersistentClass,
315+
// so set it to null collection.setOwner( null );
317316
collection.setRole( memberDetails.getDeclaringType().getName() + "." + property.getName() );
318317
// To copy the element and key values, we need to defer setting the type name until the CollectionBinder ran
319318
final var originalValue = property.getValue();
320-
context.getMetadataCollector().addSecondPass(
321-
new SecondPass() {
322-
@Override
323-
public void doSecondPass(Map<String, PersistentClass> persistentClasses) {
324-
final var initializedCollection = (Collection) originalValue;
325-
final var element = initializedCollection.getElement().copy();
326-
setTypeName( element, memberDetails.getElementType().getName() );
327-
if ( initializedCollection instanceof IndexedCollection indexedCollection ) {
328-
final var index = indexedCollection.getIndex().copy();
329-
if ( memberDetails.getMapKeyType() != null ) {
330-
setTypeName( index, memberDetails.getMapKeyType().getName() );
331-
}
332-
( (IndexedCollection) collection ).setIndex( index );
333-
}
334-
collection.setElement( element );
335-
}
319+
context.getMetadataCollector().addSecondPass( persistentClasses -> {
320+
final var initializedCollection = (Collection) originalValue;
321+
final var element = initializedCollection.getElement().copy();
322+
setTypeName( element, memberDetails.getElementType().getName() );
323+
if ( initializedCollection instanceof IndexedCollection indexedCollection ) {
324+
final var index = indexedCollection.getIndex().copy();
325+
final var mapKeyType = memberDetails.getMapKeyType();
326+
if ( mapKeyType != null ) {
327+
setTypeName( index, mapKeyType.getName() );
336328
}
337-
);
329+
( (IndexedCollection) collection ).setIndex( index );
330+
}
331+
collection.setElement( element );
332+
} );
338333
}
339334
else {
340335
setTypeName( value, memberDetails.getType().getName() );

hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ private DomainType<?> determineSimpleType(ValueContext typeContext) {
212212
public static DomainType<?> determineSimpleType(ValueContext typeContext, MetadataContext context) {
213213
return switch ( typeContext.getValueClassification() ) {
214214
case BASIC -> basicDomainType( typeContext, context );
215-
case ENTITY -> entityDomainType (typeContext, context );
215+
case ENTITY -> entityDomainType( typeContext, context );
216216
case EMBEDDABLE -> embeddableDomainType( typeContext, context );
217217
default -> throw new AssertionFailure( "Unknown type : " + typeContext.getValueClassification() );
218218
};

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

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,8 @@ public interface JpaMetamodel extends Metamodel {
3333

3434
/**
3535
* Access to a managed type through its name
36-
*
37-
* @deprecated This method performs an unchecked type cast
3836
*/
39-
@Deprecated(since = "7.2")
40-
<X> ManagedDomainType<X> managedType(String typeName);
37+
ManagedDomainType<?> managedType(String typeName);
4138

4239
/**
4340
* Access to an entity supporting Hibernate's entity-name feature
@@ -52,20 +49,14 @@ public interface JpaMetamodel extends Metamodel {
5249
/**
5350
* Specialized handling for resolving entity-name references in
5451
* an HQL query
55-
*
56-
* @deprecated This method performs an unchecked type cast
5752
*/
58-
@Deprecated(since = "7.2")
59-
<X> EntityDomainType<X> getHqlEntityReference(String entityName);
53+
EntityDomainType<?> getHqlEntityReference(String entityName);
6054

6155
/**
6256
* Specialized handling for resolving entity-name references in
6357
* an HQL query
64-
*
65-
* @deprecated This method performs an unchecked type cast
6658
*/
67-
@Deprecated(since = "7.2")
68-
<X> EntityDomainType<X> resolveHqlEntityReference(String entityName);
59+
EntityDomainType<?> resolveHqlEntityReference(String entityName);
6960

7061
/**
7162
* Same as {@link #managedType(Class)} except {@code null} is returned rather
@@ -88,11 +79,8 @@ public interface JpaMetamodel extends Metamodel {
8879
/**
8980
* Same as {@link #managedType(String)} except {@code null} is returned rather
9081
* than throwing an exception
91-
*
92-
* @deprecated This method performs an unchecked type cast
9382
*/
94-
@Deprecated(since = "7.2")
95-
@Nullable <X> ManagedDomainType<X> findManagedType(@Nullable String typeName);
83+
@Nullable ManagedDomainType<?> findManagedType(@Nullable String typeName);
9684

9785
/**
9886
* Same as {@link #entity(String)} except {@code null} is returned rather

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

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,15 @@ public boolean hasSingleIdAttribute() {
114114
}
115115

116116
@Override
117-
@SuppressWarnings("unchecked")
118117
public <Y> SqmSingularPersistentAttribute<? super J, Y> getId(Class<Y> javaType) {
119118
ensureNoIdClass();
120119
final var id = findIdAttribute();
121120
if ( id != null ) {
122121
checkType( id, javaType );
123122
}
124-
return (SqmSingularPersistentAttribute<? super J, Y>) id;
123+
@SuppressWarnings("unchecked") // safe, we just checked
124+
final var castId = (SqmSingularPersistentAttribute<? super J, Y>) id;
125+
return castId;
125126
}
126127

127128
private void ensureNoIdClass() {
@@ -148,8 +149,7 @@ else if ( getSuperType() != null ) {
148149

149150
private void checkType(SingularPersistentAttribute<?, ?> attribute, Class<?> javaType) {
150151
if ( !javaType.isAssignableFrom( attribute.getType().getJavaType() ) ) {
151-
final JavaType<?> attributeJavaType = attribute.getAttributeJavaType();
152-
if ( !( attributeJavaType instanceof PrimitiveJavaType<?> primitiveJavaType )
152+
if ( !( attribute.getAttributeJavaType() instanceof PrimitiveJavaType<?> primitiveJavaType )
153153
|| primitiveJavaType.getPrimitiveClass() != javaType ) {
154154
throw new IllegalArgumentException(
155155
String.format(
@@ -165,14 +165,15 @@ private void checkType(SingularPersistentAttribute<?, ?> attribute, Class<?> jav
165165
}
166166

167167
@Override
168-
@SuppressWarnings("unchecked")
169168
public <Y> SqmSingularPersistentAttribute<J, Y> getDeclaredId(Class<Y> javaType) {
170169
ensureNoIdClass();
171170
if ( id == null ) {
172171
throw new IllegalArgumentException( "The id attribute is not declared on this type [" + getTypeName() + "]" );
173172
}
174173
checkType( id, javaType );
175-
return (SqmSingularPersistentAttribute<J, Y>) id;
174+
@SuppressWarnings("unchecked") // safe, we just checked
175+
final var castId = (SqmSingularPersistentAttribute<J, Y>) id;
176+
return castId;
176177
}
177178

178179
@Override
@@ -226,14 +227,16 @@ else if ( idClassType instanceof SimpleDomainType<?> simpleDomainType ) {
226227
}
227228

228229
@Override
229-
@SuppressWarnings("unchecked")
230230
public void visitIdClassAttributes(Consumer<SingularPersistentAttribute<? super J, ?>> attributeConsumer) {
231231
if ( nonAggregatedIdAttributes != null ) {
232232
nonAggregatedIdAttributes.forEach( attributeConsumer );
233233
}
234-
else if ( getSuperType() != null ) {
235-
//noinspection rawtypes
236-
getSuperType().visitIdClassAttributes( (Consumer) attributeConsumer );
234+
else {
235+
final var superType = getSuperType();
236+
if ( superType != null ) {
237+
//noinspection rawtypes, unchecked
238+
superType.visitIdClassAttributes( (Consumer) attributeConsumer );
239+
}
237240
}
238241
}
239242

@@ -247,14 +250,15 @@ public boolean hasDeclaredVersionAttribute() {
247250
}
248251

249252
@Override
250-
@SuppressWarnings("unchecked")
251253
public <Y> SingularPersistentAttribute<? super J, Y> getVersion(Class<Y> javaType) {
252254
if ( hasVersionAttribute() ) {
253255
final var version = findVersionAttribute();
254256
if ( version != null ) {
255257
checkType( version, javaType );
256258
}
257-
return (SingularPersistentAttribute<? super J, Y>) version;
259+
@SuppressWarnings("unchecked") // safe, we just checked
260+
final var castVersion = (SingularPersistentAttribute<? super J, Y>) version;
261+
return castVersion;
258262
}
259263
else {
260264
return null;
@@ -288,11 +292,12 @@ else if ( getSuperType() != null ) {
288292
}
289293

290294
@Override
291-
@SuppressWarnings("unchecked")
292295
public <Y> SingularPersistentAttribute<J, Y> getDeclaredVersion(Class<Y> javaType) {
293296
checkDeclaredVersion();
294297
checkType( versionAttribute, javaType );
295-
return (SingularPersistentAttribute<J, Y>) versionAttribute;
298+
@SuppressWarnings("unchecked") // safe, we just checked
299+
final var castVersion = (SingularPersistentAttribute<J, Y>) versionAttribute;
300+
return castVersion;
296301
}
297302

298303
private void checkDeclaredVersion() {
@@ -360,9 +365,8 @@ public void applyNonAggregatedIdAttributes(
360365
nonAggregatedIdAttributes.add( (SqmSingularPersistentAttribute<? super J, ?>) idAttribute );
361366
if ( AbstractIdentifiableType.this == idAttribute.getDeclaringType() ) {
362367
@SuppressWarnings("unchecked")
363-
// Safe, because we know it's declared by this type
364-
final PersistentAttribute<J, ?> declaredAttribute =
365-
(PersistentAttribute<J, ?>) idAttribute;
368+
// Safe, because we know it's declared by this type
369+
final var declaredAttribute = (PersistentAttribute<J, ?>) idAttribute;
366370
addAttribute( declaredAttribute );
367371
}
368372
}

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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
package org.hibernate.metamodel.model.domain.internal;
66

77
import org.hibernate.metamodel.MappingMetamodel;
8-
import org.hibernate.metamodel.mapping.EntityMappingType;
98
import org.hibernate.metamodel.mapping.ModelPart;
109
import org.hibernate.metamodel.model.domain.EntityDomainType;
1110
import org.hibernate.metamodel.model.domain.ManagedDomainType;
@@ -28,9 +27,9 @@ static boolean isCompatible(
2827
return true;
2928
}
3029
else {
31-
final ModelPart modelPart1 =
30+
final var modelPart1 =
3231
getEntityAttributeModelPart( attribute1, attribute1.getDeclaringType(), mappingMetamodel );
33-
final ModelPart modelPart2 =
32+
final var modelPart2 =
3433
getEntityAttributeModelPart( attribute2, attribute2.getDeclaringType(), mappingMetamodel );
3534
return modelPart1 != null
3635
&& modelPart2 != null
@@ -43,13 +42,13 @@ static ModelPart getEntityAttributeModelPart(
4342
ManagedDomainType<?> domainType,
4443
MappingMetamodel mappingMetamodel) {
4544
if ( domainType instanceof EntityDomainType<?> ) {
46-
final EntityMappingType entity = mappingMetamodel.getEntityDescriptor( domainType.getTypeName() );
47-
return entity.findSubPart( attribute.getName() );
45+
return mappingMetamodel.getEntityDescriptor( domainType.getTypeName() )
46+
.findSubPart( attribute.getName() );
4847
}
4948
else {
5049
ModelPart candidate = null;
51-
for ( ManagedDomainType<?> subType : domainType.getSubTypes() ) {
52-
final ModelPart modelPart = getEntityAttributeModelPart( attribute, subType, mappingMetamodel );
50+
for ( var subType : domainType.getSubTypes() ) {
51+
final var modelPart = getEntityAttributeModelPart( attribute, subType, mappingMetamodel );
5352
if ( modelPart != null ) {
5453
if ( candidate != null && !isCompatibleModelPart( candidate, modelPart ) ) {
5554
return null;

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

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
package org.hibernate.metamodel.model.domain.internal;
66

77
import java.io.Serializable;
8+
import java.util.ArrayList;
89
import java.util.Collection;
10+
import java.util.List;
911

1012
import org.checkerframework.checker.nullness.qual.Nullable;
13+
import org.hibernate.AssertionFailure;
1114
import org.hibernate.metamodel.UnsupportedMappingException;
1215
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
1316
import org.hibernate.metamodel.model.domain.DomainType;
@@ -33,6 +36,7 @@ public class EmbeddableTypeImpl<J>
3336
implements SqmEmbeddableDomainType<J>, Serializable {
3437
private final boolean isDynamic;
3538
private final EmbeddedDiscriminatorSqmPathSource<?> discriminatorPathSource;
39+
private final List<SqmEmbeddableDomainType<? extends J>> subtypes = new ArrayList<>();
3640

3741
public EmbeddableTypeImpl(
3842
JavaType<J> javaType,
@@ -61,15 +65,27 @@ public PersistenceType getPersistenceType() {
6165
public int getTupleLength() {
6266
int count = 0;
6367
for ( var attribute : getSingularAttributes() ) {
64-
count += ( (SqmDomainType<?>) attribute.getType() ).getTupleLength();
68+
if ( attribute.getType() instanceof SqmDomainType<?> domainType ) {
69+
count += domainType.getTupleLength();
70+
}
71+
else {
72+
throw new AssertionFailure( "Should have been a domain type" );
73+
}
6574
}
6675
return count;
6776
}
6877

6978
@Override
7079
public Collection<? extends SqmEmbeddableDomainType<? extends J>> getSubTypes() {
71-
//noinspection unchecked
72-
return (Collection<? extends SqmEmbeddableDomainType<? extends J>>) super.getSubTypes();
80+
return subtypes;
81+
}
82+
83+
@Override
84+
public void addSubType(ManagedDomainType<? extends J> subType) {
85+
super.addSubType( subType );
86+
if ( subType instanceof SqmEmbeddableDomainType<? extends J> entityDomainType ) {
87+
subtypes.add( entityDomainType );
88+
}
7389
}
7490

7591
@Override

0 commit comments

Comments
 (0)