I've tried to build the example confluence macro following this page:
I am using atlas SDK v6.2.3 and JRE 1.8.0_74 (64 bit).
I have tried numerous times, but reach a dead end. Following the example I get the following problem when running confluence with the plugin (atlas-run):
[INFO] [talledLocalContainer] 2016-03-08 07:52:05,984 ERROR [AtlassianEvent::CustomizableThreadFactory-1] [atlassian.plugin.module.PrefixDelegatingModuleFactory] createModule Detected an error instantiating the module via Spring. This usually means that you haven't created a <component-import> for the interface you're trying to use. https://developer.atlassian.com/x/TAEr for more details.
[INFO] [talledLocalContainer] 2016-03-08 07:52:05,985 WARN [AtlassianEvent::CustomizableThreadFactory-1] [impl.macro.metadata.AllMacroMetadataCache] lambda$loadMacroMetadata$1 Failed to make metadata for module 'com.example.plugins.tutorial.confluence.tutorial-confluence-macro-demo:my-macro': Error creating bean with name 'com.example.plugins.tutorial.confluence.ExampleMacro': Unsatisfied dependency expressed through constructor argument with index 0 of type [com.atlassian.confluence.xhtml.api.XhtmlContent]: : No qualifying bean of type [com.atlassian.confluence.xhtml.api.XhtmlContent] 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.confluence.xhtml.api.XhtmlContent] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
[INFO] [talledLocalContainer] org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.example.plugins.tutorial.confluence.ExampleMacro': Unsatisfied dependency expressed through constructor argument with index 0 of type [com.atlassian.confluence.xhtml.api.XhtmlContent]: : No qualifying bean of type [com.atlassian.confluence.xhtml.api.XhtmlContent] 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.confluence.xhtml.api.XhtmlContent] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
So I try to follow the instructions here: https://developer.atlassian.com/docs/faq/troubleshooting/unsatisfieddependencyexception-error-creating-bean-with-name
Adding the following to atlassian-plugin.xml:
<component-import key="xhtmlContent" interface="com.atlassian.confluence.xhtml.api.XhtmlContent"/>
....I get the following error when running atlas-package (after atlas-mvn eclipse:eclipse):
[ERROR] Failed to execute goal com.atlassian.maven.plugins:maven-confluence-plugin:6.2.2:validate-manifest (default-validate-manifest) on project tutorial-confluence-macro-demo:
[ERROR]
[ERROR] atlassian-plugin.xml contains a definition of component-import. This is not allowed when Atlassian-Plugin-Key is set.
[ERROR]
Since the plugin is of version 2 I expected the constructor injection to work, but I cannot figure this out.
How do I resolve this?
Thanks.
Community moderators have prevented the ability to post new answers.
Thanks a lot Jon!
I added the annotations and the build worked. However, I still got a run-time error saying that there was no qualifying bean:
Unsatisfied dependency expressed through constructor argument with index 0 of type [com.atlassian.confluence.xhtml.api.XhtmlContent]: : No qualifying bean of type [com.atlassian.confluence.xhtml.api.XhtmlContent] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
So I tried to adding things to plugin-context.xml
(not really understanding what I was doing), but it didn't help. Finally I stumbled upon som open source code in Bitbucket, which led me to the solution:
@Scanned
annotation (@Component
Your constructor will need an @Autowired
annotation
The XhtmlContent argument in the constructor will need an @ComponentImport
annotation
Now it worked!
If anyone can point to a reference where this is explained (not just a "general" reference, but an explanation), it would probably help the community a lot. For example, I did play around with annotations before asking the community, but since I didn't find any source on the Internet explaining this I wasn't able to find the right combination.
For other's who read this thread:
This is how the main class now looks:
... @Scanned public class ExampleMacro implements Macro { private final XhtmlContent xhtmlUtils; @Autowired public ExampleMacro(@ComponentImport XhtmlContent xhtmlUtils) { this.xhtmlUtils = xhtmlUtils; } ...
My (auto-generated) plugin-context.xml
looks like this (and needed no changes):
<?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>
This source helped me:
So you'll need to make sure you have a valid src/main/resources/META-INF/spring/plugin-context.xml
which should have been generated for you by the atlas-create-confluence-plugin command.
Additionally, on your class you need a number of Spring Scanner annotations:
Once those annotations have been added, you can remove the <component-import>
from your atlassian-plugin.xml and recompile.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I have a similar Problem.
@Scanned @Path("/test") public class TestRest { private static final Logger log = LoggerFactory.getLogger(Test.class); @Autowired public TestRest(@ComponentImport ApplicationLinkService appLinkService) { } }
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.atlassian.applinks.api.ApplicationLinkService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport(value=)}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi,
for my plugin, this works. Check your pom for:
<dependency> <groupId>com.atlassian.plugins.rest</groupId> <artifactId>atlassian-rest-common</artifactId> <version>1.0.2</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.atlassian.plugin</groupId> <artifactId>atlassian-spring-scanner-annotation</artifactId> <version>${atlassian.spring.scanner.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.atlassian.plugin</groupId> <artifactId>atlassian-spring-scanner-runtime</artifactId> <version>${atlassian.spring.scanner.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> <scope>provided</scope> </dependency>
...and
<properties> <confluence.version>5.7.4</confluence.version> <confluence.data.version>5.7.4</confluence.data.version> <amps.version>6.2.6</amps.version> <plugin.testrunner.version>1.2.3</plugin.testrunner.version> <atlassian.spring.scanner.version>1.2.13</atlassian.spring.scanner.version> <!-- This key is used to keep the consistency between the key in atlassian-plugin.xml and the key to generate bundle. --> <atlassian.plugin.key>${project.groupId}.${project.artifactId}</atlassian.plugin.key> </properties>
Maybe you want to develop to another version, but this is just what works for me.
My main class looks like this:
@Named("istabsolutegal") //do I need this? @Path("/getRestrictedPagesForUser") public class DeactivatedUserViewRestrictions { @ComponentImport private final PageManager pageManager; @ComponentImport private final SpaceManager spaceManager; @ComponentImport private final UserAccessor userAccessor; private static final Logger log = LoggerFactory.getLogger(DeactivatedUserViewRestrictions.class); @Inject public DeactivatedUserViewRestrictions(PageManager pageManager, UserAccessor userAccessor, SpaceManager spaceManager) { this.pageManager = pageManager; this.userAccessor = userAccessor; this.spaceManager = spaceManager; log.debug("constructed"); } @GET @AnonymousAllowed @Produces({ MediaType.APPLICATION_JSON }) public Response getMessage(@QueryParam("user") String userName) { ... } }
By the way: Maybe you want to set your logger to:
private static final Logger log = LoggerFactory.getLogger(TestRest.class);
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I am not sure what of that is really necessary to get the rest plugin working with constructor based injection, but it works.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.