How to handle DI for services in java plugin

Hello Community!

I would like to implement a service or factory in a plugin that would be used in several places across the plugin.
It relies on several jira services that map and manipulate issue data coming from external sources.
How can i handle dependency injection in this class in a way that the users of the service do not need to know about dependencies and handle DI on class construction manually?
Is there a way to handle jira componentimports without having to pass each in the constructor when instantiating the class?
Any help appreciated.

Have you tried using the ComponentAccessor? Almost all jira service can be retrieved via the ComponentAccessor.

https://docs.atlassian.com/software/jira/docs/api/7.6.1/com/atlassian/jira/component/ComponentAccessor.html

I read about using ComponentAccessor being an antipattern and something to avoid so i thought it’s an internal thing.
But now tried it and it works well so far. Apart from i18Resolver i could get every service and factory i needed.
Thanks!

Yeah, I would try to stay away from ComponentAccessor and read up on Spring Scanner or Spring Java Config

2 Likes

I highly recommend going the spring scanner 2.x route, if you can. The SDK still uses 1.x, but if you follow the instructions on the link to upgrade (read EVERY word!) and have some experience with Spring or inject annotations, it makes everything real nice in the end.

If you find conflicting information between Atlassian tutorials and the scanner, trust the scanner.

Also, to note, some classes that extend/implement certain Atlassian classes/interfaces will already be checked for DI. Such as actions, I think it was. If you include @Component/@ComponentImport, you will get OSGi errors due to it attempting to duplicate services. I do not believe this is documented anywhere.

I found a few different annotation layouts to work, but I recommend this:

@Component
public class MyService {

    @ComponentImport
    private final NotMyService notMyService;

    @Autowired
    public MyService(NotMyService notMyService) {
        this.notMyService = notMyService;
    }

}

That will keep the annotations out of your constructor arg list and keep it as short as possible.

1 Like

Exactly, if I’m not missing anything, every class that is referenced in the atlassian-plugin.xml, e.g. <some element class="my.package.SomeClass" ...> will be instantiated by the host application and for these classes @Component, ... is not needed and can actually cause problems.

1 Like

Thanks, i’ll take a look into other options.
Maybe autowired factories for all my classes then i can get away with handling manual DI once.