Merge pull request #100 from lukasz-antoniak/HHH-4760

HHH-4760 - NotAuditedException occurs when AuditReader.getRevisions() is called for Javassist proxies
This commit is contained in:
Adam Warski 2011-06-08 00:36:11 -07:00
commit c93ce70f9d
4 changed files with 97 additions and 2 deletions

View File

@ -30,6 +30,7 @@ import org.hibernate.envers.query.impl.RevisionsOfEntityQuery;
import org.hibernate.envers.reader.AuditReaderImplementor;
import static org.hibernate.envers.tools.ArgumentsTools.*;
import static org.hibernate.envers.tools.Tools.getTargetClassIfProxied;
/**
* @author Adam Warski (adam at warski dot org)
@ -57,6 +58,7 @@ public class AuditQueryCreator {
public AuditQuery forEntitiesAtRevision(Class<?> c, Number revision) {
checkNotNull(revision, "Entity revision");
checkPositive(revision, "Entity revision");
c = getTargetClassIfProxied(c);
return new EntitiesAtRevisionQuery(auditCfg, auditReaderImplementor, c, revision);
}
@ -73,6 +75,7 @@ public class AuditQueryCreator {
public AuditQuery forEntitiesAtRevision(Class<?> c, String entityName, Number revision) {
checkNotNull(revision, "Entity revision");
checkPositive(revision, "Entity revision");
c = getTargetClassIfProxied(c);
return new EntitiesAtRevisionQuery(auditCfg, auditReaderImplementor, c, entityName, revision);
}
@ -92,6 +95,7 @@ public class AuditQueryCreator {
public AuditQuery forEntitiesModifiedAtRevision(Class<?> c, String entityName, Number revision) {
checkNotNull(revision, "Entity revision");
checkPositive(revision, "Entity revision");
c = getTargetClassIfProxied(c);
return new EntitiesModifiedAtRevisionQuery(auditCfg, auditReaderImplementor, c, entityName, revision);
}
@ -110,6 +114,7 @@ public class AuditQueryCreator {
public AuditQuery forEntitiesModifiedAtRevision(Class<?> c, Number revision) {
checkNotNull(revision, "Entity revision");
checkPositive(revision, "Entity revision");
c = getTargetClassIfProxied(c);
return new EntitiesModifiedAtRevisionQuery(auditCfg, auditReaderImplementor, c, revision);
}
@ -134,6 +139,7 @@ public class AuditQueryCreator {
* unless an order or projection is added.
*/
public AuditQuery forRevisionsOfEntity(Class<?> c, boolean selectEntitiesOnly, boolean selectDeletedEntities) {
c = getTargetClassIfProxied(c);
return new RevisionsOfEntityQuery(auditCfg, auditReaderImplementor, c, selectEntitiesOnly,selectDeletedEntities);
}
@ -159,6 +165,7 @@ public class AuditQueryCreator {
* unless an order or projection is added.
*/
public AuditQuery forRevisionsOfEntity(Class<?> c, String entityName, boolean selectEntitiesOnly, boolean selectDeletedEntities) {
c = getTargetClassIfProxied(c);
return new RevisionsOfEntityQuery(auditCfg, auditReaderImplementor, c, entityName, selectEntitiesOnly,selectDeletedEntities);
}
}

View File

@ -24,6 +24,7 @@
package org.hibernate.envers.reader;
import static org.hibernate.envers.tools.ArgumentsTools.checkNotNull;
import static org.hibernate.envers.tools.ArgumentsTools.checkPositive;
import static org.hibernate.envers.tools.Tools.getTargetClassIfProxied;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@ -90,13 +91,14 @@ public class AuditReaderImpl implements AuditReaderImplementor {
public <T> T find(Class<T> cls, Object primaryKey, Number revision) throws
IllegalArgumentException, NotAuditedException, IllegalStateException {
cls = getTargetClassIfProxied(cls);
return this.find(cls, cls.getName(), primaryKey, revision);
}
@SuppressWarnings({"unchecked"})
public <T> T find(Class<T> cls, String entityName, Object primaryKey, Number revision) throws
IllegalArgumentException, NotAuditedException, IllegalStateException {
cls = getTargetClassIfProxied(cls);
checkNotNull(cls, "Entity class");
checkNotNull(entityName, "Entity name");
checkNotNull(primaryKey, "Primary key");
@ -128,7 +130,7 @@ public class AuditReaderImpl implements AuditReaderImplementor {
public List<Number> getRevisions(Class<?> cls, Object primaryKey)
throws IllegalArgumentException, NotAuditedException, IllegalStateException {
cls = getTargetClassIfProxied(cls);
return this.getRevisions(cls, cls.getName(), primaryKey);
}
@ -136,6 +138,7 @@ public class AuditReaderImpl implements AuditReaderImplementor {
public List<Number> getRevisions(Class<?> cls, String entityName, Object primaryKey)
throws IllegalArgumentException, NotAuditedException, IllegalStateException {
// todo: if a class is not versioned from the beginning, there's a missing ADD rev - what then?
cls = getTargetClassIfProxied(cls);
checkNotNull(cls, "Entity class");
checkNotNull(entityName, "Entity name");
checkNotNull(primaryKey, "Primary key");
@ -193,6 +196,7 @@ public class AuditReaderImpl implements AuditReaderImplementor {
@SuppressWarnings({"unchecked"})
public <T> T findRevision(Class<T> revisionEntityClass, Number revision) throws IllegalArgumentException,
RevisionDoesNotExistException, IllegalStateException {
revisionEntityClass = getTargetClassIfProxied(revisionEntityClass);
checkNotNull(revision, "Entity revision");
checkPositive(revision, "Entity revision");
checkSession();
@ -217,6 +221,7 @@ public class AuditReaderImpl implements AuditReaderImplementor {
@SuppressWarnings({"unchecked"})
public <T> Map<Number, T> findRevisions(Class<T> revisionEntityClass, Set<Number> revisions) throws IllegalArgumentException,
IllegalStateException {
revisionEntityClass = getTargetClassIfProxied(revisionEntityClass);
Map<Number, T> result = new HashMap<Number, T>(revisions.size());
for (Number revision : revisions) {
@ -303,6 +308,7 @@ public class AuditReaderImpl implements AuditReaderImplementor {
@SuppressWarnings({"unchecked"})
public <T> T getCurrentRevision(Class<T> revisionEntityClass, boolean persist) {
revisionEntityClass = getTargetClassIfProxied(revisionEntityClass);
if (!(session instanceof EventSource)) {
throw new IllegalArgumentException("The provided session is not an EventSource!");
}
@ -319,6 +325,7 @@ public class AuditReaderImpl implements AuditReaderImplementor {
}
public boolean isEntityClassAudited(Class<?> entityClass) {
entityClass = getTargetClassIfProxied(entityClass);
return this.isEntityNameAudited(entityClass.getName());
}

View File

@ -31,6 +31,7 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javassist.util.proxy.ProxyFactory;
import org.hibernate.Session;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
@ -39,6 +40,7 @@ import org.hibernate.proxy.HibernateProxy;
/**
* @author Adam Warski (adam at warski dot org)
* @author Hern<EFBFBD>n Chanfreau
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class Tools {
public static <K,V> Map<K,V> newHashMap() {
@ -95,6 +97,23 @@ public class Tools {
}
}
/**
* @param clazz Class wrapped with a proxy or not.
* @param <T> Class type.
* @return Returns target class in case it has been wrapped with a proxy. If {@code null} reference is passed,
* method returns {@code null}.
*/
@SuppressWarnings({"unchecked"})
public static <T> Class<T> getTargetClassIfProxied(Class<T> clazz) {
if (clazz == null) {
return null;
} else if (ProxyFactory.isProxyClass(clazz)) {
// Get the source class of Javassist proxy instance.
return (Class<T>) clazz.getSuperclass();
}
return clazz;
}
public static boolean objectsEqual(Object obj1, Object obj2) {
if (obj1 == null) {
return obj2 == null;

View File

@ -0,0 +1,62 @@
package org.hibernate.envers.test.integration.proxy;
import org.hibernate.MappingException;
import org.hibernate.envers.test.AbstractSessionTest;
import org.hibernate.envers.test.Priority;
import org.hibernate.envers.test.entities.StrTestEntity;
import org.hibernate.testing.TestForIssue;
import org.junit.Assert;
import org.junit.Test;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.List;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class QueryingWithProxyObjectTest extends AbstractSessionTest {
private Integer id = null;
@Override
protected void initMappings() throws MappingException, URISyntaxException {
config.addAnnotatedClass(StrTestEntity.class);
}
@Test
@Priority(10)
public void initData() {
// Revision 1
getSession().getTransaction().begin();
StrTestEntity ste = new StrTestEntity("data");
getSession().persist(ste);
getSession().getTransaction().commit();
id = ste.getId();
}
@Test
@TestForIssue(jiraKey="HHH-4760")
@SuppressWarnings("unchecked")
public void testQueryingWithProxyObject() {
StrTestEntity originalSte = new StrTestEntity("data", id);
// Load the proxy instance
StrTestEntity proxySte = (StrTestEntity) getSession().load(StrTestEntity.class, id);
Assert.assertTrue(getAuditReader().isEntityClassAudited(proxySte.getClass()));
StrTestEntity ste = getAuditReader().find(proxySte.getClass(), proxySte.getId(), 1);
Assert.assertEquals(originalSte, ste);
List<Number> revisions = getAuditReader().getRevisions(proxySte.getClass(), proxySte.getId());
Assert.assertEquals(Arrays.asList(1), revisions);
List<StrTestEntity> entities = getAuditReader().createQuery().forEntitiesAtRevision(proxySte.getClass(), 1).getResultList();
Assert.assertEquals(Arrays.asList(originalSte), entities);
ste = (StrTestEntity) getAuditReader().createQuery().forRevisionsOfEntity(proxySte.getClass(), true, false).getSingleResult();
Assert.assertEquals(originalSte, ste);
ste = (StrTestEntity) getAuditReader().createQuery().forEntitiesModifiedAtRevision(proxySte.getClass(), 1).getSingleResult();
Assert.assertEquals(originalSte, ste);
}
}