Skip to end of metadata
Go to start of metadata

Introduction

A component plugin module defines a Java component which will be injected into the component system used by your plugin.
The details differ depending on whether you are writing a Plugins1 or Plugins2 plugin.

Components under Plugins1

A component in a Plugins1 plugin will be installed into JIRA's core component manager (PicoContainer).
This means it will be inherently "public", that is available to other plugins to have injected into them.
Note, however, that these other plugins have no way to declare their dependency on your plugin, and so they would just throw errors at runtime if your plugin is unavailable.

A new component is simple to define as follows:

This example here defines a component implementing UserService that is put into the PicoContainer to inject into any other plugin modules. If you include this component module in your plugin, then your other plugin modules can define a constructor with a UserService parameter and this implementation will be provided to your plugin module automatically.

These components allow you to simplify the creation and management of your plugin modules quite a lot.

Components under Plugins2

A component in a Plugins2 plugin will be installed into the Spring container for your plugin.
It will be "private" by default. This means classes in your plugin will be able to get that component dependency-injected, but other plugins will not.
However the component can be declared public, which allows other Plugins2 plugins to import a dependency on your component.

See the Plugins2 Component Plugin Module documentation for details.

Replacing core components considered harmful!

A number of plugin developers in the past used Plugins1 Components to replace/override core JIRA components.
This is not guaranteed to work, and can cause subtle problems that would be very difficult to trace even if it "appears" to work.
Additionally, the behaviour can change wildly from version to version because of changes in the startup order of components and component inter-dependencies.

  • No labels

6 Comments

  1. The Subversion plugin is a good example of a plugin that uses a component module.

    p.s. there's a typo in the word constructor

  2. In Jira 3.13 we developed quite a few plugins that altered behaviour in Jira by overriding an existing Jira component using a 'component' plugin module. We've done this with about a dozen components.

    I'm working now on migrating to Jira 4. The first plugin I tried to migrate was one that I wrote so that the user picker would find users using their initials in addition to partial name matches.

    To do that before I had injected a new UserPickerSearchService to replace the DefaultUserPickerSearchService. It worked great in Jira 3.13.
    I modified the code to compile in Jira 4 and fired it up. I can see that my code is loaded but it isn't getting called.

    Has the ability to override Jira components been reduced? I see a brief mention of it here.
    The only solution I can see now is replacing the DefaultUserPickerSearchService.class file with mine and abandoning the plugin approach which seems like a less than elegant solution.

    1. Have you been able to get an answer? The way I read the docus above is that v1 plugins should still be able to override jira components.

      EDIT: Also see: http://jira.atlassian.com/browse/JRA-20052

    2. Here is the quote from the page you link to:

      In fact, it is even possible to create a component to replace existing core components, although this is not considered a good idea - it is difficult, error-prone, and can't be guaranteed to always work.

      You have hit a case where it is error-prone and not guaranteed to work.

      The problem is that first we register the original components to Pico Container, and then later we register the plugin components.
      In the case of overriding an existing JIRA component, there is a period of time during start up that the old component is registered, and then later it is replaced by your custom implementation.
      Now if any code that runs before we replace the old component has a dependency on (eg) UserPickerSearchService, it will get the original version.
      Other code that runs later may get the new one, and now we have 2 versions floating around.
      Remember that in the case of dependencies, most code will get the dependency once and then hold onto it for the lifetime of the server.
      Also remember that it doesn't have to be a direct dependency.

      Worse still, what if some other plugin were to try to override the UserPickerSearchService as well, and a user were to install both plugins?

      The only solution I can see now is replacing the DefaultUserPickerSearchService.class file with mine and abandoning the plugin approach which seems like a less than elegant solution.

      The plugin approach seems more elegant, but it is a bad idea for the reasons stated above.
      Even when the approach appears to work, it may be broken in some subtle way as you can have 2 different implementations in existence at once.
      Replacing the DefaultUserPickerSearchService.class file is admittedly not ideal, but at least it is guaranteed to work.
      In the long run if you want a more elegant solution you may have to raise an improvement request on http://jira.atlassian.com eg to make User Picker pluggable or more configurable etc.

  3. There is related question: http://forums.atlassian.com/thread.jspa?messageID=257357610

    We want not to inject objects, but have Abstract classes on classpath, so that we can extend them and not to double our code. How can I do that? Thx.