HHH-15150 EmbeddedId CacheKeys are no longer Serializable
This commit is contained in:
parent
1194e7f23b
commit
6c5870ee0b
|
@ -26,7 +26,7 @@ import org.hibernate.type.Type;
|
|||
@Internal
|
||||
public final class CacheKeyImplementation implements Serializable {
|
||||
private final Object id;
|
||||
private final Type type;
|
||||
private final CacheKeyValueDescriptor cacheKeyValueDescriptor;
|
||||
private final String entityOrRoleName;
|
||||
private final String tenantId;
|
||||
private final int hashCode;
|
||||
|
@ -50,15 +50,15 @@ public final class CacheKeyImplementation implements Serializable {
|
|||
final String tenantId,
|
||||
final SessionFactoryImplementor factory) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.cacheKeyValueDescriptor = type.toCacheKeyDescriptor( factory );
|
||||
this.entityOrRoleName = entityOrRoleName;
|
||||
this.tenantId = tenantId;
|
||||
this.hashCode = calculateHashCode( type, factory );
|
||||
this.hashCode = calculateHashCode( );
|
||||
}
|
||||
|
||||
private int calculateHashCode(Type type, SessionFactoryImplementor factory) {
|
||||
int result = type.getHashCode( id, factory );
|
||||
result = 31 * result + (tenantId != null ? tenantId.hashCode() : 0);
|
||||
private int calculateHashCode() {
|
||||
int result = cacheKeyValueDescriptor.getHashCode( id );
|
||||
result = 31 * result + ( tenantId != null ? tenantId.hashCode() : 0 );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ public final class CacheKeyImplementation implements Serializable {
|
|||
}
|
||||
final CacheKeyImplementation that = (CacheKeyImplementation) other;
|
||||
return Objects.equals( entityOrRoleName, that.entityOrRoleName )
|
||||
&& type.isEqual( id, that.id )
|
||||
&& cacheKeyValueDescriptor.isEqual( id, that.id )
|
||||
&& Objects.equals( tenantId, that.tenantId );
|
||||
}
|
||||
|
||||
|
|
14
hibernate-core/src/main/java/org/hibernate/cache/internal/CacheKeyValueDescriptor.java
vendored
Normal file
14
hibernate-core/src/main/java/org/hibernate/cache/internal/CacheKeyValueDescriptor.java
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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.cache.internal;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public interface CacheKeyValueDescriptor extends Serializable {
|
||||
int getHashCode(Object key);
|
||||
boolean isEqual(Object key1, Object key2);
|
||||
}
|
86
hibernate-core/src/main/java/org/hibernate/cache/internal/ComponentCacheKeyValueDescriptor.java
vendored
Normal file
86
hibernate-core/src/main/java/org/hibernate/cache/internal/ComponentCacheKeyValueDescriptor.java
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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.cache.internal;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.usertype.CompositeUserType;
|
||||
|
||||
public class ComponentCacheKeyValueDescriptor implements CacheKeyValueDescriptor {
|
||||
|
||||
private SessionFactoryImplementor sessionFactory;
|
||||
private NavigableRole role;
|
||||
private Type[] propertyTypes;
|
||||
private CompositeUserType<Object> compositeUserType;
|
||||
private int propertySpan;
|
||||
|
||||
public ComponentCacheKeyValueDescriptor(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
NavigableRole role,
|
||||
Type[] propertyTypes,
|
||||
CompositeUserType<Object> compositeUserType,
|
||||
int propertySpan) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
this.role = role;
|
||||
this.propertyTypes = propertyTypes;
|
||||
this.compositeUserType = compositeUserType;
|
||||
this.propertySpan = propertySpan;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHashCode(Object key) {
|
||||
if ( compositeUserType != null ) {
|
||||
return compositeUserType.hashCode( key );
|
||||
}
|
||||
int result = 17;
|
||||
for ( int i = 0; i < propertySpan; i++ ) {
|
||||
Object y = getPropertyValue( key, i );
|
||||
result *= 37;
|
||||
if ( y != null ) {
|
||||
result += propertyTypes[i].getHashCode( y );
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEqual(Object key1, Object key2) {
|
||||
if ( key1 == key2 ) {
|
||||
return true;
|
||||
}
|
||||
if ( compositeUserType != null ) {
|
||||
return compositeUserType.equals( key1, key2 );
|
||||
}
|
||||
// null value and empty component are considered equivalent
|
||||
for ( int i = 0; i < propertySpan; i++ ) {
|
||||
if ( !propertyTypes[i].isEqual( getPropertyValue( key1, i ), getPropertyValue( key2, i ) ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Object getPropertyValue(Object component, int i) {
|
||||
if ( component == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( component instanceof Object[] ) {
|
||||
// A few calls to hashCode pass the property values already in an
|
||||
// Object[] (ex: QueryKey hash codes for cached queries).
|
||||
// It's easiest to just check for the condition here prior to
|
||||
// trying reflection.
|
||||
return ( (Object[]) component )[i];
|
||||
}
|
||||
else {
|
||||
return sessionFactory.getRuntimeMetamodels().getEmbedded( role )
|
||||
.getEmbeddableTypeDescriptor()
|
||||
.getValue( component, i );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ import java.util.stream.Stream;
|
|||
import org.hibernate.Incubating;
|
||||
import org.hibernate.graph.RootGraph;
|
||||
import org.hibernate.graph.spi.RootGraphImplementor;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||
import org.hibernate.query.BindableType;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
|
@ -91,6 +92,16 @@ public interface MappingMetamodel {
|
|||
*/
|
||||
EntityPersister getEntityDescriptor(NavigableRole name);
|
||||
|
||||
/**
|
||||
* Get an EmbeddableMappingType based on its NavigableRole.
|
||||
*
|
||||
* @throws IllegalArgumentException if the role does not refer to an entity
|
||||
*
|
||||
* @see #findEntityDescriptor
|
||||
*/
|
||||
EmbeddableValuedModelPart getEmbeddableValuedModelPart(NavigableRole role);
|
||||
|
||||
|
||||
/**
|
||||
* Get an entity mapping descriptor based on its Class.
|
||||
*
|
||||
|
|
|
@ -11,6 +11,7 @@ import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
|||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.model.domain.JpaMetamodel;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
|
||||
/**
|
||||
* Access to Hibernate's runtime metamodels which includes its domain-model (JPA impl) and its
|
||||
|
@ -45,8 +46,12 @@ public interface RuntimeMetamodels {
|
|||
return getMappingMetamodel().findCollectionDescriptor( role ).getAttributeMapping();
|
||||
}
|
||||
|
||||
// todo (6.0) : I think we might need a form of mapping-model look-up for embeddables, something like:
|
||||
/**
|
||||
@deprecated Use {@link #getEmbedded(NavigableRole)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
EmbeddableValuedModelPart getEmbedded(String role);
|
||||
EmbeddableValuedModelPart getEmbedded(NavigableRole role);
|
||||
|
||||
default String getImportedName(String name) {
|
||||
return getMappingMetamodel().getImportedName( name );
|
||||
|
|
|
@ -11,6 +11,7 @@ import org.hibernate.boot.spi.BootstrapContext;
|
|||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.internal.SessionFactoryImpl;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl;
|
||||
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
|
||||
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
|
||||
|
@ -41,6 +42,11 @@ public class RuntimeMetamodelsImpl implements RuntimeMetamodelsImplementor {
|
|||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmbeddableValuedModelPart getEmbedded(NavigableRole role) {
|
||||
return mappingMetamodel.getEmbeddableValuedModelPart( role );
|
||||
}
|
||||
|
||||
/**
|
||||
* Chicken-and-egg because things try to use the SessionFactory (specifically the MappingMetamodel)
|
||||
* before it is ready. So we do this fugly code...
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.model.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.hibernate.spi.DotIdentifierSequence;
|
||||
|
@ -21,7 +22,7 @@ import org.hibernate.spi.NavigablePath;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NavigableRole implements DotIdentifierSequence {
|
||||
public class NavigableRole implements DotIdentifierSequence, Serializable {
|
||||
public static final String IDENTIFIER_MAPPER_PROPERTY = NavigablePath.IDENTIFIER_MAPPER_PROPERTY;
|
||||
|
||||
private final NavigableRole parent;
|
||||
|
|
|
@ -49,6 +49,7 @@ import org.hibernate.mapping.PersistentClass;
|
|||
import org.hibernate.metamodel.MappingMetamodel;
|
||||
import org.hibernate.metamodel.internal.JpaMetaModelPopulationSetting;
|
||||
import org.hibernate.metamodel.internal.JpaStaticMetaModelPopulationSetting;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||
|
@ -73,6 +74,7 @@ import org.hibernate.query.sqm.tree.domain.SqmPath;
|
|||
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.ComponentType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
@ -116,7 +118,7 @@ public class MappingMetamodelImpl implements MappingMetamodelImplementor, Metamo
|
|||
private final Map<String, CollectionPersister> collectionPersisterMap = new ConcurrentHashMap<>();
|
||||
private final Map<String, Set<String>> collectionRolesByEntityParticipant = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
private final Map<NavigableRole, EmbeddableValuedModelPart> embeddableValuedModelPart = new ConcurrentHashMap<>();
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// DomainMetamodel
|
||||
|
||||
|
@ -236,6 +238,7 @@ public class MappingMetamodelImpl implements MappingMetamodelImplementor, Metamo
|
|||
|
||||
collectionPersisterMap.values().forEach( CollectionPersister::postInstantiate );
|
||||
|
||||
registerEmbeddableMappingType( bootModel );
|
||||
|
||||
( (JpaMetamodelImpl) this.jpaMetamodel ).processJpa(
|
||||
bootModel,
|
||||
|
@ -248,6 +251,18 @@ public class MappingMetamodelImpl implements MappingMetamodelImplementor, Metamo
|
|||
);
|
||||
}
|
||||
|
||||
private void registerEmbeddableMappingType(MetadataImplementor bootModel) {
|
||||
bootModel.visitRegisteredComponents(
|
||||
composite -> {
|
||||
final EmbeddableValuedModelPart mappingModelPart = ((ComponentType) composite.getType()).getMappingModelPart();
|
||||
embeddableValuedModelPart.put(
|
||||
mappingModelPart.getNavigableRole(),
|
||||
mappingModelPart
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private void processBootEntities(
|
||||
java.util.Collection<PersistentClass> entityBindings,
|
||||
CacheImplementor cacheImplementor,
|
||||
|
@ -400,6 +415,15 @@ public class MappingMetamodelImpl implements MappingMetamodelImplementor, Metamo
|
|||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmbeddableValuedModelPart getEmbeddableValuedModelPart(NavigableRole role){
|
||||
EmbeddableValuedModelPart embeddableMappingType = embeddableValuedModelPart.get( role );
|
||||
if ( embeddableMappingType == null ) {
|
||||
throw new IllegalArgumentException( "Unable to locate EmbeddableValuedModelPart: " + role );
|
||||
}
|
||||
return embeddableMappingType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPersister findEntityDescriptor(String entityName) {
|
||||
return entityPersisterMap.get( entityName );
|
||||
|
|
|
@ -21,15 +21,14 @@ import org.hibernate.NotYetImplementedFor6Exception;
|
|||
import org.hibernate.PropertyNotFoundException;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.cache.internal.CacheKeyValueDescriptor;
|
||||
import org.hibernate.cache.internal.ComponentCacheKeyValueDescriptor;
|
||||
import org.hibernate.engine.spi.CascadeStyle;
|
||||
import org.hibernate.engine.spi.Mapping;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
||||
|
@ -64,7 +63,6 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
|
|||
|
||||
private final boolean isKey;
|
||||
private boolean hasNotNullProperty;
|
||||
private final boolean createEmptyCompositesEnabled;
|
||||
private final CompositeUserType<Object> compositeUserType;
|
||||
|
||||
private EmbeddableValuedModelPart mappingModelPart;
|
||||
|
@ -100,11 +98,6 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
|
|||
i++;
|
||||
}
|
||||
|
||||
this.createEmptyCompositesEnabled = ConfigurationHelper.getBoolean(
|
||||
Environment.CREATE_EMPTY_COMPOSITES_ENABLED,
|
||||
buildingContext.getBootstrapContext().getServiceRegistry().getService( ConfigurationService.class ).getSettings(),
|
||||
false
|
||||
);
|
||||
if ( component.getTypeName() != null ) {
|
||||
//noinspection unchecked
|
||||
this.compositeUserType = (CompositeUserType<Object>) buildingContext.getBootstrapContext()
|
||||
|
@ -708,6 +701,17 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheKeyValueDescriptor toCacheKeyDescriptor(SessionFactoryImplementor sessionFactory) {
|
||||
return new ComponentCacheKeyValueDescriptor(
|
||||
sessionFactory,
|
||||
mappingModelPart.getNavigableRole(),
|
||||
propertyTypes,
|
||||
compositeUserType,
|
||||
propertySpan
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmbedded() {
|
||||
return false;
|
||||
|
@ -825,10 +829,6 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
|
|||
return hasNotNullProperty;
|
||||
}
|
||||
|
||||
private boolean isCreateEmptyCompositesEnabled() {
|
||||
return createEmptyCompositesEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getBindableJavaType() {
|
||||
return getReturnedClass();
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.util.Map;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.cache.internal.CacheKeyValueDescriptor;
|
||||
import org.hibernate.engine.spi.Mapping;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
@ -34,7 +35,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
@Internal
|
||||
public interface Type extends Serializable {
|
||||
public interface Type extends CacheKeyValueDescriptor {
|
||||
/**
|
||||
* Return true if the implementation is castable to {@link AssociationType}. This does not necessarily imply that
|
||||
* the type actually represents an association. Essentially a polymorphic version of
|
||||
|
@ -431,4 +432,7 @@ public interface Type extends Serializable {
|
|||
*/
|
||||
boolean[] toColumnNullness(Object value, Mapping mapping);
|
||||
|
||||
default CacheKeyValueDescriptor toCacheKeyDescriptor(SessionFactoryImplementor sessionFactory) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue