From 8a58b176b9ea4cdefc766ac044c401a97ac54d9d Mon Sep 17 00:00:00 2001 From: Adam Warski Date: Thu, 30 Apr 2009 08:39:38 +0000 Subject: [PATCH] HHH-3878: - fixing reading deleted entities with null-only values, when the field is primitive git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@16487 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- .../entities/mapper/SinglePropertyMapper.java | 22 +++- .../test/entities/PrimitiveTestEntity.java | 109 ++++++++++++++++++ .../primitive/PrimitiveAddDelete.java | 97 ++++++++++++++++ envers/src/test/resources/testng.xml | 1 + 4 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 envers/src/test/java/org/hibernate/envers/test/entities/PrimitiveTestEntity.java create mode 100644 envers/src/test/java/org/hibernate/envers/test/integration/primitive/PrimitiveAddDelete.java diff --git a/envers/src/main/java/org/hibernate/envers/entities/mapper/SinglePropertyMapper.java b/envers/src/main/java/org/hibernate/envers/entities/mapper/SinglePropertyMapper.java index 2e08110e74..db8f2fefb3 100644 --- a/envers/src/main/java/org/hibernate/envers/entities/mapper/SinglePropertyMapper.java +++ b/envers/src/main/java/org/hibernate/envers/entities/mapper/SinglePropertyMapper.java @@ -36,7 +36,9 @@ import org.hibernate.envers.tools.reflection.ReflectionTools; import org.hibernate.collection.PersistentCollection; import org.hibernate.property.Setter; +import org.hibernate.property.DirectPropertyAccessor; import org.hibernate.engine.SessionImplementor; +import org.hibernate.HibernateException; /** * TODO: diff @@ -68,9 +70,27 @@ public class SinglePropertyMapper implements PropertyMapper, SimpleMapperBuilder } Setter setter = ReflectionTools.getSetter(obj.getClass(), propertyData); - setter.set(obj, data.get(propertyData.getName()), null); + Object value = data.get(propertyData.getName()); + // We only set a null value if the field is not primite. Otherwise, we leave it intact. + if (value != null || !isPrimitive(setter, propertyData, obj.getClass())) { + setter.set(obj, value, null); + } } + private boolean isPrimitive(Setter setter, PropertyData propertyData, Class cls) { + if (setter instanceof DirectPropertyAccessor.DirectSetter) { + // In a direct setter, getMethod() returns null + // Trying to look up the field + try { + return cls.getDeclaredField(propertyData.getBeanName()).getType().isPrimitive(); + } catch (NoSuchFieldException e) { + throw new HibernateException(e); + } + } else { + return setter.getMethod().getParameterTypes()[0].isPrimitive(); + } + } + public List mapCollectionChanges(String referencingPropertyName, PersistentCollection newColl, Serializable oldColl, diff --git a/envers/src/test/java/org/hibernate/envers/test/entities/PrimitiveTestEntity.java b/envers/src/test/java/org/hibernate/envers/test/entities/PrimitiveTestEntity.java new file mode 100644 index 0000000000..0c7cf7fd50 --- /dev/null +++ b/envers/src/test/java/org/hibernate/envers/test/entities/PrimitiveTestEntity.java @@ -0,0 +1,109 @@ +/* + * 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; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +import org.hibernate.envers.Audited; + +/** + * @author Adam Warski (adam at warski dot org) + */ +@Entity +public class PrimitiveTestEntity { + @Id + @GeneratedValue + private Integer id; + + @Audited + private int number; + + private int number2; + + public PrimitiveTestEntity() { + } + + public PrimitiveTestEntity(int number, int number2) { + this.number = number; + this.number2 = number2; + } + + public PrimitiveTestEntity(Integer id, int number, int number2) { + this.id = id; + this.number = number; + this.number2 = number2; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getNumber() { + return number; + } + + public void setNumber(Integer number) { + this.number = number; + } + + public int getNumber2() { + return number2; + } + + public void setNumber2(int number2) { + this.number2 = number2; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof PrimitiveTestEntity)) return false; + + PrimitiveTestEntity that = (PrimitiveTestEntity) o; + + if (number != that.number) return false; + if (number2 != that.number2) return false; + if (id != null ? !id.equals(that.id) : that.id != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = id != null ? id.hashCode() : 0; + result = 31 * result + number; + result = 31 * result + number2; + return result; + } + + public String toString() { + return "PTE(id = " + id + ", number = " + number + ", number2 = " + number2 + ")"; + } +} \ No newline at end of file diff --git a/envers/src/test/java/org/hibernate/envers/test/integration/primitive/PrimitiveAddDelete.java b/envers/src/test/java/org/hibernate/envers/test/integration/primitive/PrimitiveAddDelete.java new file mode 100644 index 0000000000..78c3bdd610 --- /dev/null +++ b/envers/src/test/java/org/hibernate/envers/test/integration/primitive/PrimitiveAddDelete.java @@ -0,0 +1,97 @@ +/* + * 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.primitive; + +import java.util.Arrays; +import java.util.List; +import javax.persistence.EntityManager; + +import org.hibernate.envers.test.AbstractEntityTest; +import org.hibernate.envers.test.entities.PrimitiveTestEntity; +import org.testng.annotations.Test; + +import org.hibernate.ejb.Ejb3Configuration; + +/** + * @author Adam Warski (adam at warski dot org) + */ +public class PrimitiveAddDelete extends AbstractEntityTest { + private Integer id1; + + public void configure(Ejb3Configuration cfg) { + cfg.addAnnotatedClass(PrimitiveTestEntity.class); + } + + @Test + public void initData() { + EntityManager em = getEntityManager(); + + // Revision 1 + em.getTransaction().begin(); + PrimitiveTestEntity pte = new PrimitiveTestEntity(10, 11); + em.persist(pte); + id1 = pte.getId(); + em.getTransaction().commit(); + + // Revision 2 + em.getTransaction().begin(); + pte = em.find(PrimitiveTestEntity.class, id1); + pte.setNumber(20); + pte.setNumber2(21); + em.getTransaction().commit(); + + // Revision 3 + em.getTransaction().begin(); + pte = em.find(PrimitiveTestEntity.class, id1); + em.remove(pte); + em.getTransaction().commit(); + } + + @Test(dependsOnMethods = "initData") + public void testRevisionsCounts() { + assert Arrays.asList(1, 2, 3).equals(getAuditReader().getRevisions(PrimitiveTestEntity.class, id1)); + } + + @Test(dependsOnMethods = "initData") + public void testHistoryOfId1() { + PrimitiveTestEntity ver1 = new PrimitiveTestEntity(id1, 10, 0); + PrimitiveTestEntity ver2 = new PrimitiveTestEntity(id1, 20, 0); + + assert getAuditReader().find(PrimitiveTestEntity.class, id1, 1).equals(ver1); + assert getAuditReader().find(PrimitiveTestEntity.class, id1, 2).equals(ver2); + assert getAuditReader().find(PrimitiveTestEntity.class, id1, 3) == null; + } + + @Test(dependsOnMethods = "initData") + public void testQueryWithDeleted() { + // Selecting all entities, also the deleted ones + List entities = getAuditReader().createQuery().forRevisionsOfEntity(PrimitiveTestEntity.class, true, true) + .getResultList(); + + assert entities.size() == 3; + assert entities.get(0).equals(new PrimitiveTestEntity(id1, 10, 0)); + assert entities.get(1).equals(new PrimitiveTestEntity(id1, 20, 0)); + assert entities.get(2).equals(new PrimitiveTestEntity(id1, 0, 0)); + } +} \ No newline at end of file diff --git a/envers/src/test/resources/testng.xml b/envers/src/test/resources/testng.xml index 1f0e39ddcb..ef5f8b6f9c 100644 --- a/envers/src/test/resources/testng.xml +++ b/envers/src/test/resources/testng.xml @@ -42,6 +42,7 @@ +