I have been testing and analyzing my new loader for a few days now, It seems to be working
perfectly.
I have written a comprehensive testing script available here:
http://jira.xwiki.org/jira/browse/XWIKI-2874
There is a change which must be made:
ListProperty.equals must be change to convert null values to empty ArrayList objects in
the event that
it is asked to compare to a BaseProperty.
The change looks like this:
Index: core/xwiki-core/src/main/java/com/xpn/xwiki/objects/ListProperty.java
===================================================================
--- core/xwiki-core/src/main/java/com/xpn/xwiki/objects/ListProperty.java (revision
23877)
+++ core/xwiki-core/src/main/java/com/xpn/xwiki/objects/ListProperty.java (working copy)
@@ -145,6 +145,14 @@
return true;
}
+ //The save opperation triggers hibernate to compare the new property to the
original
+ //If the property was gotten by a query like "SELECT prop FROM BaseProperty
AS prop WHERE..."
+ //and the value stored in the db is null, hibernate thinks the original is a
BaseProperty,
+ //thus we may end up comparing a ListProperty to a BaseProperty with value =
null.
+ if (list2 == null &&
obj.getClass().getName().indexOf(".BaseProperty")!=-1){
+ list2 = new ArrayList<String>();
+ }
+
if (list1.size() != list2.size()) {
return false;
}
Why is this necessary?
Because the new loader loads all types of properties at once with a query like
"select prop from BaseProperty prop where prop.id in (:ids)"
(ids being the list of object ids from the objects attached to the document.)
This is okay until the property is saved, then hibernate has to check that the
id of the property is the same. The id of the property is an empty property with
the same name and object id number. Because the property is loaded by a query
for BaseProperty, if the value in the database is null, Hibernate thinks the
property IS a BaseProperty and passes a BaseProperty to the equals method.
If these changes are not made, we get this exception.
java.lang.NullPointerException
at com.xpn.xwiki.objects.ListProperty.equals(ListProperty.java:148)
at org.hibernate.event.def.ProxyVisitor.isOwnerUnchanged(ProxyVisitor.java:44)
at org.hibernate.event.def.OnUpdateVisitor.processCollection(OnUpdateVisitor.java:45)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:101)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:61)
at
org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:55)
at org.hibernate.event.def.AbstractVisitor.process(AbstractVisitor.java:123)
at
org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:293)
at
org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:223)
at
org.hibernate.event.def.DefaultUpdateEventListener.performSaveOrUpdate(DefaultUpdateEventListener.java:33)
at
org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireUpdate(SessionImpl.java:564)
at org.hibernate.impl.SessionImpl.update(SessionImpl.java:552)
at org.hibernate.impl.SessionImpl.update(SessionImpl.java:544)
at
com.xpn.xwiki.store.XWikiHibernateStore.saveXWikiProperty(XWikiHibernateStore.java:1726)
at
com.xpn.xwiki.store.XWikiHibernateStore.saveXWikiCollection(XWikiHibernateStore.java:1072)
at com.xpn.xwiki.store.XWikiHibernateStore.saveXWikiDoc(XWikiHibernateStore.java:582)
at com.xpn.xwiki.store.XWikiCacheStore.saveXWikiDoc(XWikiCacheStore.java:181)
at com.xpn.xwiki.store.XWikiCacheStore.saveXWikiDoc(XWikiCacheStore.java:174)
at com.xpn.xwiki.XWiki.saveDocument(XWiki.java:1309)
I suggest we apply the patch to 2.1, but leave the functionality deactivated in xwiki.cfg
until 2.2 so there is
time to see if there are any latent issues. I don't expect any but I don't know
what it might do with corrupt
data in storage.
Better safe than sorry.
Caleb James DeLisle