HHH-4760 - Fix and test
This commit is contained in:
parent
252eee4dd2
commit
337bec4574
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue