Implement support for using generically typed associations to re-enable inheritance/discriminator tests
This commit is contained in:
parent
eb572376a9
commit
9b53ca8559
|
@ -13,19 +13,25 @@ import jakarta.persistence.Converts;
|
|||
import jakarta.persistence.JoinTable;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.annotations.common.reflection.XClass;
|
||||
import org.hibernate.annotations.common.reflection.XProperty;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.cfg.annotations.EntityBinder;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.IndexedCollection;
|
||||
import org.hibernate.mapping.Join;
|
||||
import org.hibernate.mapping.KeyValue;
|
||||
import org.hibernate.mapping.MappedSuperclass;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.ToOne;
|
||||
import org.hibernate.mapping.Value;
|
||||
|
||||
/**
|
||||
* @author Emmanuel Bernard
|
||||
|
@ -234,7 +240,82 @@ public class ClassPropertyHolder extends AbstractPropertyHolder {
|
|||
private void addPropertyToMappedSuperclass(Property prop, XClass declaringClass) {
|
||||
final Class<?> type = getContext().getBootstrapContext().getReflectionManager().toClass( declaringClass );
|
||||
MappedSuperclass superclass = getContext().getMetadataCollector().getMappedSuperclass( type );
|
||||
superclass.addDeclaredProperty( prop );
|
||||
if ( type.getTypeParameters().length == 0 ) {
|
||||
superclass.addDeclaredProperty( prop );
|
||||
}
|
||||
else {
|
||||
// If the type has type parameters, we have to look up the XClass and actual property again
|
||||
// because the given XClass has a TypeEnvironment based on the type variable assignments of a subclass
|
||||
// and that might result in a wrong property type being used for a property which uses a type variable
|
||||
final XClass actualDeclaringClass = getContext().getBootstrapContext().getReflectionManager().toXClass( type );
|
||||
for ( XProperty declaredProperty : actualDeclaringClass.getDeclaredProperties( prop.getPropertyAccessorName() ) ) {
|
||||
if ( prop.getName().equals( declaredProperty.getName() ) ) {
|
||||
final PropertyData inferredData = new PropertyInferredData(
|
||||
actualDeclaringClass,
|
||||
declaredProperty,
|
||||
null,
|
||||
getContext().getBootstrapContext().getReflectionManager()
|
||||
);
|
||||
final Value originalValue = prop.getValue();
|
||||
if ( originalValue instanceof SimpleValue ) {
|
||||
// Avoid copying when the property doesn't depend on a type variable
|
||||
if ( inferredData.getTypeName().equals( ( (SimpleValue) originalValue ).getTypeName() ) ) {
|
||||
superclass.addDeclaredProperty( prop );
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If the property depends on a type variable, we have to copy it and the Value
|
||||
final Property actualProperty = prop.copy();
|
||||
actualProperty.setReturnedClassName( inferredData.getTypeName() );
|
||||
final Value value = actualProperty.getValue().copy();
|
||||
if ( value instanceof Collection ) {
|
||||
final Collection collection = (Collection) value;
|
||||
// The owner is a MappedSuperclass which is not a PersistentClass, so set it to null
|
||||
// collection.setOwner( null );
|
||||
collection.setRole( type.getName() + "." + prop.getName() );
|
||||
// To copy the element and key values, we need to defer setting the type name until the CollectionBinder ran
|
||||
getContext().getMetadataCollector().addSecondPass(
|
||||
new SecondPass() {
|
||||
@Override
|
||||
public void doSecondPass(Map persistentClasses) throws MappingException {
|
||||
final Collection initializedCollection = (Collection) originalValue;
|
||||
final Value element = initializedCollection.getElement().copy();
|
||||
setTypeName( element, inferredData.getProperty().getElementClass().getName() );
|
||||
if ( initializedCollection instanceof IndexedCollection ) {
|
||||
final Value index = ( (IndexedCollection) initializedCollection ).getIndex().copy();
|
||||
setTypeName( index, inferredData.getProperty().getMapKey().getName() );
|
||||
( (IndexedCollection) collection ).setIndex( index );
|
||||
}
|
||||
collection.setElement( element );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
else {
|
||||
setTypeName( value, inferredData.getTypeName() );
|
||||
}
|
||||
actualProperty.setValue( value );
|
||||
superclass.addDeclaredProperty( actualProperty );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setTypeName(Value value, String typeName) {
|
||||
if ( value instanceof ToOne ) {
|
||||
final ToOne toOne = (ToOne) value;
|
||||
toOne.setReferencedEntityName( typeName );
|
||||
toOne.setTypeName( typeName );
|
||||
}
|
||||
else if ( value instanceof Component ) {
|
||||
final Component component = (Component) value;
|
||||
component.setComponentClassName( typeName );
|
||||
component.setTypeName( typeName );
|
||||
}
|
||||
else if ( value instanceof SimpleValue ) {
|
||||
( (SimpleValue) value ).setTypeName( typeName );
|
||||
}
|
||||
}
|
||||
|
||||
private void addPropertyToJoin(Property prop, XClass declaringClass, Join join) {
|
||||
|
|
|
@ -63,6 +63,11 @@ public class ExportableColumn extends Column {
|
|||
this.database = database;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value copy() {
|
||||
return new ValueImpl( column, table, type, database );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnSpan() {
|
||||
return 1;
|
||||
|
|
|
@ -57,6 +57,30 @@ public class Any extends SimpleValue {
|
|||
|
||||
}
|
||||
|
||||
public Any(Any original) {
|
||||
super( original );
|
||||
|
||||
this.metaMapping = original.metaMapping == null ? null : original.metaMapping.copy();
|
||||
this.keyMapping = original.keyMapping == null ? null : (SimpleValue) original.keyMapping.copy();
|
||||
|
||||
// annotations
|
||||
this.discriminatorDescriptor = original.discriminatorDescriptor == null
|
||||
? null
|
||||
: original.discriminatorDescriptor.copy();
|
||||
this.keyDescriptor = original.keyDescriptor == null ? null : original.keyDescriptor.copy();
|
||||
|
||||
// common
|
||||
this.metaValueToEntityNameMap = original.metaValueToEntityNameMap == null
|
||||
? null
|
||||
: new HashMap<>(original.metaValueToEntityNameMap);
|
||||
this.lazy = original.lazy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Any copy() {
|
||||
return new Any( this );
|
||||
}
|
||||
|
||||
public void addSelectable(Selectable selectable) {
|
||||
if ( selectable == null ) {
|
||||
return;
|
||||
|
@ -281,6 +305,18 @@ public class Any extends SimpleValue {
|
|||
this.selectableConsumer = selectableConsumer;
|
||||
}
|
||||
|
||||
private MetaValue(MetaValue original) {
|
||||
super( original );
|
||||
this.typeName = original.typeName;
|
||||
this.columnName = original.columnName;
|
||||
this.selectableConsumer = original.selectableConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaValue copy() {
|
||||
return new MetaValue( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() throws MappingException {
|
||||
return getMetadata().getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( typeName );
|
||||
|
@ -365,6 +401,17 @@ public class Any extends SimpleValue {
|
|||
this.selectableConsumer = selectableConsumer;
|
||||
}
|
||||
|
||||
private KeyValue(KeyValue original) {
|
||||
super( original );
|
||||
this.typeName = original.typeName;
|
||||
this.selectableConsumer = original.selectableConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyValue copy() {
|
||||
return new KeyValue( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() throws MappingException {
|
||||
return getMetadata().getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( typeName );
|
||||
|
|
|
@ -35,6 +35,16 @@ public class Array extends List {
|
|||
super( customTypeBeanResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
protected Array(Array original) {
|
||||
super( original );
|
||||
this.elementClassName = original.elementClassName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array copy() {
|
||||
return new Array( this );
|
||||
}
|
||||
|
||||
public Class<?> getElementClass() throws MappingException {
|
||||
if ( elementClassName == null ) {
|
||||
final org.hibernate.type.Type elementType = getElement().getType();
|
||||
|
|
|
@ -34,6 +34,15 @@ public class Bag extends Collection {
|
|||
super( customTypeBeanResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
private Bag(Collection original) {
|
||||
super( original );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bag copy() {
|
||||
return new Bag( this );
|
||||
}
|
||||
|
||||
public CollectionType getDefaultCollectionType() {
|
||||
return new BagType( getRole(), getReferencedPropertyName() );
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.mapping;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -109,6 +110,29 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
buildingContext.getMetadataCollector().registerValueMappingResolver( this::resolve );
|
||||
}
|
||||
|
||||
public BasicValue(BasicValue original) {
|
||||
super( original );
|
||||
this.typeConfiguration = original.typeConfiguration;
|
||||
this.explicitTypeName = original.explicitTypeName;
|
||||
this.explicitLocalTypeParams = original.explicitLocalTypeParams == null
|
||||
? null
|
||||
: new HashMap(original.explicitLocalTypeParams);
|
||||
this.explicitJavaTypeAccess = original.explicitJavaTypeAccess;
|
||||
this.explicitJdbcTypeAccess = original.explicitJdbcTypeAccess;
|
||||
this.explicitMutabilityPlanAccess = original.explicitMutabilityPlanAccess;
|
||||
this.implicitJavaTypeAccess = original.implicitJavaTypeAccess;
|
||||
this.enumerationStyle = original.enumerationStyle;
|
||||
this.temporalPrecision = original.temporalPrecision;
|
||||
this.timeZoneStorageType = original.timeZoneStorageType;
|
||||
this.resolvedJavaType = original.resolvedJavaType;
|
||||
this.ownerName = original.ownerName;
|
||||
this.propertyName = original.propertyName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue copy() {
|
||||
return new BasicValue( this );
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Setters - in preparation of resolution
|
||||
|
|
|
@ -121,6 +121,55 @@ public abstract class Collection implements Fetchable, Value, Filterable {
|
|||
this.buildingContext = buildingContext;
|
||||
}
|
||||
|
||||
protected Collection(Collection original) {
|
||||
this.buildingContext = original.buildingContext;
|
||||
this.owner = original.owner;
|
||||
this.key = original.key == null ? null : (KeyValue) original.key.copy();
|
||||
this.element = original.element == null ? null : original.element.copy();
|
||||
this.collectionTable = original.collectionTable;
|
||||
this.role = original.role;
|
||||
this.lazy = original.lazy;
|
||||
this.extraLazy = original.extraLazy;
|
||||
this.inverse = original.inverse;
|
||||
this.mutable = original.mutable;
|
||||
this.subselectLoadable = original.subselectLoadable;
|
||||
this.cacheConcurrencyStrategy = original.cacheConcurrencyStrategy;
|
||||
this.cacheRegionName = original.cacheRegionName;
|
||||
this.orderBy = original.orderBy;
|
||||
this.where = original.where;
|
||||
this.manyToManyWhere = original.manyToManyWhere;
|
||||
this.manyToManyOrderBy = original.manyToManyOrderBy;
|
||||
this.referencedPropertyName = original.referencedPropertyName;
|
||||
this.mappedByProperty = original.mappedByProperty;
|
||||
this.sorted = original.sorted;
|
||||
this.comparator = original.comparator;
|
||||
this.comparatorClassName = original.comparatorClassName;
|
||||
this.orphanDelete = original.orphanDelete;
|
||||
this.batchSize = original.batchSize;
|
||||
this.fetchMode = original.fetchMode;
|
||||
this.optimisticLocked = original.optimisticLocked;
|
||||
this.typeName = original.typeName;
|
||||
this.typeParameters = original.typeParameters == null ? null : new Properties(original.typeParameters);
|
||||
this.customTypeBeanResolver = original.customTypeBeanResolver;
|
||||
this.collectionPersisterClass = original.collectionPersisterClass;
|
||||
this.filters.addAll( original.filters );
|
||||
this.manyToManyFilters.addAll( original.manyToManyFilters );
|
||||
this.synchronizedTables.addAll( original.synchronizedTables );
|
||||
this.customSQLInsert = original.customSQLInsert;
|
||||
this.customInsertCallable = original.customInsertCallable;
|
||||
this.insertCheckStyle = original.insertCheckStyle;
|
||||
this.customSQLUpdate = original.customSQLUpdate;
|
||||
this.customUpdateCallable = original.customUpdateCallable;
|
||||
this.updateCheckStyle = original.updateCheckStyle;
|
||||
this.customSQLDelete = original.customSQLDelete;
|
||||
this.customDeleteCallable = original.customDeleteCallable;
|
||||
this.deleteCheckStyle = original.deleteCheckStyle;
|
||||
this.customSQLDeleteAll = original.customSQLDeleteAll;
|
||||
this.customDeleteAllCallable = original.customDeleteAllCallable;
|
||||
this.deleteAllCheckStyle = original.deleteAllCheckStyle;
|
||||
this.loaderName = original.loaderName;
|
||||
}
|
||||
|
||||
public MetadataBuildingContext getBuildingContext() {
|
||||
return buildingContext;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.mapping;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -81,6 +82,27 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
|
|||
metadata.getMetadataCollector().registerComponent( this );
|
||||
}
|
||||
|
||||
private Component(Component original) {
|
||||
super( original );
|
||||
this.properties.addAll( original.properties );
|
||||
this.originalPropertyOrder = original.originalPropertyOrder.clone();
|
||||
this.componentClassName = original.componentClassName;
|
||||
this.embedded = original.embedded;
|
||||
this.parentProperty = original.parentProperty;
|
||||
this.owner = original.owner;
|
||||
this.dynamic = original.dynamic;
|
||||
this.metaAttributes = original.metaAttributes == null ? null : new HashMap(original.metaAttributes);
|
||||
this.isKey = original.isKey;
|
||||
this.roleName = original.roleName;
|
||||
this.customInstantiator = original.customInstantiator;
|
||||
this.type = original.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component copy() {
|
||||
return new Component( this );
|
||||
}
|
||||
|
||||
public int getPropertySpan() {
|
||||
return properties.size();
|
||||
}
|
||||
|
|
|
@ -29,6 +29,18 @@ public class DependantBasicValue extends BasicValue {
|
|||
this.updateable = updateable;
|
||||
}
|
||||
|
||||
private DependantBasicValue(DependantBasicValue original) {
|
||||
super( original );
|
||||
this.referencedValue = original.referencedValue.copy();
|
||||
this.nullable = original.nullable;
|
||||
this.updateable = original.updateable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependantBasicValue copy() {
|
||||
return new DependantBasicValue( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Resolution<?> buildResolution() {
|
||||
return referencedValue.resolve();
|
||||
|
|
|
@ -28,6 +28,19 @@ public class DependantValue extends SimpleValue implements Resolvable, SortableV
|
|||
this.wrappedValue = prototype;
|
||||
}
|
||||
|
||||
private DependantValue(DependantValue original) {
|
||||
super( original );
|
||||
this.wrappedValue = (KeyValue) original.wrappedValue.copy();
|
||||
this.nullable = original.nullable;
|
||||
this.updateable = original.updateable;
|
||||
this.sorted = original.sorted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependantValue copy() {
|
||||
return new DependantValue( this );
|
||||
}
|
||||
|
||||
public KeyValue getWrappedValue() {
|
||||
return wrappedValue;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,15 @@ public class IdentifierBag extends IdentifierCollection {
|
|||
super( customTypeBeanResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
public IdentifierBag(IdentifierBag original) {
|
||||
super( original );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentifierBag copy() {
|
||||
return new IdentifierBag( this );
|
||||
}
|
||||
|
||||
public CollectionType getDefaultCollectionType() {
|
||||
return new IdentifierBagType( getRole(), getReferencedPropertyName() );
|
||||
}
|
||||
|
|
|
@ -31,6 +31,11 @@ public abstract class IdentifierCollection extends Collection {
|
|||
super( customTypeBeanResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
protected IdentifierCollection(IdentifierCollection original) {
|
||||
super( original );
|
||||
this.identifier = (KeyValue) original.identifier.copy();
|
||||
}
|
||||
|
||||
public KeyValue getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,11 @@ public abstract class IndexedCollection extends Collection {
|
|||
super( customTypeBeanResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
protected IndexedCollection(IndexedCollection original) {
|
||||
super( original );
|
||||
this.index = original.index == null ? null : original.index.copy();
|
||||
}
|
||||
|
||||
public Value getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,16 @@ public class List extends IndexedCollection {
|
|||
super( customTypeBeanResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
protected List(List original) {
|
||||
super( original );
|
||||
this.baseIndex = original.baseIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List copy() {
|
||||
return new List( this );
|
||||
}
|
||||
|
||||
public boolean isList() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,17 @@ public class ManyToOne extends ToOne {
|
|||
super( buildingContext, table );
|
||||
}
|
||||
|
||||
private ManyToOne(ManyToOne original) {
|
||||
super( original );
|
||||
this.ignoreNotFound = original.ignoreNotFound;
|
||||
this.isLogicalOneToOne = original.isLogicalOneToOne;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManyToOne copy() {
|
||||
return new ManyToOne( this );
|
||||
}
|
||||
|
||||
public Type getType() throws MappingException {
|
||||
if ( resolvedType == null ) {
|
||||
resolvedType = MappingHelper.manyToOne(
|
||||
|
|
|
@ -33,6 +33,15 @@ public class Map extends IndexedCollection {
|
|||
super( customTypeBeanResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
private Map(Map original) {
|
||||
super( original );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map copy() {
|
||||
return new Map( this );
|
||||
}
|
||||
|
||||
public boolean isMap() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,19 @@ public class OneToMany implements Value {
|
|||
this.referencingTable = owner == null ? null : owner.getTable();
|
||||
}
|
||||
|
||||
private OneToMany(OneToMany original) {
|
||||
this.buildingContext = original.buildingContext;
|
||||
this.referencingTable = original.referencingTable;
|
||||
this.referencedEntityName = original.referencedEntityName;
|
||||
this.associatedClass = original.associatedClass;
|
||||
this.ignoreNotFound = original.ignoreNotFound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value copy() {
|
||||
return new OneToMany( this );
|
||||
}
|
||||
|
||||
public MetadataBuildingContext getBuildingContext() {
|
||||
return buildingContext;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,21 @@ public class OneToOne extends ToOne {
|
|||
this.entityName = owner.getEntityName();
|
||||
}
|
||||
|
||||
private OneToOne(OneToOne original) {
|
||||
super( original );
|
||||
this.constrained = original.constrained;
|
||||
this.foreignKeyType = original.foreignKeyType;
|
||||
this.identifier = original.identifier == null ? null : (KeyValue) original.identifier.copy();
|
||||
this.propertyName = original.propertyName;
|
||||
this.entityName = original.entityName;
|
||||
this.mappedByProperty = original.mappedByProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OneToOne copy() {
|
||||
return new OneToOne( this );
|
||||
}
|
||||
|
||||
public String getPropertyName() {
|
||||
return propertyName;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,15 @@ public class PrimitiveArray extends Array {
|
|||
super( customTypeBeanResolver, owner, buildingContext );
|
||||
}
|
||||
|
||||
private PrimitiveArray(PrimitiveArray original) {
|
||||
super( original );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array copy() {
|
||||
return new PrimitiveArray( this );
|
||||
}
|
||||
|
||||
public boolean isPrimitiveArray() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -426,4 +426,27 @@ public class Property implements Serializable, MetaAttributable {
|
|||
public void setReturnedClassName(String returnedClassName) {
|
||||
this.returnedClassName = returnedClassName;
|
||||
}
|
||||
|
||||
public Property copy() {
|
||||
final Property prop = new Property();
|
||||
prop.setName( getName() );
|
||||
prop.setValue( getValue() );
|
||||
prop.setCascade( getCascade() );
|
||||
prop.setUpdateable( isUpdateable() );
|
||||
prop.setInsertable( isInsertable() );
|
||||
prop.setSelectable( isSelectable() );
|
||||
prop.setOptimisticLocked( isOptimisticLocked() );
|
||||
prop.setValueGenerationStrategy( getValueGenerationStrategy() );
|
||||
prop.setPropertyAccessorName( getPropertyAccessorName() );
|
||||
prop.setLazy( isLazy() );
|
||||
prop.setLazyGroup( getLazyGroup() );
|
||||
prop.setOptional( isOptional() );
|
||||
prop.setMetaAttributes( getMetaAttributes() );
|
||||
prop.setPersistentClass( getPersistentClass() );
|
||||
prop.setNaturalIdentifier( isNaturalIdentifier() );
|
||||
prop.setLob( isLob() );
|
||||
prop.addCallbackDefinitions( getCallbackDefinitions() );
|
||||
prop.setReturnedClassName( getReturnedClassName() );
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,15 @@ public class Set extends Collection {
|
|||
super( customTypeBeanResolver, persistentClass, buildingContext );
|
||||
}
|
||||
|
||||
private Set(Collection original) {
|
||||
super( original );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set copy() {
|
||||
return new Set( this );
|
||||
}
|
||||
|
||||
public void validate(Mapping mapping) throws MappingException {
|
||||
super.validate( mapping );
|
||||
//for backward compatibility, disable this:
|
||||
|
|
|
@ -108,6 +108,33 @@ public abstract class SimpleValue implements KeyValue {
|
|||
this.table = table;
|
||||
}
|
||||
|
||||
protected SimpleValue(SimpleValue original) {
|
||||
this.buildingContext = original.buildingContext;
|
||||
this.metadata = original.metadata;
|
||||
this.columns.addAll( original.columns );
|
||||
this.insertability.addAll( original.insertability );
|
||||
this.updatability.addAll( original.updatability );
|
||||
this.typeName = original.typeName;
|
||||
this.typeParameters = original.typeParameters == null ? null : new Properties( original.typeParameters );
|
||||
this.isVersion = original.isVersion;
|
||||
this.isNationalized = original.isNationalized;
|
||||
this.isLob = original.isLob;
|
||||
this.identifierGeneratorProperties = original.identifierGeneratorProperties == null
|
||||
? null
|
||||
: new Properties( original.identifierGeneratorProperties );
|
||||
this.identifierGeneratorStrategy = original.identifierGeneratorStrategy;
|
||||
this.nullValue = original.nullValue;
|
||||
this.table = original.table;
|
||||
this.foreignKeyName = original.foreignKeyName;
|
||||
this.foreignKeyDefinition = original.foreignKeyDefinition;
|
||||
this.alternateUniqueKey = original.alternateUniqueKey;
|
||||
this.cascadeDeleteEnabled = original.cascadeDeleteEnabled;
|
||||
this.attributeConverterDescriptor = original.attributeConverterDescriptor;
|
||||
this.type = original.type;
|
||||
this.customIdGeneratorCreator = original.customIdGeneratorCreator;
|
||||
this.identifierGenerator = original.identifierGenerator;
|
||||
}
|
||||
|
||||
public MetadataBuildingContext getBuildingContext() {
|
||||
return buildingContext;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,19 @@ public abstract class ToOne extends SimpleValue implements Fetchable, SortableVa
|
|||
super( buildingContext, table );
|
||||
}
|
||||
|
||||
protected ToOne(ToOne original) {
|
||||
super( original );
|
||||
this.fetchMode = original.fetchMode;
|
||||
this.referencedPropertyName = original.referencedPropertyName;
|
||||
this.referencedEntityName = original.referencedEntityName;
|
||||
this.propertyName = original.propertyName;
|
||||
this.lazy = original.lazy;
|
||||
this.sorted = original.sorted;
|
||||
this.unwrapProxy = original.unwrapProxy;
|
||||
this.isUnwrapProxyImplicit = original.isUnwrapProxyImplicit;
|
||||
this.referenceToPrimaryKey = original.referenceToPrimaryKey;
|
||||
}
|
||||
|
||||
public FetchMode getFetchMode() {
|
||||
return fetchMode;
|
||||
}
|
||||
|
|
|
@ -100,4 +100,5 @@ public interface Value extends Serializable {
|
|||
boolean hasAnyUpdatableColumns();
|
||||
|
||||
ServiceRegistry getServiceRegistry();
|
||||
Value copy();
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.hibernate.metamodel.model.domain.SimpleDomainType;
|
|||
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.internal.AnyMappingDomainTypeImpl;
|
||||
import org.hibernate.metamodel.model.domain.internal.EmbeddableTypeImpl;
|
||||
import org.hibernate.metamodel.model.domain.internal.EntityTypeImpl;
|
||||
import org.hibernate.metamodel.model.domain.internal.MapMember;
|
||||
import org.hibernate.metamodel.model.domain.internal.MappedSuperclassTypeImpl;
|
||||
import org.hibernate.metamodel.model.domain.internal.PluralAttributeBuilder;
|
||||
|
@ -223,7 +224,17 @@ public class AttributeFactory {
|
|||
final org.hibernate.type.Type type = typeContext.getHibernateValue().getType();
|
||||
if ( type instanceof EntityType ) {
|
||||
final EntityType entityType = (EntityType) type;
|
||||
return context.locateEntityType( entityType.getAssociatedEntityName() );
|
||||
final IdentifiableDomainType<Y> domainType = context.locateIdentifiableType( entityType.getAssociatedEntityName() );
|
||||
if ( domainType == null ) {
|
||||
// Due to the use of generics, it can happen that a mapped super class uses a type
|
||||
// for an attribute that is not a managed type. Since this case is not specifically mentioned
|
||||
// in the Jakarta Persistence spec, we handle this by returning a "dummy" entity type
|
||||
final JavaType<Y> domainJavaType = context.getJavaTypeRegistry().resolveDescriptor(
|
||||
typeContext.getJpaBindableType()
|
||||
);
|
||||
return new EntityTypeImpl<>( domainJavaType, context.getJpaMetamodel() );
|
||||
}
|
||||
return domainType;
|
||||
}
|
||||
|
||||
assert type instanceof AnyType;
|
||||
|
|
|
@ -83,7 +83,7 @@ public class MetadataContext {
|
|||
private final AttributeFactory attributeFactory = new AttributeFactory( this );
|
||||
|
||||
private final Map<Class<?>, EntityDomainType<?>> entityTypes = new HashMap<>();
|
||||
private final Map<String, EntityDomainType<?>> entityTypesByEntityName = new HashMap<>();
|
||||
private final Map<String, IdentifiableDomainType<?>> identifiableTypesByName = new HashMap<>();
|
||||
private final Map<PersistentClass, EntityDomainType<?>> entityTypesByPersistentClass = new HashMap<>();
|
||||
|
||||
private final Map<Class<?>, EmbeddableDomainType<?>> embeddables = new HashMap<>();
|
||||
|
@ -172,7 +172,7 @@ public class MetadataContext {
|
|||
entityTypes.put( entityType.getBindableJavaType(), entityType );
|
||||
}
|
||||
|
||||
entityTypesByEntityName.put( persistentClass.getEntityName(), entityType );
|
||||
identifiableTypesByName.put( persistentClass.getEntityName(), entityType );
|
||||
entityTypesByPersistentClass.put( persistentClass, entityType );
|
||||
orderedMappings.add( persistentClass );
|
||||
}
|
||||
|
@ -202,6 +202,7 @@ public class MetadataContext {
|
|||
public void registerMappedSuperclassType(
|
||||
MappedSuperclass mappedSuperclass,
|
||||
MappedSuperclassDomainType<?> mappedSuperclassType) {
|
||||
identifiableTypesByName.put( mappedSuperclassType.getTypeName(), mappedSuperclassType );
|
||||
mappedSuperclassByMappedSuperclassMapping.put( mappedSuperclass, mappedSuperclassType );
|
||||
orderedMappings.add( mappedSuperclass );
|
||||
mappedSuperClassTypeToPersistentClass.put( mappedSuperclassType, getEntityWorkedOn() );
|
||||
|
@ -242,12 +243,12 @@ public class MetadataContext {
|
|||
* @return The corresponding JPA {@link org.hibernate.type.EntityType}, or null.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <E> EntityDomainType<E> locateEntityType(String entityName) {
|
||||
return (EntityDomainType<E>) entityTypesByEntityName.get( entityName );
|
||||
public <E> IdentifiableDomainType<E> locateIdentifiableType(String entityName) {
|
||||
return (IdentifiableDomainType<E>) identifiableTypesByName.get( entityName );
|
||||
}
|
||||
|
||||
public Map<String, EntityDomainType<?>> getEntityTypesByEntityName() {
|
||||
return Collections.unmodifiableMap( entityTypesByEntityName );
|
||||
public Map<String, IdentifiableDomainType<?>> getIdentifiableTypesByName() {
|
||||
return Collections.unmodifiableMap( identifiableTypesByName );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -452,7 +453,7 @@ public class MetadataContext {
|
|||
assert cidValue.isEmbedded();
|
||||
|
||||
AbstractIdentifiableType<?> idType = (AbstractIdentifiableType<?>)
|
||||
entityTypesByEntityName.get( cidValue.getOwner().getEntityName() );
|
||||
identifiableTypesByName.get( cidValue.getOwner().getEntityName() );
|
||||
//noinspection rawtypes
|
||||
Set idAttributes = idType.getIdClassAttributesSafely();
|
||||
if ( idAttributes == null ) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.persister.entity.UnionSubclassEntityPersister;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
|
@ -22,6 +23,11 @@ import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnRefere
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MappingModelHelper {
|
||||
|
||||
private MappingModelHelper() {
|
||||
// disallow direct instantiation
|
||||
}
|
||||
|
||||
public static Expression buildColumnReferenceExpression(
|
||||
ModelPart modelPart,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
|
@ -99,8 +105,60 @@ public class MappingModelHelper {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private MappingModelHelper() {
|
||||
// disallow direct instantiation
|
||||
public static boolean isCompatibleModelPart(ModelPart attribute1, ModelPart attribute2) {
|
||||
if ( attribute1 == attribute2 ) {
|
||||
return true;
|
||||
}
|
||||
if ( attribute1.getClass() != attribute2.getClass() || attribute1.getJavaType() != attribute2.getJavaType() ) {
|
||||
return false;
|
||||
}
|
||||
if ( attribute1 instanceof Association ) {
|
||||
final Association association1 = (Association) attribute1;
|
||||
final Association association2 = (Association) attribute2;
|
||||
return association1.getForeignKeyDescriptor().getAssociationKey().equals(
|
||||
association2.getForeignKeyDescriptor().getAssociationKey()
|
||||
);
|
||||
}
|
||||
else if ( attribute1 instanceof PluralAttributeMapping ) {
|
||||
final PluralAttributeMapping plural1 = (PluralAttributeMapping) attribute1;
|
||||
final PluralAttributeMapping plural2 = (PluralAttributeMapping) attribute2;
|
||||
final CollectionPart element1 = plural1.getElementDescriptor();
|
||||
final CollectionPart element2 = plural2.getElementDescriptor();
|
||||
final CollectionPart index1 = plural1.getIndexDescriptor();
|
||||
final CollectionPart index2 = plural2.getIndexDescriptor();
|
||||
return plural1.getKeyDescriptor().getAssociationKey().equals(
|
||||
plural2.getKeyDescriptor().getAssociationKey()
|
||||
) && ( index1 == null && index2 == null || isCompatibleModelPart( index1, index2 ) )
|
||||
&& isCompatibleModelPart( element1, element2 );
|
||||
}
|
||||
else if ( attribute1 instanceof EmbeddableValuedModelPart ) {
|
||||
final EmbeddableValuedModelPart embedded1 = (EmbeddableValuedModelPart) attribute1;
|
||||
final EmbeddableValuedModelPart embedded2 = (EmbeddableValuedModelPart) attribute2;
|
||||
final List<AttributeMapping> attrs1 = embedded1.getEmbeddableTypeDescriptor().getAttributeMappings();
|
||||
final List<AttributeMapping> attrs2 = embedded2.getEmbeddableTypeDescriptor().getAttributeMappings();
|
||||
if ( attrs1.size() != attrs2.size() ) {
|
||||
return false;
|
||||
}
|
||||
for ( int i = 0; i < attrs1.size(); i++ ) {
|
||||
if ( !isCompatibleModelPart( attrs1.get( i ), attrs2.get( i ) ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if ( attribute1 instanceof BasicValuedModelPart ) {
|
||||
final BasicValuedModelPart basic1 = (BasicValuedModelPart) attribute1;
|
||||
final BasicValuedModelPart basic2 = (BasicValuedModelPart) attribute2;
|
||||
if ( !basic1.getSelectionExpression().equals( basic2.getSelectionExpression() ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( basic1.getContainingTableExpression().equals( basic2.getContainingTableExpression() ) ) {
|
||||
return true;
|
||||
}
|
||||
// For union subclass mappings we also consider mappings compatible that just match the selection expression,
|
||||
// because we match up columns of disjoint union subclass types by column name
|
||||
return attribute1.findContainingEntityMapping().getEntityPersister() instanceof UnionSubclassEntityPersister;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import java.util.HashSet;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -31,8 +32,12 @@ import org.hibernate.graph.internal.SubGraphImpl;
|
|||
import org.hibernate.graph.spi.SubGraphImplementor;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.RepresentationMode;
|
||||
import org.hibernate.metamodel.RuntimeMetamodels;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingModelHelper;
|
||||
import org.hibernate.metamodel.model.domain.internal.AttributeContainer;
|
||||
import org.hibernate.metamodel.model.domain.internal.DomainModelHelper;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
||||
/**
|
||||
|
@ -167,11 +172,45 @@ public abstract class AbstractManagedType<J>
|
|||
for ( ManagedDomainType subType : subTypes ) {
|
||||
PersistentAttribute subTypeAttribute = subType.findSubTypesAttribute( name );
|
||||
if ( subTypeAttribute != null ) {
|
||||
return subTypeAttribute;
|
||||
if ( attribute != null && !isCompatible( attribute, subTypeAttribute ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
new SemanticException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Could not resolve attribute '%s' of '%s' due to the attribute being declared in multiple sub types: ['%s', '%s']",
|
||||
name,
|
||||
getExpressibleJavaType().getJavaType().getTypeName(),
|
||||
attribute.getDeclaringType().getExpressibleJavaType().getJavaType().getTypeName(),
|
||||
subTypeAttribute.getDeclaringType().getExpressibleJavaType().getJavaType().getTypeName()
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
attribute = subTypeAttribute;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return attribute;
|
||||
}
|
||||
|
||||
private boolean isCompatible(PersistentAttribute<?, ?> attribute1, PersistentAttribute<?, ?> attribute2) {
|
||||
if ( attribute1 == attribute2 ) {
|
||||
return true;
|
||||
}
|
||||
final RuntimeMetamodels runtimeMetamodels = jpaMetamodel().getTypeConfiguration()
|
||||
.getSessionFactory()
|
||||
.getRuntimeMetamodels();
|
||||
final EntityMappingType entity1 = runtimeMetamodels.getEntityMappingType(
|
||||
attribute1.getDeclaringType().getTypeName()
|
||||
);
|
||||
final EntityMappingType entity2 = runtimeMetamodels.getEntityMappingType(
|
||||
attribute2.getDeclaringType().getTypeName()
|
||||
);
|
||||
|
||||
return entity1 != null && entity2 != null && MappingModelHelper.isCompatibleModelPart(
|
||||
entity1.findSubPart( attribute1.getName() ),
|
||||
entity2.findSubPart( attribute2.getName() )
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.model.domain;
|
||||
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
|
||||
import jakarta.persistence.metamodel.MappedSuperclassType;
|
||||
|
||||
/**
|
||||
|
@ -13,5 +15,5 @@ import jakarta.persistence.metamodel.MappedSuperclassType;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface MappedSuperclassDomainType<J> extends IdentifiableDomainType<J>, MappedSuperclassType<J> {
|
||||
public interface MappedSuperclassDomainType<J> extends IdentifiableDomainType<J>, MappedSuperclassType<J>, SqmPathSource<J> {
|
||||
}
|
||||
|
|
|
@ -82,6 +82,20 @@ public class EntityTypeImpl<J>
|
|||
entityDescriptor
|
||||
);
|
||||
}
|
||||
public EntityTypeImpl(JavaType<J> javaTypeDescriptor, JpaMetamodel jpaMetamodel) {
|
||||
super(
|
||||
javaTypeDescriptor.getJavaTypeClass().getName(),
|
||||
javaTypeDescriptor,
|
||||
null,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
jpaMetamodel
|
||||
);
|
||||
|
||||
this.jpaEntityName = javaTypeDescriptor.getJavaTypeClass().getName();
|
||||
this.discriminatorPathSource = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
|
@ -131,7 +145,6 @@ public class EntityTypeImpl<J>
|
|||
}
|
||||
|
||||
if ( "id".equalsIgnoreCase( name ) || EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( name ) ) {
|
||||
//noinspection unchecked
|
||||
final SingularPersistentAttribute<J, ?> idAttribute = findIdAttribute();
|
||||
//noinspection RedundantIfStatement
|
||||
if ( idAttribute != null ) {
|
||||
|
|
|
@ -490,16 +490,21 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
|
|||
|
||||
context.wrapUp();
|
||||
|
||||
this.jpaEntityTypeMap.putAll( context.getEntityTypesByEntityName() );
|
||||
for ( Map.Entry<String, IdentifiableDomainType<?>> entry : context.getIdentifiableTypesByName().entrySet() ) {
|
||||
if ( entry.getValue() instanceof EntityDomainType<?> ) {
|
||||
this.jpaEntityTypeMap.put( entry.getKey(), (EntityDomainType<?>) entry.getValue() );
|
||||
}
|
||||
}
|
||||
|
||||
this.jpaManagedTypeMap.putAll( context.getEntityTypeMap() );
|
||||
this.jpaManagedTypeMap.putAll( context.getMappedSuperclassTypeMap() );
|
||||
this.jpaManagedTypes.addAll( context.getMappedSuperclassTypeMap().values() );
|
||||
switch ( jpaMetaModelPopulationSetting ) {
|
||||
case IGNORE_UNSUPPORTED:
|
||||
this.jpaManagedTypes.addAll( context.getEntityTypeMap().values() );
|
||||
this.jpaManagedTypes.addAll( context.getMappedSuperclassTypeMap().values() );
|
||||
break;
|
||||
case ENABLED:
|
||||
this.jpaManagedTypes.addAll( context.getEntityTypesByEntityName().values() );
|
||||
this.jpaManagedTypes.addAll( context.getIdentifiableTypesByName().values() );
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -562,11 +567,8 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
|
|||
|
||||
private static Stream<ManagedDomainType<?>> domainTypeStream(MetadataContext context) {
|
||||
return Stream.concat(
|
||||
context.getEntityTypesByEntityName().values().stream(),
|
||||
Stream.concat(
|
||||
context.getMappedSuperclassTypeMap().values().stream(),
|
||||
context.getEmbeddableTypeSet().stream()
|
||||
)
|
||||
context.getIdentifiableTypesByName().values().stream(),
|
||||
context.getEmbeddableTypeSet().stream()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.metamodel.model.domain.internal;
|
||||
|
||||
import org.hibernate.metamodel.model.domain.MappedSuperclassDomainType;
|
||||
import org.hibernate.query.hql.spi.SqmCreationState;
|
||||
import org.hibernate.query.spi.NavigablePath;
|
||||
import org.hibernate.query.sqm.SqmJoinable;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
import org.hibernate.query.sqm.tree.SqmJoinType;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPluralPartJoin;
|
||||
import org.hibernate.query.sqm.tree.from.SqmFrom;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MappedSuperclassSqmPathSource<J> extends AbstractSqmPathSource<J> implements SqmJoinable<Object, J> {
|
||||
public MappedSuperclassSqmPathSource(
|
||||
String localPathName,
|
||||
MappedSuperclassDomainType<J> domainType,
|
||||
BindableType jpaBindableType) {
|
||||
super( localPathName, domainType, jpaBindableType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappedSuperclassDomainType<J> getSqmPathType() {
|
||||
//noinspection unchecked
|
||||
return ( MappedSuperclassDomainType<J> ) super.getSqmPathType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPathSource<?> findSubPathSource(String name) {
|
||||
final MappedSuperclassDomainType<J> sqmPathType = getSqmPathType();
|
||||
return sqmPathType.findSubPathSource( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPath<J> createSqmPath(SqmPath<?> lhs, SqmPathSource<?> intermediatePathSource) {
|
||||
final NavigablePath navigablePath;
|
||||
if ( intermediatePathSource == null ) {
|
||||
navigablePath = lhs.getNavigablePath().append( getPathName() );
|
||||
}
|
||||
else {
|
||||
navigablePath = lhs.getNavigablePath().append( intermediatePathSource.getPathName() ).append( getPathName() );
|
||||
}
|
||||
return new SqmEntityValuedSimplePath<>(
|
||||
navigablePath,
|
||||
this,
|
||||
lhs,
|
||||
lhs.nodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPluralPartJoin<Object, J> createSqmJoin(
|
||||
SqmFrom<?, Object> lhs,
|
||||
SqmJoinType joinType,
|
||||
String alias,
|
||||
boolean fetched,
|
||||
SqmCreationState creationState) {
|
||||
return new SqmPluralPartJoin<>(
|
||||
lhs,
|
||||
this,
|
||||
alias,
|
||||
joinType,
|
||||
creationState.getCreationContext().getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getPathName();
|
||||
}
|
||||
}
|
|
@ -7,23 +7,33 @@
|
|||
package org.hibernate.metamodel.model.domain.internal;
|
||||
|
||||
import org.hibernate.cfg.NotYetImplementedException;
|
||||
import org.hibernate.graph.internal.SubGraphImpl;
|
||||
import org.hibernate.graph.spi.SubGraphImplementor;
|
||||
import org.hibernate.mapping.MappedSuperclass;
|
||||
import org.hibernate.metamodel.UnsupportedMappingException;
|
||||
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.model.domain.AbstractIdentifiableType;
|
||||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.metamodel.model.domain.IdentifiableDomainType;
|
||||
import org.hibernate.metamodel.model.domain.JpaMetamodel;
|
||||
import org.hibernate.metamodel.model.domain.MappedSuperclassDomainType;
|
||||
import org.hibernate.metamodel.model.domain.PersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
||||
/**
|
||||
* @author Emmanuel Bernard
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MappedSuperclassTypeImpl<X> extends AbstractIdentifiableType<X> implements MappedSuperclassDomainType<X> {
|
||||
public class MappedSuperclassTypeImpl<J> extends AbstractIdentifiableType<J> implements MappedSuperclassDomainType<J> {
|
||||
public MappedSuperclassTypeImpl(
|
||||
JavaType<X> javaType,
|
||||
JavaType<J> javaType,
|
||||
MappedSuperclass mappedSuperclass,
|
||||
IdentifiableDomainType<? super X> superType,
|
||||
IdentifiableDomainType<? super J> superType,
|
||||
JpaMetamodel jpaMetamodel) {
|
||||
super(
|
||||
javaType.getJavaType().getTypeName(),
|
||||
|
@ -36,18 +46,91 @@ public class MappedSuperclassTypeImpl<X> extends AbstractIdentifiableType<X> imp
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getPathName() {
|
||||
return getTypeName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappedSuperclassDomainType<J> getSqmPathType() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPathSource<?> findSubPathSource(String name) {
|
||||
final PersistentAttribute<?,?> attribute = findAttribute( name );
|
||||
if ( attribute != null ) {
|
||||
return (SqmPathSource<?>) attribute;
|
||||
}
|
||||
|
||||
if ( "id".equalsIgnoreCase( name ) ) {
|
||||
if ( hasIdClass() ) {
|
||||
return getIdentifierDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistentAttribute<? super J, ?> findAttribute(String name) {
|
||||
final PersistentAttribute<? super J, ?> attribute = super.findAttribute( name );
|
||||
if ( attribute != null ) {
|
||||
return attribute;
|
||||
}
|
||||
|
||||
if ( "id".equalsIgnoreCase( name ) || EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( name ) ) {
|
||||
final SingularPersistentAttribute<J, ?> idAttribute = findIdAttribute();
|
||||
//noinspection RedundantIfStatement
|
||||
if ( idAttribute != null ) {
|
||||
return idAttribute;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BindableType getBindableType() {
|
||||
return BindableType.ENTITY_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistenceType getPersistenceType() {
|
||||
return PersistenceType.MAPPED_SUPERCLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends X> SubGraphImplementor<S> makeSubGraph(Class<S> subType) {
|
||||
throw new NotYetImplementedException( );
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S extends J> SubGraphImplementor<S> makeSubGraph(Class<S> subType) {
|
||||
if ( ! getBindableJavaType().isAssignableFrom( subType ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"MappedSuperclass type [%s] cannot be treated as requested sub-type [%s]",
|
||||
getTypeName(),
|
||||
subType.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return new SubGraphImpl( this, true, jpaMetamodel() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubGraphImplementor<J> makeSubGraph() {
|
||||
return makeSubGraph( getBindableJavaType() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isIdMappingRequired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPath<J> createSqmPath(SqmPath<?> lhs, SqmPathSource<?> intermediatePathSource) {
|
||||
throw new UnsupportedMappingException(
|
||||
"MappedSuperclassType cannot be used to create an SqmPath - that would be an SqmFrom which are created directly"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.HashSet;
|
|||
import java.util.IdentityHashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
@ -164,6 +165,7 @@ import org.hibernate.metamodel.mapping.EntityVersionMapping;
|
|||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingModelHelper;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.NaturalIdMapping;
|
||||
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
|
||||
|
@ -202,6 +204,7 @@ import org.hibernate.property.access.spi.PropertyAccess;
|
|||
import org.hibernate.property.access.spi.Setter;
|
||||
import org.hibernate.query.sqm.ComparisonOperator;
|
||||
import org.hibernate.query.spi.NavigablePath;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.named.NamedQueryMemento;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.sql.internal.SQLQueryParser;
|
||||
|
@ -6337,13 +6340,36 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
else {
|
||||
if ( subclassMappingTypes != null && !subclassMappingTypes.isEmpty() ) {
|
||||
ModelPart attribute = null;
|
||||
for ( EntityMappingType subMappingType : subclassMappingTypes.values() ) {
|
||||
final ModelPart subDefinedAttribute = subMappingType.findSubTypesSubPart( name, treatTargetType );
|
||||
|
||||
if ( subDefinedAttribute != null ) {
|
||||
return subDefinedAttribute;
|
||||
if ( attribute != null && !MappingModelHelper.isCompatibleModelPart( attribute, subDefinedAttribute ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
new SemanticException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Could not resolve attribute '%s' of '%s' due to the attribute being declared in multiple sub types: ['%s', '%s']",
|
||||
name,
|
||||
getJavaType().getJavaType().getTypeName(),
|
||||
( (AttributeMapping) attribute ).getDeclaringType()
|
||||
.getJavaType()
|
||||
.getJavaType()
|
||||
.getTypeName(),
|
||||
( (AttributeMapping) subDefinedAttribute ).getDeclaringType()
|
||||
.getJavaType()
|
||||
.getJavaType()
|
||||
.getTypeName()
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
attribute = subDefinedAttribute;
|
||||
}
|
||||
}
|
||||
if ( attribute != null ) {
|
||||
return attribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -245,7 +245,12 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
|
|||
public void consumeTreat(String entityName, boolean isTerminal) {
|
||||
final EntityDomainType<Object> entityDomainType = creationState.getCreationContext().getJpaMetamodel()
|
||||
.entity( entityName );
|
||||
currentPath = currentPath.treatAs( entityDomainType, isTerminal ? alias : null );
|
||||
if ( isTerminal ) {
|
||||
currentPath = currentPath.treatAs( entityDomainType, alias );
|
||||
}
|
||||
else {
|
||||
currentPath = currentPath.treatAs( entityDomainType );
|
||||
}
|
||||
creationState.getCurrentProcessingState().getPathRegistry().register( currentPath );
|
||||
}
|
||||
|
||||
|
|
|
@ -4259,8 +4259,16 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
@Override
|
||||
public SqmPath<?> visitTreatedNavigablePath(HqlParser.TreatedNavigablePathContext ctx) {
|
||||
final DotIdentifierConsumer consumer = dotIdentifierConsumerStack.getCurrent();
|
||||
final boolean madeNested;
|
||||
if ( consumer instanceof QualifiedJoinPathConsumer) {
|
||||
( (QualifiedJoinPathConsumer) consumer ).setNested( true );
|
||||
final QualifiedJoinPathConsumer qualifiedJoinPathConsumer = (QualifiedJoinPathConsumer) consumer;
|
||||
madeNested = !qualifiedJoinPathConsumer.isNested();
|
||||
if ( madeNested ) {
|
||||
qualifiedJoinPathConsumer.setNested( true );
|
||||
}
|
||||
}
|
||||
else {
|
||||
madeNested = false;
|
||||
}
|
||||
consumeManagedTypeReference( (HqlParser.PathContext) ctx.getChild( 2 ) );
|
||||
|
||||
|
@ -4272,18 +4280,27 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
SqmPath<?> result = (SqmPath<?>) consumer.getConsumedPart();
|
||||
|
||||
if ( hasContinuation ) {
|
||||
dotIdentifierConsumerStack.push(
|
||||
new BasicDotIdentifierConsumer( result, this ) {
|
||||
@Override
|
||||
protected void reset() {
|
||||
if ( madeNested ) {
|
||||
// Reset the nested state before consuming the terminal identifier
|
||||
( (QualifiedJoinPathConsumer) consumer ).setNested( false );
|
||||
}
|
||||
final boolean addConsumer = !( consumer instanceof QualifiedJoinPathConsumer );
|
||||
if ( addConsumer ) {
|
||||
dotIdentifierConsumerStack.push(
|
||||
new BasicDotIdentifierConsumer( result, this ) {
|
||||
@Override
|
||||
protected void reset() {
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
}
|
||||
try {
|
||||
result = consumeDomainPath( (HqlParser.SimplePathContext) ctx.getChild( 6 ).getChild( 1 ) );
|
||||
}
|
||||
finally {
|
||||
dotIdentifierConsumerStack.pop();
|
||||
if ( addConsumer ) {
|
||||
dotIdentifierConsumerStack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,11 +20,13 @@ import org.hibernate.metamodel.model.domain.BasicDomainType;
|
|||
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.MappedSuperclassDomainType;
|
||||
import org.hibernate.metamodel.model.domain.internal.AnyMappingSqmPathSource;
|
||||
import org.hibernate.metamodel.model.domain.internal.BasicSqmPathSource;
|
||||
import org.hibernate.metamodel.model.domain.internal.EmbeddedSqmPathSource;
|
||||
import org.hibernate.metamodel.model.domain.internal.EntitySqmPathSource;
|
||||
import org.hibernate.metamodel.MappingMetamodel;
|
||||
import org.hibernate.metamodel.model.domain.internal.MappedSuperclassSqmPathSource;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.spi.NavigablePath;
|
||||
import org.hibernate.query.sqm.SqmExpressible;
|
||||
|
@ -75,7 +77,7 @@ public class SqmMappingModelHelper {
|
|||
DomainType<J> valueDomainType,
|
||||
Bindable.BindableType jpaBindableType) {
|
||||
|
||||
if ( valueDomainType instanceof BasicDomainType ) {
|
||||
if ( valueDomainType instanceof BasicDomainType<?> ) {
|
||||
return new BasicSqmPathSource<>(
|
||||
name,
|
||||
(BasicDomainType<J>) valueDomainType,
|
||||
|
@ -83,7 +85,7 @@ public class SqmMappingModelHelper {
|
|||
);
|
||||
}
|
||||
|
||||
if ( valueDomainType instanceof AnyMappingDomainType ) {
|
||||
if ( valueDomainType instanceof AnyMappingDomainType<?> ) {
|
||||
return new AnyMappingSqmPathSource<>(
|
||||
name,
|
||||
(AnyMappingDomainType<J>) valueDomainType,
|
||||
|
@ -91,7 +93,7 @@ public class SqmMappingModelHelper {
|
|||
);
|
||||
}
|
||||
|
||||
if ( valueDomainType instanceof EmbeddableDomainType ) {
|
||||
if ( valueDomainType instanceof EmbeddableDomainType<?> ) {
|
||||
return new EmbeddedSqmPathSource<>(
|
||||
name,
|
||||
(EmbeddableDomainType<J>) valueDomainType,
|
||||
|
@ -99,7 +101,7 @@ public class SqmMappingModelHelper {
|
|||
);
|
||||
}
|
||||
|
||||
if ( valueDomainType instanceof EntityDomainType ) {
|
||||
if ( valueDomainType instanceof EntityDomainType<?> ) {
|
||||
return new EntitySqmPathSource<>(
|
||||
name,
|
||||
(EntityDomainType<J>) valueDomainType,
|
||||
|
@ -107,6 +109,14 @@ public class SqmMappingModelHelper {
|
|||
);
|
||||
}
|
||||
|
||||
if ( valueDomainType instanceof MappedSuperclassDomainType<?> ) {
|
||||
return new MappedSuperclassSqmPathSource<>(
|
||||
name,
|
||||
(MappedSuperclassDomainType<J>) valueDomainType,
|
||||
jpaBindableType
|
||||
);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"Unrecognized value type Java-type [" + valueDomainType.getTypeName() + "] for plural attribute value"
|
||||
);
|
||||
|
@ -169,8 +179,9 @@ public class SqmMappingModelHelper {
|
|||
public static EntityMappingType resolveExplicitTreatTarget(
|
||||
SqmPath<?> sqmPath,
|
||||
SqmToSqlAstConverter converter) {
|
||||
if ( sqmPath instanceof SqmTreatedPath ) {
|
||||
final SqmTreatedPath treatedPath = (SqmTreatedPath) sqmPath;
|
||||
final SqmPath<?> parentPath = sqmPath.getLhs();
|
||||
if ( parentPath instanceof SqmTreatedPath ) {
|
||||
final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) parentPath;
|
||||
return resolveEntityPersister( treatedPath.getTreatTarget(), converter.getCreationContext().getSessionFactory() );
|
||||
}
|
||||
|
||||
|
|
|
@ -39,19 +39,15 @@ import jakarta.persistence.InheritanceType;
|
|||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
|
||||
import org.hibernate.query.sqm.InterpretationException;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.JiraKey;
|
||||
import org.hibernate.testing.orm.junit.NotImplementedYet;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.Assert;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
|
@ -109,7 +105,6 @@ public class JoinedInheritanceEagerTest {
|
|||
|
||||
@Test
|
||||
@JiraKey("HHH-12375")
|
||||
@NotImplementedYet( strict = false )
|
||||
public void joinUnrelatedCollectionOnBaseType(SessionFactoryScope scope) {
|
||||
scope.inSession(
|
||||
session -> {
|
||||
|
@ -119,8 +114,8 @@ public class JoinedInheritanceEagerTest {
|
|||
session.createQuery( "from BaseEntity b join b.attributes" ).list();
|
||||
fail( "Expected a resolution exception for property 'attributes'!" );
|
||||
}
|
||||
catch (InterpretationException ex) {
|
||||
assertTrue( ex.getMessage().contains( "could not resolve property: attributes " ) );
|
||||
catch (IllegalArgumentException ex) {
|
||||
Assert.assertTrue( ex.getCause().getCause().getMessage().contains( "Could not resolve attribute 'attributes' "));
|
||||
}
|
||||
finally {
|
||||
session.getTransaction().commit();
|
||||
|
|
|
@ -37,6 +37,14 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||
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.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.AssociationOverride;
|
||||
import jakarta.persistence.AssociationOverrides;
|
||||
import jakarta.persistence.Basic;
|
||||
|
@ -57,14 +65,6 @@ import jakarta.persistence.MappedSuperclass;
|
|||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OrderColumn;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.NotImplementedYet;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
|
@ -79,68 +79,60 @@ import org.junit.jupiter.api.Test;
|
|||
MultiInheritanceImplicitDowncastTest.PolymorphicPropertySub2.class,
|
||||
MultiInheritanceImplicitDowncastTest.PolymorphicSub1.class,
|
||||
MultiInheritanceImplicitDowncastTest.PolymorphicSub2.class
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@NotImplementedYet( strict = false )
|
||||
})
|
||||
@SessionFactory(statementInspectorClass = SQLStatementInspector.class)
|
||||
public class MultiInheritanceImplicitDowncastTest {
|
||||
@Test
|
||||
public void testQueryingSingle(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (s) -> {
|
||||
final String base = "from PolymorphicPropertyBase p left join ";
|
||||
s.createQuery( base + "p.base b left join b.relation1 " ).getResultList();
|
||||
s.createQuery( base + "p.base b left join b.relation2 " ).getResultList();
|
||||
s.createQuery( base + "p.baseEmbeddable.embeddedRelation1 b left join b.relation1" ).getResultList();
|
||||
s.createQuery( base + "p.baseEmbeddable.embeddedRelation2 b left join b.relation2" ).getResultList();
|
||||
s.createQuery( base + "p.baseEmbeddable.embeddedBase b left join b.relation1" ).getResultList();
|
||||
s.createQuery( base + "p.baseEmbeddable.embeddedBase b left join b.relation2" ).getResultList();
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryingMultiple(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (s) -> {
|
||||
final String base = "from PolymorphicPropertyBase p left join ";
|
||||
s.createQuery( base + "p.base b left join b.relation1 left join b.relation2" ).getResultList();
|
||||
s.createQuery( base + "p.base b left join b.relation2 left join b.relation1" ).getResultList();
|
||||
s.createQuery( base + "p.baseEmbeddable.embeddedBase b left join b.relation1 left join b.relation2" ).getResultList();
|
||||
s.createQuery( base + "p.baseEmbeddable.embeddedBase b left join b.relation2 left join b.relation1" ).getResultList();
|
||||
} );
|
||||
public void testIllegalBaseJoin(SessionFactoryScope scope) {
|
||||
try {
|
||||
scope.inSession(
|
||||
s -> s.createQuery( "from PolymorphicPropertyBase p left join p.base b left join b.relation1" )
|
||||
);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
Assertions.assertTrue( ex.getCause()
|
||||
.getCause()
|
||||
.getMessage()
|
||||
.contains( "Could not resolve attribute 'base' " ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiJoinAddition1(SessionFactoryScope scope) {
|
||||
testMultiJoinAddition( "from PolymorphicPropertyBase p left join p.base b left join b.relation1", scope );
|
||||
testMultiJoinAddition(
|
||||
scope,
|
||||
"base_sub_1",
|
||||
"select 1 from PolymorphicPropertyBase p left join treat(p as PolymorphicPropertySub1).base b left join b.relation1"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiJoinAddition2(SessionFactoryScope scope) {
|
||||
testMultiJoinAddition( "from PolymorphicPropertyBase p left join p.base b left join b.relation2", scope );
|
||||
testMultiJoinAddition(
|
||||
scope,
|
||||
"base_sub_2",
|
||||
"select 1 from PolymorphicPropertyBase p left join treat(p as PolymorphicPropertySub2).base b left join b.relation2"
|
||||
);
|
||||
}
|
||||
|
||||
private void testMultiJoinAddition(String hql, SessionFactoryScope scope) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
// final HQLQueryPlan plan = sessionFactory().getQueryInterpretationCache().getHQLQueryPlan(
|
||||
// hql,
|
||||
// false,
|
||||
// Collections.EMPTY_MAP
|
||||
// );
|
||||
// assertEquals( 1, plan.getTranslators().length );
|
||||
// final QueryTranslator translator = plan.getTranslators()[0];
|
||||
// final String generatedSql = translator.getSQLString();
|
||||
//
|
||||
// int sub1JoinColumnIndex = generatedSql.indexOf( ".base_sub_1" );
|
||||
// assertNotEquals(
|
||||
// "Generated SQL doesn't contain a join for 'base' with 'PolymorphicSub1' via 'base_sub_1':\n" + generatedSql,
|
||||
// -1,
|
||||
// sub1JoinColumnIndex
|
||||
// );
|
||||
// int sub2JoinColumnIndex = generatedSql.indexOf( ".base_sub_2" );
|
||||
// assertNotEquals(
|
||||
// "Generated SQL doesn't contain a join for 'base' with 'PolymorphicSub2' via 'base_sub_2':\n" + generatedSql,
|
||||
// -1,
|
||||
// sub2JoinColumnIndex
|
||||
// );
|
||||
private void testMultiJoinAddition(SessionFactoryScope scope, String joinColumnBase, String hql) {
|
||||
SQLStatementInspector sqlStatementInterceptor = (SQLStatementInspector) scope.getStatementInspector();
|
||||
scope.inTransaction(
|
||||
s -> {
|
||||
sqlStatementInterceptor.clear();
|
||||
s.createQuery( hql ).getResultList();
|
||||
sqlStatementInterceptor.assertExecutedCount( 1 );
|
||||
final String generatedSql = sqlStatementInterceptor.getSqlQueries().get( 0 );
|
||||
|
||||
int sub1JoinColumnIndex = generatedSql.indexOf( "." + joinColumnBase );
|
||||
Assertions.assertNotEquals(
|
||||
-1,
|
||||
sub1JoinColumnIndex,
|
||||
"Generated SQL doesn't contain a join for 'base' via '" + joinColumnBase + "':\n" + generatedSql
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
|
@ -466,13 +458,12 @@ public class MultiInheritanceImplicitDowncastTest {
|
|||
}
|
||||
|
||||
@MappedSuperclass
|
||||
public abstract static class PolymorphicPropertyMapBase<T extends PolymorphicBase, E extends BaseEmbeddable> extends
|
||||
PolymorphicPropertyBase {
|
||||
public abstract static class PolymorphicPropertyMapBase<T extends PolymorphicBase> extends PolymorphicPropertyBase {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private T base;
|
||||
private E baseEmbeddable;
|
||||
private Set<T> bases;
|
||||
|
||||
public PolymorphicPropertyMapBase() {
|
||||
}
|
||||
|
@ -486,21 +477,22 @@ public class MultiInheritanceImplicitDowncastTest {
|
|||
this.base = base;
|
||||
}
|
||||
|
||||
@Embedded
|
||||
public E getBaseEmbeddable() {
|
||||
return baseEmbeddable;
|
||||
@OneToMany
|
||||
public Set<T> getBases() {
|
||||
return bases;
|
||||
}
|
||||
|
||||
public void setBaseEmbeddable(E baseEmbeddable) {
|
||||
this.baseEmbeddable = baseEmbeddable;
|
||||
public void setBases(Set<T> bases) {
|
||||
this.bases = bases;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Entity(name = "PolymorphicPropertySub1")
|
||||
@AssociationOverrides({
|
||||
@AssociationOverride(name = "base", joinColumns = @JoinColumn(name = "base_sub_1"))
|
||||
})
|
||||
public static class PolymorphicPropertySub1 extends PolymorphicPropertyMapBase<PolymorphicSub1, Embeddable1> {
|
||||
public static class PolymorphicPropertySub1 extends PolymorphicPropertyMapBase<PolymorphicSub1> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public PolymorphicPropertySub1() {
|
||||
|
@ -511,7 +503,7 @@ public class MultiInheritanceImplicitDowncastTest {
|
|||
@AssociationOverrides({
|
||||
@AssociationOverride(name = "base", joinColumns = @JoinColumn(name = "base_sub_2"))
|
||||
})
|
||||
public static class PolymorphicPropertySub2 extends PolymorphicPropertyMapBase<PolymorphicSub2, Embeddable2> {
|
||||
public static class PolymorphicPropertySub2 extends PolymorphicPropertyMapBase<PolymorphicSub2> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public PolymorphicPropertySub2() {
|
||||
|
|
|
@ -16,7 +16,6 @@ import org.hibernate.Hibernate;
|
|||
import org.hibernate.query.Query;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.NotImplementedYet;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
@ -47,7 +46,6 @@ public class JoinedSubclassTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@NotImplementedYet( strict = false )
|
||||
public void testJoinedSubclass(SessionFactoryScope scope) {
|
||||
scope.inTransaction( s -> {
|
||||
|
||||
|
@ -76,8 +74,6 @@ public class JoinedSubclassTest {
|
|||
s.save( mark );
|
||||
s.save( joe );
|
||||
|
||||
assertEquals( s.createQuery( "from java.lang.Object" ).list().size(), 0 );
|
||||
|
||||
assertEquals( s.createQuery( "from Person" ).list().size(), 3 );
|
||||
assertEquals( s.createQuery( "from Person p where p.class = Customer" ).list().size(), 1 );
|
||||
assertEquals( s.createQuery( "from Person p where p.class = Person" ).list().size(), 1 );
|
||||
|
|
Loading…
Reference in New Issue