Java API Changes in JIRA 5.0
As part of clearly defining the public, supported Java API for JIRA, several third-party libraries have been upgraded, previously deprecated classes have been removed and existing plugin points have changed behaviour and/or interface.
Changes in JIRA 5.0's core Java libraries, which differ from JIRA 4.4.x and earlier, are indicated in our Clirr report. This report is likely to change throughout the development of JIRA 5.0. If you are updating or developing plugins for JIRA 5.0, you may wish to check this page periodically.
On this page:
Upgrade to Lucene 3.2
Upgrading to Lucene 3.2 has caused a number of changes to the search interfaces of JIRA. The most notable is the replacement of the HitCollector class by the Collector class. There are also a number of smaller changes.
HitCollector replaced by Collector
Search methods on the
com.atlassian.jira.issue.search.SearchProvider class now take a org.apache.lucene.search.Collector where previously they took a
If you previously had a class that implemented
HitCollector you will need to modify it to implement the Collector interface. For most applications this is simple. See the example below.
The notable points here are that more than one reader may be used by the search and that the document index returned in the collect method is related to the document base of the reader. You need to remember the document base that is set on the call to
setNextReader and add this to the value passed in the
collect(int i) method.
acceptsDocsOutOfOrder() method should generally return true as the actual ordering of the documents in the index is not relevant to JIRA in any way.
You should of course consult the Javadoc for the Collect interface.
IndexSearcher replaces Searcher
SearchProviderFactory.getSearcher() method now returns org.apache.lucene.search.IndexSearcher instead of a Searcher. The methods of
IndexSearcher are largely compatible with those of the previous searcher interface, but some require an additional parameter specifying how many results you wish to have returned. You can specify
Integer.MAX_VALUE but performance may be better if the actual maximum number of results you want is specified.
SortComparatorSource is replaced by FieldComparatorSource
Implementations of the
NavigableField interface must now return a FieldComparatorSource from the
FieldComparator interface, which is returned by a
FieldComparatorSource, is quite different from the previous
SortComparator, but as most abstract implementations of
NavigableField already implement this method, it is unlikely to affect most plugin developers.
Removal of OSUser
With the introduction of Embedded Crowd in JIRA in 4.3, many methods which referred to the old
org.opensymphony.user.Group classes were deprecated and a thin emulation layer implemented to allow a simplified transition for plugin developers to the new Crowd User and Group classes.
In JIRA 5.0, this emulation layer has been removed. Consequently,
org.opensymphony.user.Group and a small number of supporting classes have been removed. Furthermore, all deprecated methods have been either changed to use the new Crowd User and Group classes or removed (where they were simply duplicated by new Crowd versions).
Most plugins should just need recompiling.
The OpenSymphony Group class had methods for getting the members of the group and for adding and removing members. The OpenSymphony User class had similar methods for finding the groups a user was a member of. Use the new
GroupManager component for getting members of a group or adding user to a group. For more low-level manipulation of groups and memberships use the
Exceptions thrown by some methods may have changed. Hence, plugin developers will need to adjust their code accordingly.
OpenSymphony classes generally threw
EntityNotFoundException when a user or group was not found. The Crowd implementation will return null if a user or group is not found. So in places where you caught EntityNotFoundException, you will now need to test the return value for null.
Removal of Portlets
JIRA 4.0 introduced gadgets to replace the old portlets that were used in earlier versions of JIRA. From JIRA 4.0, we still shipped all the code for portlets to:
- Allow customer's existing portlets to continue to function on the new dashboard introduced in JIRA 4.0 and
- Give plugin developers time to upgrade their plugins to use gadgets instead.
In JIRA 5.0, we've finally removed all portlet-specific code from JIRA plugin points and APIs. Some plugins implement upgrade tasks to convert portlets to gadgets. These upgrade tasks may now fail if they depend on portlet specific APIs. These upgrade tasks should either be removed (since upgrading to JIRA 4.0+ should have removed portlets already anyway), or rewritten so that they do not rely on the portlet API.
Rendering of Issue Tab Panels
JIRA 5.0 changes the way in which tabs are rendered on the view issue page. Previously the <issue-tabpanel> module was always rendered in the same request as the View Issue screen. In JIRA 5.0, however, the issue tab panel HTML may returned by an AJAX call and inserted into the view issue page without triggering a full page reload. This has two important implications:
- calling WebResourceManager.requireResource(String) does not include the web resource in the page when the user switches tabs, and
Use of WebResourceManager.requireResource(java.lang.String)
Since IssueTabPanel.getActions(Issue, User) is now called in a separate request from the one that renders the view issue page, calling WebResourceManager.requireResource(java.lang.String) does not guarantee that the resource will be included on the view issue page. To make sure that resources are included, use the jira.view.issue web resource context in your <web-resource> definition as in the following example.
Use of AJS.$(document).ready()
JIRA.ViewIssueTabs.onTabReady() instead of using
This file should be changed to the following in order to work in JIRA 5.0.
Custom Field Types
Class Hierarchy Changes
The class hierarchy of the various CustomFieldType classes has been changed. The following diagrams show the old hierarchy and new hierarchy. Removed relationships are marked in red, and new relationships are marked in green.
Old CustomFieldType Hierarchy
New CustomFieldType Hierarchy
What will break?
Please check your
instanceof's comparisons to ensure they are still behave as expected.
CustomFieldType has now been parameterized based on its Transport Object. This should hopefully simplify implementations and make it much easier to figure out whats going on. The generics are defined as follows:
T represents the Transport Object of a Custom Field Type. This is can be thought of as the in-memory data representation, or logical representation. For example this could be a User or a Project, or maybe a Collection of Users. T can contain a single data type or an aggregate data type such as a Collection. JIRA needs to know what is inside this aggregate. S represents the single form of the T. In the case where it is a single data type, T and S will be the same.
Currently we support the following aggregate Transport Objects: Collection<S>, Map<String, S> or Map<String, Collection<S>>. N.B. Support for CustomFieldParams as the Transport Object has been deprecated since 5.0.
We have two abstract class which we recommend you use to help simplify some of this.
What will break?
Because we have typed all of our own CustomFieldType implementations, this means you may get method signature compilation problems if you are extending a concrete class. E.g. a NumberCFType now returns Doubles where it used to return Object.
Because of the large number of plugins extending the StringCFType and the TextCFType we have not genericised these classes, to assist with backwards compatability. However, we strongly suggest migrating to the new GenericTextCFType class.
StringCFType - use GenericTextCFType instead
TextCFType - use GenericTextCFType instead
AbstractMultiSettableCFType - implement the methods yourself.
Using CustomFieldParams as your Custom Field Transport Type (T or S) - use one of the other aggregates supported (see above)
Transform methods on the CustomFieldParams - CustomFieldParams should only be containing Strings, so therefore these should not be used.
The CascadingCFType has had a complete overhall. It was incorrectly using the CustomFieldParams map so now has been updated to use a Map for representation of the selected Options. Database storage remains the same. If you were extending or using this class there is a high chance of breakage.
AbstractMultiCFType received a bit of an overhall in 5.0. It used to assume that everything was stored as a String, but this is no longer the case. This class has also been further parameterized. This has resulted in:
- Method signature changes (deal with Object rather than String)
- String specific implementations have been removed (you will have to provide these now yourself if required)
- New parametrized methods to be implemented that will hopefully simplify behaviour.
convertToStringsIfRequiredno longer does the "if required" bit, it will now always convert to strings.
- It no longer implements
SortableCustomFieldby default. Include this yourself if required