HHH-11202 : IllegalAccessException on Embeddable ID after serializing Getter in cache key
This commit is contained in:
parent
4a32f1a0d5
commit
99a033c21c
|
@ -31,7 +31,9 @@ public abstract class AbstractFieldSerialForm implements Serializable {
|
||||||
|
|
||||||
protected Field resolveField() {
|
protected Field resolveField() {
|
||||||
try {
|
try {
|
||||||
return declaringClass.getDeclaredField( fieldName );
|
final Field field = declaringClass.getDeclaredField( fieldName );
|
||||||
|
field.setAccessible( true );
|
||||||
|
return field;
|
||||||
}
|
}
|
||||||
catch (NoSuchFieldException e) {
|
catch (NoSuchFieldException e) {
|
||||||
throw new PropertyAccessSerializationException(
|
throw new PropertyAccessSerializationException(
|
||||||
|
|
|
@ -121,7 +121,9 @@ public class GetterMethodImpl implements Getter {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Method resolveMethod() {
|
private Method resolveMethod() {
|
||||||
try {
|
try {
|
||||||
return declaringClass.getDeclaredMethod( methodName );
|
final Method method = declaringClass.getDeclaredMethod( methodName );
|
||||||
|
method.setAccessible( true );
|
||||||
|
return method;
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodException e) {
|
catch (NoSuchMethodException e) {
|
||||||
throw new PropertyAccessSerializationException(
|
throw new PropertyAccessSerializationException(
|
||||||
|
|
|
@ -145,7 +145,9 @@ public class SetterMethodImpl implements Setter {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Method resolveMethod() {
|
private Method resolveMethod() {
|
||||||
try {
|
try {
|
||||||
return declaringClass.getDeclaredMethod( methodName, argumentType );
|
final Method method = declaringClass.getDeclaredMethod( methodName, argumentType );
|
||||||
|
method.setAccessible( true );
|
||||||
|
return method;
|
||||||
}
|
}
|
||||||
catch (NoSuchMethodException e) {
|
catch (NoSuchMethodException e) {
|
||||||
throw new PropertyAccessSerializationException(
|
throw new PropertyAccessSerializationException(
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* 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.serialization;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.hibernate.internal.util.ReflectHelper;
|
||||||
|
import org.hibernate.property.access.spi.Getter;
|
||||||
|
import org.hibernate.property.access.spi.GetterFieldImpl;
|
||||||
|
import org.hibernate.property.access.spi.GetterMethodImpl;
|
||||||
|
import org.hibernate.property.access.spi.Setter;
|
||||||
|
import org.hibernate.property.access.spi.SetterFieldImpl;
|
||||||
|
import org.hibernate.property.access.spi.SetterMethodImpl;
|
||||||
|
import org.hibernate.serialization.entity.AnEntity;
|
||||||
|
import org.hibernate.serialization.entity.PK;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that the can access inaccessible private fields and
|
||||||
|
* inaccessible protected methods via Getter/Setter.
|
||||||
|
*
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
public class GetterSetterSerializationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue( jiraKey = "HHH-11202")
|
||||||
|
public void testPrivateFieldGetter() throws Exception {
|
||||||
|
final AnEntity entity = new AnEntity( new PK( 1L ) );
|
||||||
|
|
||||||
|
final Getter getter = new GetterFieldImpl(
|
||||||
|
AnEntity.class,
|
||||||
|
"pk",
|
||||||
|
ReflectHelper.findField( AnEntity.class, "pk")
|
||||||
|
);
|
||||||
|
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
final ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||||
|
oos.writeObject( getter );
|
||||||
|
|
||||||
|
final ObjectInputStream ois = new ObjectInputStream( new ByteArrayInputStream( baos.toByteArray() ) );
|
||||||
|
|
||||||
|
final Getter getterClone = (Getter) ois.readObject();
|
||||||
|
|
||||||
|
assertSame( getter.get( entity ), getterClone.get( entity ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue( jiraKey = "HHH-11202")
|
||||||
|
public void testPrivateFieldSetter() throws Exception {
|
||||||
|
AnEntity entity = new AnEntity( new PK( 1L ) );
|
||||||
|
|
||||||
|
final Getter getter = new GetterFieldImpl(
|
||||||
|
AnEntity.class,
|
||||||
|
"pk",
|
||||||
|
ReflectHelper.findField( AnEntity.class, "pk")
|
||||||
|
);
|
||||||
|
final Setter setter = new SetterFieldImpl(
|
||||||
|
AnEntity.class,
|
||||||
|
"pk",
|
||||||
|
ReflectHelper.findField( AnEntity.class, "pk")
|
||||||
|
);
|
||||||
|
|
||||||
|
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
final ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||||
|
oos.writeObject( setter );
|
||||||
|
|
||||||
|
final ObjectInputStream ois = new ObjectInputStream( new ByteArrayInputStream( baos.toByteArray() ) );
|
||||||
|
|
||||||
|
final Setter setterClone = (Setter) ois.readObject();
|
||||||
|
final PK pkNew = new PK( 2L );
|
||||||
|
setterClone.set( entity, pkNew, null );
|
||||||
|
|
||||||
|
assertSame( pkNew, getter.get( entity ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue( jiraKey = "HHH-11202")
|
||||||
|
public void testProtectedMethodGetter() throws Exception {
|
||||||
|
final AnEntity entity = new AnEntity( new PK( 1L ) );
|
||||||
|
|
||||||
|
final Getter getter = new GetterMethodImpl(
|
||||||
|
AnEntity.class,
|
||||||
|
"pk",
|
||||||
|
ReflectHelper.findGetterMethod( AnEntity.class, "pk" )
|
||||||
|
);
|
||||||
|
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
final ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||||
|
oos.writeObject( getter );
|
||||||
|
|
||||||
|
final ObjectInputStream ois = new ObjectInputStream( new ByteArrayInputStream( baos.toByteArray() ) );
|
||||||
|
|
||||||
|
final Getter getterClone = (Getter) ois.readObject();
|
||||||
|
|
||||||
|
assertSame( getter.get( entity ), getterClone.get( entity ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestForIssue( jiraKey = "HHH-11202")
|
||||||
|
public void testProtectedMethodSetter() throws Exception {
|
||||||
|
final AnEntity entity = new AnEntity( new PK( 1L ) );
|
||||||
|
|
||||||
|
final Getter getter = new GetterMethodImpl(
|
||||||
|
AnEntity.class,
|
||||||
|
"pk",
|
||||||
|
ReflectHelper.findGetterMethod( AnEntity.class, "pk" )
|
||||||
|
);
|
||||||
|
final Setter setter = new SetterMethodImpl(
|
||||||
|
AnEntity.class,
|
||||||
|
"pk",
|
||||||
|
ReflectHelper.findSetterMethod( AnEntity.class, "pk", PK.class )
|
||||||
|
);
|
||||||
|
|
||||||
|
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
final ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||||
|
oos.writeObject( setter );
|
||||||
|
|
||||||
|
final ObjectInputStream ois = new ObjectInputStream( new ByteArrayInputStream( baos.toByteArray() ) );
|
||||||
|
|
||||||
|
final Setter setterClone = (Setter) ois.readObject();
|
||||||
|
final PK pkNew = new PK( 2L );
|
||||||
|
setterClone.set( entity, pkNew, null );
|
||||||
|
|
||||||
|
assertSame( pkNew, getter.get( entity ) );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* 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.serialization.entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class should be in a package that is different from the test
|
||||||
|
* so that the test does not have access to private field,
|
||||||
|
* and the protected getter and setter.
|
||||||
|
*
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
public class AnEntity {
|
||||||
|
private PK pk;
|
||||||
|
|
||||||
|
public AnEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnEntity(PK pk) {
|
||||||
|
this.pk = pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PK getPk() {
|
||||||
|
return pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setPk(PK pk) {
|
||||||
|
this.pk = pk;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* 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.serialization.entity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* key does not have access to private field, and the protected getter and setter.
|
||||||
|
*
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
public class PK {
|
||||||
|
private Long value;
|
||||||
|
|
||||||
|
public PK() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public PK(Long value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Long getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setValue(Long value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* 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.test.cache.infinispan;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
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.jpa.AvailableSettings;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.test.cache.infinispan.functional.entities.WithEmbeddedId;
|
||||||
|
import org.hibernate.test.cache.infinispan.functional.entities.PK;
|
||||||
|
import org.hibernate.test.cache.infinispan.functional.entities.WithSimpleId;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
public class CacheKeySerializationTest extends BaseUnitTestCase {
|
||||||
|
@Rule
|
||||||
|
public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup();
|
||||||
|
|
||||||
|
private SessionFactoryImplementor getSessionFactory(String cacheKeysFactory) {
|
||||||
|
Configuration configuration = new Configuration()
|
||||||
|
.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true")
|
||||||
|
.setProperty(Environment.CACHE_REGION_FACTORY, TestInfinispanRegionFactory.class.getName())
|
||||||
|
.setProperty(Environment.DEFAULT_CACHE_CONCURRENCY_STRATEGY, "transactional")
|
||||||
|
.setProperty( AvailableSettings.SHARED_CACHE_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.getEntityPersister( 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* 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.test.cache.infinispan.functional.entities;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* key does not have access to private field.
|
||||||
|
*
|
||||||
|
* @author Gail Badner
|
||||||
|
*/
|
||||||
|
public class PK implements Serializable {
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
public PK() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public PK(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 !( id != null ? !id.equals( pk.id ) : pk.id != null );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return id != null ? id.hashCode() : 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.test.cache.infinispan.functional.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Cacheable;
|
||||||
|
import javax.persistence.EmbeddedId;
|
||||||
|
import javax.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;
|
||||||
|
}
|
|
@ -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.test.cache.infinispan.functional.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Cacheable;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.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;
|
||||||
|
}
|
Loading…
Reference in New Issue