Merge remote-tracking branch 'upstream/master' into wip/6.0
This commit is contained in:
commit
1b7017ff71
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<LockMode>, 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 );
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -641,8 +641,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
|
||||
subclassNamesBySubclassTable = buildSubclassNamesBySubclassTableMapping( persistentClass, factory );
|
||||
|
||||
initLockers();
|
||||
|
||||
initSubclassPropertyAliasesMap( persistentClass );
|
||||
|
||||
postConstruct( creationContext.getMetadata() );
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -210,8 +210,6 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
|||
constraintOrderedKeyColumnNames = new String[][] {getIdentifierColumnNames()};
|
||||
}
|
||||
|
||||
initLockers();
|
||||
|
||||
initSubclassPropertyAliasesMap( persistentClass );
|
||||
|
||||
postConstruct( creationContext.getMetadata() );
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue