Comparison method violates its general contract
During certain Velocity and XSLT transformations, you may encounter an error like the following:
An error occurred while rendering asset preview: org.apache.velocity.exception.MethodInvocationException: Invocation of method 'sort' in class com.hannonhill.cascade.velocity.NodeSortTool threw exception java.lang.IllegalArgumentException: Comparison method violates its general contract!
This typically occurs when one or more objects are missing a value for the property that is being used to sort on.
Consider the following code which is intended to sort a number of stories by their Start Date:
#set($stories = $_XPathTool.selectNodes($contentRoot, "/system-index-block/system-page"))
$_SortTool.addSortCriterion("start-date", "en", "number", "descending", "upper-first")
$_SortTool.sort($stories)
If any of those stories don't happen to have a value for their start-date, the sorting will fail with the aforementioned error. To prevent this from happening, one of the following strategies can be utilized:
Using XPath:
Rather than simply selecting all Pages and then attempting to sort by their Start Dates, you can select only Pages that have Start Dates to begin with by changing this line:
#set($stories = $_XPathTool.selectNodes($contentRoot, "/system-index-block/system-page"))
to this:
#set($stories = $_XPathTool.selectNodes($contentRoot, "/system-index-block/system-page[start-date]"))
Using $_ListTool:
Pages without a Start Date can be removed from consideration by using the ListTool's removeNull method just prior to sorting. For example:
#set($stories = $_XPathTool.selectNodes($contentRoot, "/system-index-block/system-page"))
#set ($removed = $_ListTool.removeNull($stories, "child(start-date)"))
$_SortTool.addSortCriterion("start-date", "en", "number", "descending", "upper-first")
$_SortTool.sort($stories)
Optionally, you can then see which Pages did not have a Start Date by iterating over each of those items and outputting their path.
#foreach ($r in $removed)
$r.getChild("path").value
#end