HHH-5288:

- applying patch by Erik-Berndt Scheper - thanks!
- Envers auditReader.find() returns wrong data for embedded components using fields with default values

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@19750 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Adam Warski 2010-06-16 18:06:57 +00:00
parent ef90b00b14
commit 704503eea2
5 changed files with 635 additions and 7 deletions

View File

@ -27,16 +27,15 @@ import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.hibernate.envers.entities.PropertyData;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.envers.configuration.AuditConfiguration;
import org.hibernate.envers.entities.PropertyData;
import org.hibernate.envers.exception.AuditException;
import org.hibernate.envers.reader.AuditReaderImplementor;
import org.hibernate.envers.tools.reflection.ReflectionTools;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.property.Setter;
import org.hibernate.util.ReflectHelper;
import org.hibernate.engine.SessionImplementor;
/**
* @author Adam Warski (adam at warski dot org)
@ -84,8 +83,11 @@ public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperB
}
}
// And we don't have to set anything on the object - the default value is null
if (!allNullAndSingle) {
if (allNullAndSingle) {
// single property, but default value need not be null, so we'll set it to null anyway
setter.set(obj, null, null);
} else {
// set the component
try {
Object subObj = ReflectHelper.getDefaultConstructor(
Thread.currentThread().getContextClassLoader().loadClass(componentClassName)).newInstance();
@ -97,7 +99,7 @@ public class ComponentPropertyMapper implements PropertyMapper, CompositeMapperB
}
}
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
public List<PersistentCollectionChangeData> mapCollectionChanges(String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
Serializable id) {

View File

@ -0,0 +1,68 @@
package org.hibernate.envers.test.entities.components;
import javax.persistence.Embedded;
/**
*
* @author Erik-Berndt Scheper
*
*/
public class DefaultValueComponent1 {
private String str1;
@Embedded
private DefaultValueComponent2 comp2 = new DefaultValueComponent2();
public static final DefaultValueComponent1 of(String str1,
DefaultValueComponent2 comp2) {
DefaultValueComponent1 instance = new DefaultValueComponent1();
instance.setStr1(str1);
instance.setComp2(comp2);
return instance;
}
public String getStr1() {
return str1;
}
public void setStr1(String str1) {
this.str1 = str1;
}
public DefaultValueComponent2 getComp2() {
return comp2;
}
public void setComp2(DefaultValueComponent2 comp2) {
this.comp2 = comp2;
}
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof DefaultValueComponent1))
return false;
DefaultValueComponent1 that = (DefaultValueComponent1) o;
if (str1 != null ? !str1.equals(that.str1) : that.str1 != null)
return false;
if (comp2 != null ? !comp2.equals(that.comp2) : that.comp2 != null)
return false;
return true;
}
public int hashCode() {
int result;
result = (str1 != null ? str1.hashCode() : 0);
result = 31 * result + (comp2 != null ? comp2.hashCode() : 0);
return result;
}
public String toString() {
return "Comp1(str1 = " + str1 + ", comp2 = " + comp2 + ")";
}
}

View File

@ -0,0 +1,64 @@
package org.hibernate.envers.test.entities.components;
/**
*
* @author Erik-Berndt Scheper
*
*/
public class DefaultValueComponent2 {
private String str1 = "defaultValue";
private String str2;
public static final DefaultValueComponent2 of(String str1, String str2) {
DefaultValueComponent2 instance = new DefaultValueComponent2();
instance.setStr1(str1);
instance.setStr2(str2);
return instance;
}
public String getStr2() {
return str2;
}
public void setStr2(String str2) {
this.str2 = str2;
}
public String getStr1() {
return str1;
}
public void setStr1(String str1) {
this.str1 = str1;
}
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof DefaultValueComponent2))
return false;
DefaultValueComponent2 that = (DefaultValueComponent2) o;
if (str1 != null ? !str1.equals(that.str1) : that.str1 != null)
return false;
if (str2 != null ? !str2.equals(that.str2) : that.str2 != null)
return false;
return true;
}
public int hashCode() {
int result;
result = (str1 != null ? str1.hashCode() : 0);
result = 31 * result + (str2 != null ? str2.hashCode() : 0);
return result;
}
public String toString() {
return "Comp2(str1 = " + str1 + ", str2 = " + str2 + ")";
}
}

View File

@ -0,0 +1,111 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.entities.components;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.envers.Audited;
/**
* @author Erik-Berndt Scheper
*/
@Entity
@Audited
public class DefaultValueComponentTestEntity {
@Id
@GeneratedValue
private Integer id;
@Embedded
@Audited
@AttributeOverrides( { @AttributeOverride(name = "comp2.str1", column = @Column(name = "COMP2_STR1")) })
private DefaultValueComponent1 comp1 = null;
public DefaultValueComponentTestEntity() {
}
public static DefaultValueComponentTestEntity of(
DefaultValueComponent1 comp1) {
DefaultValueComponentTestEntity instance = new DefaultValueComponentTestEntity();
instance.setComp1(comp1);
return instance;
}
public static DefaultValueComponentTestEntity of(Integer id,
DefaultValueComponent1 comp1) {
DefaultValueComponentTestEntity instance = new DefaultValueComponentTestEntity();
instance.setId(id);
instance.setComp1(comp1);
return instance;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public DefaultValueComponent1 getComp1() {
return comp1;
}
public void setComp1(DefaultValueComponent1 comp1) {
this.comp1 = comp1;
}
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof DefaultValueComponentTestEntity))
return false;
DefaultValueComponentTestEntity that = (DefaultValueComponentTestEntity) o;
if (comp1 != null ? !comp1.equals(that.comp1) : that.comp1 != null)
return false;
if (id != null ? !id.equals(that.id) : that.id != null)
return false;
return true;
}
public int hashCode() {
int result;
result = (id != null ? id.hashCode() : 0);
result = 31 * result + (comp1 != null ? comp1.hashCode() : 0);
return result;
}
public String toString() {
return "CTE(id = " + id + ", comp1 = " + comp1 + ")";
}
}

View File

@ -0,0 +1,383 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.envers.test.integration.components;
import java.math.BigInteger;
import java.util.Arrays;
import javax.persistence.EntityManager;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.AbstractEntityTest;
import org.hibernate.envers.test.entities.components.DefaultValueComponent1;
import org.hibernate.envers.test.entities.components.DefaultValueComponent2;
import org.hibernate.envers.test.entities.components.DefaultValueComponentTestEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* Test class for components with default values.
*
* @see <a
* href="http://opensource.atlassian.com/projects/hibernate/browse/HHH-5288">
* Hibernate JIRA </a>
*
* @author Erik-Berndt Scheper
*/
public class DefaultValueComponents extends AbstractEntityTest {
private static final Logger log = LoggerFactory
.getLogger(DefaultValueComponents.class);
private Integer id0;
private Integer id1;
private Integer id2;
private Integer id3;
private Integer id4;
private Integer id5;
private Integer id6;
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(DefaultValueComponentTestEntity.class);
}
@BeforeClass(dependsOnMethods = "init")
public void initData() {
// Revision 1
EntityManager em = getEntityManager();
em.getTransaction().begin();
DefaultValueComponentTestEntity cte0 = DefaultValueComponentTestEntity
.of(null);
DefaultValueComponentTestEntity cte1 = DefaultValueComponentTestEntity
.of(DefaultValueComponent1.of("c1-str1", null));
DefaultValueComponentTestEntity cte2 = DefaultValueComponentTestEntity
.of(DefaultValueComponent1.of("c1-str1", DefaultValueComponent2
.of("c2-str1", "c2-str2")));
DefaultValueComponentTestEntity cte3 = DefaultValueComponentTestEntity
.of(DefaultValueComponent1.of(null, DefaultValueComponent2.of(
"c2-str1", "c2-str2")));
DefaultValueComponentTestEntity cte4 = DefaultValueComponentTestEntity
.of(DefaultValueComponent1.of(null, DefaultValueComponent2.of(
null, "c2-str2")));
DefaultValueComponentTestEntity cte5 = DefaultValueComponentTestEntity
.of(DefaultValueComponent1.of(null, DefaultValueComponent2.of(
"c2-str1", null)));
DefaultValueComponentTestEntity cte6 = DefaultValueComponentTestEntity
.of(DefaultValueComponent1.of(null, DefaultValueComponent2.of(
null, null)));
em.persist(cte0);
em.persist(cte1);
em.persist(cte2);
em.persist(cte3);
em.persist(cte4);
em.persist(cte5);
em.persist(cte6);
em.getTransaction().commit();
// Revision 2
em = getEntityManager();
em.getTransaction().begin();
cte0 = em.find(DefaultValueComponentTestEntity.class, cte0.getId());
cte1 = em.find(DefaultValueComponentTestEntity.class, cte1.getId());
cte2 = em.find(DefaultValueComponentTestEntity.class, cte2.getId());
cte3 = em.find(DefaultValueComponentTestEntity.class, cte3.getId());
cte4 = em.find(DefaultValueComponentTestEntity.class, cte4.getId());
cte5 = em.find(DefaultValueComponentTestEntity.class, cte5.getId());
cte6 = em.find(DefaultValueComponentTestEntity.class, cte6.getId());
cte0.setComp1(DefaultValueComponent1.of("upd-c1-str1", null));
cte1.setComp1(DefaultValueComponent1.of(null, DefaultValueComponent2
.of("upd-c2-str1", "upd-c2-str2")));
cte2.getComp1().getComp2().setStr1("upd-c2-str1");
cte3.getComp1().getComp2().setStr1("upd-c2-str1");
cte4.getComp1().getComp2().setStr1("upd-c2-str1");
cte5.getComp1().getComp2().setStr1("upd-c2-str1");
cte6.getComp1().getComp2().setStr1("upd-c2-str1");
em.getTransaction().commit();
// afterwards
id0 = cte0.getId();
id1 = cte1.getId();
id2 = cte2.getId();
id3 = cte3.getId();
id4 = cte4.getId();
id5 = cte5.getId();
id6 = cte6.getId();
}
@Test
public void testRevisionsCounts() {
log.error(getAuditReader().getRevisions(
DefaultValueComponentTestEntity.class, id0).toString());
log.error(getAuditReader().getRevisions(
DefaultValueComponentTestEntity.class, id1).toString());
log.error(getAuditReader().getRevisions(
DefaultValueComponentTestEntity.class, id2).toString());
log.error(getAuditReader().getRevisions(
DefaultValueComponentTestEntity.class, id3).toString());
log.error(getAuditReader().getRevisions(
DefaultValueComponentTestEntity.class, id4).toString());
log.error(getAuditReader().getRevisions(
DefaultValueComponentTestEntity.class, id5).toString());
log.error(getAuditReader().getRevisions(
DefaultValueComponentTestEntity.class, id6).toString());
assert Arrays.asList(1, 2).equals(
getAuditReader().getRevisions(
DefaultValueComponentTestEntity.class, id0));
assert Arrays.asList(1, 2).equals(
getAuditReader().getRevisions(
DefaultValueComponentTestEntity.class, id1));
assert Arrays.asList(1, 2).equals(
getAuditReader().getRevisions(
DefaultValueComponentTestEntity.class, id2));
assert Arrays.asList(1, 2).equals(
getAuditReader().getRevisions(
DefaultValueComponentTestEntity.class, id3));
assert Arrays.asList(1, 2).equals(
getAuditReader().getRevisions(
DefaultValueComponentTestEntity.class, id4));
assert Arrays.asList(1, 2).equals(
getAuditReader().getRevisions(
DefaultValueComponentTestEntity.class, id5));
assert Arrays.asList(1, 2).equals(
getAuditReader().getRevisions(
DefaultValueComponentTestEntity.class, id6));
}
@Test
public void testHistoryOfId0() {
DefaultValueComponentTestEntity ent1 = getAuditReader().find(
DefaultValueComponentTestEntity.class, id0, 1);
DefaultValueComponentTestEntity ent2 = getAuditReader().find(
DefaultValueComponentTestEntity.class, id0, 2);
log.error("------------ id0 -------------");
log.error(ent1.toString());
log.error(ent2.toString());
checkCorrectlyPersisted(id0, null, null);
DefaultValueComponentTestEntity expectedVer1 = DefaultValueComponentTestEntity
.of(id0, DefaultValueComponent1.of(null, null));
DefaultValueComponentTestEntity expectedVer2 = DefaultValueComponentTestEntity
.of(id0, DefaultValueComponent1.of("upd-c1-str1", null));
assert ent1.equals(expectedVer1);
assert ent2.equals(expectedVer2);
}
@Test
public void testHistoryOfId1() {
DefaultValueComponentTestEntity ent1 = getAuditReader().find(
DefaultValueComponentTestEntity.class, id1, 1);
DefaultValueComponentTestEntity ent2 = getAuditReader().find(
DefaultValueComponentTestEntity.class, id1, 2);
log.error("------------ id1 -------------");
log.error(ent1.toString());
log.error(ent2.toString());
checkCorrectlyPersisted(id1, null, "upd-c2-str1");
DefaultValueComponentTestEntity expectedVer1 = DefaultValueComponentTestEntity
.of(id1, DefaultValueComponent1.of("c1-str1", null));
DefaultValueComponentTestEntity expectedVer2 = DefaultValueComponentTestEntity
.of(id1, DefaultValueComponent1.of(null, DefaultValueComponent2
.of("upd-c2-str1", "upd-c2-str2")));
assert ent2.equals(expectedVer2);
assert ent1.equals(expectedVer1);
}
@Test
public void testHistoryOfId2() {
DefaultValueComponentTestEntity ent1 = getAuditReader().find(
DefaultValueComponentTestEntity.class, id2, 1);
DefaultValueComponentTestEntity ent2 = getAuditReader().find(
DefaultValueComponentTestEntity.class, id2, 2);
log.error("------------ id2 -------------");
log.error(ent1.toString());
log.error(ent2.toString());
DefaultValueComponentTestEntity expectedVer1 = DefaultValueComponentTestEntity
.of(id2, DefaultValueComponent1.of("c1-str1",
DefaultValueComponent2.of("c2-str1", "c2-str2")));
DefaultValueComponentTestEntity expectedVer2 = DefaultValueComponentTestEntity
.of(id2, DefaultValueComponent1.of("c1-str1",
DefaultValueComponent2.of("upd-c2-str1", "c2-str2")));
assert ent1.equals(expectedVer1);
assert ent2.equals(expectedVer2);
}
@Test
public void testHistoryOfId3() {
DefaultValueComponentTestEntity ent1 = getAuditReader().find(
DefaultValueComponentTestEntity.class, id3, 1);
DefaultValueComponentTestEntity ent2 = getAuditReader().find(
DefaultValueComponentTestEntity.class, id3, 2);
log.error("------------ id3 -------------");
log.error(ent1.toString());
log.error(ent2.toString());
DefaultValueComponentTestEntity expectedVer1 = DefaultValueComponentTestEntity
.of(id3, DefaultValueComponent1.of(null, DefaultValueComponent2
.of("c2-str1", "c2-str2")));
DefaultValueComponentTestEntity expectedVer2 = DefaultValueComponentTestEntity
.of(id3, DefaultValueComponent1.of(null, DefaultValueComponent2
.of("upd-c2-str1", "c2-str2")));
assert ent1.equals(expectedVer1);
assert ent2.equals(expectedVer2);
}
@Test
public void testHistoryOfId4() {
DefaultValueComponentTestEntity ent1 = getAuditReader().find(
DefaultValueComponentTestEntity.class, id4, 1);
DefaultValueComponentTestEntity ent2 = getAuditReader().find(
DefaultValueComponentTestEntity.class, id4, 2);
log.error("------------ id4 -------------");
log.error(ent1.toString());
log.error(ent2.toString());
DefaultValueComponentTestEntity expectedVer1 = DefaultValueComponentTestEntity
.of(id4, DefaultValueComponent1.of(null, DefaultValueComponent2
.of(null, "c2-str2")));
DefaultValueComponentTestEntity expectedVer2 = DefaultValueComponentTestEntity
.of(id4, DefaultValueComponent1.of(null, DefaultValueComponent2
.of("upd-c2-str1", "c2-str2")));
assert ent1.equals(expectedVer1);
assert ent2.equals(expectedVer2);
}
@Test
public void testHistoryOfId5() {
DefaultValueComponentTestEntity ent1 = getAuditReader().find(
DefaultValueComponentTestEntity.class, id5, 1);
DefaultValueComponentTestEntity ent2 = getAuditReader().find(
DefaultValueComponentTestEntity.class, id5, 2);
log.error("------------ id5 -------------");
log.error(ent1.toString());
log.error(ent2.toString());
DefaultValueComponentTestEntity expectedVer1 = DefaultValueComponentTestEntity
.of(id5, DefaultValueComponent1.of(null, DefaultValueComponent2
.of("c2-str1", null)));
DefaultValueComponentTestEntity expectedVer2 = DefaultValueComponentTestEntity
.of(id5, DefaultValueComponent1.of(null, DefaultValueComponent2
.of("upd-c2-str1", null)));
assert ent1.equals(expectedVer1);
assert ent2.equals(expectedVer2);
}
@Test
public void testHistoryOfId6() {
DefaultValueComponentTestEntity ent1 = getAuditReader().find(
DefaultValueComponentTestEntity.class, id6, 1);
DefaultValueComponentTestEntity ent2 = getAuditReader().find(
DefaultValueComponentTestEntity.class, id6, 2);
log.error("------------ id6 -------------");
log.error(ent1.toString());
log.error(ent2.toString());
DefaultValueComponentTestEntity expectedVer1 = DefaultValueComponentTestEntity
.of(id6, DefaultValueComponent1.of(null, null));
DefaultValueComponentTestEntity expectedVer2 = DefaultValueComponentTestEntity
.of(id6, DefaultValueComponent1.of(null, DefaultValueComponent2
.of("upd-c2-str1", null)));
assert ent2.equals(expectedVer2);
assert ent1.equals(expectedVer1);
}
private void checkCorrectlyPersisted(Integer expectedId,
String expectedComp2Str1Rev1, String expectedComp2Str1Rev2) {
// Verify that the entity was correctly persisted
EntityManager em = getEntityManager();
em.getTransaction().begin();
Long entCount = (Long) em.createQuery(
"select count(s) from DefaultValueComponentTestEntity s where s.id = "
+ expectedId.toString()).getSingleResult();
BigInteger auditCount = (BigInteger) em.createNativeQuery(
"select count(ID) from DefaultValueComponentTestEntity_AUD s where s.id = "
+ expectedId.toString()).getSingleResult();
String comp2Str1Rev1 = (String) em
.createNativeQuery(
"select COMP2_STR1 from DefaultValueComponentTestEntity_AUD s where rev=1 and s.id = "
+ expectedId.toString()).getSingleResult();
String comp2Str1Rev2 = (String) em
.createNativeQuery(
"select COMP2_STR1 from DefaultValueComponentTestEntity_AUD s where rev=2 and s.id = "
+ expectedId.toString()).getSingleResult();
assert Long.valueOf(1L).equals(entCount);
assert BigInteger.valueOf(2L).equals(auditCount);
if (expectedComp2Str1Rev1 == null) {
assert comp2Str1Rev1 == null;
} else {
assert expectedComp2Str1Rev1.equals(comp2Str1Rev1);
}
if (expectedComp2Str1Rev2 == null) {
assert comp2Str1Rev2 == null;
} else {
assert expectedComp2Str1Rev2.equals(comp2Str1Rev2);
}
em.getTransaction().commit();
}
}