diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ClassPropertyHolder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ClassPropertyHolder.java index f2e8a47cd6..59d0ab5088 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ClassPropertyHolder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ClassPropertyHolder.java @@ -320,6 +320,7 @@ public class ClassPropertyHolder extends AbstractPropertyHolder { setTypeName( value, inferredData.getTypeName() ); } if ( value instanceof Component ) { + actualProperty.setGenericEmbeddable( true ); final Component component = ( (Component) value ); final Iterator propertyIterator = component.getPropertyIterator(); while ( propertyIterator.hasNext() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java index 3e0e9bcfc9..72f1ce6eba 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java @@ -57,6 +57,7 @@ public class Property implements Serializable, MetaAttributable { private java.util.Map metaAttributes; private PersistentClass persistentClass; private boolean naturalIdentifier; + private boolean genericEmbeddable; private boolean lob; private java.util.List callbackDefinitions; private String returnedClassName; @@ -417,6 +418,14 @@ public class Property implements Serializable, MetaAttributable { this.naturalIdentifier = naturalIdentifier; } + public boolean isGenericEmbeddable() { + return genericEmbeddable; + } + + public void setGenericEmbeddable(boolean genericEmbeddable) { + this.genericEmbeddable = genericEmbeddable; + } + public boolean isLob() { return lob; } @@ -473,6 +482,7 @@ public class Property implements Serializable, MetaAttributable { property.setMetaAttributes( getMetaAttributes() ); property.setPersistentClass( getPersistentClass() ); property.setNaturalIdentifier( isNaturalIdentifier() ); + property.setGeneric( isGeneric() ); property.setLob( isLob() ); property.addCallbackDefinitions( getCallbackDefinitions() ); property.setReturnedClassName( getReturnedClassName() ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java index 7e5f3f03c2..e7126d010a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java @@ -129,6 +129,7 @@ public class AttributeFactory { false, false, property.isOptional(), + property.isGenericEmbeddable(), metadataContext ); } @@ -176,6 +177,7 @@ public class AttributeFactory { (SimpleDomainType) determineSimpleType( attributeMetadata.getValueContext() ), attributeMetadata.getMember(), attributeMetadata.getAttributeClassification(), + property.isGenericEmbeddable(), context ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java index 7921cec1ab..d2ff45cd1c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java @@ -420,20 +420,26 @@ public class MetadataContext { private void applyIdMetadata(PersistentClass persistentClass, IdentifiableDomainType identifiableType) { if ( persistentClass.hasIdentifierProperty() ) { final Property declaredIdentifierProperty = persistentClass.getDeclaredIdentifierProperty(); + //noinspection rawtypes + final AttributeContainer attributeContainer = (AttributeContainer) identifiableType; if ( declaredIdentifierProperty != null ) { final SingularPersistentAttribute idAttribute = attributeFactory.buildIdAttribute( identifiableType, declaredIdentifierProperty ); - - //noinspection unchecked rawtypes - ( ( AttributeContainer) identifiableType ).getInFlightAccess().applyIdAttribute( idAttribute ); + //noinspection unchecked + attributeContainer.getInFlightAccess().applyIdAttribute( idAttribute ); } else if ( persistentClass.getIdentifier() instanceof Component && persistentClass.getIdentifierProperty() != getSuperclassIdentifier( persistentClass ) ) { // If the identifier is a generic component, we have to call buildIdAttribute anyway, // as this will create and register the EmbeddableType for the subtype - attributeFactory.buildIdAttribute( identifiableType, persistentClass.getIdentifierProperty() ); + final SingularPersistentAttribute concreteEmbeddable = attributeFactory.buildIdAttribute( + identifiableType, + persistentClass.getIdentifierProperty() + ); + //noinspection unchecked + attributeContainer.getInFlightAccess().addConcreteEmbeddableAttribute( concreteEmbeddable ); } } else { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractIdentifiableType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractIdentifiableType.java index fda777cb45..6b2ab31605 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractIdentifiableType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractIdentifiableType.java @@ -424,7 +424,8 @@ public abstract class AbstractIdentifiableType return new EmbeddedSqmPathSource<>( EntityIdentifierMapping.ROLE_LOCAL_NAME, compositeType, - Bindable.BindableType.SINGULAR_ATTRIBUTE + Bindable.BindableType.SINGULAR_ATTRIBUTE, + id.isGeneric() ); } } @@ -441,7 +442,8 @@ public abstract class AbstractIdentifiableType return new EmbeddedSqmPathSource<>( EntityIdentifierMapping.ROLE_LOCAL_NAME, idClassType, - Bindable.BindableType.SINGULAR_ATTRIBUTE + Bindable.BindableType.SINGULAR_ATTRIBUTE, + false ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java index fd0a44d5ff..6580d04c28 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/AbstractManagedType.java @@ -56,6 +56,7 @@ public abstract class AbstractManagedType private final Map> declaredSingularAttributes = new LinkedHashMap<>(); private volatile Map> declaredPluralAttributes ; + private volatile Map> declaredConcreteEmbeddedAttributes; private final List subTypes = new ArrayList<>(); @@ -464,6 +465,24 @@ public abstract class AbstractManagedType } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Generic Embeddable attributes + + @Override + public SingularPersistentAttribute findConcreteEmbeddableAttribute(String name) { + SingularPersistentAttribute attribute = findDeclaredConcreteEmbeddableAttribute( name ); + if ( attribute == null && getSuperType() != null ) { + attribute = getSuperType().findDeclaredConcreteEmbeddableAttribute( name ); + } + return attribute; + } + + @Override + public SingularPersistentAttribute findDeclaredConcreteEmbeddableAttribute(String name) { + return declaredConcreteEmbeddedAttributes == null ? null : declaredConcreteEmbeddedAttributes.get( name ); + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Bags @@ -740,6 +759,14 @@ public abstract class AbstractManagedType } } + @Override + public void addConcreteEmbeddableAttribute(SingularPersistentAttribute attribute) { + if ( declaredConcreteEmbeddedAttributes == null ) { + declaredConcreteEmbeddedAttributes = new HashMap<>(); + } + declaredConcreteEmbeddedAttributes.put( attribute.getName(), attribute ); + } + @Override public void finishUp() { inFlightAccess = null; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/ManagedDomainType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/ManagedDomainType.java index c223fbfb06..ba8ff2740f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/ManagedDomainType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/ManagedDomainType.java @@ -59,10 +59,12 @@ public interface ManagedDomainType extends SqmExpressible, DomainType, SingularPersistentAttribute findSingularAttribute(String name); PluralPersistentAttribute findPluralAttribute(String name); + SingularPersistentAttribute findConcreteEmbeddableAttribute(String name); PersistentAttribute findDeclaredAttribute(String name); SingularPersistentAttribute findDeclaredSingularAttribute(String name); PluralPersistentAttribute findDeclaredPluralAttribute(String name); + SingularPersistentAttribute findDeclaredConcreteEmbeddableAttribute(String name); SubGraphImplementor makeSubGraph(); SubGraphImplementor makeSubGraph(Class subClassType); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AttributeContainer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AttributeContainer.java index ad2b82b3ed..6a6fd807f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AttributeContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AttributeContainer.java @@ -66,6 +66,12 @@ public interface AttributeContainer { ); } + default void addConcreteEmbeddableAttribute(SingularPersistentAttribute idAttribute) { + throw new UnsupportedMappingException( + "AttributeContainer [" + getClass().getName() + "] does not generic embeddables" + ); + } + /** * Called when configuration of the type is complete */ diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddedSqmPathSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddedSqmPathSource.java index ef36d86bc7..f343a433bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddedSqmPathSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddedSqmPathSource.java @@ -7,10 +7,10 @@ package org.hibernate.metamodel.model.domain.internal; import org.hibernate.metamodel.model.domain.EmbeddableDomainType; -import org.hibernate.spi.NavigablePath; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath; import org.hibernate.query.sqm.tree.domain.SqmPath; +import org.hibernate.spi.NavigablePath; /** * @author Steve Ebersole @@ -18,12 +18,15 @@ import org.hibernate.query.sqm.tree.domain.SqmPath; public class EmbeddedSqmPathSource extends AbstractSqmPathSource implements CompositeSqmPathSource { + private final boolean isGeneric; public EmbeddedSqmPathSource( String localPathName, EmbeddableDomainType domainType, - BindableType jpaBindableType) { + BindableType jpaBindableType, + boolean isGeneric) { super( localPathName, domainType, jpaBindableType ); + this.isGeneric = isGeneric; } @Override @@ -37,6 +40,11 @@ public class EmbeddedSqmPathSource return (SqmPathSource) getSqmPathType().findAttribute( name ); } + @Override + public boolean isGeneric() { + return isGeneric; + } + @Override public SqmPath createSqmPath(SqmPath lhs, SqmPathSource intermediatePathSource) { final NavigablePath navigablePath; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java index f00206fc12..4a02e5d358 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java @@ -59,6 +59,7 @@ public class SingularAttributeImpl boolean isIdentifier, boolean isVersion, boolean isOptional, + boolean isGeneric, MetadataContext metadataContext) { super( declaringType, @@ -77,7 +78,8 @@ public class SingularAttributeImpl this.sqmPathSource = SqmMappingModelHelper.resolveSqmPathSource( name, attributeType, - BindableType.SINGULAR_ATTRIBUTE + BindableType.SINGULAR_ATTRIBUTE, + isGeneric ); } @@ -121,6 +123,11 @@ public class SingularAttributeImpl return sqmPathSource.findSubPathSource( name ); } + @Override + public boolean isGeneric() { + return sqmPathSource.isGeneric(); + } + @Override public SqmAttributeJoin createSqmJoin( SqmFrom lhs, @@ -154,6 +161,7 @@ public class SingularAttributeImpl SimpleDomainType attributeType, Member member, AttributeClassification attributeClassification, + boolean isGeneric, MetadataContext metadataContext) { super( declaringType, @@ -164,6 +172,7 @@ public class SingularAttributeImpl true, false, false, + isGeneric, metadataContext ); } @@ -204,6 +213,7 @@ public class SingularAttributeImpl false, true, false, + false, metadataContext ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/SqmPathSource.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/SqmPathSource.java index 19fe2dd671..ec405f2e1d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/SqmPathSource.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/SqmPathSource.java @@ -86,4 +86,11 @@ public interface SqmPathSource extends SqmExpressible, Bindable, SqmExp default SqmExpressible getExpressible() { return (SqmExpressible) getSqmPathType(); } + + /** + * Indicates if this path source is generically typed + */ + default boolean isGeneric() { + return false; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmMappingModelHelper.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmMappingModelHelper.java index 5b5d722a9e..8654ed9b3a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmMappingModelHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmMappingModelHelper.java @@ -78,6 +78,14 @@ public class SqmMappingModelHelper { String name, DomainType valueDomainType, Bindable.BindableType jpaBindableType) { + return resolveSqmPathSource( name, valueDomainType, jpaBindableType, false ); + } + + public static SqmPathSource resolveSqmPathSource( + String name, + DomainType valueDomainType, + Bindable.BindableType jpaBindableType, + boolean isGeneric) { if ( valueDomainType instanceof BasicDomainType ) { return new BasicSqmPathSource<>( @@ -99,7 +107,8 @@ public class SqmMappingModelHelper { return new EmbeddedSqmPathSource<>( name, (EmbeddableDomainType) valueDomainType, - jpaBindableType + jpaBindableType, + isGeneric ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmEmbeddedValuedSimplePath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmEmbeddedValuedSimplePath.java index 8cf65f561c..d3e9726958 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmEmbeddedValuedSimplePath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmEmbeddedValuedSimplePath.java @@ -6,8 +6,11 @@ */ package org.hibernate.query.sqm.tree.domain; +import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.EmbeddableDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.metamodel.model.domain.ManagedDomainType; +import org.hibernate.metamodel.model.domain.internal.CompositeSqmPathSource; import org.hibernate.spi.NavigablePath; import org.hibernate.query.PathException; import org.hibernate.query.hql.spi.SqmCreationState; @@ -77,6 +80,24 @@ public class SqmEmbeddedValuedSimplePath return sqmPath; } + @Override + public SqmPath get(String attributeName) { + final DomainType lhsType; + final SqmPathSource pathSource = getReferencedPathSource(); + if ( pathSource.isGeneric() && ( lhsType = getLhs().getReferencedPathSource() + .getSqmPathType() ) instanceof ManagedDomainType ) { + //noinspection rawtypes + final SqmPathSource concreteEmbeddable = ( (ManagedDomainType) lhsType ).findConcreteEmbeddableAttribute( + pathSource.getPathName() + ); + if ( concreteEmbeddable != null ) { + final SqmPathSource subNavigable = concreteEmbeddable.getSubPathSource( attributeName ); + return resolvePath( attributeName, subNavigable ); + } + } + return super.get( attributeName ); + } + @Override public X accept(SemanticQueryWalker walker) { return walker.visitEmbeddableValuedPath( this ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java index a96c07335f..cf389d9744 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPolymorphicRootDescriptor.java @@ -209,6 +209,11 @@ public class SqmPolymorphicRootDescriptor implements EntityDomainType { return (PluralPersistentAttribute) findAttribute( name ); } + @Override + public SingularPersistentAttribute findConcreteEmbeddableAttribute(String name) { + return null; + } + @Override public PersistentAttribute findDeclaredAttribute(String name) { return null; @@ -224,6 +229,11 @@ public class SqmPolymorphicRootDescriptor implements EntityDomainType { return null; } + @Override + public SingularPersistentAttribute findDeclaredConcreteEmbeddableAttribute(String name) { + return null; + } + @Override public Set> getAttributes() { //noinspection unchecked