Author: adamw
Date: 2008-09-24 07:17:25 -0400 (Wed, 24 Sep 2008)
New Revision: 167
Added:
trunk/src/main/org/jboss/envers/entities/mapper/relation/ListCollectionMapper.java
trunk/src/test/org/jboss/envers/test/entities/collection/StringListEntity.java
trunk/src/test/org/jboss/envers/test/integration/collection/StringList.java
Modified:
trunk/src/main/org/jboss/envers/configuration/metadata/CollectionMetadataGenerator.java
trunk/src/main/org/jboss/envers/entities/mapper/relation/lazy/initializor/ListCollectionInitializor.java
trunk/src/main/org/jboss/envers/tools/Tools.java
trunk/src/test/org/jboss/envers/test/tools/TestTools.java
Log:
ENVERS-42: support for (indexed) lists
Modified:
trunk/src/main/org/jboss/envers/configuration/metadata/CollectionMetadataGenerator.java
===================================================================
---
trunk/src/main/org/jboss/envers/configuration/metadata/CollectionMetadataGenerator.java 2008-09-24
10:42:17 UTC (rev 166)
+++
trunk/src/main/org/jboss/envers/configuration/metadata/CollectionMetadataGenerator.java 2008-09-24
11:17:25 UTC (rev 167)
@@ -377,6 +377,10 @@
} else if (type instanceof BagType) {
currentMapper.addComposite(propertyName, new
BasicCollectionMapper<List>(commonCollectionMapperData,
ArrayList.class, ListProxy.class, elementComponentData));
+ } else if (type instanceof ListType) {
+ // Indexed collection, so <code>indexComponentData</code> is not
null.
+ currentMapper.addComposite(propertyName, new
ListCollectionMapper(commonCollectionMapperData,
+ elementComponentData, indexComponentData));
} else {
mainGenerator.throwUnsupportedTypeException(type, referencingEntityName,
propertyName);
}
Copied: trunk/src/main/org/jboss/envers/entities/mapper/relation/ListCollectionMapper.java
(from rev 156,
trunk/src/main/org/jboss/envers/entities/mapper/relation/MapCollectionMapper.java)
===================================================================
--- trunk/src/main/org/jboss/envers/entities/mapper/relation/ListCollectionMapper.java
(rev 0)
+++
trunk/src/main/org/jboss/envers/entities/mapper/relation/ListCollectionMapper.java 2008-09-24
11:17:25 UTC (rev 167)
@@ -0,0 +1,67 @@
+package org.jboss.envers.entities.mapper.relation;
+
+import org.jboss.envers.entities.mapper.PropertyMapper;
+import org.jboss.envers.entities.mapper.relation.lazy.initializor.Initializor;
+import
org.jboss.envers.entities.mapper.relation.lazy.initializor.ListCollectionInitializor;
+import org.jboss.envers.entities.mapper.relation.lazy.proxy.ListProxy;
+import org.jboss.envers.configuration.VersionsConfiguration;
+import org.jboss.envers.reader.VersionsReaderImplementor;
+import org.jboss.envers.tools.Tools;
+import org.jboss.envers.tools.Pair;
+import org.hibernate.collection.PersistentCollection;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.io.Serializable;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public final class ListCollectionMapper extends AbstractCollectionMapper<List>
implements PropertyMapper {
+ private final MiddleComponentData elementComponentData;
+ private final MiddleComponentData indexComponentData;
+
+ public ListCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
+ MiddleComponentData elementComponentData,
MiddleComponentData indexComponentData) {
+ super(commonCollectionMapperData, List.class, ListProxy.class);
+ this.elementComponentData = elementComponentData;
+ this.indexComponentData = indexComponentData;
+ }
+
+ protected Initializor<List> getInitializor(VersionsConfiguration verCfg,
VersionsReaderImplementor versionsReader,
+ Object primaryKey, Number revision) {
+ return new ListCollectionInitializor(verCfg, versionsReader,
commonCollectionMapperData.getQueryGenerator(),
+ primaryKey, revision, elementComponentData, indexComponentData);
+ }
+
+ @SuppressWarnings({"unchecked"})
+ protected Collection getNewCollectionContent(PersistentCollection newCollection) {
+ if (newCollection == null) {
+ return null;
+ } else {
+ return Tools.listToIndexElementPairList((List<Object>) newCollection);
+ }
+ }
+
+ @SuppressWarnings({"unchecked"})
+ protected Collection getOldCollectionContent(Serializable oldCollection) {
+ if (oldCollection == null) {
+ return null;
+ } else {
+ return Tools.listToIndexElementPairList((List<Object>) oldCollection);
+ }
+ }
+
+ @SuppressWarnings({"unchecked"})
+ protected void mapToMapFromObject(Map<String, Object> data, Object changed) {
+ Pair<Integer, Object> indexValuePair = (Pair<Integer, Object>)
changed;
+ elementComponentData.getComponentMapper().mapToMapFromObject(data,
indexValuePair.getSecond());
+ indexComponentData.getComponentMapper().mapToMapFromObject(data,
indexValuePair.getFirst());
+ }
+
+ @SuppressWarnings({"unchecked"})
+ protected Object getElement(Object changedObject) {
+ return ((Pair<Integer, Object>) changedObject).getFirst();
+ }
+}
\ No newline at end of file
Modified:
trunk/src/main/org/jboss/envers/entities/mapper/relation/lazy/initializor/ListCollectionInitializor.java
===================================================================
---
trunk/src/main/org/jboss/envers/entities/mapper/relation/lazy/initializor/ListCollectionInitializor.java 2008-09-24
10:42:17 UTC (rev 166)
+++
trunk/src/main/org/jboss/envers/entities/mapper/relation/lazy/initializor/ListCollectionInitializor.java 2008-09-24
11:17:25 UTC (rev 167)
@@ -27,8 +27,13 @@
this.indexComponentData = indexComponentData;
}
+ @SuppressWarnings({"unchecked"})
protected List initializeCollection(int size) {
- return new ArrayList();
+ // Creating a list of the given capacity with all elements null initially. This
ensures that we can then
+ // fill the elements safely using the <code>List.set</code> method.
+ List list = new ArrayList(size);
+ for (int i=0; i<size; i++) { list.add(null); }
+ return list;
}
@SuppressWarnings({"unchecked"})
Modified: trunk/src/main/org/jboss/envers/tools/Tools.java
===================================================================
--- trunk/src/main/org/jboss/envers/tools/Tools.java 2008-09-24 10:42:17 UTC (rev 166)
+++ trunk/src/main/org/jboss/envers/tools/Tools.java 2008-09-24 11:17:25 UTC (rev 167)
@@ -59,4 +59,19 @@
return true;
}
+
+ /**
+ * Transforms a list of arbitrary elements to a list of index-element pairs.
+ * @param list List to transform.
+ * @return A list of pairs: ((0, element_at_index_0), (1, element_at_index_1), ...)
+ */
+ public static <T> List<Pair<Integer, T>>
listToIndexElementPairList(List<T> list) {
+ List<Pair<Integer, T>> ret = new ArrayList<Pair<Integer,
T>>();
+ Iterator<T> listIter = list.iterator();
+ for (int i=0; i<list.size(); i++) {
+ ret.add(Pair.make(i, listIter.next()));
+ }
+
+ return ret;
+ }
}
Copied: trunk/src/test/org/jboss/envers/test/entities/collection/StringListEntity.java
(from rev 153,
trunk/src/test/org/jboss/envers/test/entities/collection/StringSetEntity.java)
===================================================================
--- trunk/src/test/org/jboss/envers/test/entities/collection/StringListEntity.java
(rev 0)
+++
trunk/src/test/org/jboss/envers/test/entities/collection/StringListEntity.java 2008-09-24
11:17:25 UTC (rev 167)
@@ -0,0 +1,65 @@
+package org.jboss.envers.test.entities.collection;
+
+import org.jboss.envers.Versioned;
+import org.hibernate.annotations.CollectionOfElements;
+import org.hibernate.annotations.IndexColumn;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+@Entity
+public class StringListEntity {
+ @Id
+ @GeneratedValue
+ private Integer id;
+
+ @Versioned
+ @CollectionOfElements
+ @IndexColumn(name = "list_index")
+ private List<String> strings;
+
+ public StringListEntity() {
+ strings = new ArrayList<String>();
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public List<String> getStrings() {
+ return strings;
+ }
+
+ public void setStrings(List<String> strings) {
+ this.strings = strings;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof StringListEntity)) return false;
+
+ StringListEntity that = (StringListEntity) o;
+
+ if (id != null ? !id.equals(that.id) : that.id != null) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ return (id != null ? id.hashCode() : 0);
+ }
+
+ public String toString() {
+ return "SLE(id = " + id + ", strings = " + strings +
")";
+ }
+}
\ No newline at end of file
Property changes on:
trunk/src/test/org/jboss/envers/test/entities/collection/StringListEntity.java
___________________________________________________________________
Name: svn:mergeinfo
+
Copied: trunk/src/test/org/jboss/envers/test/integration/collection/StringList.java (from
rev 154, trunk/src/test/org/jboss/envers/test/integration/collection/StringSet.java)
===================================================================
--- trunk/src/test/org/jboss/envers/test/integration/collection/StringList.java
(rev 0)
+++ trunk/src/test/org/jboss/envers/test/integration/collection/StringList.java 2008-09-24
11:17:25 UTC (rev 167)
@@ -0,0 +1,101 @@
+package org.jboss.envers.test.integration.collection;
+
+import org.jboss.envers.test.integration.AbstractEntityTest;
+import org.jboss.envers.test.tools.TestTools;
+import org.jboss.envers.test.entities.collection.StringListEntity;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.hibernate.ejb.Ejb3Configuration;
+
+import javax.persistence.EntityManager;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * @author Adam Warski (adam at warski dot org)
+ */
+public class StringList extends AbstractEntityTest {
+ private Integer sle1_id;
+ private Integer sle2_id;
+
+ public void configure(Ejb3Configuration cfg) {
+ cfg.addAnnotatedClass(StringListEntity.class);
+ }
+
+ @BeforeClass(dependsOnMethods = "init")
+ public void initData() {
+ EntityManager em = getEntityManager();
+
+ StringListEntity sle1 = new StringListEntity();
+ StringListEntity sle2 = new StringListEntity();
+
+ // Revision 1 (sle1: initialy empty, sle2: initialy 2 elements)
+ em.getTransaction().begin();
+
+ sle2.getStrings().add("sle2_string1");
+ sle2.getStrings().add("sle2_string2");
+
+ em.persist(sle1);
+ em.persist(sle2);
+
+ em.getTransaction().commit();
+
+ // Revision 2 (sle1: adding 2 elements, sle2: adding an existing element)
+ em.getTransaction().begin();
+
+ sle1 = em.find(StringListEntity.class, sle1.getId());
+ sle2 = em.find(StringListEntity.class, sle2.getId());
+
+ sle1.getStrings().add("sle1_string1");
+ sle1.getStrings().add("sle1_string2");
+
+ sle2.getStrings().add("sle2_string1");
+
+ em.getTransaction().commit();
+
+ // Revision 3 (sle1: replacing an element at index 0, sle2: removing an element
at index 0)
+ em.getTransaction().begin();
+
+ sle1 = em.find(StringListEntity.class, sle1.getId());
+ sle2 = em.find(StringListEntity.class, sle2.getId());
+
+ sle1.getStrings().set(0, "sle1_string3");
+
+ sle2.getStrings().remove(0);
+
+ em.getTransaction().commit();
+
+ //
+
+ sle1_id = sle1.getId();
+ sle2_id = sle2.getId();
+ }
+
+ @Test
+ public void testRevisionsCounts() {
+ assert Arrays.asList(1, 2,
3).equals(getVersionsReader().getRevisions(StringListEntity.class, sle1_id));
+ assert Arrays.asList(1, 2,
3).equals(getVersionsReader().getRevisions(StringListEntity.class, sle2_id));
+ }
+
+ @Test
+ public void testHistoryOfSle1() {
+ StringListEntity rev1 = getVersionsReader().find(StringListEntity.class, sle1_id,
1);
+ StringListEntity rev2 = getVersionsReader().find(StringListEntity.class, sle1_id,
2);
+ StringListEntity rev3 = getVersionsReader().find(StringListEntity.class, sle1_id,
3);
+
+ assert rev1.getStrings().equals(Collections.EMPTY_LIST);
+ assert rev2.getStrings().equals(TestTools.makeList("sle1_string1",
"sle1_string2"));
+ assert rev3.getStrings().equals(TestTools.makeList("sle1_string3",
"sle1_string2"));
+ }
+
+ @Test
+ public void testHistoryOfSse2() {
+ StringListEntity rev1 = getVersionsReader().find(StringListEntity.class, sle2_id,
1);
+ StringListEntity rev2 = getVersionsReader().find(StringListEntity.class, sle2_id,
2);
+ StringListEntity rev3 = getVersionsReader().find(StringListEntity.class, sle2_id,
3);
+
+ assert rev1.getStrings().equals(TestTools.makeList("sle2_string1",
"sle2_string2"));
+ assert rev2.getStrings().equals(TestTools.makeList("sle2_string1",
"sle2_string2", "sle2_string1"));
+ assert rev3.getStrings().equals(TestTools.makeList("sle2_string2",
"sle2_string1"));
+ }
+}
\ No newline at end of file
Modified: trunk/src/test/org/jboss/envers/test/tools/TestTools.java
===================================================================
--- trunk/src/test/org/jboss/envers/test/tools/TestTools.java 2008-09-24 10:42:17 UTC (rev
166)
+++ trunk/src/test/org/jboss/envers/test/tools/TestTools.java 2008-09-24 11:17:25 UTC (rev
167)
@@ -16,6 +16,10 @@
return ret;
}
+ public static <T> List<T> makeList(T... objects) {
+ return Arrays.asList(objects);
+ }
+
public static Map<Object, Object> makeMap(Object... objects) {
Map<Object, Object> ret = new HashMap<Object, Object>();
// The number of objects must be divisable by 2.