HHH-4760 - Fix and test

This commit is contained in:
Lukasz Antoniak 2011-06-04 14:41:25 +02:00
parent 252eee4dd2
commit 337bec4574
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 org.hibernate.envers.reader.AuditReaderImplementor;
import static org.hibernate.envers.tools.ArgumentsTools.*; import static org.hibernate.envers.tools.ArgumentsTools.*;
import static org.hibernate.envers.tools.Tools.getTargetClassIfProxied;
/** /**
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
@ -57,6 +58,7 @@ public class AuditQueryCreator {
public AuditQuery forEntitiesAtRevision(Class<?> c, Number revision) { public AuditQuery forEntitiesAtRevision(Class<?> c, Number revision) {
checkNotNull(revision, "Entity revision"); checkNotNull(revision, "Entity revision");
checkPositive(revision, "Entity revision"); checkPositive(revision, "Entity revision");
c = getTargetClassIfProxied(c);
return new EntitiesAtRevisionQuery(auditCfg, auditReaderImplementor, c, revision); return new EntitiesAtRevisionQuery(auditCfg, auditReaderImplementor, c, revision);
} }
@ -73,6 +75,7 @@ public class AuditQueryCreator {
public AuditQuery forEntitiesAtRevision(Class<?> c, String entityName, Number revision) { public AuditQuery forEntitiesAtRevision(Class<?> c, String entityName, Number revision) {
checkNotNull(revision, "Entity revision"); checkNotNull(revision, "Entity revision");
checkPositive(revision, "Entity revision"); checkPositive(revision, "Entity revision");
c = getTargetClassIfProxied(c);
return new EntitiesAtRevisionQuery(auditCfg, auditReaderImplementor, c, entityName, revision); return new EntitiesAtRevisionQuery(auditCfg, auditReaderImplementor, c, entityName, revision);
} }
@ -92,6 +95,7 @@ public class AuditQueryCreator {
public AuditQuery forEntitiesModifiedAtRevision(Class<?> c, String entityName, Number revision) { public AuditQuery forEntitiesModifiedAtRevision(Class<?> c, String entityName, Number revision) {
checkNotNull(revision, "Entity revision"); checkNotNull(revision, "Entity revision");
checkPositive(revision, "Entity revision"); checkPositive(revision, "Entity revision");
c = getTargetClassIfProxied(c);
return new EntitiesModifiedAtRevisionQuery(auditCfg, auditReaderImplementor, c, entityName, revision); return new EntitiesModifiedAtRevisionQuery(auditCfg, auditReaderImplementor, c, entityName, revision);
} }
@ -110,6 +114,7 @@ public class AuditQueryCreator {
public AuditQuery forEntitiesModifiedAtRevision(Class<?> c, Number revision) { public AuditQuery forEntitiesModifiedAtRevision(Class<?> c, Number revision) {
checkNotNull(revision, "Entity revision"); checkNotNull(revision, "Entity revision");
checkPositive(revision, "Entity revision"); checkPositive(revision, "Entity revision");
c = getTargetClassIfProxied(c);
return new EntitiesModifiedAtRevisionQuery(auditCfg, auditReaderImplementor, c, revision); return new EntitiesModifiedAtRevisionQuery(auditCfg, auditReaderImplementor, c, revision);
} }
@ -134,6 +139,7 @@ public class AuditQueryCreator {
* unless an order or projection is added. * unless an order or projection is added.
*/ */
public AuditQuery forRevisionsOfEntity(Class<?> c, boolean selectEntitiesOnly, boolean selectDeletedEntities) { public AuditQuery forRevisionsOfEntity(Class<?> c, boolean selectEntitiesOnly, boolean selectDeletedEntities) {
c = getTargetClassIfProxied(c);
return new RevisionsOfEntityQuery(auditCfg, auditReaderImplementor, c, selectEntitiesOnly,selectDeletedEntities); return new RevisionsOfEntityQuery(auditCfg, auditReaderImplementor, c, selectEntitiesOnly,selectDeletedEntities);
} }
@ -159,6 +165,7 @@ public class AuditQueryCreator {
* unless an order or projection is added. * unless an order or projection is added.
*/ */
public AuditQuery forRevisionsOfEntity(Class<?> c, String entityName, boolean selectEntitiesOnly, boolean selectDeletedEntities) { public AuditQuery forRevisionsOfEntity(Class<?> c, String entityName, boolean selectEntitiesOnly, boolean selectDeletedEntities) {
c = getTargetClassIfProxied(c);
return new RevisionsOfEntityQuery(auditCfg, auditReaderImplementor, c, entityName, selectEntitiesOnly,selectDeletedEntities); return new RevisionsOfEntityQuery(auditCfg, auditReaderImplementor, c, entityName, selectEntitiesOnly,selectDeletedEntities);
} }
} }

View File

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

View File

@ -31,6 +31,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import javassist.util.proxy.ProxyFactory;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
@ -39,6 +40,7 @@ import org.hibernate.proxy.HibernateProxy;
/** /**
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author Hern<EFBFBD>n Chanfreau * @author Hern<EFBFBD>n Chanfreau
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
public class Tools { public class Tools {
public static <K,V> Map<K,V> newHashMap() { 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) { public static boolean objectsEqual(Object obj1, Object obj2) {
if (obj1 == null) { if (obj1 == null) {
return obj2 == 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);
}
}