Fix bug with creating a NaturalIdCacheKey via SimpleCacheKeysFactory
This commit is contained in:
parent
9fe3c861ca
commit
834426e8f6
|
@ -51,7 +51,7 @@ public class DefaultCacheKeysFactory implements CacheKeysFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object staticCreateNaturalIdKey(Object naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) {
|
public static Object staticCreateNaturalIdKey(Object naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) {
|
||||||
return new NaturalIdCacheKey( naturalIdValues, persister.getPropertyTypes(), persister.getNaturalIdentifierProperties(), persister.getRootEntityName(), session );
|
return new NaturalIdCacheKey( naturalIdValues, persister, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object staticGetEntityId(Object cacheKey) {
|
public static Object staticGetEntityId(Object cacheKey) {
|
||||||
|
|
|
@ -13,9 +13,8 @@ import java.util.Objects;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.util.ValueHolder;
|
import org.hibernate.internal.util.ValueHolder;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
|
||||||
import org.hibernate.metamodel.mapping.NaturalIdMapping;
|
import org.hibernate.metamodel.mapping.NaturalIdMapping;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a key for caching natural identifier resolutions into the second level cache.
|
* Defines a key for caching natural identifier resolutions into the second level cache.
|
||||||
|
@ -34,24 +33,15 @@ public class NaturalIdCacheKey implements Serializable {
|
||||||
// "transient" is important here -- NaturalIdCacheKey needs to be Serializable
|
// "transient" is important here -- NaturalIdCacheKey needs to be Serializable
|
||||||
private transient ValueHolder<String> toString;
|
private transient ValueHolder<String> toString;
|
||||||
|
|
||||||
/**
|
public NaturalIdCacheKey(Object naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) {
|
||||||
* Construct a new key for a caching natural identifier resolutions into the second level cache.
|
this( naturalIdValues, persister, persister.getRootEntityName(), session );
|
||||||
* @param naturalIdValues The naturalIdValues associated with the cached data
|
}
|
||||||
* @param propertyTypes
|
|
||||||
* @param naturalIdPropertyIndexes
|
public NaturalIdCacheKey(Object naturalIdValues, EntityPersister persister, String entityName, SharedSessionContractImplementor session) {
|
||||||
* @param session The originating session
|
|
||||||
*/
|
|
||||||
public NaturalIdCacheKey(
|
|
||||||
final Object naturalIdValues,
|
|
||||||
Type[] propertyTypes,
|
|
||||||
int[] naturalIdPropertyIndexes,
|
|
||||||
final String entityName,
|
|
||||||
final SharedSessionContractImplementor session) {
|
|
||||||
this.entityName = entityName;
|
this.entityName = entityName;
|
||||||
this.tenantId = session.getTenantIdentifier();
|
this.tenantId = session.getTenantIdentifier();
|
||||||
|
|
||||||
final EntityMappingType entityMappingType = session.getFactory().getRuntimeMetamodels().getEntityMappingType( entityName );
|
final NaturalIdMapping naturalIdMapping = persister.getNaturalIdMapping();
|
||||||
final NaturalIdMapping naturalIdMapping = entityMappingType.getNaturalIdMapping();
|
|
||||||
|
|
||||||
this.naturalIdValues = naturalIdMapping.disassemble( naturalIdValues, session );
|
this.naturalIdValues = naturalIdMapping.disassemble( naturalIdValues, session );
|
||||||
this.hashCode = naturalIdMapping.calculateHashCode( naturalIdValues, session );
|
this.hashCode = naturalIdMapping.calculateHashCode( naturalIdValues, session );
|
||||||
|
@ -61,28 +51,24 @@ public class NaturalIdCacheKey implements Serializable {
|
||||||
|
|
||||||
private void initTransients() {
|
private void initTransients() {
|
||||||
this.toString = new ValueHolder<>(
|
this.toString = new ValueHolder<>(
|
||||||
new ValueHolder.DeferredInitializer<String>() {
|
() -> {
|
||||||
@Override
|
//Complex toString is needed as naturalIds for entities are not simply based on a single value like primary keys
|
||||||
public String initialize() {
|
//the only same way to differentiate the keys is to include the disassembled values in the string.
|
||||||
//Complex toString is needed as naturalIds for entities are not simply based on a single value like primary keys
|
final StringBuilder toStringBuilder = new StringBuilder().append( entityName ).append( "##NaturalId[" );
|
||||||
//the only same way to differentiate the keys is to include the disassembled values in the string.
|
if ( naturalIdValues instanceof Object[] ) {
|
||||||
final StringBuilder toStringBuilder = new StringBuilder()
|
final Object[] values = (Object[]) naturalIdValues;
|
||||||
.append( entityName ).append( "##NaturalId[" );
|
for ( int i = 0; i < values.length; i++ ) {
|
||||||
if ( naturalIdValues instanceof Object[] ) {
|
toStringBuilder.append( values[ i ] );
|
||||||
final Object[] values = (Object[]) naturalIdValues;
|
if ( i + 1 < values.length ) {
|
||||||
for ( int i = 0; i < values.length; i++ ) {
|
toStringBuilder.append( ", " );
|
||||||
toStringBuilder.append( values[ i ] );
|
|
||||||
if ( i + 1 < values.length ) {
|
|
||||||
toStringBuilder.append( ", " );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
toStringBuilder.append( naturalIdValues );
|
|
||||||
}
|
|
||||||
|
|
||||||
return toStringBuilder.toString();
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
toStringBuilder.append( naturalIdValues );
|
||||||
|
}
|
||||||
|
|
||||||
|
return toStringBuilder.toString();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class SimpleCacheKeysFactory implements CacheKeysFactory {
|
||||||
@Override
|
@Override
|
||||||
public Object createNaturalIdKey(Object naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) {
|
public Object createNaturalIdKey(Object naturalIdValues, EntityPersister persister, SharedSessionContractImplementor session) {
|
||||||
// natural ids always need to be wrapped
|
// natural ids always need to be wrapped
|
||||||
return new NaturalIdCacheKey(naturalIdValues, persister.getPropertyTypes(), persister.getNaturalIdentifierProperties(), null, session);
|
return new NaturalIdCacheKey(naturalIdValues, persister, null, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.caching;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.NaturalId;
|
||||||
|
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||||
|
import org.hibernate.cache.internal.SimpleCacheKeysFactory;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@DomainModel( annotatedClasses = NaturalIdCacheKeyCreationTests.TheEntity.class )
|
||||||
|
@SessionFactory
|
||||||
|
public class NaturalIdCacheKeyCreationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimpleKeyCreation(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
final EntityPersister entityDescriptor = (EntityPersister) session
|
||||||
|
.getFactory()
|
||||||
|
.getRuntimeMetamodels()
|
||||||
|
.getEntityMappingType( TheEntity.class );
|
||||||
|
|
||||||
|
SimpleCacheKeysFactory.INSTANCE.createEntityKey( 1, entityDescriptor, session.getSessionFactory(), null );
|
||||||
|
SimpleCacheKeysFactory.INSTANCE.createNaturalIdKey( "Steve", entityDescriptor, session );
|
||||||
|
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDefaultKeyCreation(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
final EntityPersister entityDescriptor = (EntityPersister) session
|
||||||
|
.getFactory()
|
||||||
|
.getRuntimeMetamodels()
|
||||||
|
.getEntityMappingType( TheEntity.class );
|
||||||
|
|
||||||
|
DefaultCacheKeysFactory.INSTANCE.createEntityKey( 1, entityDescriptor, session.getSessionFactory(), null );
|
||||||
|
DefaultCacheKeysFactory.INSTANCE.createNaturalIdKey( "Steve", entityDescriptor, session );
|
||||||
|
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity( name = "TheEntity" )
|
||||||
|
@Table( name = "`entities`" )
|
||||||
|
public static class TheEntity {
|
||||||
|
@Id
|
||||||
|
private Integer id;
|
||||||
|
@Basic
|
||||||
|
@NaturalId
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private TheEntity() {
|
||||||
|
// for use by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
public TheEntity(Integer id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import java.io.ByteArrayOutputStream;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.NaturalId;
|
||||||
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
|
||||||
import org.hibernate.cache.internal.NaturalIdCacheKey;
|
import org.hibernate.cache.internal.NaturalIdCacheKey;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
@ -21,6 +22,11 @@ import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import jakarta.persistence.Basic;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
@ -30,6 +36,7 @@ import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
public class NaturalIdCacheKeyTest {
|
public class NaturalIdCacheKeyTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSerializationRoundTrip() throws Exception {
|
public void testSerializationRoundTrip() throws Exception {
|
||||||
final SessionFactoryImplementor sessionFactoryImplementor = mock( SessionFactoryImplementor.class );
|
final SessionFactoryImplementor sessionFactoryImplementor = mock( SessionFactoryImplementor.class );
|
||||||
|
@ -65,4 +72,10 @@ public class NaturalIdCacheKeyTest {
|
||||||
assertEquals(key.getTenantId(), keyClone.getTenantId());
|
assertEquals(key.getTenantId(), keyClone.getTenantId());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSimpleKeyCreation() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue