Hello,
When I start JIRA from the SDK, I notice my plugin is not enabled under Manage Add-Ons. Upon clicking Enable, I receive the following message:
"This add-on failed to enable. Refer to the logs for more information."
The logs say,
"Cannot execute atlasian-spring-scanner-runtime: plugin has an extra copy of atlassian-spring-scanner-annotation clases, perhaps embedded inside the target plugin 'com.psi.intern.jira.custom-fields'; embedding scanner-annotations is not supported since scanner version 2.0. Use 'mvn dependency:tree' and ensure the atlassian-spring-scanner-annotation depenency in your plugin has <scope>provided</scope>, not 'runtime' or 'compile', and you have NO dependency on atlassian-spring-scanner-runtime.
I changed these dependencies in the pom accordingly, however, I receive this message nonetheless. Uncertain where else I should look for this problem.
My pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>xxx</groupId>
<artifactId>custom-fields</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>atlassian-plugin</packaging>
<name>JIRA Add-On :: Custom Fields AND One Gadget</name>
<description>This is the container plugin for all internally used custom fields for Atlassian JIRA and one gadget.</description>
<organization>
</organization>
<dependencies>
<dependency>
<groupId>com.atlassian.jira</groupId>
<artifactId>jira-api</artifactId>
<version>${jira.version}</version>
<scope>provided</scope>
</dependency>
<!-- Add dependency on jira-core if you want access to JIRA implementation classes as well as the sanctioned API. -->
<!-- This is not normally recommended, but may be required eg when migrating a plugin originally developed against JIRA 4.x -->
<dependency>
<groupId>com.atlassian.jira</groupId>
<artifactId>jira-core</artifactId>
<version>${jira.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.atlassian.jira</groupId>
<artifactId>jira-rest-plugin</artifactId>
<version>7.1.0-QR20151013113456</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.atlassian.plugins.rest</groupId>
<artifactId>atlassian-rest-common</artifactId>
<version>${rest.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.atlassian.jira</groupId>
<artifactId>jira-gadgets-plugin</artifactId>
<version>${jira.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-annotation</artifactId>
<version>${atlassian.spring.scanner.version}</version>
<scope>provided</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>
<!-- WIRED TEST RUNNER DEPENDENCIES -->
<dependency>
<groupId>com.atlassian.plugins</groupId>
<artifactId>atlassian-plugins-osgi-testrunner</artifactId>
<version>${plugin.testrunner.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.2-atlassian-1</version>
</dependency>
<!-- Uncomment to use TestKit in your project. Details at https://bitbucket.org/atlassian/jira-testkit -->
<!-- You can read more about TestKit at https://developer.atlassian.com/display/JIRADEV/Plugin+Tutorial+-+Smarter+integration+testing+with+TestKit -->
<!--
<dependency>
<groupId>com.atlassian.jira.tests</groupId>
<artifactId>jira-testkit-client</artifactId>
<version>${testkit.version}</version>
<scope>test</scope>
</dependency>
-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.8.5</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>maven-jira-plugin</artifactId>
<version>${amps.version}</version>
<extensions>true</extensions>
<configuration>
<noWebapp>true</noWebapp>
<productVersion>${jira.version}</productVersion>
<productDataVersion>${jira.version}</productDataVersion>
<allowGoogleTracking>false</allowGoogleTracking>
<!-- Uncomment to install TestKit backdoor in JIRA. -->
<!--
<pluginArtifacts>
<pluginArtifact>
<groupId>com.atlassian.jira.tests</groupId>
<artifactId>jira-testkit-plugin</artifactId>
<version>${testkit.version}</version>
</pluginArtifact>
</pluginArtifacts>
-->
<enableQuickReload>true</enableQuickReload>
<enableFastdev>false</enableFastdev>
<!-- See here for an explanation of default instructions: -->
<!-- https://developer.atlassian.com/docs/advanced-topics/configuration-of-instructions-in-atlassian-plugins -->
<instructions>
<Atlassian-Plugin-Key>${atlassian.plugin.key}</Atlassian-Plugin-Key>
<!-- Add package to export here -->
<Export-Package>com.psi.intern.jira.customfield.api.*</Export-Package>
<!-- Add package import here -->
<Import-Package>org.springframework.osgi.*;resolution:="optional", org.eclipse.gemini.blueprint.*;resolution:="optional", *</Import-Package>
<!-- Ensure plugin is spring powered -->
<Spring-Context>*</Spring-Context>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-maven-plugin</artifactId>
<version>${atlassian.spring.scanner.version}</version>
<executions>
<execution>
<goals>
<goal>atlassian-spring-scanner</goal>
</goals>
<phase>process-classes</phase>
</execution>
</executions>
<configuration>
<scannedDependencies>
<dependency>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-external-jar</artifactId>
</dependency>
</scannedDependencies>
<verbose>false</verbose>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<jira.version>7.3.0</jira.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>
<!-- TestKit version 6.x for JIRA 6.x -->
<testkit.version>6.3.11</testkit.version>
<rest.version>3.2.14</rest.version>
</properties>
</project>
Thanks!
some good examples -that really work, would be helpful. I tried some tutorials, but they all finally led to exceptions..... frustrating
Agreed, some (most - all the ones I've worked thorugh) of the tutorials provided by Atlassian are somewhat dated now - I too have hit a number of issues continually refactoring plugins against endless list of deprecated, removed and repackaged objects...
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hello,
I just tried your code with your pom and everything worked fine for me. There must be something else.
and you should change //@Autowired to @Inject
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi,
I deleted the class MyPluginComponentImpl because I wasn't using it anyway, and everything is working fine now.
Why should @Autowired be @Inject? What is the difference there exactly?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I had problems with autowired in constructors before. I use inject and had no ptoblems so far. Instead of scanned i use named. also the same reason. You removed the file but it does not mean you solved the problem. You can get same error later when you call your custom field.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Okay, I restored the file and changed @Autowired to @Inject, as well as @Scanned to @Named, and I get the following errors:
cannot find symbol
symbol class Named
and the same for Inject. Sorry when the solution is obvious but after a Google Search the solution for 'cannot find symbol' seems to be injecting a dependency into the constructor, which I think is exactly what I'm doing right now...?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Can you add imports to the class
import javax.inject.Inject;
import javax.inject.Named;
add dependency to the pom.xml
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>provided</scope>
</dependency>
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks. Now I get BUILD SUCCESSFUL with atlas-mvn install.
However now I receive "Plugin 'com.psi.intern.jira.custom-fields-tests' never resolved service '&myComponent' with filter '(objectClass=com.psi.intern.jira.customfield.api.MyPluginComponent)'"
Class in question:
package com.psi.intern.jira.customfield.api;
public interface MyPluginComponent
{
String getName();
}
Do you have an idea where I should start looking for the problem?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I also don't understand why it's telling me the Plugin 'com.psi.intern.jira.custom-fields-tests' is not resolving. This is the plugin key in an atlassian-plugin.xml in target\test-classes. Where is that coming from?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You can delete test folder in your plugin. And run atlas-mvn clean install
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hello Alexey. Thank you for your continued support. I deleted the test folder and ran atlas-mvn clean install.
Now everything is running, I am getting a new error but this I can discuss in a different post as it is a different topic. Important for this topic, the modules of my plugin are enabled again!
Here is my code:
PercentageField.java:
package com.psi.intern.jira.customfield;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.atlassian.jira.issue.customfields.impl.AbstractSingleFieldType;
import com.atlassian.jira.issue.customfields.impl.FieldValidationException;
import com.atlassian.jira.issue.customfields.manager.GenericConfigManager;
import com.atlassian.jira.issue.customfields.persistence.CustomFieldValuePersister;
import com.atlassian.jira.issue.customfields.persistence.PersistenceFieldType;
import com.atlassian.plugin.spring.scanner.annotation.component.Scanned;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
import javax.inject.Inject;
import javax.inject.Named;
import org.springframework.beans.factory.annotation.Autowired;
import java.math.BigDecimal;
@Scanned
public class PercentageField extends AbstractSingleFieldType<BigDecimal> {
private static final Logger log = LoggerFactory.getLogger(PercentageField.class);
//@Inject
public PercentageField(@ComponentImport CustomFieldValuePersister customFieldValuePersister, @ComponentImport GenericConfigManager genericConfigManager) {
super(customFieldValuePersister, genericConfigManager);
}
@Override
protected PersistenceFieldType getDatabaseType()
{
return PersistenceFieldType.TYPE_DECIMAL;
}
@Override
protected Object getDbValueFromObject(final BigDecimal customFieldObject)
{
return getStringFromSingularObject(customFieldObject);
}
@Override
protected BigDecimal getObjectFromDbValue(final Object databaseValue)
throws FieldValidationException
{
return getSingularObjectFromString(String.valueOf(databaseValue));
}
@Override
public String getStringFromSingularObject(final BigDecimal singularObject)
{
if (singularObject == null) {
return "";
}
// format
return singularObject.toString();
}
@Override
public BigDecimal getSingularObjectFromString(final String string)
throws FieldValidationException
{
if (string == null)
return null;
try
{
final BigDecimal decimal = new BigDecimal(string);
// Check that we don't have too many decimal places
if (decimal.scale() > 2)
{
throw new FieldValidationException(
"Maximum of 2 decimal places are allowed.");
}
return decimal.setScale(2);
}
catch (NumberFormatException ex)
{
throw new FieldValidationException("Not a valid number.");
}
}
}
MyPluginComponentImpl.java:
package com.psi.intern.jira.customfield.impl;
import com.atlassian.plugin.spring.scanner.annotation.export.ExportAsService;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
//import com.atlassian.sal.api.ApplicationProperties;
import com.atlassian.jira.config.properties.ApplicationProperties;
import com.psi.intern.jira.customfield.api.MyPluginComponent;
import javax.inject.Inject;
import javax.inject.Named;
import org.springframework.beans.factory.annotation.Autowired;
@ExportAsService ({MyPluginComponent.class})
@Named ("myPluginComponent")
public class MyPluginComponentImpl implements MyPluginComponent
{
private final ApplicationProperties applicationProperties;
@Inject
public MyPluginComponentImpl(final ApplicationProperties applicationProperties)
{
this.applicationProperties = applicationProperties;
}
public String getName()
{
if(null != applicationProperties)
{
return "myComponent:";
}
return "myComponent";
}
}
MyPluginComponent.java:
package com.psi.intern.jira.customfield.api;
public interface MyPluginComponent
{
//String getString(String name);
}
As you'll notice, I had to comment out the method getString() in the MyPluginComponent interface, as well as remove the call to getDisplayName() in the MyPluginComponentImpl.java, because these methods appear not to exist in com.atlassian.jira.config.properties.ApplicationProperties and I am just having problems when I import com.atlassian.sal.api.ApplicationProperties.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I find it quite frustrating that I have to change so much from what's given in the tutorials, though. Why do the tutorials include methods that don't exist in the classes they import? Why is there a whole test folder which I should just delete?
In any case thank you very much for your help, I would have been stuck in the same place for a while otherwise!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Try to go to the folder of your plugin and make a clean package
atlas-mvn clean package
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks Alexey, that helped change the error message. Now I am getting "No qualifying bean of type [com.atlassian.jira.config.properties.ApplicationProperties] ... expected at least 1 bean which qualifies as autowire candidate for this dependency."
Will try to figure this out and get back to this question with an update.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hello,
Unfortunately I can not provide feedback about the new error. I would need to see your code.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Here is the Java class for the custom field in my plugin, as well as MyPluginComponentImpl.java:
package com.psi.intern.jira.customfield;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.atlassian.jira.issue.customfields.impl.AbstractSingleFieldType;
import com.atlassian.jira.issue.customfields.impl.FieldValidationException;
import com.atlassian.jira.issue.customfields.manager.GenericConfigManager;
import com.atlassian.jira.issue.customfields.persistence.CustomFieldValuePersister;
import com.atlassian.jira.issue.customfields.persistence.PersistenceFieldType;
import com.atlassian.plugin.spring.scanner.annotation.component.Scanned;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
import java.math.BigDecimal;
@Scanned
public class PercentageField extends AbstractSingleFieldType<BigDecimal> {
private static final Logger log = LoggerFactory.getLogger(PercentageField.class);
//@Autowired
public PercentageField(@ComponentImport CustomFieldValuePersister customFieldValuePersister, @ComponentImport GenericConfigManager genericConfigManager ) {
super(customFieldValuePersister, genericConfigManager);
}
@Override
protected PersistenceFieldType getDatabaseType()
{
return PersistenceFieldType.TYPE_DECIMAL;
}
@Override
protected Object getDbValueFromObject(final BigDecimal customFieldObject)
{
return getStringFromSingularObject(customFieldObject);
}
@Override
protected BigDecimal getObjectFromDbValue(final Object databaseValue)
throws FieldValidationException
{
return getSingularObjectFromString(String.valueOf(databaseValue));
}
@Override
public String getStringFromSingularObject(final BigDecimal singularObject)
{
if (singularObject == null) {
return "";
}
// format
return singularObject.toString();
}
@Override
public BigDecimal getSingularObjectFromString(final String string)
throws FieldValidationException
{
if (string == null)
return null;
try
{
final BigDecimal decimal = new BigDecimal(string);
// Check that we don't have too many decimal places
if (decimal.scale() > 2)
{
throw new FieldValidationException(
"Maximum of 2 decimal places are allowed.");
}
return decimal.setScale(2);
}
catch (NumberFormatException ex)
{
throw new FieldValidationException("Not a valid number.");
}
}
}
package com.psi.intern.jira.customfield.impl;
import com.atlassian.plugin.spring.scanner.annotation.export.ExportAsService;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
import com.atlassian.sal.api.ApplicationProperties;
import com.psi.intern.jira.customfield.api.MyPluginComponent;
import javax.inject.Inject;
import javax.inject.Named;
@ExportAsService ({MyPluginComponent.class})
@Named ("myPluginComponent")
public class MyPluginComponentImpl implements MyPluginComponent
{
@ComponentImport
private final ApplicationProperties applicationProperties;
@Inject
public MyPluginComponentImpl(final ApplicationProperties applicationProperties)
{
this.applicationProperties = applicationProperties;
}
public String getName()
{
if(null != applicationProperties)
{
return "myComponent:" + applicationProperties.getDisplayName();
}
return "myComponent";
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
It sounds like you are now being bitten by https://ecosystem.atlassian.net/browse/SCANNER-67. Either try the workaround suggested there, or migrate to Spring Java config, which doesn't have this bug.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.