org.hibernate.mapping.PersistentClass Maven / Gradle / Ivy
Show all versions of beangle-hibernate-core Show documentation
/*
* 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 .
*/
package org.hibernate.mapping;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.function.Supplier;
import org.hibernate.Internal;
import org.hibernate.MappingException;
import org.hibernate.annotations.CacheLayout;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.boot.spi.ClassLoaderAccess;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.internal.FilterConfiguration;
import org.hibernate.internal.util.collections.JoinedList;
import org.hibernate.jdbc.Expectation;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.jpa.event.spi.CallbackDefinition;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.sql.Alias;
import org.hibernate.type.CollectionType;
import org.hibernate.type.Type;
import org.hibernate.type.spi.TypeConfiguration;
import static java.util.Collections.emptyList;
import static java.util.Collections.unmodifiableList;
import static java.util.Comparator.comparing;
import static org.hibernate.internal.util.StringHelper.qualify;
import static org.hibernate.internal.util.StringHelper.root;
import static org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle.expectationConstructor;
import static org.hibernate.mapping.MappingHelper.checkPropertyColumnDuplication;
import static org.hibernate.sql.Template.collectColumnNames;
/**
* A mapping model object that represents an {@linkplain jakarta.persistence.Entity entity class}.
*
* @author Gavin King
*/
public abstract class PersistentClass implements IdentifiableTypeClass, AttributeContainer, Filterable, MetaAttributable, Contributable, Serializable {
private static final Alias PK_ALIAS = new Alias( 15, "PK" );
/**
* The magic value of {@link jakarta.persistence.DiscriminatorValue#value}
* which indicates that the subclass is distinguished by a null value of the
* discriminator column.
*/
public static final String NULL_DISCRIMINATOR_MAPPING = "null";
/**
* The magic value of {@link jakarta.persistence.DiscriminatorValue#value}
* which indicates that the subclass is distinguished by any non-null value
* of the discriminator column.
*/
public static final String NOT_NULL_DISCRIMINATOR_MAPPING = "not null";
private final MetadataBuildingContext metadataBuildingContext;
private final String contributor;
private String entityName;
private String className;
private transient Class> mappedClass;
private String proxyInterfaceName;
private transient Class> proxyInterface;
private String jpaEntityName;
private String discriminatorValue;
private boolean lazy;
private final List properties = new ArrayList<>();
private final List declaredProperties = new ArrayList<>();
private final List subclasses = new ArrayList<>();
private final List subclassProperties = new ArrayList<>();
private final List subclassTables = new ArrayList<>();
private boolean dynamicInsert;
private boolean dynamicUpdate;
private int batchSize = -1;
private boolean selectBeforeUpdate;
private java.util.Map metaAttributes;
private final List joins = new ArrayList<>();
private final List subclassJoins = new ArrayList<>();
private final List filters = new ArrayList<>();
protected final Set synchronizedTables = new HashSet<>();
private String loaderName;
private Boolean isAbstract;
private boolean hasSubselectLoadableCollections;
private Component identifierMapper;
private List callbackDefinitions;
private final List checkConstraints = new ArrayList<>();
// Custom SQL
private String customSQLInsert;
private boolean customInsertCallable;
private ExecuteUpdateResultCheckStyle insertCheckStyle;
private String customSQLUpdate;
private boolean customUpdateCallable;
private ExecuteUpdateResultCheckStyle updateCheckStyle;
private String customSQLDelete;
private boolean customDeleteCallable;
private ExecuteUpdateResultCheckStyle deleteCheckStyle;
private MappedSuperclass superMappedSuperclass;
private Component declaredIdentifierMapper;
private OptimisticLockStyle optimisticLockStyle;
private Supplier extends Expectation> insertExpectation;
private Supplier extends Expectation> updateExpectation;
private Supplier extends Expectation> deleteExpectation;
private boolean isCached;
private CacheLayout queryCacheLayout;
public PersistentClass(MetadataBuildingContext buildingContext) {
this.metadataBuildingContext = buildingContext;
this.contributor = buildingContext.getCurrentContributorName();
}
public String getContributor() {
return contributor;
}
public ServiceRegistry getServiceRegistry() {
return metadataBuildingContext.getBuildingOptions().getServiceRegistry();
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className == null ? null : className.intern();
this.mappedClass = null;
}
public String getProxyInterfaceName() {
return proxyInterfaceName;
}
public void setProxyInterfaceName(String proxyInterfaceName) {
this.proxyInterfaceName = proxyInterfaceName;
this.proxyInterface = null;
}
private ClassLoaderAccess getClassLoaderAccess() {
return metadataBuildingContext.getBootstrapContext().getClassLoaderAccess();
}
public Class> getMappedClass() throws MappingException {
if ( className == null ) {
return null;
}
try {
if ( mappedClass == null ) {
mappedClass = getClassLoaderAccess().classForName( className );
}
return mappedClass;
}
catch (ClassLoadingException e) {
throw new MappingException( "entity class not found: " + className, e );
}
}
public Class> getProxyInterface() {
if ( proxyInterfaceName == null ) {
return null;
}
try {
if ( proxyInterface == null ) {
proxyInterface = getClassLoaderAccess().classForName( proxyInterfaceName );
}
return proxyInterface;
}
catch (ClassLoadingException e) {
throw new MappingException( "proxy class not found: " + proxyInterfaceName, e );
}
}
public boolean useDynamicInsert() {
return dynamicInsert;
}
abstract int nextSubclassId();
public abstract int getSubclassId();
public boolean useDynamicUpdate() {
return dynamicUpdate;
}
public void setDynamicInsert(boolean dynamicInsert) {
this.dynamicInsert = dynamicInsert;
}
public void setDynamicUpdate(boolean dynamicUpdate) {
this.dynamicUpdate = dynamicUpdate;
}
public String getDiscriminatorValue() {
return discriminatorValue;
}
public void addSubclass(Subclass subclass) throws MappingException {
// inheritance cycle detection (paranoid check)
PersistentClass superclass = getSuperclass();
while ( superclass != null ) {
if ( subclass.getEntityName().equals( superclass.getEntityName() ) ) {
throw new MappingException(
"Circular inheritance mapping detected: " +
subclass.getEntityName() +
" will have itself as superclass when extending " +
getEntityName()
);
}
superclass = superclass.getSuperclass();
}
subclasses.add( subclass );
}
public boolean hasSubclasses() {
return !subclasses.isEmpty();
}
public int getSubclassSpan() {
int span = subclasses.size();
for ( Subclass subclass : subclasses ) {
span += subclass.getSubclassSpan();
}
return span;
}
/**
* Get the subclasses in a special 'order', most derived subclasses first.
*/
public List getSubclasses() {
@SuppressWarnings("unchecked")
List[] subclassLists = new List[subclasses.size() + 1];
int j;
for (j = 0; j < subclasses.size(); j++) {
subclassLists[j] = subclasses.get(j).getSubclasses();
}
subclassLists[j] = subclasses;
return new JoinedList<>( subclassLists );
}
public List getSubclassClosure() {
final ArrayList> lists = new ArrayList<>();
lists.add( List.of( this ) );
for ( Subclass subclass : getSubclasses() ) {
lists.add( subclass.getSubclassClosure() );
}
return new JoinedList<>( lists );
}
public Table getIdentityTable() {
return getRootTable();
}
public List getDirectSubclasses() {
return subclasses;
}
@Override
public void addProperty(Property property) {
properties.add( property );
declaredProperties.add( property );
property.setPersistentClass( this );
}
@Override
public boolean contains(Property property) {
return properties.contains( property );
}
public abstract Table getTable();
public String getEntityName() {
return entityName;
}
public abstract boolean isMutable();
public abstract boolean hasIdentifierProperty();
public abstract Property getIdentifierProperty();
public abstract Property getDeclaredIdentifierProperty();
public abstract KeyValue getIdentifier();
public abstract Property getVersion();
public abstract Property getDeclaredVersion();
public abstract Value getDiscriminator();
public abstract boolean isInherited();
public abstract boolean isPolymorphic();
public abstract boolean isVersioned();
public boolean isCached() {
return isCached;
}
public void setCached(boolean cached) {
isCached = cached;
}
/**
* @deprecated Use {@link #isCached} instead
*/
@Deprecated(forRemoval = true)
public boolean isCachingExplicitlyRequested() {
return isCached();
}
/**
* @deprecated Use {@link #setCached} instead
*/
@Deprecated(forRemoval = true)
public void setCachingExplicitlyRequested(boolean cached) {
setCached( cached );
}
public CacheLayout getQueryCacheLayout() {
return queryCacheLayout;
}
public void setQueryCacheLayout(CacheLayout queryCacheLayout) {
this.queryCacheLayout = queryCacheLayout;
}
public abstract String getCacheConcurrencyStrategy();
public abstract String getNaturalIdCacheRegionName();
public abstract PersistentClass getSuperclass();
public abstract boolean isExplicitPolymorphism();
public abstract boolean isDiscriminatorInsertable();
public abstract List getPropertyClosure();
public abstract List getTableClosure();
public abstract List getKeyClosure();
protected void addSubclassProperty(Property prop) {
subclassProperties.add( prop );
}
protected void addSubclassJoin(Join join) {
subclassJoins.add( join );
}
protected void addSubclassTable(Table subclassTable) {
subclassTables.add( subclassTable );
}
public List getSubclassPropertyClosure() {
final ArrayList> lists = new ArrayList<>();
lists.add( getPropertyClosure() );
lists.add( subclassProperties );
for ( Join join : subclassJoins ) {
lists.add( join.getProperties() );
}
return new JoinedList<>( lists );
}
public List getSubclassJoinClosure() {
return new JoinedList<>( getJoinClosure(), subclassJoins );
}
public List getSubclassTableClosure() {
return new JoinedList<>( getTableClosure(), subclassTables );
}
public boolean isClassOrSuperclassJoin(Join join) {
return joins.contains( join );
}
public boolean isClassOrSuperclassTable(Table closureTable) {
return getTable() == closureTable;
}
public boolean isLazy() {
return lazy;
}
public void setLazy(boolean lazy) {
this.lazy = lazy;
}
public abstract boolean isConcreteProxy();
public abstract boolean hasEmbeddedIdentifier();
public abstract Class extends EntityPersister> getEntityPersisterClass();
public abstract void setEntityPersisterClass(Class extends EntityPersister> classPersisterClass);
public abstract Table getRootTable();
public abstract RootClass getRootClass();
public abstract KeyValue getKey();
public void setDiscriminatorValue(String discriminatorValue) {
this.discriminatorValue = discriminatorValue;
}
public void setEntityName(String entityName) {
this.entityName = entityName == null ? null : entityName.intern();
}
public void createPrimaryKey() {
//Primary key constraint
final Table table = getTable();
final PrimaryKey pk = new PrimaryKey( table );
pk.setName( PK_ALIAS.toAliasString( table.getName() ) );
pk.addColumns( getKey() );
table.setPrimaryKey( pk );
}
public abstract String getWhere();
public int getBatchSize() {
return batchSize;
}
public void setBatchSize(int batchSize) {
this.batchSize = batchSize;
}
public boolean hasSelectBeforeUpdate() {
return selectBeforeUpdate;
}
public void setSelectBeforeUpdate(boolean selectBeforeUpdate) {
this.selectBeforeUpdate = selectBeforeUpdate;
}
/**
* Build a list of properties which may be referenced in association mappings.
*
* Includes properties defined in superclasses of the mapping inheritance.
* Includes all properties defined as part of a join.
*
* @see #getReferencedProperty
* @return The referenceable property iterator.
*/
public List getReferenceableProperties() {
return getPropertyClosure();
}
/**
* Given a property path, locate the appropriate referenceable property reference.
*
* A referenceable property is a property which can be a target of a foreign-key
* mapping (e.g. {@code @ManyToOne}, {@code @OneToOne}).
*
* @param propertyPath The property path to resolve into a property reference.
*
* @return The property reference (never null).
*
* @throws MappingException If the property could not be found.
*/
public Property getReferencedProperty(String propertyPath) throws MappingException {
try {
return getRecursiveProperty( propertyPath, getReferenceableProperties() );
}
catch ( MappingException e ) {
throw new MappingException(
"property-ref [" + propertyPath + "] not found on entity [" + getEntityName() + "]", e
);
}
}
public Property getRecursiveProperty(String propertyPath) throws MappingException {
try {
return getRecursiveProperty( propertyPath, getPropertyClosure() );
}
catch ( MappingException e ) {
throw new MappingException(
"property [" + propertyPath + "] not found on entity [" + getEntityName() + "]", e
);
}
}
private Property getRecursiveProperty(String propertyPath, List properties) throws MappingException {
Property property = null;
StringTokenizer st = new StringTokenizer( propertyPath, ".", false );
try {
while ( st.hasMoreElements() ) {
final String element = (String) st.nextElement();
if ( property == null ) {
Property identifierProperty = getIdentifierProperty();
if ( identifierProperty != null && identifierProperty.getName().equals( element ) ) {
// we have a mapped identifier property and the root of
// the incoming property path matched that identifier
// property
property = identifierProperty;
}
else if ( identifierProperty == null && getIdentifierMapper() != null ) {
// we have an embedded composite identifier
try {
identifierProperty = getProperty( element, getIdentifierMapper().getProperties() );
// the root of the incoming property path matched one
// of the embedded composite identifier properties
property = identifierProperty;
}
catch ( MappingException ignore ) {
// ignore it...
}
}
if ( property == null ) {
property = getProperty( element, properties );
}
}
else {
//flat recursive algorithm
property = ( (Component) property.getValue() ).getProperty( element );
}
}
}
catch ( MappingException e ) {
throw new MappingException( "property [" + propertyPath + "] not found on entity [" + getEntityName() + "]" );
}
return property;
}
private Property getProperty(String propertyName, List properties) throws MappingException {
String root = root( propertyName );
for ( Property prop : properties ) {
if ( prop.getName().equals( root )
|| ( prop instanceof Backref || prop instanceof IndexBackref )
&& prop.getName().equals( propertyName ) ) {
return prop;
}
}
throw new MappingException( "property [" + propertyName + "] not found on entity [" + getEntityName() + "]" );
}
public Property getProperty(String propertyName) throws MappingException {
Property identifierProperty = getIdentifierProperty();
if ( identifierProperty != null
&& identifierProperty.getName().equals( root( propertyName ) ) ) {
return identifierProperty;
}
else {
List closure = getPropertyClosure();
Component identifierMapper = getIdentifierMapper();
if ( identifierMapper != null ) {
closure = new JoinedList<>( identifierMapper.getProperties(), closure );
}
return getProperty( propertyName, closure );
}
}
/**
* @deprecated This will be removed with no replacement.
*/
@Deprecated(since = "6.2", forRemoval = true)
public Property getSubclassProperty(String propertyName) throws MappingException {
final Property identifierProperty = getIdentifierProperty();
if ( identifierProperty != null
&& identifierProperty.getName().equals( root( propertyName ) ) ) {
return identifierProperty;
}
else {
final Component identifierMapper = getIdentifierMapper();
final List closure = identifierMapper != null
? new JoinedList<>( identifierMapper.getProperties(), getSubclassPropertyClosure() )
: getSubclassPropertyClosure();
return getProperty( propertyName, closure );
}
}
/**
* Check to see if this PersistentClass defines a property with the given name.
*
* @param name The property name to check
*
* @return {@code true} if a property with that name exists; {@code false} if not
*/
public boolean hasProperty(String name) {
final Property identifierProperty = getIdentifierProperty();
if ( identifierProperty != null && identifierProperty.getName().equals( name ) ) {
return true;
}
for ( Property property : getPropertyClosure() ) {
if ( property.getName().equals(name) ) {
return true;
}
}
return false;
}
/**
* Check to see if a property with the given name exists in the super hierarchy
* of this PersistentClass. Does not check this PersistentClass, just up the
* hierarchy
*
* @param name The property name to check
*
* @return {@code true} if a property with that name exists; {@code false} if not
*/
public boolean isPropertyDefinedInSuperHierarchy(String name) {
return getSuperclass() != null && getSuperclass().isPropertyDefinedInHierarchy( name );
}
/**
* Check to see if a property with the given name exists in this PersistentClass
* or in any of its super hierarchy. Unlike {@link #isPropertyDefinedInSuperHierarchy},
* this method does check this PersistentClass
*
* @param name The property name to check
*
* @return {@code true} if a property with that name exists; {@code false} if not
*/
public boolean isPropertyDefinedInHierarchy(String name) {
return hasProperty( name )
|| getSuperMappedSuperclass() != null && getSuperMappedSuperclass().isPropertyDefinedInHierarchy( name )
|| getSuperclass() != null && getSuperclass().isPropertyDefinedInHierarchy( name );
}
/**
* @deprecated prefer {@link #getOptimisticLockStyle}
*/
@Deprecated(forRemoval = true)
public int getOptimisticLockMode() {
return getOptimisticLockStyle().getOldCode();
}
/**
* @deprecated prefer {@link #setOptimisticLockStyle}
*/
@Deprecated(forRemoval = true)
public void setOptimisticLockMode(int optimisticLockMode) {
setOptimisticLockStyle( OptimisticLockStyle.interpretOldCode( optimisticLockMode ) );
}
public OptimisticLockStyle getOptimisticLockStyle() {
return optimisticLockStyle;
}
public void setOptimisticLockStyle(OptimisticLockStyle optimisticLockStyle) {
this.optimisticLockStyle = optimisticLockStyle;
}
public void validate(Metadata mapping) throws MappingException {
for ( Property prop : getProperties() ) {
if ( !prop.isValid( mapping ) ) {
final Type type = prop.getType();
final int actualColumns = prop.getColumnSpan();
final int requiredColumns = type.getColumnSpan( mapping );
throw new MappingException(
"Property '" + qualify( getEntityName(), prop.getName() )
+ "' maps to " + actualColumns + " columns but " + requiredColumns
+ " columns are required (type '" + type.getName()
+ "' spans " + requiredColumns + " columns)"
);
}
}
checkPropertyDuplication();
checkColumnDuplication();
}
private void checkPropertyDuplication() throws MappingException {
final HashSet names = new HashSet<>();
for ( Property prop : getProperties() ) {
if ( !names.add( prop.getName() ) ) {
throw new MappingException( "Duplicate property mapping of " + prop.getName() + " found in " + getEntityName() );
}
}
}
public boolean isDiscriminatorValueNotNull() {
return NOT_NULL_DISCRIMINATOR_MAPPING.equals( getDiscriminatorValue() );
}
public boolean isDiscriminatorValueNull() {
return NULL_DISCRIMINATOR_MAPPING.equals( getDiscriminatorValue() );
}
public Map getMetaAttributes() {
return metaAttributes;
}
public void setMetaAttributes(java.util.Map metas) {
this.metaAttributes = metas;
}
public MetaAttribute getMetaAttribute(String name) {
return metaAttributes == null ? null : metaAttributes.get( name );
}
@Override
public String toString() {
return getClass().getSimpleName() + '(' + getEntityName() + ')';
}
public List getJoins() {
return joins;
}
public List getJoinClosure() {
return joins;
}
public void addJoin(Join join) {
if ( !joins.contains(join) ) {
joins.add( join );
}
join.setPersistentClass( this );
}
public int getJoinClosureSpan() {
return joins.size();
}
public int getPropertyClosureSpan() {
int span = properties.size();
for ( Join join : joins ) {
span += join.getPropertySpan();
}
return span;
}
public int getJoinNumber(Property prop) {
int result = 1;
for ( Join join : getSubclassJoinClosure() ) {
if ( join.containsProperty( prop ) ) {
return result;
}
result++;
}
return 0;
}
/**
* Build a list of the properties defined on this class. The returned
* iterator only accounts for "normal" properties (i.e. non-identifier
* properties).
*
* Differs from {@link #getUnjoinedProperties} in that the returned list
* will include properties defined as part of a join.
*
* Differs from {@link #getReferenceableProperties} in that the properties
* defined in superclasses of the mapping inheritance are not included.
*
* @return A list over the "normal" properties.
*/
public List getProperties() {
final ArrayList> list = new ArrayList<>();
list.add( properties );
for ( Join join : joins ) {
list.add( join.getProperties() );
}
return new JoinedList<>( list );
}
/**
* Get a list of the properties defined on this class which
* are not defined as part of a join. As with {@link #getProperties},
* the returned iterator only accounts for non-identifier properties.
*
* @return An iterator over the non-joined "normal" properties.
*/
public List getUnjoinedProperties() {
return properties;
}
public void setCustomSQLInsert(String customSQLInsert, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
this.customSQLInsert = customSQLInsert;
this.customInsertCallable = callable;
this.insertCheckStyle = checkStyle;
this.insertExpectation = expectationConstructor( checkStyle );
}
public String getCustomSQLInsert() {
return customSQLInsert;
}
public boolean isCustomInsertCallable() {
return customInsertCallable;
}
/**
* @deprecated use {@link #getInsertExpectation()}
*/
@Deprecated(since = "6.5", forRemoval = true)
public ExecuteUpdateResultCheckStyle getCustomSQLInsertCheckStyle() {
return insertCheckStyle;
}
public void setCustomSQLUpdate(String customSQLUpdate, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
this.customSQLUpdate = customSQLUpdate;
this.customUpdateCallable = callable;
this.updateCheckStyle = checkStyle;
this.updateExpectation = expectationConstructor( checkStyle );
}
public String getCustomSQLUpdate() {
return customSQLUpdate;
}
public boolean isCustomUpdateCallable() {
return customUpdateCallable;
}
/**
* @deprecated use {@link #getUpdateExpectation()}
*/
@Deprecated(since = "6.5", forRemoval = true)
public ExecuteUpdateResultCheckStyle getCustomSQLUpdateCheckStyle() {
return updateCheckStyle;
}
public void setCustomSQLDelete(String customSQLDelete, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) {
this.customSQLDelete = customSQLDelete;
this.customDeleteCallable = callable;
this.deleteCheckStyle = checkStyle;
this.deleteExpectation = expectationConstructor( checkStyle );
}
public String getCustomSQLDelete() {
return customSQLDelete;
}
public boolean isCustomDeleteCallable() {
return customDeleteCallable;
}
/**
* @deprecated use {@link #getDeleteExpectation()}
*/
@Deprecated(since = "6.5", forRemoval = true)
public ExecuteUpdateResultCheckStyle getCustomSQLDeleteCheckStyle() {
return deleteCheckStyle;
}
public void addFilter(
String name,
String condition,
boolean autoAliasInjection,
java.util.Map aliasTableMap,
java.util.Map aliasEntityMap) {
filters.add(
new FilterConfiguration(
name,
condition,
autoAliasInjection,
aliasTableMap,
aliasEntityMap,
this
)
);
}
public java.util.List getFilters() {
return filters;
}
public boolean isForceDiscriminator() {
return false;
}
public abstract boolean isJoinedSubclass();
public String getLoaderName() {
return loaderName;
}
public void setLoaderName(String loaderName) {
this.loaderName = loaderName == null ? null : loaderName.intern();
}
public abstract Set getSynchronizedTables();
public void addSynchronizedTable(String table) {
synchronizedTables.add( table );
}
public Boolean isAbstract() {
return isAbstract;
}
public void setAbstract(Boolean isAbstract) {
this.isAbstract = isAbstract;
}
protected List getNonDuplicatedProperties() {
return getUnjoinedProperties();
}
protected void checkColumnDuplication() {
final String owner = "entity '" + getEntityName() + "'";
final HashSet cols = new HashSet<>();
if ( getIdentifierMapper() == null ) {
//an identifier mapper => getKey will be included in the getNonDuplicatedPropertyIterator()
//and checked later, so it needs to be excluded
getKey().checkColumnDuplication( cols, owner );
}
if ( isDiscriminatorInsertable() && getDiscriminator() != null ) {
getDiscriminator().checkColumnDuplication( cols, owner );
}
if ( getRootClass().getSoftDeleteColumn() != null ) {
getRootClass().getSoftDeleteColumn().getValue().checkColumnDuplication( cols, owner );
}
checkPropertyColumnDuplication( cols, getNonDuplicatedProperties(), owner );
for ( Join join : getJoins() ) {
cols.clear();
join.getKey().checkColumnDuplication( cols, owner );
checkPropertyColumnDuplication( cols, join.getProperties(), owner );
}
}
public abstract Object accept(PersistentClassVisitor mv);
public String getJpaEntityName() {
return jpaEntityName;
}
public void setJpaEntityName(String jpaEntityName) {
this.jpaEntityName = jpaEntityName;
}
public boolean hasPojoRepresentation() {
return getClassName() != null;
}
public boolean hasSubselectLoadableCollections() {
return hasSubselectLoadableCollections;
}
public void setSubselectLoadableCollections(boolean hasSubselectCollections) {
this.hasSubselectLoadableCollections = hasSubselectCollections;
}
public boolean hasCollectionNotReferencingPK() {
return hasCollectionNotReferencingPK( properties );
}
private boolean hasCollectionNotReferencingPK(Collection properties) {
for ( Property property : properties ) {
final Value value = property.getValue();
if ( value instanceof Component ) {
if ( hasCollectionNotReferencingPK( ( (Component) value ).getProperties() ) ) {
return true;
}
}
else if ( value instanceof org.hibernate.mapping.Collection ) {
final org.hibernate.mapping.Collection collection = (org.hibernate.mapping.Collection) value;
if ( !( (CollectionType) collection.getType() ).useLHSPrimaryKey() ) {
return true;
}
}
}
return false;
}
public boolean hasPartitionedSelectionMapping() {
if ( getSuperclass() != null && getSuperclass().hasPartitionedSelectionMapping() ) {
return true;
}
for ( Property property : getProperties() ) {
final Value value = property.getValue();
if ( value instanceof BasicValue && ( (BasicValue) value ).isPartitionKey() ) {
return true;
}
}
return false;
}
public Component getIdentifierMapper() {
return identifierMapper;
}
public Component getDeclaredIdentifierMapper() {
return declaredIdentifierMapper;
}
public void setDeclaredIdentifierMapper(Component declaredIdentifierMapper) {
this.declaredIdentifierMapper = declaredIdentifierMapper;
}
public boolean hasIdentifierMapper() {
return identifierMapper != null;
}
public void addCallbackDefinitions(java.util.List callbackDefinitions) {
if ( callbackDefinitions == null || callbackDefinitions.isEmpty() ) {
return;
}
if ( this.callbackDefinitions == null ) {
this.callbackDefinitions = new ArrayList<>();
}
this.callbackDefinitions.addAll( callbackDefinitions );
}
public java.util.List getCallbackDefinitions() {
return callbackDefinitions == null ? emptyList() : unmodifiableList( callbackDefinitions );
}
public void setIdentifierMapper(Component handle) {
this.identifierMapper = handle;
}
private Boolean hasNaturalId;
public boolean hasNaturalId() {
if ( hasNaturalId == null ) {
hasNaturalId = determineIfNaturalIdDefined();
}
return hasNaturalId;
}
private boolean determineIfNaturalIdDefined() {
final List props = getRootClass().getProperties();
for ( Property p : props ) {
if ( p.isNaturalIdentifier() ) {
return true;
}
}
return false;
}
// The following methods are added to support @MappedSuperclass in the metamodel
public List getDeclaredProperties() {
final ArrayList> lists = new ArrayList<>();
lists.add( declaredProperties );
for ( Join join : joins ) {
lists.add( join.getDeclaredProperties() );
}
return new JoinedList<>( lists );
}
public void addMappedSuperclassProperty(Property p) {
properties.add( p );
p.setPersistentClass( this );
}
public MappedSuperclass getSuperMappedSuperclass() {
return superMappedSuperclass;
}
public void setSuperMappedSuperclass(MappedSuperclass superMappedSuperclass) {
this.superMappedSuperclass = superMappedSuperclass;
}
public void assignCheckConstraintsToTable(Dialect dialect, TypeConfiguration types, SqmFunctionRegistry functions) {
for ( CheckConstraint checkConstraint : checkConstraints ) {
container( collectColumnNames( checkConstraint.getConstraint(), dialect, types, functions ) )
.getTable().addCheck( checkConstraint );
}
}
// End of @MappedSuperclass support
public void prepareForMappingModel(RuntimeModelCreationContext context) {
if ( !joins.isEmpty() ) {
// we need to deal with references to secondary tables
// in SQL formulas
final Dialect dialect = context.getDialect();
final TypeConfiguration types = context.getTypeConfiguration();
final SqmFunctionRegistry functions = context.getFunctionRegistry();
// now, move @Formulas to the correct AttributeContainers
//TODO: skip this step for hbm.xml
for ( Property property : new ArrayList<>( properties ) ) {
for ( Selectable selectable : property.getSelectables() ) {
if ( selectable.isFormula() && properties.contains( property ) ) {
final Formula formula = (Formula) selectable;
final AttributeContainer container =
container( collectColumnNames( formula.getTemplate( dialect, types, functions ) ) );
if ( !container.contains( property ) ) {
properties.remove( property );
container.addProperty( property );
break; //TODO: embeddables
}
}
}
}
}
properties.sort( comparing( Property::getName ) );
}
private AttributeContainer container(List constrainedColumnNames) {
long matches = matchesInTable( constrainedColumnNames, getTable() );
if ( matches == constrainedColumnNames.size() ) {
// perfect, all columns matched in the primary table
return this;
}
else {
// go searching for a secondary table which better matches
AttributeContainer result = this;
long max = matches;
for ( Join join : getJoins() ) {
long secondaryMatches = matchesInTable( constrainedColumnNames, join.getTable() );
if ( secondaryMatches > max ) {
result = join;
max = secondaryMatches;
}
}
return result;
}
}
private static long matchesInTable(List names, Table table) {
return table.getColumns().stream()
.filter( col -> col.isQuoted()
? names.contains( col.getName() )
: names.stream().anyMatch( name -> name.equalsIgnoreCase( col.getName() ) )
)
.count();
}
public void addCheckConstraint(CheckConstraint checkConstraint) {
checkConstraints.add( checkConstraint );
}
public List getCheckConstraints() {
return checkConstraints;
}
public Table getImplicitTable() {
return getTable();
}
@Override
public Table findTable(String name) {
if ( getTable().getName().equals( name ) ) {
return getTable();
}
final Join secondaryTable = findSecondaryTable( name );
if ( secondaryTable != null ) {
return secondaryTable.getTable();
}
return null;
}
@Override
public Table getTable(String name) {
final Table table = findTable( name );
if ( table == null ) {
throw new MappingException( "Could not locate Table : " + name );
}
return table;
}
@Override
public Join findSecondaryTable(String name) {
for ( int i = 0; i < joins.size(); i++ ) {
final Join join = joins.get( i );
if ( join.getTable().getNameIdentifier().matches( name ) ) {
return join;
}
}
return null;
}
@Override
public Join getSecondaryTable(String name) {
final Join secondaryTable = findSecondaryTable( name );
if ( secondaryTable == null ) {
throw new MappingException( "Could not locate secondary Table : " + name );
}
return secondaryTable;
}
@Override
public IdentifiableTypeClass getSuperType() {
final PersistentClass superPersistentClass = getSuperclass();
if ( superPersistentClass != null ) {
return superPersistentClass;
}
return superMappedSuperclass;
}
@Override
public List getSubTypes() {
throw new UnsupportedOperationException( "Not implemented yet" );
}
@Override
public void applyProperty(Property property) {
if ( property.getValue().getTable().equals( getImplicitTable() ) ) {
addProperty( property );
}
else {
final Join secondaryTable = getSecondaryTable( property.getValue().getTable().getName() );
secondaryTable.addProperty( property );
}
}
private boolean containsColumn(Column column) {
for ( Property declaredProperty : declaredProperties ) {
if ( declaredProperty.getSelectables().contains( column ) ) {
return true;
}
}
return false;
}
@Internal
public boolean isDefinedOnMultipleSubclasses(Column column) {
PersistentClass declaringType = null;
for ( PersistentClass persistentClass : getSubclassClosure() ) {
if ( persistentClass.containsColumn( column ) ) {
if ( declaringType != null && declaringType != persistentClass ) {
return true;
}
else {
declaringType = persistentClass;
}
}
}
return false;
}
@Internal
public PersistentClass getSuperPersistentClass() {
return getSuperclass() != null ? getSuperclass() : getSuperPersistentClass( getSuperMappedSuperclass() );
}
private static PersistentClass getSuperPersistentClass(MappedSuperclass mappedSuperclass) {
if ( mappedSuperclass != null ) {
final PersistentClass superClass = mappedSuperclass.getSuperPersistentClass();
if ( superClass != null ) {
return superClass;
}
return getSuperPersistentClass( mappedSuperclass.getSuperMappedSuperclass() );
}
return null;
}
public Supplier extends Expectation> getInsertExpectation() {
return insertExpectation;
}
public void setInsertExpectation(Supplier extends Expectation> insertExpectation) {
this.insertExpectation = insertExpectation;
}
public Supplier extends Expectation> getUpdateExpectation() {
return updateExpectation;
}
public void setUpdateExpectation(Supplier extends Expectation> updateExpectation) {
this.updateExpectation = updateExpectation;
}
public Supplier extends Expectation> getDeleteExpectation() {
return deleteExpectation;
}
public void setDeleteExpectation(Supplier extends Expectation> deleteExpectation) {
this.deleteExpectation = deleteExpectation;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy