Merge remote-tracking branch 'upstream/master' into wip/6.0

This commit is contained in:
Andrea Boriero 2020-11-02 15:46:54 +00:00
commit 1b7017ff71
12 changed files with 307 additions and 70 deletions

View File

@ -1737,12 +1737,17 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings {
/**
* Controls how the individual Loaders for an entity are created.
*
* When `true` (the default), only the minimal set of Loaders are
* created. These include the handling for {@link org.hibernate.LockMode#READ}
* and {@link org.hibernate.LockMode#NONE} as well as specialized Loaders for
* merge and refresh handling.
* When `true` (the default), the loaders are only created on first
* access; this ensures that all access patterns which are not useful
* to the application are never instantiated, possibly saving a
* substantial amount of memory for applications having many entities.
* The only exception is the loader for <code>LockMode.NONE</code>,
* which will always be eagerly initialized; this is necessary to
* detect mapping errors.
*
* `false` indicates that all loaders should be created up front
* `false` indicates that all loaders should be created up front; this
* will consume more memory but ensures all necessary memory is
* allocated right away.
*
* @since 5.3
*/

View File

@ -13,6 +13,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@ -291,4 +292,73 @@ public final class CollectionHelper {
return properties;
}
/**
* Use to convert sets which will be retained for a long time,
* such as for the lifetime of the Hibernate ORM instance.
* The returned Set might be immutable, but there is no guarantee of this:
* consider it immutable but don't rely on this.
* The goal is to save memory.
* @param set
* @param <T>
* @return
*/
public static <T> Set<T> toSmallSet(Set<T> set) {
switch ( set.size() ) {
case 0:
return Collections.EMPTY_SET;
case 1:
return Collections.singleton( set.iterator().next() );
default:
//TODO assert tests pass even if this is set to return an unmodifiable Set
return set;
}
}
/**
* Use to convert Maps which will be retained for a long time,
* such as for the lifetime of the Hibernate ORM instance.
* The returned Map might be immutable, but there is no guarantee of this:
* consider it immutable but don't rely on this.
* The goal is to save memory.
* @param map
* @param <K>
* @param <V>
* @return
*/
public static <K, V> Map<K, V> toSmallMap(final Map<K, V> map) {
switch ( map.size() ) {
case 0:
return Collections.EMPTY_MAP;
case 1:
Map.Entry<K, V> entry = map.entrySet().iterator().next();
return Collections.singletonMap( entry.getKey(), entry.getValue() );
default:
//TODO assert tests pass even if this is set to return an unmodifiable Map
return map;
}
}
/**
* Use to convert ArrayList instances which will be retained for a long time,
* such as for the lifetime of the Hibernate ORM instance.
* The returned List might be immutable, but there is no guarantee of this:
* consider it immutable but don't rely on this.
* The goal is to save memory.
* @param arrayList
* @param <V>
* @return
*/
public static <V> List<V> toSmallList(ArrayList<V> arrayList) {
switch ( arrayList.size() ) {
case 0:
return Collections.EMPTY_LIST;
case 1:
return Collections.singletonList( arrayList.get( 0 ) );
default:
arrayList.trimToSize();
return arrayList;
}
}
}

View File

@ -0,0 +1,84 @@
/*
* 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.internal.util.collections;
import java.util.Arrays;
import java.util.function.Function;
/**
* This is an internal data structure designed for very specific needs;
* it will most often be used as a replacement for EnumMap, although
* the focus on the Enum aspect is modelled as an int primitive:
* think of using the ordinals of an Enum to simulate the EnumMap.
* Proper abstraction of the indexing strategy is left to subclasses.
* <p/>
* There are various reasons to not expose the Enum on this class API;
* the primary is that in some of the cases in which we need the pattern,
* there is the need to hold an additional couple of values beyond the
* ones modelled by the Enum, essentially having some extra keys in the map;
* this could be modelled by defining a new Enum but that's also not ideal.
* <p/>
* Another reason is that the goal of this class is to allow the host to
* save memory, as we typically need to keep references to many of these
* objects for a long time; being able to refer purely to an array is
* less practical but gets us benefits in memory layout and total retained
* memory.
*
* @param <K> the types used to model the key
* @param <V> the types used to model the value
*/
public abstract class LazyIndexedMap<K,V> {
private volatile Object[] values;
private static final Object NOT_INITIALIZED = new Object();
protected LazyIndexedMap(final int size) {
final Object[] vs = new Object[size];
//could rely on null, then then we should ensure that the valueGenerator function never returns null.
//Seems safer to guard with a custom token: the memory impact is negligible since it's a constant,
//and we're not needing to create these objects frequently.
Arrays.fill( vs, NOT_INITIALIZED );
this.values = vs;
}
/**
* Both the index and the original key are requested for efficiency reasons.
* It is the responsibility of the caller to ensure there is a 1:1 matching relation between them.
* @param index storage index in the array
* @param originalKey the original key object, used to efficiently pass it into the valueGenerator function
* @param valueGenerator if no value was generated before for this index, then the valueGenerator is invoked to
* associate a new value and store it into the internal array at the provided index.
* @return the associated value to this index/key.
*/
protected <K1 extends K> V computeIfAbsent(final int index, final K1 originalKey, final Function<K1,V> valueGenerator) {
final Object value = this.values[index];
if ( value != NOT_INITIALIZED ) {
return (V) value;
}
else {
return lockedComputeIfAbsent( index, originalKey, valueGenerator );
}
}
private synchronized <K1 extends K> V lockedComputeIfAbsent(final int index, final K1 originalKey, final Function<K1,V> valueGenerator) {
//Get a fresh copy from the volatile read, while holding the global pessimistic lock in this:
final Object[] values = this.values;
final Object value = values[index];
//Check again
if ( value != NOT_INITIALIZED ) {
return (V) value;
}
else {
//Actually need to generate the value
final V generated = valueGenerator.apply( originalKey );
values[index] = generated;
//re-write on the volatile reference to publish any changes to the array
this.values = values;
return generated;
}
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.internal.util.collections;
import java.util.function.Function;
import org.hibernate.LockMode;
/**
* A concurrent safe EnumMap&lt;LockMode&gt;, suitable to
* lazily associate values to the enum keys.
* This implementation favours fast read operations
* and low memory consumption over other metrics.
*
* Specifically designed with specific use cases in mind:
* do not overly reuse without good reasons.
*
* @param <V> the value type to be associated with each key
*/
public final class LockModeEnumMap<V> extends LazyIndexedMap<LockMode,V> {
private static final int ENUM_DIMENSION = LockMode.values().length;
public LockModeEnumMap() {
super( ENUM_DIMENSION );
}
public V computeIfAbsent(LockMode key, Function<LockMode,V> valueGenerator) {
return super.computeIfAbsent( key.ordinal(), key, valueGenerator );
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.metamodel.model.domain;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
@ -331,13 +332,18 @@ public abstract class AbstractIdentifiableType<J>
throw new IllegalStateException( "Non-aggregated id attributes were already set" );
}
for ( SingularPersistentAttribute idAttribute : (Set<SingularPersistentAttribute>) idAttributes ) {
if ( AbstractIdentifiableType.this == idAttribute.getDeclaringType() ) {
addAttribute( idAttribute );
}
if ( idAttributes.isEmpty() ) {
AbstractIdentifiableType.this.nonAggregatedIdAttributes = Collections.EMPTY_SET;
}
else {
for ( SingularPersistentAttribute idAttribute : (Set<SingularPersistentAttribute>) idAttributes ) {
if ( AbstractIdentifiableType.this == idAttribute.getDeclaringType() ) {
addAttribute( idAttribute );
}
}
AbstractIdentifiableType.this.nonAggregatedIdAttributes = (Set) idAttributes;
AbstractIdentifiableType.this.nonAggregatedIdAttributes = (Set) idAttributes;
}
}
@Override

View File

@ -9,6 +9,7 @@ package org.hibernate.metamodel.model.domain;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@ -28,6 +29,7 @@ import javax.persistence.metamodel.SingularAttribute;
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.model.domain.internal.AttributeContainer;
import org.hibernate.metamodel.model.domain.internal.DomainModelHelper;
@ -47,7 +49,7 @@ public abstract class AbstractManagedType<J>
private final RepresentationMode representationMode;
private final Map<String, SingularPersistentAttribute<J, ?>> declaredSingularAttributes = new LinkedHashMap<>();
private final Map<String, PluralPersistentAttribute<J, ?, ?>> declaredPluralAttributes = new LinkedHashMap<>();
private volatile Map<String, PluralPersistentAttribute<J, ?, ?>> declaredPluralAttributes ;
private final List<ManagedDomainType> subTypes = new ArrayList<>();
@ -118,12 +120,21 @@ public abstract class AbstractManagedType<J>
@Override
@SuppressWarnings("unchecked")
public Set<Attribute<J, ?>> getDeclaredAttributes() {
if ( declaredSingularAttributes.isEmpty() && declaredPluralAttributes.isEmpty() ) {
final boolean isDeclaredSingularAttributesEmpty = CollectionHelper.isEmpty( declaredSingularAttributes );
final boolean isDeclaredPluralAttributes = CollectionHelper.isEmpty( declaredPluralAttributes );
if ( isDeclaredSingularAttributesEmpty && isDeclaredPluralAttributes ) {
return Collections.emptySet();
}
final HashSet attributes = new LinkedHashSet( declaredSingularAttributes.values() );
attributes.addAll( declaredPluralAttributes.values() );
final HashSet attributes;
if ( !isDeclaredSingularAttributesEmpty ) {
attributes = new LinkedHashSet( declaredSingularAttributes.values() );
if ( !isDeclaredPluralAttributes ) {
attributes.addAll( declaredPluralAttributes.values() );
}
}
else {
attributes = new LinkedHashSet( declaredPluralAttributes.values() );
}
return attributes;
}
@ -191,6 +202,9 @@ public abstract class AbstractManagedType<J>
}
// next plural
if ( declaredPluralAttributes == null ) {
return null;
}
attribute = declaredPluralAttributes.get( name );
//noinspection RedundantIfStatement
if ( attribute != null ) {
@ -347,18 +361,17 @@ public abstract class AbstractManagedType<J>
@Override
@SuppressWarnings("unchecked")
public Set<PluralAttribute<? super J, ?, ?>> getPluralAttributes() {
final Set attributes = getDeclaredPluralAttributes();
HashSet attributes = declaredPluralAttributes == null ? new HashSet<PluralAttribute<? super J, ?, ?>>() : new HashSet<PluralAttribute<? super J, ?, ?>>( declaredPluralAttributes.values() );
if ( getSuperType() != null ) {
attributes.addAll( getSuperType().getPluralAttributes() );
}
return attributes;
}
@Override
public Set<PluralAttribute<J, ?, ?>> getDeclaredPluralAttributes() {
return new HashSet<>( declaredPluralAttributes.values() );
return declaredPluralAttributes == null ?
Collections.EMPTY_SET : new HashSet<>( declaredPluralAttributes.values() );
}
@Override
@ -380,8 +393,9 @@ public abstract class AbstractManagedType<J>
}
@Override
@SuppressWarnings("unchecked")
public PluralPersistentAttribute<? super J, ?, ?> findDeclaredPluralAttribute(String name) {
return declaredPluralAttributes.get( name );
return declaredPluralAttributes == null ? null : declaredPluralAttributes.get( name );
}
private <E> void checkTypeForPluralAttributes(
@ -429,7 +443,7 @@ public abstract class AbstractManagedType<J>
@Override
@SuppressWarnings( "unchecked")
public CollectionAttribute<J, ?> getDeclaredCollection(String name) {
final PluralAttribute attribute = findDeclaredPluralAttribute( name );
final PluralPersistentAttribute<? super J, ?, ?> attribute = findDeclaredPluralAttribute( name );
basicCollectionCheck( attribute, name );
return ( CollectionAttribute<J, ?> ) attribute;
}
@ -476,7 +490,7 @@ public abstract class AbstractManagedType<J>
@Override
@SuppressWarnings( "unchecked")
public SetPersistentAttribute<J, ?> getDeclaredSet(String name) {
final PluralAttribute attribute = findDeclaredPluralAttribute( name );
final PluralPersistentAttribute<? super J, ?, ?> attribute = findDeclaredPluralAttribute( name );
basicSetCheck( attribute, name );
return (SetPersistentAttribute) attribute;
}
@ -523,7 +537,7 @@ public abstract class AbstractManagedType<J>
@Override
@SuppressWarnings("unchecked")
public ListPersistentAttribute<J, ?> getDeclaredList(String name) {
final PluralAttribute attribute = findDeclaredPluralAttribute( name );
final PluralPersistentAttribute<? super J, ?, ?> attribute = findDeclaredPluralAttribute( name );
basicListCheck( attribute, name );
return (ListPersistentAttribute) attribute;
}
@ -570,7 +584,7 @@ public abstract class AbstractManagedType<J>
@Override
@SuppressWarnings("unchecked")
public MapPersistentAttribute<J, ?, ?> getDeclaredMap(String name) {
final PluralAttribute attribute = findDeclaredPluralAttribute( name );
final PluralPersistentAttribute<? super J, ?, ?> attribute = findDeclaredPluralAttribute( name );
basicMapCheck( attribute, name );
return (MapPersistentAttribute) attribute;
}
@ -598,7 +612,7 @@ public abstract class AbstractManagedType<J>
@Override
@SuppressWarnings("unchecked")
public <K, V> MapAttribute<J, K, V> getDeclaredMap(String name, Class<K> keyType, Class<V> valueType) {
final PluralAttribute attribute = findDeclaredPluralAttribute( name );
final PluralPersistentAttribute<? super J, ?, ?> attribute = findDeclaredPluralAttribute( name );
checkMapValueType( attribute, name, valueType );
final MapAttribute<J, K, V> mapAttribute = ( MapAttribute<J, K, V> ) attribute;
checkMapKeyType( mapAttribute, name, keyType );
@ -645,7 +659,10 @@ public abstract class AbstractManagedType<J>
declaredSingularAttributes.put( attribute.getName(), (SingularPersistentAttribute) attribute );
}
else if ( attribute instanceof PluralPersistentAttribute ) {
declaredPluralAttributes.put(attribute.getName(), (PluralPersistentAttribute) attribute );
if ( AbstractManagedType.this.declaredPluralAttributes == null ) {
AbstractManagedType.this.declaredPluralAttributes = new HashMap<>();
}
AbstractManagedType.this.declaredPluralAttributes.put( attribute.getName(), (PluralPersistentAttribute<J,?,?>) attribute );
}
else {
throw new IllegalArgumentException(

View File

@ -78,6 +78,8 @@ import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.CachedNaturalIdValueSource;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.CascadingAction;
import org.hibernate.engine.spi.CascadingActions;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityEntryFactory;
@ -105,6 +107,8 @@ import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.FilterHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.internal.util.collections.LockModeEnumMap;
import org.hibernate.jdbc.Expectation;
import org.hibernate.jdbc.Expectations;
import org.hibernate.jdbc.TooManyRowsAffectedException;
@ -296,7 +300,7 @@ public abstract class AbstractEntityPersister
private final boolean[] propertyUniqueness;
private final boolean[] propertySelectable;
private final List<Integer> lobProperties = new ArrayList<>();
private final List<Integer> lobProperties;
//information about lazy properties of this class
private final String[] lazyPropertyNames;
@ -333,10 +337,9 @@ public abstract class AbstractEntityPersister
// dynamic filters attached to the class-level
private final FilterHelper filterHelper;
private final Set<String> affectingFetchProfileNames = new HashSet<>();
private volatile Set<String> affectingFetchProfileNames;
private final Map uniqueKeyLoaders = new HashMap();
private final Map lockers = new HashMap();
private final LockModeEnumMap<LockingStrategy> lockers = new LockModeEnumMap<>();
// SQL strings
private String sqlVersionSelectString;
@ -811,6 +814,7 @@ public abstract class AbstractEntityPersister
ArrayList lazyTypes = new ArrayList();
ArrayList lazyColAliases = new ArrayList();
final ArrayList<Integer> lobPropertiesLocalCollector = new ArrayList<>();
iter = bootDescriptor.getPropertyClosureIterator();
i = 0;
boolean foundFormula = false;
@ -873,12 +877,13 @@ public abstract class AbstractEntityPersister
propertyUniqueness[i] = prop.getValue().isAlternateUniqueKey();
if ( prop.isLob() && dialect.forceLobAsLastValue() ) {
lobProperties.add( i );
lobPropertiesLocalCollector.add( i );
}
i++;
}
this.lobProperties = CollectionHelper.toSmallList( lobPropertiesLocalCollector );
hasFormulaProperties = foundFormula;
lazyPropertyColumnAliases = ArrayHelper.to2DStringArray( lazyColAliases );
lazyPropertyNames = ArrayHelper.toStringArray( lazyNames );
@ -2148,25 +2153,12 @@ public abstract class AbstractEntityPersister
}
}
protected void initLockers() {
lockers.put( LockMode.READ, generateLocker( LockMode.READ ) );
lockers.put( LockMode.UPGRADE, generateLocker( LockMode.UPGRADE ) );
lockers.put( LockMode.UPGRADE_NOWAIT, generateLocker( LockMode.UPGRADE_NOWAIT ) );
lockers.put( LockMode.UPGRADE_SKIPLOCKED, generateLocker( LockMode.UPGRADE_SKIPLOCKED ) );
lockers.put( LockMode.FORCE, generateLocker( LockMode.FORCE ) );
lockers.put( LockMode.PESSIMISTIC_READ, generateLocker( LockMode.PESSIMISTIC_READ ) );
lockers.put( LockMode.PESSIMISTIC_WRITE, generateLocker( LockMode.PESSIMISTIC_WRITE ) );
lockers.put( LockMode.PESSIMISTIC_FORCE_INCREMENT, generateLocker( LockMode.PESSIMISTIC_FORCE_INCREMENT ) );
lockers.put( LockMode.OPTIMISTIC, generateLocker( LockMode.OPTIMISTIC ) );
lockers.put( LockMode.OPTIMISTIC_FORCE_INCREMENT, generateLocker( LockMode.OPTIMISTIC_FORCE_INCREMENT ) );
}
protected LockingStrategy generateLocker(LockMode lockMode) {
return factory.getDialect().getLockingStrategy( this, lockMode );
}
private LockingStrategy getLocker(LockMode lockMode) {
return (LockingStrategy) lockers.get( lockMode );
return lockers.computeIfAbsent( lockMode, this::generateLocker );
}
public void lock(
@ -4576,6 +4568,9 @@ public abstract class AbstractEntityPersister
}
public void registerAffectingFetchProfile(String fetchProfileName) {
if ( affectingFetchProfileNames == null ) {
this.affectingFetchProfileNames = new HashSet<>();
}
affectingFetchProfileNames.add( fetchProfileName );
}
@ -4590,9 +4585,12 @@ public abstract class AbstractEntityPersister
@Override
public boolean isAffectedByEnabledFetchProfiles(LoadQueryInfluencers loadQueryInfluencers) {
for ( String s : loadQueryInfluencers.getEnabledFetchProfileNames() ) {
if ( affectingFetchProfileNames.contains( s ) ) {
return true;
final Set<String> fetchProfileNames = this.affectingFetchProfileNames;
if ( fetchProfileNames != null ) {
for ( String s : loadQueryInfluencers.getEnabledFetchProfileNames() ) {
if ( fetchProfileNames.contains( s ) ) {
return true;
}
}
}
return false;

View File

@ -41,7 +41,11 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractPropertyMapping.class );
private final Map<String, Type> typesByPropertyPath = new HashMap<>();
private final Set<String> duplicateIncompatiblePaths = new HashSet<>();
//This field is only used during initialization, no need for threadsafety:
//FIXME get rid of the field, or at least clear it after boot? Not urgent as we typically won't initialize it at all.
private Set<String> duplicateIncompatiblePaths = null;
private final Map<String, String[]> columnsByPropertyPath = new HashMap<>();
private final Map<String, String[]> columnReadersByPropertyPath = new HashMap<>();
private final Map<String, String[]> columnReaderTemplatesByPropertyPath = new HashMap<>();
@ -168,7 +172,7 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
String[] formulaTemplates,
Mapping factory) {
Type existingType = typesByPropertyPath.get( path );
if ( existingType != null || duplicateIncompatiblePaths.contains( path ) ) {
if ( existingType != null || ( duplicateIncompatiblePaths != null && duplicateIncompatiblePaths.contains( path ) ) ) {
// If types match or the new type is not an association type, there is nothing for us to do
if ( type == existingType || existingType == null || !( type instanceof AssociationType ) ) {
logDuplicateRegistration( path, existingType, type );
@ -212,6 +216,9 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
logIncompatibleRegistration( path, existingType, type );
}
if ( commonType == null ) {
if ( duplicateIncompatiblePaths == null ) {
duplicateIncompatiblePaths = new HashSet<>();
}
duplicateIncompatiblePaths.add( path );
typesByPropertyPath.remove( path );
// Set everything to empty to signal action has to be taken!

View File

@ -641,8 +641,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
subclassNamesBySubclassTable = buildSubclassNamesBySubclassTableMapping( persistentClass, factory );
initLockers();
initSubclassPropertyAliasesMap( persistentClass );
postConstruct( creationContext.getMetadata() );

View File

@ -8,6 +8,7 @@ package org.hibernate.persister.entity;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@ -31,6 +32,7 @@ import org.hibernate.internal.FilterAliasGenerator;
import org.hibernate.internal.util.MarkerObject;
import org.hibernate.internal.util.MutableInteger;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Formula;
import org.hibernate.mapping.Join;
@ -103,7 +105,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
private final int[] subclassFormulaTableNumberClosure;
// discriminator column
private final Map<Object, String> subclassesByDiscriminatorValue = new HashMap<>();
private final Map<Object, String> subclassesByDiscriminatorValue;
private final boolean forceDiscriminator;
private final String discriminatorColumnName;
private final String discriminatorColumnReaders;
@ -120,9 +122,10 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
private final String[][] constraintOrderedKeyColumnNames;
//private final Map propertyTableNumbersByName = new HashMap();
private final Map<String, Integer> propertyTableNumbersByNameAndSubclass = new HashMap<>();
private final Map<String, Integer> propertyTableNumbersByNameAndSubclass;
private final Map<String, String> sequentialSelectStringsByEntityName = new HashMap<>();
//Efficiency note: try to not allocate an HashMap if we're not going to need it.
private final Map<String, String> sequentialSelectStringsByEntityName;
private static final Object NULL_DISCRIMINATOR = new MarkerObject( "<null discriminator>" );
private static final Object NOT_NULL_DISCRIMINATOR = new MarkerObject( "<not null discriminator>" );
@ -292,6 +295,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
isNullableSubclassTable = ArrayHelper.toBooleanArray( isNullables );
hasSequentialSelects = hasDeferred;
this.sequentialSelectStringsByEntityName = hasSequentialSelects ? new HashMap<>() : Collections.EMPTY_MAP;
// DISCRIMINATOR
if ( persistentClass.isPolymorphic() ) {
@ -382,6 +387,9 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
ArrayList<Integer> formulaJoinedNumbers = new ArrayList<>();
ArrayList<Integer> propertyJoinNumbers = new ArrayList<>();
final HashMap<String, Integer> propertyTableNumbersByNameAndSubclassLocal = new HashMap<>();
final Map<Object, String> subclassesByDiscriminatorValueLocal = new HashMap<>();
iter = persistentClass.getSubclassPropertyClosureIterator();
while ( iter.hasNext() ) {
Property prop = (Property) iter.next();
@ -389,7 +397,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
propertyJoinNumbers.add( join );
//propertyTableNumbersByName.put( prop.getName(), join );
propertyTableNumbersByNameAndSubclass.put(
propertyTableNumbersByNameAndSubclassLocal.put(
prop.getPersistentClass().getEntityName() + '.' + prop.getName(),
join
);
@ -405,6 +413,9 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
}
}
}
propertyTableNumbersByNameAndSubclass = CollectionHelper.toSmallMap( propertyTableNumbersByNameAndSubclassLocal );
subclassColumnTableNumberClosure = ArrayHelper.toIntArray( columnJoinNumbers );
subclassFormulaTableNumberClosure = ArrayHelper.toIntArray( formulaJoinedNumbers );
subclassPropertyTableNumberClosure = ArrayHelper.toIntArray( propertyJoinNumbers );
@ -413,7 +424,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
subclassClosure = new String[subclassSpan];
subclassClosure[0] = getEntityName();
if ( persistentClass.isPolymorphic() ) {
addSubclassByDiscriminatorValue( discriminatorValue, getEntityName() );
addSubclassByDiscriminatorValue( subclassesByDiscriminatorValueLocal, discriminatorValue, getEntityName() );
}
// SUBCLASSES
@ -424,15 +435,16 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
Subclass sc = (Subclass) iter.next();
subclassClosure[k++] = sc.getEntityName();
if ( sc.isDiscriminatorValueNull() ) {
addSubclassByDiscriminatorValue( NULL_DISCRIMINATOR, sc.getEntityName() );
addSubclassByDiscriminatorValue( subclassesByDiscriminatorValueLocal, NULL_DISCRIMINATOR, sc.getEntityName() );
}
else if ( sc.isDiscriminatorValueNotNull() ) {
addSubclassByDiscriminatorValue( NOT_NULL_DISCRIMINATOR, sc.getEntityName() );
addSubclassByDiscriminatorValue( subclassesByDiscriminatorValueLocal, NOT_NULL_DISCRIMINATOR, sc.getEntityName() );
}
else {
try {
DiscriminatorType dtype = (DiscriminatorType) discriminatorType;
addSubclassByDiscriminatorValue(
subclassesByDiscriminatorValueLocal,
dtype.stringToObject( sc.getDiscriminatorValue() ),
sc.getEntityName()
);
@ -447,7 +459,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
}
}
initLockers();
// Don't hold a reference to an empty HashMap:
this.subclassesByDiscriminatorValue = CollectionHelper.toSmallMap( subclassesByDiscriminatorValueLocal );
initSubclassPropertyAliasesMap( persistentClass );
@ -455,7 +468,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
}
private void addSubclassByDiscriminatorValue(Object discriminatorValue, String entityName) {
private static void addSubclassByDiscriminatorValue(Map<Object, String> subclassesByDiscriminatorValue, Object discriminatorValue, String entityName) {
String mappedEntityName = subclassesByDiscriminatorValue.put( discriminatorValue, entityName );
if ( mappedEntityName != null ) {
throw new MappingException(

View File

@ -210,8 +210,6 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
constraintOrderedKeyColumnNames = new String[][] {getIdentifierColumnNames()};
}
initLockers();
initSubclassPropertyAliasesMap( persistentClass );
postConstruct( creationContext.getMetadata() );

View File

@ -29,6 +29,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.mapping.Component;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
@ -118,8 +119,8 @@ public class EntityMetamodel implements Serializable {
private final boolean explicitPolymorphism;
private final boolean inherited;
private final boolean hasSubclasses;
private final Set subclassEntityNames = new HashSet();
private final Map entityNameByInheritenceClassMap = new HashMap();
private final Set subclassEntityNames;
private final Map<Class,String> entityNameByInheritenceClassMap;
private final BytecodeEnhancementMetadata bytecodeEnhancementMetadata;
@ -395,19 +396,23 @@ public class EntityMetamodel implements Serializable {
hasMutableProperties = foundMutable;
iter = persistentClass.getSubclassIterator();
final Set<String> subclassEntityNamesLocal = new HashSet<>();
while ( iter.hasNext() ) {
subclassEntityNames.add( ( (PersistentClass) iter.next() ).getEntityName() );
subclassEntityNamesLocal.add( ( (PersistentClass) iter.next() ).getEntityName() );
}
subclassEntityNames.add( name );
subclassEntityNamesLocal.add( name );
subclassEntityNames = CollectionHelper.toSmallSet( subclassEntityNamesLocal );
HashMap<Class, String> entityNameByInheritenceClassMapLocal = new HashMap<Class, String>();
if ( persistentClass.hasPojoRepresentation() ) {
entityNameByInheritenceClassMap.put( persistentClass.getMappedClass(), persistentClass.getEntityName() );
entityNameByInheritenceClassMapLocal.put( persistentClass.getMappedClass(), persistentClass.getEntityName() );
iter = persistentClass.getSubclassIterator();
while ( iter.hasNext() ) {
final PersistentClass pc = ( PersistentClass ) iter.next();
entityNameByInheritenceClassMap.put( pc.getMappedClass(), pc.getEntityName() );
entityNameByInheritenceClassMapLocal.put( pc.getMappedClass(), pc.getEntityName() );
}
}
entityNameByInheritenceClassMap = CollectionHelper.toSmallMap( entityNameByInheritenceClassMapLocal );
}
private static GenerationStrategyPair buildGenerationStrategyPair(
@ -947,7 +952,7 @@ public class EntityMetamodel implements Serializable {
* @return The mapped entity-name, or null if no such mapping was found.
*/
public String findEntityNameByEntityClass(Class inheritenceClass) {
return ( String ) entityNameByInheritenceClassMap.get( inheritenceClass );
return entityNameByInheritenceClassMap.get( inheritenceClass );
}
@Override