J tricks - Little JIRA Tricks
  • Home
  • Plugins ↓
    • JQL Tricks Plugin
      • JQL Tricks Plugin - Cloud
        • JQLT Cloud Installation
        • JQLT Cloud Configuration
        • JQLT Cloud Usage
        • JQLT Cloud License
        • JQLT Cloud FAQ
      • JQL Tricks Plugin - DC
        • JQLT DC Installation
        • JQLT DC Configuration
        • JQLT DC Usage
          • JQLT Issue Functions
          • JQLT Subtask Functions
          • JQLT Links Functions
          • JQLT Development Functions
          • JQLT Worklog Functions
          • JQLT Project Functions
          • JQLT Component Functions
          • JQLT Version Functions
          • JQLT Group Functions
          • JQLT User Functions
          • JQLT Date Functions
        • JQLT DC License
        • JQLT DC FAQ
        • JQLT DC Known Issues
        • JQLT DC Performance
      • JQL Tricks Cloud Migration
    • Simplified Planner
      • J-Planner Installation
      • J-Planner Configuration
      • J-Planner Usage
        • Creating a plan
        • Editing a plan
        • Deleting a plan
        • Viewing a plan
        • Modifying a plan
      • J-Planner FAQ
    • Atla-Search Plugin
      • Atla-Search Installation
      • Atla-Search Configuration
      • Atla-Search Usage
      • Atla-Search License
      • Atla-Search FAQ
    • Copy to subtask Plugin
    • All Plugins
  • Tutorials
  • The Book
  • Contact Us
  • Home
  • Plugins ↓
    • JQL Tricks Plugin
      • JQL Tricks Plugin - Cloud
        • JQLT Cloud Installation
        • JQLT Cloud Configuration
        • JQLT Cloud Usage
        • JQLT Cloud License
        • JQLT Cloud FAQ
      • JQL Tricks Plugin - DC
        • JQLT DC Installation
        • JQLT DC Configuration
        • JQLT DC Usage
          • JQLT Issue Functions
          • JQLT Subtask Functions
          • JQLT Links Functions
          • JQLT Development Functions
          • JQLT Worklog Functions
          • JQLT Project Functions
          • JQLT Component Functions
          • JQLT Version Functions
          • JQLT Group Functions
          • JQLT User Functions
          • JQLT Date Functions
        • JQLT DC License
        • JQLT DC FAQ
        • JQLT DC Known Issues
        • JQLT DC Performance
      • JQL Tricks Cloud Migration
    • Simplified Planner
      • J-Planner Installation
      • J-Planner Configuration
      • J-Planner Usage
        • Creating a plan
        • Editing a plan
        • Deleting a plan
        • Viewing a plan
        • Modifying a plan
      • J-Planner FAQ
    • Atla-Search Plugin
      • Atla-Search Installation
      • Atla-Search Configuration
      • Atla-Search Usage
      • Atla-Search License
      • Atla-Search FAQ
    • Copy to subtask Plugin
    • All Plugins
  • Tutorials
  • The Book
  • Contact Us

Atlassian Spring Scanner and NoSuchBeanDefinitionException

1/26/2016

30 Comments

 
NoSuchBeanDefinitionException is a notorious exception in the JIRA Development world. Some even have had nightmares about it I hear!

But then, this is a well documented error and even we have attempted documenting it here - to save hours of debugging and, of course, to provide a good night's sleep!!

With the latest Atlassian Plugin SDK though, it seems the nightmares are back. And I have seen a rising number of questions about this error in Atlassian Answers and other forums. Are you one of those who ran into the same? If so, don't blame it on Atlassian or the plugin SDK. You are just ignorant, as I was for a good few hours, about the Atlassian Spring Scanner libraries.


"Atlassian Spring Scanner is a set of libraries that make plugins faster to load and easier to develop.". It scans the source code to find special annotations and creates special index files in the JAR's META-INF directory. These index files are read at runtime to create the necessary Spring components and OSGI services.

What does it mean though?

Once you have the spring scanner plugin, and related dependencies, added in the pom.xml, it will not look for component definitions in the atlassian-plugin.xml and will, instead, look for scanner annotations. Even the dependency injection requires the special annotations in the code.

And yes, spring scanner plugin is enabled by default in the pom.xml when you create the plugin skeleton, by running atlas-create-jira-plugin, using the latest plugin SDK. That means you will run into NoSuchBeanDefinitionException when you inject components in the constructor without using the required annotations. Or when you use component-import definitions inside the atlassian-plugin.xml. Or when you use public="true" to export one of your components. And so on..

For example, let is create a simple skeleton plugin using the new Plugin SDK (6.1.2 as of now) and add a webwork module definition.

<webwork1 key="plugin-scanner-action" name="Plugin Scanner Action" i18n-name-key="plugin-scanner-action.name">
    <description key="plugin-scanner-action.description">Demos how the scanner annotations work</description>
    <actions>
      <action name="com.jtricks.jira.webwork.PluginScannerDemo" alias="PluginScannerDemo">
        <view name="success">/templates/plugin-scanner-action/pluginscannerdemo/success.vm</view>
      </action>
    </actions>
</webwork1>


In the action class, we can keep it simple by injecting the ever popular JiraAuthenticationContext interface, as shown below:

public class PluginScannerDemo extends JiraWebActionSupport {
    private static final Logger log = LoggerFactory.getLogger(PluginScannerDemo.class);

    private final JiraAuthenticationContext authContext;

    private String currentUser;

    public PluginScannerDemo(JiraAuthenticationContext authContext) {
        super();
        this.authContext = authContext;
    }

    @Override
    protected String doExecute() throws Exception {
        if (this.authContext.getLoggedInUser() != null) {
            this.currentUser = this.authContext.getLoggedInUser().getDisplayName();
        } else {
            this.currentUser = "Anonymous";
        }
        return super.doExecute();
    }

    public String getCurrentUser() {
        return currentUser;
    }
}


And we can create a success view that prints the currentUser.

<h1>Welcome $!currentUser!</h1>

It looks very simple but you will run into the, you guessed it right, NoSuchBeanDefinitionException when this code is executed.

[INFO] [talledLocalContainer] 2016-01-26 10:52:19,659 http-nio-2990-exec-7 ERROR admin 652x237x3 zb3hwx 0:0:0:0:0:0:0:1 /secure/PluginScannerDemo.jspa [c.a.j.web.dispatcher.JiraWebworkActionDispatcher] Exception thrown from action 'PluginScannerDemo', returning 404
[INFO] [talledLocalContainer] org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.jtricks.jira.webwork.PluginScannerDemo': Unsatisfied dependency expressed through constructor argument with index 0 of type [com.atlassian.jira.security.JiraAuthenticationContext]: : No qualifying bean of type [com.atlassian.jira.security.JiraAuthenticationContext] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.atlassian.jira.security.JiraAuthenticationContext] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}


We know that JiraAuthenticationContext is a public component and doesn't need a component-import definition. Even if we add it in the atlassian-plugin.xml, as described in one of our earlier tips, that is not going to help with this error.

This is where we need to start adding the new scanner annotations. Following are the important ones.
  • @ExportAsService: Replaces <component ... public="true"> and exposes the class as a OSGi service.
  • @Named (JSR) or @Component (Spring): Replaces <component ...> definition.
  • @Autowired or @Inject: Used for dependency injection
  • @ComponentImport: Replaces <component-import ...> definition.
  • @ClasspathComponent: Defined a component whose class is contained in some other library.
  • @ModuleType: Replaces <module-type.. > definition.

And you will find more annotations and finer details at https://bitbucket.org/atlassian/atlassian-spring-scanner.

Our modified code, with all these annotations, will look like this:

@Named ("PluginScannerDemo")
public class PluginScannerDemo extends JiraWebActionSupport {
    private static final Logger log = LoggerFactory.getLogger(PluginScannerDemo.class);

    @ComponentImport
    private final JiraAuthenticationContext authContext;

    private String currentUser;

    @Inject
    public PluginScannerDemo(JiraAuthenticationContext authContext) {
        super();
        this.authContext = authContext;
    }

    @Override
    protected String doExecute() throws Exception {
        if (this.authContext.getLoggedInUser() != null) {
            this.currentUser = this.authContext.getLoggedInUser().getDisplayName();
        } else {
            this.currentUser = "Anonymous";
        }
        return super.doExecute();
    }

    public String getCurrentUser() {
        return currentUser;
    }
}


And, voilà, Everything works as expected!

You can find the full code attached at the end of this blog.

But, if you want to stick with old style, maybe because you are upgrading a huge plugin, you can do that by removing the Spring Scanner plugin and its dependencies from the pom.xml. As simple as that! You can find the source code, for the above example, without the spring scanner attached as plugin-scanner-demo-old-style.zip.

Note that Spring Scanner is recommended because the code with annotations load significantly faster than traditional P2 plugins that require runtime transformation. As per Atlassian, local tests show plugins that took 5 seconds to load now load in under 2 seconds. Being more explicit about the code, using annotations, is indeed a fair trade-off, if that is the case.

Hope you enjoyed this tip. You can read more such tips in the new version of JIRA Development Cookbook, that is coming out soon. Stay tuned!
plugin-scanner-demo.zip
File Size: 21 kb
File Type: zip
Download File

plugin-scanner-demo-old-style.zip
File Size: 21 kb
File Type: zip
Download File

30 Comments
John Strzempa
2/16/2016 06:11:04 pm

How does this work when you're extending a class. I'm trying to extend the CreateWorklog and I'm getting this error. Do I have to use the @ComponentImport and initialize the object in my class even if I'm not using the object in my code? Like below for the worklogService?

@ComponentImport
private final WorklogService worklogService;

public MyTimelogs(WorklogService worklogService, CommentService commentService, ProjectRoleManager projectRoleManager, JiraDurationUtils jiraDurationUtils, OutlookDateManager outlookDateManager,
FieldVisibilityManager fieldVisibilityManager, final FieldLayoutManager fieldLayoutManager, final RendererManager rendererManager, UserUtil userUtil, final FeatureManager featureManager, final ProjectManager projectManager, final IssueManager issueManager)
{

super(worklogService, commentService, projectRoleManager, jiraDurationUtils, outlookDateManager, fieldVisibilityManager, fieldLayoutManager, rendererManager, userUtil, featureManager);


this.worklogService = worklogService;
this.projectManager = projectManager;
this.issueManager = issueManager;

}

Reply
John
2/17/2016 12:50:34 am

Can you explain how to do this with JiraDurationUtils. I keep getting this
No default constructor found

Reply
Steve Kling link
3/10/2016 05:58:52 pm

Appreciate the writeup! An absolute abysmal lack of documentation on this from ATL.

Question: Are there some tips for getting around the problem of importing packages that use the old methods? We're abandoning things like activityStreams because we can use ComponentManger to lazyload the services that fail in constructor DI but then *those* components fail due to same issues in their constructor.

Atlassian is utterly silent on this.

Reply
J-Tricks
3/12/2016 10:59:56 am

Anything in the constructor needs the @ComponentImport annotation and the class needs a @Scanned annotation.

You can use the components using ComponentAccessor, without the annotations.

YourComponent yourComponent = ComponentAccessor.getComponent(YourComponent.class);

But make sure your component class itself has the required annotations to publish the class as a component. @Component and @ExportAsService, as required.

Reply
Tom McCann
3/13/2016 05:10:46 am

Hi Jobin, Thank you so much for this article. I had been banging my head against a brick wall for a week trying to solve this. Nobody on Atlassian Answers had responded with anything useful and I was about to give up. You have saved the day. I not only have a solution for Jira 7 but also an approach that will work on Jira 6.

By the way, I'm getting good value from your Jira 5.x Cookbook and am looking forward to the v7 version when it comes out. Is it still on target for September?

Thanks again. Tom

Reply
J-Tricks
3/13/2016 10:00:16 am

Glad you like the book. Yes, on target for the next version :)

Reply
Lorand
5/26/2016 04:39:57 am

Hi Jobin,

I just hit atlas-run on the downloaded source code for plugin-scanner-demo and i Received an error saying Failed Plugin Report:

'com.atlassian.plugins.atlassian-plugins-osgi-testrunner-bundle' - 'TestRunner OSGI Bundle' failed to load.
Cannot start plugin: com.atlassian.plugins.atlassian-plugins-osgi-testrunner-bundle
Activator start error in bundle com.atlassian.plugins.atlassian-plugins-osgi-testrunner-bundle [119].
null

Reply
Ahmad A
8/25/2016 04:07:50 pm

I wish your new book was out now (still less than 2 weeks). It is so needed especially with all the tutorials on Atlassian's site being so outdated.
I can't wait for it!

Reply
J-Tricks
8/25/2016 10:01:19 pm

The wait is almost over :)

Reply
Ahmad A
8/26/2016 08:11:48 am

Will there be a bundle price for purchasing both the book and Kindle version? That would be cool.

I like having a book but I don't like hauling it with me everywhere.

J-Tricks
8/26/2016 09:14:14 am

I guess there is a bundle price. Will keep you posted.

Ahmad A
8/28/2016 03:23:57 pm

I have a plugin that is listening for closed events in Jira 7.1.x. The plugin was working fine in jira 6.2.x.

I tried to follow the examples but it still doesn't seem to be seeing any closed events. I put the plugin in debug mode and still don't see them.

I did try the implement the annotations for the Spring Scanner. I removed the "component key=..." and added @ExportAsService right before the class. The class implements "DisposableBean" and "LifecycleAware".

Now the issue I am getting is that the 'eventListener' does not load as one of the modules of the plugin.

Any ideas?

Thanks.

Reply
J Reinhard
9/1/2016 11:20:46 am

This saved me, thank you!

Reply
Todd
9/2/2016 11:49:30 pm

I'm obviously still missing something. I am having a hell of a time with JiraDurationUtils.

@ExportAsService ({PlxTimeTrackingProvider.class})
@Named ("PlxTimeTrackingProvider")
public class PlxTimeTrackingProvider extends AbstractJiraContextProvider
{
@ComponentImport
private final JiraDurationUtils jiraDurationUtils;

@Inject
public PlxTimeTrackingProvider(final JiraDurationUtils jiraDurationUtils)
{
super();
this.jiraDurationUtils = jiraDurationUtils;
}

Any help would be appreciated.

Reply
J-Tricks
9/4/2016 09:02:58 pm

JiraDurationUtils is an internal component. It cannot be imported just like that. See http://www.j-tricks.com/tutorials/component-import-gotchas-nosuchbeandefinitionexception for some details on that.

I haven't tried it with Atlassian Spring Scanner yet.

Reply
Todd
9/8/2016 02:05:56 pm

Is it your recommendation that I disable the use of the Spring Scanner?

Todd
9/8/2016 02:07:15 pm

Otherwise, is there an alternative library that formats the duration in the same manner as Agile/Time Tracking.

Thanks again for your help.

Todd
9/8/2016 05:12:37 pm

It would turn out that the JiraDurationUtils::PrettyDurationFormatter is a public component and worked for me.

Thanks again for your help.

Reply
J-Tricks
9/8/2016 09:43:23 pm

Awesome. Thanks for providing the detail here. I am sure someone else will benefit from it too.

Reply
Todd
10/25/2016 10:54:41 pm

Hey J-Tricks. me again.

Is there a way to get a component from within your plugin? I've tried doing @ComponentImport with @Inject with no success. Also, tried to get the component using ComponentAccessor with no success.

Any help would be appreciated.

@ExportAsService ({PlxRequirementsComponent.class})
@Named ("plxRequirementsComponent")
public class PlxRequirementsComponentImpl implements PlxRequirementsComponent, LifecycleAware,
InitializingBean, DisposableBean
{
...
}

No luck here:

@ComponentImport
private final PlxRequirementsComponent plxRequirementsComponent;

@Inject
public PlxReqPanelProvider(PluginSettingsFactory pluginSettingsFactory, PlxRequirementsComponent plxRequirementsComponent)
{
this.pluginSettingsFactory = pluginSettingsFactory;
this.plxRequirementsComponent = plxRequirementsComponent;
}

or here:

PlxRequirementsComponent plxRequirementsComponent = ComponentAccessor.getComponent(PlxRequirementsComponent.class);
if (plxRequirementsComponent != null)
System.out.println(plxRequirementsComponent.getName());
else
System.out.println("PlxRequirementsComponent is null");

Reply
J-Tricks
10/26/2016 10:07:07 pm

If the component is internal to your plugin, you can inject it without a ComponentImport. Just do plain constructor injection, without the annotation.

Reply
sameer_v
9/20/2017 12:42:47 pm

Awesome! Was struggling with this issue..removing the @ComponentImport for the class inside the same plugin fixed it.
Thanks very much!

Matt Doar
12/14/2016 04:57:44 pm

Ai, ai, ai! Also I needed to add
src/main/resources/META-INF/spring/plugin-context.xml

with

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:atlassian-scanner="http://www.atlassian.com/schema/atlassian-scanner"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.atlassian.com/schema/atlassian-scanner
http://www.atlassian.com/schema/atlassian-scanner/atlassian-scanner.xsd">
<atlassian-scanner:scan-indexes/>
</beans>

but the docs at https://developer.atlassian.com/docs/atlassian-platform-common-components/plugin-framework/advanced-configuration-with-spring-xml-files are outdated

Reply
Dan Greenthumb
1/20/2017 09:36:26 am

Nearly one year has passed since this was published and still Atlassian didn't manage to update their docs. I'm not very pleased to put this in a polite way -.-

Thank you anyway for writing this. It didn't help me solve my issues but it got me on the right track to search for the answer, hopefully.

Reply
Mike
1/26/2017 04:56:27 am

Guys, thank you so much!! It's awesome!
com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport - before class variables
javax.inject.Inject - before class constructor
import com.atlassian.plugin.spring.scanner.annotation.export.ExportAsService; javax.inject.Named; - before class declaration.
All of this worked like charm for me!

Reply
Alexej Geldt
1/27/2017 05:35:26 am

And, voilà, Everything works as expected!

No it doesn't for me.

I am biting this for several months already. I know the spring scanner documentation already like my own pocket. Its all absolutelly clear, but it does not work as documented. Also your example did not help me. Im getting this Exception no matter what combination of those annotations i use. I tried all kinds of combinations. Using ExportAsService or just Named, using ComponentImport or not. Using it on field level or in contructor. Using inject annotation or ommit it. Nothing helps. Not using any annotations at all. It keeps throwing that Exception no matter what I do with annotations.



Reply
J-Tricks
1/29/2017 03:01:01 pm

There are just so many use cases that can fail. Which component are you trying to import and what is the error?

Reply
Bastian
3/9/2017 09:19:31 am

Hi,

What do I have to consider with Atlassian Spring Scanner 2? My plugin always fires "Cannot resolve Symbol ... " for http://www.atlassian.com/schema/atlassian-scanner/2/atlassian-scanner.xsd in META-INF/spring/plugin-context.xml.

Error while fetching http://www.atlassian.com/schema/atlassian-scanner/2/atlassian-scanner.xsd

This custom Spring bean has not yet been parsed less... (Strg+F1)
Reports custom Spring beans of unknown type (corresponding custom namespace handler not run yet).

...

Cheers

Reply
peter
1/20/2019 11:19:48 am

nice to read thisi article........ but not worth the characters on the screen - the nightmare is worse. This morning my servlet plugin worked and in the afternoon no more..... why - I did not change a single line of code. I am fighting now since two weeks an I have to tell my customer it is no more possible to develop with atlassian - to worse their shred of code. I develop software since 30 years in the field of internet development and technical informatics. the atlassian mess is by far the worst I have ever seen in my career... is this the end of atlassian ? and the nightmare goes on

Reply
J-Tricks
1/21/2019 11:20:52 am

Not sure what the issue is. Something must have changed for sure. If it is not your code, did you check the JIRA version? How about Atlassian Plugin SDK version? Or the spring scanner version that is being used? There must be some variable somewhere.

Reply

Your comment will be posted after it is approved.


Leave a Reply.

    Enter your email address:

    Author

    Jobin Kuruvilla - Works in Adaptavist as Head of DevOps Professional Services. 

    Author of JIRA Development Cookbook and JIRA 5.x Development Cookbook.


    RSS Feed

    Categories

    All
    Acive Objects
    Ajs
    Book
    Components
    Condition
    Custom Fields
    Customization
    Events
    Gadgets
    Javascript
    Jql
    Listener
    Mail
    Permissions
    Plugin Framework
    Post Function
    Properties
    Remote Invocation
    Reporting
    Rest
    Scheduled Tasks
    Search
    Services
    Soap
    Summit
    User Interface
    Validator
    Webwork Actions
    Workflow

    Archives

    October 2016
    August 2016
    March 2016
    January 2016
    December 2015
    May 2014
    December 2013
    November 2013
    July 2013
    June 2013
    April 2013
    October 2012
    September 2012
    August 2012
    July 2012
    May 2012
    March 2012
    February 2012
    January 2012
    December 2011
    November 2011
    June 2011
    May 2011
    April 2011
    March 2011
    February 2011
    January 2011
    November 2010
    October 2010
    September 2010
    August 2010

SUPPORT
APPS
TUTORIALS
THE BOOK
© J-Tricks