HHH-16783 allow implicit discriminator mappings in @Any

This commit is contained in:
Gavin 2023-06-12 18:02:45 +02:00 committed by Gavin King
parent b364a9d50a
commit 925d09528d
12 changed files with 733 additions and 21 deletions

View File

@ -11,12 +11,15 @@ import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.RepresentationMode; import org.hibernate.metamodel.RepresentationMode;
import org.hibernate.metamodel.mapping.internal.DiscriminatorValueDetailsImpl; import org.hibernate.metamodel.mapping.internal.DiscriminatorValueDetailsImpl;
import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor; import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
@ -61,7 +64,8 @@ public class DiscriminatorConverter<O,R> implements BasicValueConverter<O,R> {
role, role,
domainJavaType, domainJavaType,
underlyingJdbcMapping.getJavaTypeDescriptor(), underlyingJdbcMapping.getJavaTypeDescriptor(),
valueDetailsList valueDetailsList,
mappingMetamodel
); );
} }
@ -71,15 +75,18 @@ public class DiscriminatorConverter<O,R> implements BasicValueConverter<O,R> {
private final Map<Object, DiscriminatorValueDetails> discriminatorValueToEntityNameMap; private final Map<Object, DiscriminatorValueDetails> discriminatorValueToEntityNameMap;
private final Map<String,DiscriminatorValueDetails> entityNameToDiscriminatorValueMap; private final Map<String,DiscriminatorValueDetails> entityNameToDiscriminatorValueMap;
private final MappingMetamodelImplementor mappingMetamodel;
public DiscriminatorConverter( public DiscriminatorConverter(
NavigableRole discriminatorRole, NavigableRole discriminatorRole,
JavaType<O> domainJavaType, JavaType<O> domainJavaType,
JavaType<R> relationalJavaType, JavaType<R> relationalJavaType,
List<DiscriminatorValueDetails> valueMappings) { List<DiscriminatorValueDetails> valueMappings,
MappingMetamodelImplementor mappingMetamodel) {
this.discriminatorRole = discriminatorRole; this.discriminatorRole = discriminatorRole;
this.domainJavaType = domainJavaType; this.domainJavaType = domainJavaType;
this.relationalJavaType = relationalJavaType; this.relationalJavaType = relationalJavaType;
this.mappingMetamodel = mappingMetamodel;
this.discriminatorValueToEntityNameMap = CollectionHelper.concurrentMap( valueMappings.size() ); this.discriminatorValueToEntityNameMap = CollectionHelper.concurrentMap( valueMappings.size() );
this.entityNameToDiscriminatorValueMap = CollectionHelper.concurrentMap( valueMappings.size() ); this.entityNameToDiscriminatorValueMap = CollectionHelper.concurrentMap( valueMappings.size() );
@ -125,7 +132,17 @@ public class DiscriminatorConverter<O,R> implements BasicValueConverter<O,R> {
} }
public DiscriminatorValueDetails getDetailsForEntityName(String entityName) { public DiscriminatorValueDetails getDetailsForEntityName(String entityName) {
return entityNameToDiscriminatorValueMap.get( entityName ); DiscriminatorValueDetails valueDetails = entityNameToDiscriminatorValueMap.get( entityName );
if ( valueDetails!= null) {
return valueDetails;
}
EntityPersister persister = mappingMetamodel.findEntityDescriptor( entityName );
if ( persister!= null ) {
return new DiscriminatorValueDetailsImpl( entityName, persister );
}
throw new AssertionFailure( "Unrecognized entity name: " + entityName );
} }
public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object value) { public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object value) {
@ -138,7 +155,20 @@ public class DiscriminatorConverter<O,R> implements BasicValueConverter<O,R> {
return valueMatch; return valueMatch;
} }
return discriminatorValueToEntityNameMap.get( NOT_NULL_DISCRIMINATOR ); final DiscriminatorValueDetails notNullMatch = discriminatorValueToEntityNameMap.get( NOT_NULL_DISCRIMINATOR );
if ( notNullMatch != null ) {
return notNullMatch;
}
if ( value instanceof String ) {
String entityName = mappingMetamodel.getImportedName( (String) value );
EntityPersister persister = mappingMetamodel.findEntityDescriptor( entityName );
if ( persister!= null ) {
return new DiscriminatorValueDetailsImpl( entityName, persister );
}
}
throw new HibernateException( "Unrecognized discriminator value: " + value );
} }
@Override @Override

View File

@ -41,7 +41,7 @@ import org.hibernate.type.descriptor.java.JavaType;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class AnyKeyPart implements BasicValuedModelPart, FetchOptions { public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
public static final String ROLE_NAME = "{key}"; public static final String KEY_NAME = "{key}";
private final NavigableRole navigableRole; private final NavigableRole navigableRole;
private final String table; private final String table;
@ -163,7 +163,7 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
@Override @Override
public String getPartName() { public String getPartName() {
return ROLE_NAME; return KEY_NAME;
} }
@Override @Override

View File

@ -101,7 +101,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
final BasicType<?> keyType = (BasicType<?>) anyType.getIdentifierType(); final BasicType<?> keyType = (BasicType<?>) anyType.getIdentifierType();
final BasicValuedModelPart keyPart = new AnyKeyPart( final BasicValuedModelPart keyPart = new AnyKeyPart(
containerRole.append( AnyKeyPart.ROLE_NAME), containerRole.append( AnyKeyPart.KEY_NAME ),
declaringModelPart, declaringModelPart,
tableName, tableName,
keyColumn.getText( dialect ), keyColumn.getText( dialect ),
@ -245,7 +245,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
return getDiscriminatorPart(); return getDiscriminatorPart();
} }
if ( AnyKeyPart.ROLE_NAME.equals( name ) ) { if ( AnyKeyPart.KEY_NAME.equals( name ) ) {
return getKeyPart(); return getKeyPart();
} }
@ -278,7 +278,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption
} }
if ( identifierMapping instanceof SingleAttributeIdentifierMapping ) { if ( identifierMapping instanceof SingleAttributeIdentifierMapping ) {
final String idAttrName = ( (SingleAttributeIdentifierMapping) identifierMapping ).getAttributeName(); final String idAttrName = identifierMapping.getAttributeName();
if ( idAttrName.equals( name ) ) { if ( idAttrName.equals( name ) ) {
return getKeyPart(); return getKeyPart();
} }

View File

@ -7,6 +7,8 @@
package org.hibernate.metamodel.model.domain.internal; package org.hibernate.metamodel.model.domain.internal;
import org.hibernate.metamodel.UnsupportedMappingException; import org.hibernate.metamodel.UnsupportedMappingException;
import org.hibernate.metamodel.mapping.internal.AnyDiscriminatorPart;
import org.hibernate.metamodel.mapping.internal.AnyKeyPart;
import org.hibernate.metamodel.model.domain.AnyMappingDomainType; import org.hibernate.metamodel.model.domain.AnyMappingDomainType;
import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
@ -30,7 +32,7 @@ public class AnyMappingSqmPathSource<J> extends AbstractSqmPathSource<J> {
BindableType jpaBindableType) { BindableType jpaBindableType) {
super( localPathName, pathModel, domainType, jpaBindableType ); super( localPathName, pathModel, domainType, jpaBindableType );
keyPathSource = new BasicSqmPathSource<>( keyPathSource = new BasicSqmPathSource<>(
"id", AnyKeyPart.KEY_NAME,
null, null,
(BasicDomainType<?>) domainType.getKeyType(), (BasicDomainType<?>) domainType.getKeyType(),
domainType.getKeyType().getExpressibleJavaType(), domainType.getKeyType().getExpressibleJavaType(),
@ -52,14 +54,16 @@ public class AnyMappingSqmPathSource<J> extends AbstractSqmPathSource<J> {
@Override @Override
public SqmPathSource<?> findSubPathSource(String name) { public SqmPathSource<?> findSubPathSource(String name) {
if ( "id".equals( name ) ) { switch (name) {
return keyPathSource; case "id": // deprecated HQL .id syntax
case AnyKeyPart.KEY_NAME: // standard id() function
return keyPathSource;
case "class": // deprecated HQL .class syntax
case AnyDiscriminatorPart.ROLE_NAME: // standard type() function
return discriminatorPathSource;
default:
throw new UnsupportedMappingException( "Only the key and discriminator parts of an '@Any' mapping may be dereferenced" );
} }
else if("{discriminator}".equals( name )) {
return discriminatorPathSource;
}
throw new UnsupportedMappingException( "De-referencing parts of an ANY mapping, other than the key, is not supported" );
} }
@Override @Override

View File

@ -44,6 +44,7 @@ import org.hibernate.internal.util.collections.Stack;
import org.hibernate.internal.util.collections.StandardStack; import org.hibernate.internal.util.collections.StandardStack;
import org.hibernate.metamodel.CollectionClassification; import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.internal.AnyKeyPart;
import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
@ -2793,7 +2794,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
return sqmPath.get( identifierDescriptor.getPathName() ); return sqmPath.get( identifierDescriptor.getPathName() );
} }
else if ( sqmPath instanceof SqmAnyValuedSimplePath<?> ) { else if ( sqmPath instanceof SqmAnyValuedSimplePath<?> ) {
return sqmPath.resolvePathPart("id", true, getCurrentProcessingState().getCreationState() ); return sqmPath.resolvePathPart( AnyKeyPart.KEY_NAME, true, getCurrentProcessingState().getCreationState() );
} }
else { else {
throw new SemanticException( "Path does not resolve to an entity type '" + sqmPath.getNavigablePath() + "'" ); throw new SemanticException( "Path does not resolve to an entity type '" + sqmPath.getNavigablePath() + "'" );

View File

@ -121,7 +121,7 @@ public class BasicValuedPathInterpretation<T> extends AbstractSqmPathInterpretat
} }
} }
throw new SemanticException( "`" + sqmPath.getNavigablePath() + "` did not reference a known model part" ); throw new SemanticException( "'" + sqmPath.getNavigablePath() + "' did not reference a known model part" );
} }
final TableReference tableReference = tableGroup.resolveTableReference( final TableReference tableReference = tableGroup.resolveTableReference(

View File

@ -0,0 +1,357 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.any.annotations;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@DomainModel(
annotatedPackageNames = "org.hibernate.orm.test.any.annotations",
annotatedClasses = {
StringProperty.class,
IntegerProperty.class,
LongProperty.class,
ImplicitPropertySet.class,
ImplicitPropertyMap.class,
ImplicitPropertyList.class,
ImplicitPropertyHolder.class,
CharProperty.class
}
)
@SessionFactory
public class AnyImplicitDiscriminatorTest {
@BeforeEach
public void createTestData(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
{
final ImplicitPropertySet set1 = new ImplicitPropertySet( "string" );
final Property property = new StringProperty( "name", "Alex" );
set1.setSomeProperty( property );
set1.addGeneralProperty( property );
session.persist( set1 );
final ImplicitPropertySet set2 = new ImplicitPropertySet( "integer" );
final Property property2 = new IntegerProperty( "age", 33 );
set2.setSomeProperty( property2 );
set2.addGeneralProperty( property2 );
session.persist( set2 );
}
{
final ImplicitPropertyMap map = new ImplicitPropertyMap( "sample" );
map.getProperties().put( "name", new StringProperty( "name", "Alex" ) );
map.getProperties().put( "age", new IntegerProperty( "age", 33 ) );
session.persist( map );
}
{
StringProperty nameProperty = new StringProperty( "name", "John Doe" );
session.persist( nameProperty );
ImplicitPropertyHolder namePropertyHolder = new ImplicitPropertyHolder();
namePropertyHolder.setId( 1 );
namePropertyHolder.setProperty( nameProperty );
session.persist( namePropertyHolder );
final IntegerProperty ageProperty = new IntegerProperty( "age", 23 );
session.persist( ageProperty );
ImplicitPropertyHolder agePropertyHolder = new ImplicitPropertyHolder();
agePropertyHolder.setId( 2 );
agePropertyHolder.setProperty( ageProperty );
session.persist( agePropertyHolder );
}
{
final ImplicitPropertyList list = new ImplicitPropertyList( "sample" );
final StringProperty stringProperty = new StringProperty( "name", "Alex" );
final IntegerProperty integerProperty = new IntegerProperty( "age", 33 );
final LongProperty longProperty = new LongProperty( "distance", 121L );
final CharProperty charProp = new CharProperty( "Est", 'E' );
list.setSomeProperty( longProperty );
list.addGeneralProperty( stringProperty );
list.addGeneralProperty( integerProperty );
list.addGeneralProperty( longProperty );
list.addGeneralProperty( charProp );
session.persist( list );
}
}
);
}
@AfterEach
public void dropTestData(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createMutationQuery( "delete StringProperty" ).executeUpdate();
session.createMutationQuery( "delete IntegerProperty" ).executeUpdate();
session.createMutationQuery( "delete LongProperty" ).executeUpdate();
session.createMutationQuery( "delete CharProperty" ).executeUpdate();
session.createMutationQuery( "delete ImplicitPropertyHolder" ).executeUpdate();
session.createMutationQuery( "delete ImplicitPropertyList" ).executeUpdate();
session.createMutationQuery( "delete ImplicitPropertyMap" ).executeUpdate();
session.createMutationQuery( "delete ImplicitPropertySet" ).executeUpdate();
}
);
}
@Test
@TestForIssue( jiraKey = "HHH-16732")
public void testHqlAnyIdQuery(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
List<PropertySet> list1 = session.createQuery(
"select p from ImplicitPropertyHolder p where id(p.property) = 666",
PropertySet.class ).list();
assertEquals( 0, list1.size() );
List<PropertySet> list2 = session.createQuery(
"select p from ImplicitPropertyHolder p where type(p.property) = IntegerProperty",
PropertySet.class ).list();
assertEquals( 1, list2.size() );
}
);
}
@Test
@TestForIssue( jiraKey = "HHH-15323")
public void testHqlCollectionTypeQuery(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
List<ImplicitPropertySet> propertySets = session.createQuery(
"select p from ImplicitPropertySet p where type(p.generalProperties) = IntegerProperty ",
ImplicitPropertySet.class ).list();
assertEquals( 1, propertySets.size() );
ImplicitPropertySet propertySet = propertySets.get( 0 );
assertEquals( 1, propertySet.getGeneralProperties().size() );
assertEquals( "age", propertySet.getGeneralProperties().get( 0 ).getName() );
propertySets = session.createQuery(
"select p from ImplicitPropertySet p where type(p.generalProperties) = StringProperty ",
ImplicitPropertySet.class ).list();
assertEquals( 1, propertySets.size() );
propertySet = propertySets.get( 0 );
assertEquals( 1, propertySet.getGeneralProperties().size() );
assertEquals( "name", propertySet.getGeneralProperties().get( 0 ).getName() );
}
);
}
@Test
@TestForIssue( jiraKey = "HHH-15442")
public void testHqlCollectionTypeQueryWithParameters(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
List<ImplicitPropertySet> propertySets = session.createQuery(
"select p from ImplicitPropertySet p where type(p.generalProperties) = :prop ",
ImplicitPropertySet.class )
.setParameter( "prop", IntegerProperty.class)
.list();
assertEquals( 1, propertySets.size() );
ImplicitPropertySet propertySet = propertySets.get( 0 );
assertEquals( 1, propertySet.getGeneralProperties().size() );
assertEquals( "age", propertySet.getGeneralProperties().get( 0 ).getName() );
propertySets = session.createQuery(
"select p from ImplicitPropertySet p where type(p.generalProperties) = :prop ",
ImplicitPropertySet.class )
.setParameter( "prop", StringProperty.class)
.list();
assertEquals( 1, propertySets.size() );
propertySet = propertySets.get( 0 );
assertEquals( 1, propertySet.getGeneralProperties().size() );
assertEquals( "name", propertySet.getGeneralProperties().get( 0 ).getName() );
}
);
}
@Test
@TestForIssue( jiraKey = "HHH-15323")
public void testHqlTypeQuery(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
List<ImplicitPropertyHolder> propertyHolders = session.createQuery(
"select p from ImplicitPropertyHolder p where type(p.property) = IntegerProperty ",
ImplicitPropertyHolder.class ).list();
assertEquals( 1, propertyHolders.size() );
assertEquals( "age", propertyHolders.get( 0 ).getProperty().getName() );
propertyHolders = session.createQuery(
"select p from ImplicitPropertyHolder p where type(p.property) = StringProperty ",
ImplicitPropertyHolder.class ).list();
assertEquals( 1, propertyHolders.size() );
assertEquals( "name", propertyHolders.get( 0 ).getProperty().getName() );
}
);
}
@Test
@TestForIssue( jiraKey = "HHH-15442")
public void testHqlTypeQueryWithParameter(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
List<ImplicitPropertyHolder> propertyHolders = session.createQuery(
"select p from ImplicitPropertyHolder p where type(p.property) = :prop ",
ImplicitPropertyHolder.class )
.setParameter( "prop", IntegerProperty.class)
.list();
assertEquals( 1, propertyHolders.size() );
assertEquals( "age", propertyHolders.get( 0 ).getProperty().getName() );
propertyHolders = session.createQuery(
"select p from ImplicitPropertyHolder p where type(p.property) = :prop ",
ImplicitPropertyHolder.class )
.setParameter( "prop", StringProperty.class)
.list();
assertEquals( 1, propertyHolders.size() );
assertEquals( "name", propertyHolders.get( 0 ).getProperty().getName() );
}
);
}
@Test
public void testDefaultAnyAssociation(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<ImplicitPropertySet> query = session.createQuery(
"select s from ImplicitPropertySet s where name = :name",
ImplicitPropertySet.class
);
{
final ImplicitPropertySet result = query.setParameter( "name", "string" ).uniqueResult();
assertNotNull( result );
assertNotNull( result.getSomeProperty() );
assertTrue( result.getSomeProperty() instanceof StringProperty );
assertEquals( "Alex", result.getSomeProperty().asString() );
assertNotNull( result.getGeneralProperties() );
assertEquals( 1, result.getGeneralProperties().size() );
assertEquals( "Alex", result.getGeneralProperties().get( 0 ).asString() );
}
{
final ImplicitPropertySet result = query.setParameter( "name", "integer" ).uniqueResult();
assertNotNull( result );
assertNotNull( result.getSomeProperty() );
assertTrue( result.getSomeProperty() instanceof IntegerProperty );
assertEquals( "33", result.getSomeProperty().asString() );
assertNotNull( result.getGeneralProperties() );
assertEquals( 1, result.getGeneralProperties().size() );
assertEquals( "33", result.getGeneralProperties().get( 0 ).asString() );
}
}
);
}
@Test
public void testManyToAnyWithMap(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final ImplicitPropertyMap actualMap = session
.createQuery( "SELECT m FROM ImplicitPropertyMap m WHERE m.name = :name", ImplicitPropertyMap.class )
.setParameter( "name", "sample" )
.uniqueResult();
assertNotNull( actualMap );
assertNotNull( actualMap.getProperties() );
Property property = actualMap.getProperties().get( "name" );
assertNotNull( property );
assertTrue( property instanceof StringProperty );
assertEquals( "Alex", property.asString() );
property = actualMap.getProperties().get( "age" );
assertNotNull( property );
assertTrue( property instanceof IntegerProperty );
assertEquals( "33", property.asString() );
}
);
}
@Test
public void
testMetaDataUseWithManyToAny(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
//noinspection unchecked
final ImplicitPropertyList<Property> actualList = session
.createQuery( "SELECT l FROM ImplicitPropertyList l WHERE l.name = :name", ImplicitPropertyList.class )
.setParameter( "name", "sample" )
.uniqueResult();
assertNotNull( actualList );
assertNotNull( actualList.getGeneralProperties() );
assertEquals( 4, actualList.getGeneralProperties().size() );
Property property = actualList.getSomeProperty();
assertNotNull( property );
assertTrue( property instanceof LongProperty );
assertEquals( "121", property.asString() );
assertEquals( "Alex", actualList.getGeneralProperties().get( 0 )
.asString() );
assertEquals( "33", actualList.getGeneralProperties().get( 1 ).asString() );
assertEquals( "121", actualList.getGeneralProperties().get( 2 ).asString() );
assertEquals( "E", actualList.getGeneralProperties().get( 3 ).asString() );
}
);
}
@Test
public void testFetchEager(SessionFactoryScope scope) {
final ImplicitPropertySet result = scope.fromTransaction(
session -> {
final ImplicitPropertySet localResult = session.createQuery(
"select s from ImplicitPropertySet s where name = :name",
ImplicitPropertySet.class
)
.setParameter( "name", "string" )
.getSingleResult();
assertNotNull( localResult );
assertNotNull( localResult.getSomeProperty() );
return localResult;
}
);
assertTrue( result.getSomeProperty() instanceof StringProperty );
assertEquals( "Alex", result.getSomeProperty().asString() );
}
}

View File

@ -0,0 +1,45 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.orm.test.any.annotations;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.Table;
import org.hibernate.annotations.Any;
import org.hibernate.annotations.AnyKeyJavaClass;
@Entity
@Table(name = "property_holder")
public class ImplicitPropertyHolder {
@Id
private Integer id;
@Any
@AnyKeyJavaClass(Integer.class)
@Column(name = "property_type")
@JoinColumn(name = "property_id")
private Property property;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Property getProperty() {
return property;
}
public void setProperty(Property property) {
this.property = property;
}
}

View File

@ -0,0 +1,101 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.any.annotations;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable;
import jakarta.persistence.OrderColumn;
import jakarta.persistence.Table;
import org.hibernate.annotations.Any;
import org.hibernate.annotations.AnyDiscriminatorValue;
import org.hibernate.annotations.AnyKeyJavaClass;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.ManyToAny;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table( name = "property_list" )
public class ImplicitPropertyList<T extends Property> {
private Integer id;
private String name;
private T someProperty;
private List<T> generalProperties = new ArrayList<T>();
public ImplicitPropertyList() {
super();
}
public ImplicitPropertyList(String name) {
this.name = name;
}
@ManyToAny
@Column(name = "property_type")
@AnyKeyJavaClass( Integer.class )
@Cascade( CascadeType.ALL )
@JoinTable(name = "list_properties",
joinColumns = @JoinColumn(name = "obj_id"),
inverseJoinColumns = @JoinColumn(name = "property_id")
)
@OrderColumn(name = "prop_index")
public List<T> getGeneralProperties() {
return generalProperties;
}
public void setGeneralProperties(List<T> generalProperties) {
this.generalProperties = generalProperties;
}
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Any
@Column(name = "property_type")
@JoinColumn(name = "property_id")
@AnyKeyJavaClass( Integer.class )
@AnyDiscriminatorValue( discriminator = "C", entity = CharProperty.class )
@AnyDiscriminatorValue( discriminator = "I", entity = IntegerProperty.class)
@AnyDiscriminatorValue( discriminator = "S", entity = StringProperty.class)
@AnyDiscriminatorValue( discriminator = "L", entity = LongProperty.class)
@Cascade( CascadeType.ALL )
public T getSomeProperty() {
return someProperty;
}
public void setSomeProperty(T someProperty) {
this.someProperty = someProperty;
}
public void addGeneralProperty(T property) {
this.generalProperties.add( property );
}
}

View File

@ -0,0 +1,77 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.any.annotations;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable;
import jakarta.persistence.MapKeyColumn;
import jakarta.persistence.Table;
import org.hibernate.annotations.AnyDiscriminatorValue;
import org.hibernate.annotations.AnyKeyJavaClass;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.ManyToAny;
import java.util.HashMap;
import java.util.Map;
@Entity
@Table( name = "property_map" )
public class ImplicitPropertyMap {
private Integer id;
private String name;
private Map<String, Property> properties = new HashMap<String, Property>();
public ImplicitPropertyMap(String name) {
this.name = name;
}
public ImplicitPropertyMap() {
super();
}
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToAny
@Column( name = "property_type" )
@AnyKeyJavaClass( Integer.class )
@Cascade( org.hibernate.annotations.CascadeType.ALL )
@JoinTable(
name = "map_properties",
joinColumns = @JoinColumn( name = "map_id" ),
inverseJoinColumns = @JoinColumn( name = "property_id" ) )
@MapKeyColumn( name = "map_key", nullable = false ) //keep for legacy test
public Map<String, Property> getProperties() {
return properties;
}
public void setProperties(Map<String, Property> properties) {
this.properties = properties;
}
}

View File

@ -0,0 +1,95 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.any.annotations;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.JoinTable;
import jakarta.persistence.Table;
import org.hibernate.annotations.Any;
import org.hibernate.annotations.AnyDiscriminatorValue;
import org.hibernate.annotations.AnyKeyJavaClass;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.ManyToAny;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table( name = "property_set" )
public class ImplicitPropertySet {
private Integer id;
private String name;
private Property someProperty;
private List<Property> generalProperties = new ArrayList<Property>();
public ImplicitPropertySet() {
super();
}
public ImplicitPropertySet(String name) {
this.name = name;
}
@ManyToAny
@Column( name = "property_type" )
@AnyKeyJavaClass( Integer.class )
@Cascade( CascadeType.ALL )
@JoinTable(
name = "obj_properties",
joinColumns = @JoinColumn( name = "obj_id" ),
inverseJoinColumns = @JoinColumn( name = "property_id" ) )
public List<Property> getGeneralProperties() {
return generalProperties;
}
public void setGeneralProperties(List<Property> generalProperties) {
this.generalProperties = generalProperties;
}
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Any
@Column( name = "property_type" )
@AnyKeyJavaClass( Integer.class )
@AnyDiscriminatorValue( discriminator = "S", entity = StringProperty.class )
@AnyDiscriminatorValue( discriminator = "I", entity = IntegerProperty.class )
@Cascade( value = { CascadeType.ALL } )
@JoinColumn( name = "property_id" )
public Property getSomeProperty() {
return someProperty;
}
public void setSomeProperty(Property someProperty) {
this.someProperty = someProperty;
}
public void addGeneralProperty(Property property) {
this.generalProperties.add( property );
}
}

View File

@ -8,6 +8,7 @@ package org.hibernate.orm.test.mapping;
import java.time.Instant; import java.time.Instant;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.MappingMetamodel; import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
@ -30,6 +31,7 @@ import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
/** /**
* Tests access to {@link MappingMetamodel} as API and SPI contracts * Tests access to {@link MappingMetamodel} as API and SPI contracts
@ -96,7 +98,7 @@ public class MappingModelAccessTests {
assertThat( discriminatorMapping.resolveDiscriminatorValue( 0 ).getIndicatedEntity() ).isEqualTo( paymentMapping ); assertThat( discriminatorMapping.resolveDiscriminatorValue( 0 ).getIndicatedEntity() ).isEqualTo( paymentMapping );
assertThat( discriminatorMapping.resolveDiscriminatorValue( 1 ).getIndicatedEntity() ).isEqualTo( cashPaymentMapping ); assertThat( discriminatorMapping.resolveDiscriminatorValue( 1 ).getIndicatedEntity() ).isEqualTo( cashPaymentMapping );
assertThat( discriminatorMapping.resolveDiscriminatorValue( 2 ).getIndicatedEntity() ).isEqualTo( cardPaymentMapping ); assertThat( discriminatorMapping.resolveDiscriminatorValue( 2 ).getIndicatedEntity() ).isEqualTo( cardPaymentMapping );
assertThat( discriminatorMapping.resolveDiscriminatorValue( 3 ) ).isNull(); assertThatCode( () -> discriminatorMapping.resolveDiscriminatorValue( 3 ) ).isInstanceOf(HibernateException.class);
} }
@Test @Test
@ -126,6 +128,6 @@ public class MappingModelAccessTests {
assertThat( discriminatorMapping.resolveDiscriminatorValue( "Vendor" ).getIndicatedEntity() ).isEqualTo( vendorMapping ); assertThat( discriminatorMapping.resolveDiscriminatorValue( "Vendor" ).getIndicatedEntity() ).isEqualTo( vendorMapping );
assertThat( discriminatorMapping.resolveDiscriminatorValue( "domestic" ).getIndicatedEntity() ).isEqualTo( domesticVendorMapping ); assertThat( discriminatorMapping.resolveDiscriminatorValue( "domestic" ).getIndicatedEntity() ).isEqualTo( domesticVendorMapping );
assertThat( discriminatorMapping.resolveDiscriminatorValue( "foreign" ).getIndicatedEntity() ).isEqualTo( foreignVendorMapping ); assertThat( discriminatorMapping.resolveDiscriminatorValue( "foreign" ).getIndicatedEntity() ).isEqualTo( foreignVendorMapping );
assertThat( discriminatorMapping.resolveDiscriminatorValue( "invalid" ) ).isNull(); assertThatCode( () -> discriminatorMapping.resolveDiscriminatorValue( "invalid" ) ).isInstanceOf(HibernateException.class);
} }
} }