HHH-15150 Add test for issue

This commit is contained in:
William Burns 2022-03-28 13:52:15 -04:00 committed by Steve Ebersole
parent 5d0fc0f488
commit 1194e7f23b
5 changed files with 314 additions and 18 deletions

View File

@ -0,0 +1,107 @@
package org.hibernate.orm.test.serialization;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import org.hibernate.cache.internal.DefaultCacheKeysFactory;
import org.hibernate.cache.internal.SimpleCacheKeysFactory;
import org.hibernate.cache.spi.CacheKeysFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.orm.test.serialization.entity.PK;
import org.hibernate.orm.test.serialization.entity.WithEmbeddedId;
import org.hibernate.orm.test.serialization.entity.WithSimpleId;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.cache.CachingRegionFactory;
import org.hibernate.testing.orm.junit.BaseUnitTest;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @author Gail Badner
*/
@BaseUnitTest
public class CacheKeySerializationTest {
private SessionFactoryImplementor getSessionFactory(String cacheKeysFactory) {
Configuration configuration = new Configuration()
.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true")
.setProperty(Environment.CACHE_REGION_FACTORY, CachingRegionFactory.class.getName())
.setProperty(Environment.DEFAULT_CACHE_CONCURRENCY_STRATEGY, "transactional")
.setProperty("javax.persistence.sharedCache.mode", "ALL")
.setProperty(Environment.HBM2DDL_AUTO, "create-drop");
if (cacheKeysFactory != null) {
configuration.setProperty(Environment.CACHE_KEYS_FACTORY, cacheKeysFactory);
}
configuration.addAnnotatedClass( WithSimpleId.class );
configuration.addAnnotatedClass( WithEmbeddedId.class );
return (SessionFactoryImplementor) configuration.buildSessionFactory();
}
@Test
@TestForIssue(jiraKey = "HHH-11202")
public void testSimpleCacheKeySimpleId() throws Exception {
testId( SimpleCacheKeysFactory.INSTANCE, WithSimpleId.class.getName(), 1L );
}
@Test
@TestForIssue(jiraKey = "HHH-11202")
public void testSimpleCacheKeyEmbeddedId() throws Exception {
testId( SimpleCacheKeysFactory.INSTANCE, WithEmbeddedId.class.getName(), new PK( 1L ) );
}
@Test
@TestForIssue(jiraKey = "HHH-11202")
public void testDefaultCacheKeySimpleId() throws Exception {
testId( DefaultCacheKeysFactory.INSTANCE, WithSimpleId.class.getName(), 1L );
}
@Test
@TestForIssue(jiraKey = "HHH-11202")
public void testDefaultCacheKeyEmbeddedId() throws Exception {
testId( DefaultCacheKeysFactory.INSTANCE, WithEmbeddedId.class.getName(), new PK( 1L ) );
}
private void testId(CacheKeysFactory cacheKeysFactory, String entityName, Object id) throws Exception {
final SessionFactoryImplementor sessionFactory = getSessionFactory(cacheKeysFactory.getClass().getName());
final EntityPersister persister = sessionFactory.getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor(entityName);
final Object key = cacheKeysFactory.createEntityKey(
id,
persister,
sessionFactory,
null
);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject( key );
final ObjectInputStream ois = new ObjectInputStream( new ByteArrayInputStream( baos.toByteArray() ) );
final Object keyClone = ois.readObject();
try {
assertEquals( key, keyClone );
assertEquals( keyClone, key );
assertEquals( key.hashCode(), keyClone.hashCode() );
final Object idClone = cacheKeysFactory.getEntityId( keyClone );
assertEquals( id.hashCode(), idClone.hashCode() );
assertEquals( id, idClone );
assertEquals( idClone, id );
assertTrue( persister.getIdentifierType().isEqual( id, idClone, sessionFactory ) );
assertTrue( persister.getIdentifierType().isEqual( idClone, id, sessionFactory ) );
sessionFactory.close();
}
finally {
sessionFactory.close();
}
}
}

View File

@ -6,6 +6,9 @@
*/ */
package org.hibernate.orm.test.serialization.entity; package org.hibernate.orm.test.serialization.entity;
import java.io.Serializable;
import java.util.Objects;
/** /**
* This class should be in a package that is different from the test * This class should be in a package that is different from the test
* so that the test and entity that uses this class for its primary * so that the test and entity that uses this class for its primary
@ -13,21 +16,38 @@ package org.hibernate.orm.test.serialization.entity;
* *
* @author Gail Badner * @author Gail Badner
*/ */
public class PK { public class PK implements Serializable {
private Long value; private Long id;
public PK() { public PK() {
} }
public PK(Long value) { public PK(Long id) {
this.value = value; this.id = id;
} }
protected Long getValue() { public Long getId() {
return value; return id;
} }
protected void setValue(Long value) { public void setId(Long id) {
this.value = value; this.id = id;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
PK pk = (PK) o;
return Objects.equals( id, pk.id );
}
@Override
public int hashCode() {
return Objects.hash( id );
} }
} }

View File

@ -0,0 +1,24 @@
/*
* 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.serialization.entity;
import jakarta.persistence.Cacheable;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
/**
* The class should be in a package that is different from the test
* so that the test does not have access to the private embedded ID.
*
* @author Gail Badner
*/
@Entity
@Cacheable
public class WithEmbeddedId {
@EmbeddedId
private PK embeddedId;
}

View File

@ -0,0 +1,18 @@
package org.hibernate.orm.test.serialization.entity;
import jakarta.persistence.Cacheable;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
/**
* The class should be in a package that is different from the test
* so that the test does not have access to the private ID field.
*
* @author Gail Badner
*/
@Entity
@Cacheable
public class WithSimpleId {
@Id
private Long id;
}

View File

@ -6,6 +6,11 @@
*/ */
package org.hibernate.orm.test.jcache; package org.hibernate.orm.test.jcache;
import java.io.Serializable;
import java.util.Objects;
import jakarta.persistence.Embeddable;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue; import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id; import jakarta.persistence.Id;
@ -52,6 +57,7 @@ public class InsertedDataTest {
final Metadata metadata = new MetadataSources( serviceRegistry ) final Metadata metadata = new MetadataSources( serviceRegistry )
.addAnnotatedClass( CacheableItem.class ) .addAnnotatedClass( CacheableItem.class )
.addAnnotatedClass( CacheableEmbeddedIdItem.class )
.buildMetadata(); .buildMetadata();
TestHelper.createRegions( metadata, true, false ); TestHelper.createRegions( metadata, true, false );
@ -60,6 +66,13 @@ public class InsertedDataTest {
@AfterEach @AfterEach
public void releaseResources() { public void releaseResources() {
inTransaction(
sessionFactory,
s -> {
s.createQuery( "delete CacheableItem" ).executeUpdate();
s.createQuery( "delete from CacheableEmbeddedIdItem" ).executeUpdate();
}
);
if ( sessionFactory != null ) { if ( sessionFactory != null ) {
sessionFactory.close(); sessionFactory.close();
} }
@ -84,10 +97,22 @@ public class InsertedDataTest {
assertTrue( sessionFactory().getCache().containsEntity( CacheableItem.class, 1L ) ); assertTrue( sessionFactory().getCache().containsEntity( CacheableItem.class, 1L ) );
}
@Test
public void testInsert2() {
sessionFactory().getCache().evictEntityData();
sessionFactory().getStatistics().clear();
inTransaction( inTransaction(
sessionFactory, sessionFactory,
s -> s.createQuery( "delete CacheableItem" ).executeUpdate() s -> {
CacheableEmbeddedIdItem item = new CacheableEmbeddedIdItem( new PK( 2l ), "data" );
s.save( item );
}
); );
assertTrue( sessionFactory().getCache().containsEntity( CacheableEmbeddedIdItem.class, new PK( 2l ) ) );
} }
@Test @Test
@ -125,10 +150,6 @@ public class InsertedDataTest {
assertTrue( sessionFactory().getCache().containsEntity( CacheableItem.class, 1L ) ); assertTrue( sessionFactory().getCache().containsEntity( CacheableItem.class, 1L ) );
inTransaction(
sessionFactory,
s -> s.createQuery( "delete CacheableItem" ).executeUpdate()
);
} }
@Test @Test
@ -167,10 +188,6 @@ public class InsertedDataTest {
assertTrue( sessionFactory().getCache().containsEntity( CacheableItem.class, 1L ) ); assertTrue( sessionFactory().getCache().containsEntity( CacheableItem.class, 1L ) );
inTransaction(
sessionFactory,
s -> s.createQuery( "delete CacheableItem" ).executeUpdate()
);
} }
@Test @Test
@ -233,11 +250,24 @@ public class InsertedDataTest {
); );
assertTrue( sessionFactory().getCache().containsEntity( CacheableItem.class, 1L ) ); assertTrue( sessionFactory().getCache().containsEntity( CacheableItem.class, 1L ) );
}
@Test
public void testInsertWithClear2() {
sessionFactory().getCache().evictEntityData();
sessionFactory().getStatistics().clear();
inTransaction( inTransaction(
sessionFactory, sessionFactory,
s -> s.createQuery( "delete CacheableItem" ).executeUpdate() s -> {
CacheableEmbeddedIdItem item = new CacheableEmbeddedIdItem( new PK( 2l ), "data" );
s.save( item );
s.flush();
s.clear();
}
); );
assertTrue( sessionFactory().getCache().containsEntity( CacheableEmbeddedIdItem.class, new PK( 2l ) ) );
} }
@Test @Test
@ -268,6 +298,34 @@ public class InsertedDataTest {
); );
} }
@Test
public void testInsertWithClearThenRollback2() {
sessionFactory().getCache().evictEntityData();
sessionFactory().getStatistics().clear();
inTransaction(
sessionFactory,
s -> {
CacheableEmbeddedIdItem item = new CacheableEmbeddedIdItem( new PK( 2l ), "data" );
s.save( item );
s.flush();
s.clear();
item = s.get( CacheableEmbeddedIdItem.class, item.getId() );
s.getTransaction().markRollbackOnly();
}
);
assertFalse( sessionFactory().getCache().containsEntity( CacheableEmbeddedIdItem.class, new PK( 2l ) ) );
inTransaction(
sessionFactory,
s -> {
final CacheableEmbeddedIdItem item = s.get( CacheableEmbeddedIdItem.class, new PK( 2l ) );
assertNull( item, "it should be null" );
}
);
}
@Entity(name = "CacheableItem") @Entity(name = "CacheableItem")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item") @Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item")
public static class CacheableItem { public static class CacheableItem {
@ -299,4 +357,73 @@ public class InsertedDataTest {
this.name = name; this.name = name;
} }
} }
@Entity(name = "CacheableEmbeddedIdItem")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "item")
public static class CacheableEmbeddedIdItem {
private PK id;
private String name;
public CacheableEmbeddedIdItem() {
}
public CacheableEmbeddedIdItem(PK id,String name) {
this.id = id;
this.name = name;
}
@EmbeddedId
public PK getId() {
return id;
}
public void setId(PK id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Embeddable
public static class PK implements Serializable {
private Long id;
public PK() {
}
public PK(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
PK pk = (PK) o;
return Objects.equals( id, pk.id );
}
@Override
public int hashCode() {
return Objects.hash( id );
}
}
} }