Solved: Action condition unsatisfied dependency

action
conditions
dependencies

#1

Hi all,
I’m trying to update a JIRA 6 plugin to JIRA 7 using atlassian-spring-scanner, but I’m getting an unsatisfied dependency when I try to add the condition using UserIsProjectAdminCondition:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.atlassian.jira.plugin.webfragment.conditions.UserIsProjectAdminCondition': Unsatisfied dependency expressed through constructor argument with index 0 of type [com.atlassian.jira.security.PermissionManager]: No qualifying bean of type [com.atlassian.jira.security.PermissionManager] 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.PermissionManager] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:185)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1143)

In the atlassian-plugin.xml I added:

<condition class="com.atlassian.jira.plugin.webfragment.conditions.UserIsProjectAdminCondition"/>

In the pom.xml I used this import snippet (and other variants), but didn’t find a solution yet:

<Import-Package>
    javax.ws.rs*;version="[1,2)",
	javax.servlet*;version="2.5",
	javax.xml.bind*;version="[2.1,3)",
	*;version="0";resolution:=optional
</Import-Package>

What I want is to see the action only if the user is the admin of the current project.


#2

I haven’t ever gotten any of the webfragment package conditions to work in Jira 7 so I usually implement my own.


#3

Not the answer that I was looking for, but thanks for it. :disappointed_relieved:
I will do as you suggest until I will find a better solution and let you know.

If you need a particular condition for two webfragments in two different plugins, do you rewrite it in both of them? Or there is a way to share it?


#4

Hi @luca.andreatta,

Could you try to explicitly require the PermissionManager via @ComponentImport?

import com.atlassian.jira.security.PermissionManager;
// ...
@Component("myComponentImportClass")
// This class contains all of our '@ComponentImport's
public class MyComponentImportClass {
    // Constructor:
    @Autowired
    public MyComponentImportClass(@ComponentImport PermissionManager permissionManager) {
        // no need to actually do anything with it...
    }
}

Just having the component imported in any constructor of any class you define should make the Spring scanner pick it up and import it.


#5

Tried your solution, but I didn’t find a way to make it work. :sob:

I tried to create a class as you suggested like that:

@Component("myComponentImporter")
public class ComponentImporter {

	@ComponentImport    private PermissionManager permissionMgr;

	@Autowired
	public ComponentImporter(@ComponentImport PermissionManager permissionManager) {
		// no need to actually do anything with it...
	}

}

But the stacktrace is always the same:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.atlassian.jira.plugin.webfragment.conditions.UserIsProjectAdminCondition': Unsatisfied dependency expressed through constructor argument with index 0 of type [com.atlassian.jira.security.PermissionManager]: No qualifying bean of type [com.atlassian.jira.security.PermissionManager] 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.PermissionManager] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:185)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1143)

I also tried to put this import in the plugin class, as suggested in another thread here, but the output was the same.


#6
@Component
public class ComponentImporter {

	private PermissionManager permissionMgr;

	@Autowired
	public ComponentImporter (@ComponentImport PermissionManager permissionManager) {
		this.permissionMgr = permissionManager;
	}

}

Hey, can you try this and if you have other class files which are injecting something, please check them also.


#7

I tried to build a webfragment plugin from scratch, you can find it here:

Can you take a look at it and try if it runs on your machine? :pray:

I’m getting a ClassNotFoundException now:

Caused by: java.lang.ClassNotFoundException: com.atlassian.jira.plugin.webfragment.conditions.JiraGlobalPermissionCondition not found by it.eng.jira.webfragment-test [249]
	at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:75)
	at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1955)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)


#8

Ok, I found that in the original plugin I was missing this important file:
src/main/resources/META-INF/spring/plugin-context.xml. :hushed:

The ComponentImporter class should be annotated with org.springframework.stereotype.Component and contains the missing classes, so something like that should work:

@Component("myComponentImporter")
public class ComponentImporter {
	private PermissionManager permissionMgr;

	@Autowired
	public ComponentImporter(@ComponentImport PermissionManager permissionManager) {
		// no need to actually do anything with it...
	}

}

#9

And there you were 10 minutes faster than me :slight_smile:


#10

By the way, I have many plugins to migrate and for every one I will have to add this importer class so I have removed the component name and the unecessary class variable and I have come to the end to something like this:

@Component
public class ComponentImporter {

	@Autowired
	public ComponentImporter(@ComponentImport GlobalPermissionManager globalPermissionManager,
			@ComponentImport PermissionManager permissionMgr, @ComponentImport ProjectManager projectMgr,
			@ComponentImport LabelManager labelMgr, @ComponentImport DoubleConverter doubleConverter) {
		// no need to actually do anything with it...
	}
}

I’m not happy at all, if someone has a better solution let me know, please.