diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/MappingMetamodel.java b/hibernate-core/src/main/java/org/hibernate/metamodel/MappingMetamodel.java index f939e38819d3..513c81a1a09a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/MappingMetamodel.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/MappingMetamodel.java @@ -78,14 +78,14 @@ public interface MappingMetamodel extends Metamodel { /** * Get an entity mapping descriptor based on its Class. * - * @throws IllegalArgumentException if the name does not refer to an entity + * @throws IllegalArgumentException if the class is not an entity class * * @see #findEntityDescriptor */ EntityPersister getEntityDescriptor(Class entityJavaType); /** - * Find an entity mapping descriptor based on its Hibernate entity-name. + * Find an entity mapping descriptor based on its Hibernate entity name. * * @apiNote Returns {@code null} rather than throwing exception */ diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatorConverter.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatorConverter.java index 160a12abce60..e9c24d6c58ff 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatorConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatorConverter.java @@ -50,13 +50,12 @@ public DiscriminatorValueDetails getDetailsForRelationalForm(R relationalForm) { @Override public O toDomainValue(R relationalForm) { assert relationalForm == null || relationalJavaType.isInstance( relationalForm ); - - final DiscriminatorValueDetails matchingValueDetails = getDetailsForRelationalForm( relationalForm ); + final var matchingValueDetails = getDetailsForRelationalForm( relationalForm ); if ( matchingValueDetails == null ) { throw new IllegalStateException( "Could not resolve discriminator value" ); } - final EntityMappingType indicatedEntity = matchingValueDetails.getIndicatedEntity(); + final var indicatedEntity = matchingValueDetails.getIndicatedEntity(); //noinspection unchecked return indicatedEntity.getRepresentationStrategy().getMode() == RepresentationMode.POJO && indicatedEntity.getEntityName().equals( indicatedEntity.getJavaType().getJavaTypeClass().getName() ) @@ -66,25 +65,19 @@ public O toDomainValue(R relationalForm) { @Override public R toRelationalValue(O domainForm) { - final String entityName; - if ( domainForm == null ) { + final String entityName = getEntityName( domainForm ); + if ( entityName == null ) { return null; } - else if ( domainForm instanceof Class clazz ) { - entityName = clazz.getName(); - } - else if ( domainForm instanceof String name ) { - entityName = name; - } else { - throw new IllegalArgumentException( "Illegal discriminator value: " + domainForm ); + final var discriminatorValueDetails = getDetailsForEntityName( entityName ); + //noinspection unchecked + return (R) discriminatorValueDetails.getValue(); } - - final DiscriminatorValueDetails discriminatorValueDetails = getDetailsForEntityName( entityName ); - //noinspection unchecked - return (R) discriminatorValueDetails.getValue(); } + protected abstract String getEntityName(O domainForm); + public abstract DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relationalValue); public abstract DiscriminatorValueDetails getDetailsForEntityName(String entityName); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableDiscriminatorConverter.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableDiscriminatorConverter.java index 51201c31b1b7..d5012d78c360 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableDiscriminatorConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableDiscriminatorConverter.java @@ -34,11 +34,10 @@ public static EmbeddableDiscriminatorConverter fromValueMappings( Map valueMappings, ServiceRegistry serviceRegistry) { final List valueDetailsList = new ArrayList<>( valueMappings.size() ); - final ClassLoaderService cls = serviceRegistry.requireService( ClassLoaderService.class ); - valueMappings.forEach( (value, embeddableClassName) -> valueDetailsList.add( new EmbeddableDiscriminatorValueDetailsImpl( - value, - cls.classForName( embeddableClassName ) - ) ) ); + final var classLoaderService = serviceRegistry.requireService( ClassLoaderService.class ); + valueMappings.forEach( (value, embeddableClassName) -> + valueDetailsList.add( new EmbeddableDiscriminatorValueDetailsImpl( value, + classLoaderService.classForName( embeddableClassName ) ) ) ); return new EmbeddableDiscriminatorConverter<>( discriminatedType, domainJavaType, @@ -56,9 +55,8 @@ public EmbeddableDiscriminatorConverter( JavaType relationalJavaType, List valueMappings) { super( discriminatorName, domainJavaType, relationalJavaType ); - - this.discriminatorValueToDetailsMap = new HashMap<>( valueMappings.size() ); - this.embeddableClassNameToDetailsMap = new HashMap<>( valueMappings.size() ); + discriminatorValueToDetailsMap = new HashMap<>( valueMappings.size() ); + embeddableClassNameToDetailsMap = new HashMap<>( valueMappings.size() ); valueMappings.forEach( valueDetails -> { discriminatorValueToDetailsMap.put( valueDetails.getValue(), valueDetails ); embeddableClassNameToDetailsMap.put( valueDetails.getIndicatedEntityName(), valueDetails ); @@ -68,33 +66,29 @@ public EmbeddableDiscriminatorConverter( @Override public O toDomainValue(R relationalForm) { assert relationalForm == null || getRelationalJavaType().isInstance( relationalForm ); - - final EmbeddableDiscriminatorValueDetailsImpl matchingValueDetails = getDetailsForDiscriminatorValue( relationalForm ); + final var matchingValueDetails = getDetailsForDiscriminatorValue( relationalForm ); if ( matchingValueDetails == null ) { throw new IllegalStateException( "Could not resolve discriminator value" ); } - //noinspection unchecked return (O) matchingValueDetails.getEmbeddableClass(); } @Override public EmbeddableDiscriminatorValueDetailsImpl getDetailsForDiscriminatorValue(Object relationalValue) { - final EmbeddableDiscriminatorValueDetailsImpl valueMatch = discriminatorValueToDetailsMap.get( relationalValue ); + final var valueMatch = discriminatorValueToDetailsMap.get( relationalValue ); if ( valueMatch != null ) { return valueMatch; } - throw new HibernateException( "Unrecognized discriminator value: " + relationalValue ); } @Override public DiscriminatorValueDetails getDetailsForEntityName(String embeddableClassName) { - final DiscriminatorValueDetails valueDetails = embeddableClassNameToDetailsMap.get( embeddableClassName ); + final var valueDetails = embeddableClassNameToDetailsMap.get( embeddableClassName ); if ( valueDetails != null ) { return valueDetails; } - throw new AssertionFailure( "Unrecognized embeddable class: " + embeddableClassName ); } @@ -105,7 +99,7 @@ public void forEachValueDetail(Consumer consumer) { @Override public X fromValueDetails(Function handler) { - for ( DiscriminatorValueDetails detail : discriminatorValueToDetailsMap.values() ) { + for ( var detail : discriminatorValueToDetailsMap.values() ) { final X result = handler.apply( detail ); if ( result != null ) { return result; @@ -113,4 +107,20 @@ public X fromValueDetails(Function handler) { } return null; } + + @Override + protected String getEntityName(O domainForm) { + if ( domainForm == null ) { + return null; + } + else if ( domainForm instanceof Class clazz ) { + return clazz.getName(); + } + else if ( domainForm instanceof String name ) { + return name; + } + else { + throw new IllegalArgumentException( "Illegal discriminator value: " + domainForm ); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectablePath.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectablePath.java index 6a4ff9885a5d..df31e93a8c25 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectablePath.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/SelectablePath.java @@ -8,9 +8,10 @@ import java.util.Objects; import org.hibernate.Incubating; -import org.hibernate.internal.util.StringHelper; import org.hibernate.spi.DotIdentifierSequence; +import static org.hibernate.internal.util.StringHelper.split; + /** * The path for a selectable. * @@ -38,16 +39,18 @@ public static SelectablePath parse(String path) { if ( path == null || path.isEmpty() ) { return null; } - final String[] parts = StringHelper.split( ".", path ); - SelectablePath selectablePath = new SelectablePath( parts[0] ); - for ( int i = 1; i < parts.length; i++ ) { - selectablePath = selectablePath.append( parts[i] ); + else { + final var parts = split( ".", path ); + var selectablePath = new SelectablePath( parts[0] ); + for ( int i = 1; i < parts.length; i++ ) { + selectablePath = selectablePath.append( parts[i] ); + } + return selectablePath; } - return selectablePath; } public SelectablePath[] getParts() { - final SelectablePath[] array = new SelectablePath[index + 1]; + final var array = new SelectablePath[index + 1]; parts( array ); return array; } @@ -60,7 +63,7 @@ private void parts(SelectablePath[] array) { } public SelectablePath[] relativize(SelectablePath basePath) { - final SelectablePath[] array = new SelectablePath[index - basePath.index]; + final var array = new SelectablePath[index - basePath.index]; relativize( array, basePath ); return array; } @@ -104,9 +107,9 @@ public String getFullPath() { @Override public String toString() { - final StringBuilder sb = new StringBuilder( name.length() * index ); - toString( sb ); - return sb.toString(); + final var string = new StringBuilder( name.length() * index ); + toString( string ); + return string.toString(); } private void toString(StringBuilder sb) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/UnifiedAnyDiscriminatorConverter.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/UnifiedAnyDiscriminatorConverter.java index 0b4dc5e05851..5d022bc820e8 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/UnifiedAnyDiscriminatorConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/UnifiedAnyDiscriminatorConverter.java @@ -20,6 +20,7 @@ import java.util.function.Consumer; import java.util.function.Function; +import static org.hibernate.Hibernate.unproxy; import static org.hibernate.internal.util.collections.CollectionHelper.concurrentMap; import static org.hibernate.persister.entity.DiscriminatorHelper.NOT_NULL_DISCRIMINATOR; import static org.hibernate.persister.entity.DiscriminatorHelper.NULL_DISCRIMINATOR; @@ -100,17 +101,8 @@ public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object relation } if ( relationalValue.getClass().isEnum() ) { - final Object enumValue; - if ( getRelationalJavaType() instanceof StringJavaType ) { - enumValue = ( (Enum) relationalValue ).name(); - } - else if ( getRelationalJavaType() instanceof CharacterJavaType ) { - enumValue = ( (Enum) relationalValue ).name().charAt( 0 ); - } - else { - enumValue = ( (Enum) relationalValue ).ordinal(); - } - final DiscriminatorValueDetails enumMatch = detailsByValue.get( enumValue ); + final Object enumValue = enumValue( (Enum) relationalValue ); + final var enumMatch = detailsByValue.get( enumValue ); if ( enumMatch != null ) { return enumMatch; } @@ -132,6 +124,19 @@ else if ( getRelationalJavaType() instanceof CharacterJavaType ) { throw new HibernateException( "Unknown discriminator value (" + discriminatorRole.getFullPath() + ") : " + relationalValue ); } + private Object enumValue(Enum relationalEnum) { + final var relationalJavaType = getRelationalJavaType(); + if ( relationalJavaType instanceof StringJavaType ) { + return relationalEnum.name(); + } + else if ( relationalJavaType instanceof CharacterJavaType ) { + return relationalEnum.name().charAt( 0 ); + } + else { + return relationalEnum.ordinal(); + } + } + @Override public DiscriminatorValueDetails getDetailsForEntityName(String entityName) { final var existing = detailsByEntityName.get( entityName ); @@ -168,4 +173,27 @@ public X fromValueDetails(Function handler) { } return null; } + + @Override + protected String getEntityName(O domainForm) { + final Class entityClass; + if ( domainForm == null ) { + return null; + } + else if ( domainForm instanceof Class clazz ) { + entityClass = clazz; + } + else if ( domainForm instanceof String name ) { + return name; + } + else { + entityClass = unproxy( domainForm ).getClass(); + } + try { + return mappingMetamodel.getEntityDescriptor( entityClass ).getEntityName(); + } + catch (IllegalArgumentException iae) { + throw new IllegalArgumentException( "Illegal discriminator value: " + domainForm ); + } + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/any/annotations/AnyImplicitDiscriminatorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/any/annotations/AnyImplicitDiscriminatorTest.java index 88e1f5789444..7d663596fa38 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/any/annotations/AnyImplicitDiscriminatorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/any/annotations/AnyImplicitDiscriminatorTest.java @@ -15,9 +15,9 @@ import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; @DomainModel( annotatedPackageNames = "org.hibernate.orm.test.any.annotations", @@ -244,7 +244,7 @@ public void testDefaultAnyAssociation(SessionFactoryScope scope) { final ImplicitPropertySet result = query.setParameter( "name", "string" ).uniqueResult(); assertNotNull( result ); assertNotNull( result.getSomeProperty() ); - assertTrue( result.getSomeProperty() instanceof StringProperty ); + assertInstanceOf( StringProperty.class, result.getSomeProperty() ); assertEquals( "Alex", result.getSomeProperty().asString() ); assertNotNull( result.getGeneralProperties() ); assertEquals( 1, result.getGeneralProperties().size() ); @@ -255,7 +255,7 @@ public void testDefaultAnyAssociation(SessionFactoryScope scope) { final ImplicitPropertySet result = query.setParameter( "name", "integer" ).uniqueResult(); assertNotNull( result ); assertNotNull( result.getSomeProperty() ); - assertTrue( result.getSomeProperty() instanceof IntegerProperty ); + assertInstanceOf( IntegerProperty.class, result.getSomeProperty() ); assertEquals( "33", result.getSomeProperty().asString() ); assertNotNull( result.getGeneralProperties() ); assertEquals( 1, result.getGeneralProperties().size() ); @@ -279,12 +279,12 @@ public void testManyToAnyWithMap(SessionFactoryScope scope) { Property property = actualMap.getProperties().get( "name" ); assertNotNull( property ); - assertTrue( property instanceof StringProperty ); + assertInstanceOf( StringProperty.class, property ); assertEquals( "Alex", property.asString() ); property = actualMap.getProperties().get( "age" ); assertNotNull( property ); - assertTrue( property instanceof IntegerProperty ); + assertInstanceOf( IntegerProperty.class, property ); assertEquals( "33", property.asString() ); } ); @@ -307,7 +307,7 @@ public void testManyToAnyWithMap(SessionFactoryScope scope) { Property property = actualList.getSomeProperty(); assertNotNull( property ); - assertTrue( property instanceof LongProperty ); + assertInstanceOf( LongProperty.class, property ); assertEquals( "121", property.asString() ); assertEquals( "Alex", actualList.getGeneralProperties().get( 0 ) @@ -336,7 +336,7 @@ public void testFetchEager(SessionFactoryScope scope) { } ); - assertTrue( result.getSomeProperty() instanceof StringProperty ); + assertInstanceOf( StringProperty.class, result.getSomeProperty() ); assertEquals( "Alex", result.getSomeProperty().asString() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HQLTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HQLTest.java index f7599ccb5539..94c29e613d8b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HQLTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/HQLTest.java @@ -2194,6 +2194,24 @@ public void test_hql_entity_type_exp_example_2() { }); } + @Test + public void test_hql_entity_type_exp_example_3() { + doInJPA(this::entityManagerFactory, entityManager -> { + //tag::hql-entity-type-exp-example[] + + // using a parameter instead of a literal entity type + List payments = entityManager.createQuery( + "select p " + + "from Payment p " + + "where type(p) = type(:instance)", + Payment.class) + .setParameter("instance", new WireTransferPayment()) + .getResultList(); + //end::hql-entity-type-exp-example[] + assertEquals(1, payments.size()); + }); + } + @Test public void test_simple_case_expressions_example_1() { doInJPA(this::entityManagerFactory, entityManager -> {