Skip to content

Commit 91e9fb6

Browse files
committed
HHH-19775 tolerate type(:entity) as required by JPQL
this is definitely not an elegant implementation, but it seems to work
1 parent c2e021f commit 91e9fb6

File tree

7 files changed

+117
-65
lines changed

7 files changed

+117
-65
lines changed

hibernate-core/src/main/java/org/hibernate/metamodel/MappingMetamodel.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,14 @@ public interface MappingMetamodel extends Metamodel {
7878
/**
7979
* Get an entity mapping descriptor based on its Class.
8080
*
81-
* @throws IllegalArgumentException if the name does not refer to an entity
81+
* @throws IllegalArgumentException if the class is not an entity class
8282
*
8383
* @see #findEntityDescriptor
8484
*/
8585
EntityPersister getEntityDescriptor(Class<?> entityJavaType);
8686

8787
/**
88-
* Find an entity mapping descriptor based on its Hibernate entity-name.
88+
* Find an entity mapping descriptor based on its Hibernate entity name.
8989
*
9090
* @apiNote Returns {@code null} rather than throwing exception
9191
*/

hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatorConverter.java

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,12 @@ public DiscriminatorValueDetails getDetailsForRelationalForm(R relationalForm) {
5050
@Override
5151
public O toDomainValue(R relationalForm) {
5252
assert relationalForm == null || relationalJavaType.isInstance( relationalForm );
53-
54-
final DiscriminatorValueDetails matchingValueDetails = getDetailsForRelationalForm( relationalForm );
53+
final var matchingValueDetails = getDetailsForRelationalForm( relationalForm );
5554
if ( matchingValueDetails == null ) {
5655
throw new IllegalStateException( "Could not resolve discriminator value" );
5756
}
5857

59-
final EntityMappingType indicatedEntity = matchingValueDetails.getIndicatedEntity();
58+
final var indicatedEntity = matchingValueDetails.getIndicatedEntity();
6059
//noinspection unchecked
6160
return indicatedEntity.getRepresentationStrategy().getMode() == RepresentationMode.POJO
6261
&& indicatedEntity.getEntityName().equals( indicatedEntity.getJavaType().getJavaTypeClass().getName() )
@@ -66,25 +65,19 @@ public O toDomainValue(R relationalForm) {
6665

6766
@Override
6867
public R toRelationalValue(O domainForm) {
69-
final String entityName;
70-
if ( domainForm == null ) {
68+
final String entityName = getEntityName( domainForm );
69+
if ( entityName == null ) {
7170
return null;
7271
}
73-
else if ( domainForm instanceof Class<?> clazz ) {
74-
entityName = clazz.getName();
75-
}
76-
else if ( domainForm instanceof String name ) {
77-
entityName = name;
78-
}
7972
else {
80-
throw new IllegalArgumentException( "Illegal discriminator value: " + domainForm );
73+
final var discriminatorValueDetails = getDetailsForEntityName( entityName );
74+
//noinspection unchecked
75+
return (R) discriminatorValueDetails.getValue();
8176
}
82-
83-
final DiscriminatorValueDetails discriminatorValueDetails = getDetailsForEntityName( entityName );
84-
//noinspection unchecked
85-
return (R) discriminatorValueDetails.getValue();
8677
}
8778

79+
protected abstract String getEntityName(O domainForm);
80+
8881
public abstract DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalValue);
8982

9083
public abstract DiscriminatorValueDetails getDetailsForEntityName(String entityName);

hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableDiscriminatorConverter.java

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,10 @@ public static <O, R> EmbeddableDiscriminatorConverter<O, R> fromValueMappings(
3434
Map<Object, String> valueMappings,
3535
ServiceRegistry serviceRegistry) {
3636
final List<EmbeddableDiscriminatorValueDetailsImpl> valueDetailsList = new ArrayList<>( valueMappings.size() );
37-
final ClassLoaderService cls = serviceRegistry.requireService( ClassLoaderService.class );
38-
valueMappings.forEach( (value, embeddableClassName) -> valueDetailsList.add( new EmbeddableDiscriminatorValueDetailsImpl(
39-
value,
40-
cls.classForName( embeddableClassName )
41-
) ) );
37+
final var classLoaderService = serviceRegistry.requireService( ClassLoaderService.class );
38+
valueMappings.forEach( (value, embeddableClassName) ->
39+
valueDetailsList.add( new EmbeddableDiscriminatorValueDetailsImpl( value,
40+
classLoaderService.classForName( embeddableClassName ) ) ) );
4241
return new EmbeddableDiscriminatorConverter<>(
4342
discriminatedType,
4443
domainJavaType,
@@ -56,9 +55,8 @@ public EmbeddableDiscriminatorConverter(
5655
JavaType<R> relationalJavaType,
5756
List<EmbeddableDiscriminatorValueDetailsImpl> valueMappings) {
5857
super( discriminatorName, domainJavaType, relationalJavaType );
59-
60-
this.discriminatorValueToDetailsMap = new HashMap<>( valueMappings.size() );
61-
this.embeddableClassNameToDetailsMap = new HashMap<>( valueMappings.size() );
58+
discriminatorValueToDetailsMap = new HashMap<>( valueMappings.size() );
59+
embeddableClassNameToDetailsMap = new HashMap<>( valueMappings.size() );
6260
valueMappings.forEach( valueDetails -> {
6361
discriminatorValueToDetailsMap.put( valueDetails.getValue(), valueDetails );
6462
embeddableClassNameToDetailsMap.put( valueDetails.getIndicatedEntityName(), valueDetails );
@@ -68,33 +66,29 @@ public EmbeddableDiscriminatorConverter(
6866
@Override
6967
public O toDomainValue(R relationalForm) {
7068
assert relationalForm == null || getRelationalJavaType().isInstance( relationalForm );
71-
72-
final EmbeddableDiscriminatorValueDetailsImpl matchingValueDetails = getDetailsForDiscriminatorValue( relationalForm );
69+
final var matchingValueDetails = getDetailsForDiscriminatorValue( relationalForm );
7370
if ( matchingValueDetails == null ) {
7471
throw new IllegalStateException( "Could not resolve discriminator value" );
7572
}
76-
7773
//noinspection unchecked
7874
return (O) matchingValueDetails.getEmbeddableClass();
7975
}
8076

8177
@Override
8278
public EmbeddableDiscriminatorValueDetailsImpl getDetailsForDiscriminatorValue(Object relationalValue) {
83-
final EmbeddableDiscriminatorValueDetailsImpl valueMatch = discriminatorValueToDetailsMap.get( relationalValue );
79+
final var valueMatch = discriminatorValueToDetailsMap.get( relationalValue );
8480
if ( valueMatch != null ) {
8581
return valueMatch;
8682
}
87-
8883
throw new HibernateException( "Unrecognized discriminator value: " + relationalValue );
8984
}
9085

9186
@Override
9287
public DiscriminatorValueDetails getDetailsForEntityName(String embeddableClassName) {
93-
final DiscriminatorValueDetails valueDetails = embeddableClassNameToDetailsMap.get( embeddableClassName );
88+
final var valueDetails = embeddableClassNameToDetailsMap.get( embeddableClassName );
9489
if ( valueDetails != null ) {
9590
return valueDetails;
9691
}
97-
9892
throw new AssertionFailure( "Unrecognized embeddable class: " + embeddableClassName );
9993
}
10094

@@ -105,12 +99,28 @@ public void forEachValueDetail(Consumer<DiscriminatorValueDetails> consumer) {
10599

106100
@Override
107101
public <X> X fromValueDetails(Function<DiscriminatorValueDetails, X> handler) {
108-
for ( DiscriminatorValueDetails detail : discriminatorValueToDetailsMap.values() ) {
102+
for ( var detail : discriminatorValueToDetailsMap.values() ) {
109103
final X result = handler.apply( detail );
110104
if ( result != null ) {
111105
return result;
112106
}
113107
}
114108
return null;
115109
}
110+
111+
@Override
112+
protected String getEntityName(O domainForm) {
113+
if ( domainForm == null ) {
114+
return null;
115+
}
116+
else if ( domainForm instanceof Class<?> clazz ) {
117+
return clazz.getName();
118+
}
119+
else if ( domainForm instanceof String name ) {
120+
return name;
121+
}
122+
else {
123+
throw new IllegalArgumentException( "Illegal discriminator value: " + domainForm );
124+
}
125+
}
116126
}

hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectablePath.java

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
import java.util.Objects;
99

1010
import org.hibernate.Incubating;
11-
import org.hibernate.internal.util.StringHelper;
1211
import org.hibernate.spi.DotIdentifierSequence;
1312

13+
import static org.hibernate.internal.util.StringHelper.split;
14+
1415
/**
1516
* The path for a selectable.
1617
*
@@ -38,16 +39,18 @@ public static SelectablePath parse(String path) {
3839
if ( path == null || path.isEmpty() ) {
3940
return null;
4041
}
41-
final String[] parts = StringHelper.split( ".", path );
42-
SelectablePath selectablePath = new SelectablePath( parts[0] );
43-
for ( int i = 1; i < parts.length; i++ ) {
44-
selectablePath = selectablePath.append( parts[i] );
42+
else {
43+
final var parts = split( ".", path );
44+
var selectablePath = new SelectablePath( parts[0] );
45+
for ( int i = 1; i < parts.length; i++ ) {
46+
selectablePath = selectablePath.append( parts[i] );
47+
}
48+
return selectablePath;
4549
}
46-
return selectablePath;
4750
}
4851

4952
public SelectablePath[] getParts() {
50-
final SelectablePath[] array = new SelectablePath[index + 1];
53+
final var array = new SelectablePath[index + 1];
5154
parts( array );
5255
return array;
5356
}
@@ -60,7 +63,7 @@ private void parts(SelectablePath[] array) {
6063
}
6164

6265
public SelectablePath[] relativize(SelectablePath basePath) {
63-
final SelectablePath[] array = new SelectablePath[index - basePath.index];
66+
final var array = new SelectablePath[index - basePath.index];
6467
relativize( array, basePath );
6568
return array;
6669
}
@@ -104,9 +107,9 @@ public String getFullPath() {
104107

105108
@Override
106109
public String toString() {
107-
final StringBuilder sb = new StringBuilder( name.length() * index );
108-
toString( sb );
109-
return sb.toString();
110+
final var string = new StringBuilder( name.length() * index );
111+
toString( string );
112+
return string.toString();
110113
}
111114

112115
private void toString(StringBuilder sb) {

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

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.function.Consumer;
2121
import java.util.function.Function;
2222

23+
import static org.hibernate.Hibernate.unproxy;
2324
import static org.hibernate.internal.util.collections.CollectionHelper.concurrentMap;
2425
import static org.hibernate.persister.entity.DiscriminatorHelper.NOT_NULL_DISCRIMINATOR;
2526
import static org.hibernate.persister.entity.DiscriminatorHelper.NULL_DISCRIMINATOR;
@@ -100,17 +101,8 @@ public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relation
100101
}
101102

102103
if ( relationalValue.getClass().isEnum() ) {
103-
final Object enumValue;
104-
if ( getRelationalJavaType() instanceof StringJavaType ) {
105-
enumValue = ( (Enum<?>) relationalValue ).name();
106-
}
107-
else if ( getRelationalJavaType() instanceof CharacterJavaType ) {
108-
enumValue = ( (Enum<?>) relationalValue ).name().charAt( 0 );
109-
}
110-
else {
111-
enumValue = ( (Enum<?>) relationalValue ).ordinal();
112-
}
113-
final DiscriminatorValueDetails enumMatch = detailsByValue.get( enumValue );
104+
final Object enumValue = enumValue( (Enum<?>) relationalValue );
105+
final var enumMatch = detailsByValue.get( enumValue );
114106
if ( enumMatch != null ) {
115107
return enumMatch;
116108
}
@@ -132,6 +124,19 @@ else if ( getRelationalJavaType() instanceof CharacterJavaType ) {
132124
throw new HibernateException( "Unknown discriminator value (" + discriminatorRole.getFullPath() + ") : " + relationalValue );
133125
}
134126

127+
private Object enumValue(Enum<?> relationalEnum) {
128+
final var relationalJavaType = getRelationalJavaType();
129+
if ( relationalJavaType instanceof StringJavaType ) {
130+
return relationalEnum.name();
131+
}
132+
else if ( relationalJavaType instanceof CharacterJavaType ) {
133+
return relationalEnum.name().charAt( 0 );
134+
}
135+
else {
136+
return relationalEnum.ordinal();
137+
}
138+
}
139+
135140
@Override
136141
public DiscriminatorValueDetails getDetailsForEntityName(String entityName) {
137142
final var existing = detailsByEntityName.get( entityName );
@@ -168,4 +173,27 @@ public <X> X fromValueDetails(Function<DiscriminatorValueDetails, X> handler) {
168173
}
169174
return null;
170175
}
176+
177+
@Override
178+
protected String getEntityName(O domainForm) {
179+
final Class<?> entityClass;
180+
if ( domainForm == null ) {
181+
return null;
182+
}
183+
else if ( domainForm instanceof Class<?> clazz ) {
184+
entityClass = clazz;
185+
}
186+
else if ( domainForm instanceof String name ) {
187+
return name;
188+
}
189+
else {
190+
entityClass = unproxy( domainForm ).getClass();
191+
}
192+
try {
193+
return mappingMetamodel.getEntityDescriptor( entityClass ).getEntityName();
194+
}
195+
catch (IllegalArgumentException iae) {
196+
throw new IllegalArgumentException( "Illegal discriminator value: " + domainForm );
197+
}
198+
}
171199
}

hibernate-core/src/test/java/org/hibernate/orm/test/any/annotations/AnyImplicitDiscriminatorTest.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515

1616
import java.util.List;
1717

18-
import static org.junit.Assert.assertEquals;
19-
import static org.junit.Assert.assertNotNull;
20-
import static org.junit.Assert.assertTrue;
18+
import static org.junit.jupiter.api.Assertions.assertEquals;
19+
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
20+
import static org.junit.jupiter.api.Assertions.assertNotNull;
2121

2222
@DomainModel(
2323
annotatedPackageNames = "org.hibernate.orm.test.any.annotations",
@@ -244,7 +244,7 @@ public void testDefaultAnyAssociation(SessionFactoryScope scope) {
244244
final ImplicitPropertySet result = query.setParameter( "name", "string" ).uniqueResult();
245245
assertNotNull( result );
246246
assertNotNull( result.getSomeProperty() );
247-
assertTrue( result.getSomeProperty() instanceof StringProperty );
247+
assertInstanceOf( StringProperty.class, result.getSomeProperty() );
248248
assertEquals( "Alex", result.getSomeProperty().asString() );
249249
assertNotNull( result.getGeneralProperties() );
250250
assertEquals( 1, result.getGeneralProperties().size() );
@@ -255,7 +255,7 @@ public void testDefaultAnyAssociation(SessionFactoryScope scope) {
255255
final ImplicitPropertySet result = query.setParameter( "name", "integer" ).uniqueResult();
256256
assertNotNull( result );
257257
assertNotNull( result.getSomeProperty() );
258-
assertTrue( result.getSomeProperty() instanceof IntegerProperty );
258+
assertInstanceOf( IntegerProperty.class, result.getSomeProperty() );
259259
assertEquals( "33", result.getSomeProperty().asString() );
260260
assertNotNull( result.getGeneralProperties() );
261261
assertEquals( 1, result.getGeneralProperties().size() );
@@ -279,12 +279,12 @@ public void testManyToAnyWithMap(SessionFactoryScope scope) {
279279

280280
Property property = actualMap.getProperties().get( "name" );
281281
assertNotNull( property );
282-
assertTrue( property instanceof StringProperty );
282+
assertInstanceOf( StringProperty.class, property );
283283
assertEquals( "Alex", property.asString() );
284284

285285
property = actualMap.getProperties().get( "age" );
286286
assertNotNull( property );
287-
assertTrue( property instanceof IntegerProperty );
287+
assertInstanceOf( IntegerProperty.class, property );
288288
assertEquals( "33", property.asString() );
289289
}
290290
);
@@ -307,7 +307,7 @@ public void testManyToAnyWithMap(SessionFactoryScope scope) {
307307

308308
Property property = actualList.getSomeProperty();
309309
assertNotNull( property );
310-
assertTrue( property instanceof LongProperty );
310+
assertInstanceOf( LongProperty.class, property );
311311
assertEquals( "121", property.asString() );
312312

313313
assertEquals( "Alex", actualList.getGeneralProperties().get( 0 )
@@ -336,7 +336,7 @@ public void testFetchEager(SessionFactoryScope scope) {
336336
}
337337
);
338338

339-
assertTrue( result.getSomeProperty() instanceof StringProperty );
339+
assertInstanceOf( StringProperty.class, result.getSomeProperty() );
340340
assertEquals( "Alex", result.getSomeProperty().asString() );
341341
}
342342

hibernate-core/src/test/java/org/hibernate/orm/test/hql/HQLTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2194,6 +2194,24 @@ public void test_hql_entity_type_exp_example_2() {
21942194
});
21952195
}
21962196

2197+
@Test
2198+
public void test_hql_entity_type_exp_example_3() {
2199+
doInJPA(this::entityManagerFactory, entityManager -> {
2200+
//tag::hql-entity-type-exp-example[]
2201+
2202+
// using a parameter instead of a literal entity type
2203+
List<Payment> payments = entityManager.createQuery(
2204+
"select p " +
2205+
"from Payment p " +
2206+
"where type(p) = type(:instance)",
2207+
Payment.class)
2208+
.setParameter("instance", new WireTransferPayment())
2209+
.getResultList();
2210+
//end::hql-entity-type-exp-example[]
2211+
assertEquals(1, payments.size());
2212+
});
2213+
}
2214+
21972215
@Test
21982216
public void test_simple_case_expressions_example_1() {
21992217
doInJPA(this::entityManagerFactory, entityManager -> {

0 commit comments

Comments
 (0)