|
| Description: |
{{FeedPlugin.EntriesComparator}} \ (in {{com.xpn.xwiki.plugin.feed.FeedPlugin}} \ ) reads both of the objects it is asked to compare from the *same* entry:
{code: language= java} public int compare(com.xpn.xwiki.api.Object entry1, com.xpn.xwiki.api.Object entry2) { BaseObject bobj1 = entry1.getXWikiObject(); BaseObject bobj2 = entry1.getXWikiObject(); // should be entry2 ... return (-bobj1.getDateValue("date").compareTo(bobj2.getDateValue("date"))); } {code}
Two consequences h2. What this breaks for users
{{FeedPlugin#search(String, XWikiContext)}} is the search over aggregated feed articles : it collects the {{XWiki.FeedEntryClass}} objects matching the words the user typed and is meant to hand them back most-recent-first. Sorting them is the only thing {{EntriesComparator}} exists to do, and it does not do it.
* *Search results over aggregated feeds come back in an arbitrary order.* {{com.xpn.xwiki.api.Object#getXWikiObject \ ( \ )}} returns the wrapped instance without copying it, so {{bobj1}} and {{bobj2}} are the same object . Every : every comparison compares the {{ one article's date }} property with itself and , the comparator always returns {{0}} . The , and {{Collections.sort \ (apiObjs, new EntriesComparator \ ( \ ) \ )}} call in leaves the list exactly as it was. The HQL query behind the search carries no {{ FeedPlugin#search\(String, XWikiContext\) ORDER BY }} either, so what the user actually gets is therefore raw database order: a no\ three - op: feed entries come back in whatever year-old article can sit above this morning's one, and the order can differ between two runs of the query produced them, rather than sorted by descending date as intended same search or between two databases . Anyone using the feed aggregator to find recent news has to read the whole result list instead of the top of it. * *The search fails outright for a caller without programming rights.* {{getXWikiObject \ ( \ )}} returns {{null}} when the caller does not have programming rights. In in that case , so the comparator throws a {{NullPointerException}} on the first {{bobj1.getDateValue \ ("date" \ )}} and the whole search errors out instead of comparing returning results.
What limits the blast radius: {{FeedPluginApi}} does not expose {{search}} , so the method is only reachable from Java code (this plugin and third-party plugins), not from wiki scripts. The feed plugin is also deprecated legacy code. The fix is therefore low priority — but {{EntriesComparator}} is a {{public}} class that third-party code can use as a comparator in its own right, where it will silently sort fails outright nothing .
h2. Origin
The typo dates back to commit {{d3ede03523a}} \ ("\[misc\] Introduce generics", 2009 \ ), which introduced the two {{bobj}} locals; before that the code correctly used {{entry1}} and {{entry2}}.
Note that this is deprecated legacy code \(the feed plugin\), so the fix is low priority, but the comparator is {{public}} and can be used by third\-party code.
|
|