Last updated Dec 8, 2017

Deprecation guidelines

These are guidelines related to the development of Confluence. The guidelines mainly apply to Atlassian employees, but reading them should provide insight for third-party plugin developers as well, so we decided to make them public.

Since Confluence doesn't have a complete API yet, you should assume that any change you make to manager interfaces, model objects, services, or really any commonly used code will in some way impact third-party plugin developers. As such, we should always be careful to deprecate, rather than remove old functionality.

The right way to deprecate

All deprecated methods in Confluence must include:

  1. @deprecated tag, followed by
  2. the text "since n", where n is the version number the tag was added, followed by
  3. either a short explanation of why the method shouldn't be used, or a direction to use a different method, followed by
  4. @Deprecated annotation on the method.

See examples below for more help on presenting deprecated code.

Rationale

To keep third-party developers happy, we should deprecate methods that may be used by plugins instead of just deleting them. However, deprecated methods pollute the namespace, and keeping them around indefinitely just encourages people to continue to use them.

Therefore, we should record when a method has been deprecated. Anything that has been deprecated will be regularly removed.

The use of the @Deprecated annotation also allows runtime tooling to discover and alert about deprecated method usage.

Backward compatibility

Breaking changes in Confluence must only happen in the platform releases (ie: major version releases). Any planned breaking changes should be communicated with advance notice through the deprecation method and documentation.

Breaking changes should be deprecated at least 2 feature releases or six months ahead (whatever is smaller).

Upcoming breaking changes should be documented in "Preparing for Confluence X.X release" notes, in both the release that adds the deprecation (if any), and again in the release that will have the breaking change.

Important

Breaking changes, which are required for the platform upgrade may go with minimal forward notice and without deprecation.

Examples

For a simple redirect, the deprecation tag is the only Javadoc the method should require. Developers should consult the doc for the linked alternative to find out more about what the method is likely to do:

1
2
/** @deprecated since 2.3 use {@link Space#isValidSpaceKey} */
@Deprecated
boolean isValidSpaceKey(String key);

For a "this is no longer the right way to do things" deprecation, a longer explanation may be required, and the old Javadoc may need to be retained for developers who are still stuck doing things the old way for some reason. A short explanation is put in the deprecated tag itself, and the detail is put in the main body of the Javadoc:

1
2
/**
* Return all the content a user has authored in this space.
*
* <b>Warning:</b> This method has been deprecated since Confluence 2.1 because it is
* insanely inefficient to do in the database. You should migrate your code to use the
* SmartListManager instead, which will get the results from Lucene.
*
* @deprecated since 2.1 use the {@link SmartListManager} for complex queries
*/
@Deprecated
List getContentInSpaceAuthoredBy(String spaceKey, String username);

Note that implementations of deprecated methods will result in compile warnings if they are not also marked as deprecated.

Fix Confluence Code to Avoid Deprecated Usage

When deprecating a class or method in Confluence, you must remove the majority - if not all - of the usages of that class or method throughout Confluence. If you don't have the time or inclination to do so, you should probably not deprecate the method.

This makes sure that our own code doesn't violate our own deprecation unnecessarily, and also provides a sanity check for whether you should deprecate something or not. If it is used too many times inside Confluence to begin changing, it could well be the same for external code and you should think hard about deprecating such a frequently used method.

When Not to Deprecate

In some situations, maintaining deprecated methods may be impossible. For example:

You should never deprecate when...
  • The underlying model has changed, rendering any client of the old code obselete. For example if you move from Permission getPermission() to List getPermissions(), the former method would return dangerously incorrect information if it were maintained, and thus should be deleted.
  • The old way of doing things is dangerous. For example, if userManager.getAllUsers() is being removed because it kills the server, we should not feel guilty forcing plugins to upgrade to the safe way of doing things.
  • The code is in specific packages where there is no impact on third-party plugin developers. These are:
    • classes internal to plugins - that is, packages not OSGi exported, and so are not part of the plugin API
    • classes internal to core - that is, packages not OSGi exported, and so are not part of the core API. Importantly, this includes anything under com.atlassian.confluence.api.impl, com.atlassian.confluence.impl and com.atlassian.confluence.internal
You should make a judgement call when...
  • There would be significant effort required to maintain parallel, deprecated way of doing things
  • You would be forced to write an ugly API because all the "right" method/class names are taken up with deprecated methods (assume the new way of doing things will stick around forever)

Rate this page: