Developer
Documentation
Resources
Get Support
Sign in
Developer
Get Support
Sign in
DOCUMENTATION
Cloud
Data Center
Resources
Sign in
Developer
Sign in
DOCUMENTATION
Cloud
Data Center
Resources
Sign in
Last updated Sep 6, 2019

Spring Java configuration - converting from atlassian-plugin.xml components

This page explains how to convert your P2 app to use Spring Java configuration, if it currently declares its components in its atlassian-plugin.xml.

POM changes

  1. Add the necessary dependencies.
  2. Add the <Atlassian-Plugin-Key> header to your AMPS <instructions>, to indicate that your plugin should not be transformed at runtime into an OSGi bundle. For example:
1
2
<project ...>
  <!-- ... -->
  <build>
    <plugins>
      <plugin>
        <groupId>com.atlassian.maven.plugins</groupId>
        <artifactId>amps-maven-plugin</artifactId>
        <!-- Or jira-maven-plugin, etc. -->
        <!-- For AMPS pre-8.0, use maven-amps-plugin, maven-jira-plugin, etc. -->
        <version>8.1.0</version>
        <configuration>
          <instructions>
            <!-- You may want to extract the plugin key to a POM property, for reuse elsewhere -->
            <Atlassian-Plugin-Key>my-plugin-key</Atlassian-Plugin-Key>
            <!-- You may need to import some packages whose usage is not detected by the maven-bundle-plugin, or
                 mark some packages as optional, or add version ranges to them, etc. -->
            <Import-Package>*</Import-Package>
            <!-- Ensure the plugin is Spring-powered -->
            <Spring-Context>*</Spring-Context>
            <!-- ... -->
          </instructions>
          <!-- ... -->
        </configuration>
      </plugin>
      <!-- ... -->
    </plugins>
  </build>
  <!-- ... -->
</project>

Create a Java config class

  1. Create a class for your Spring config, called (for example) SpringBeans, in a new package somewhere under src/main/java, for example com.example.myplugin.spring.
  2. Annotate that class with @org.springframework.context.annotation.Configuration.

Change your Spring XML

You will currently have a Spring XML file in src/main/resources/META-INF/spring (it could be called anything ending in .xml). Modify this file as follows:

  • Remove any mentions of the osgi namespace from the root element.
  • Replace any usages of the osgi namespace with equivalent @Bean methods in your Java config class.
  • Register your new @Configuration classes.

Importing services from OSGi

For each service you’re importing via an osgi:reference element in your Spring XML files (if any), create a method like this in your Spring config class:

1
2
@Bean(destroyMethod = "")
public FooService fooService() {
    return importOsgiService(FooService.class);
}

… where the importOsgiService method is statically imported from com.atlassian.plugins.osgi.javaconfig.OsgiServices. The empty destroyMethod attribute is only necessary if the service implements close() or shutdown(), for example the CacheManager API from atlassian-cache; for most services, you can simply use @Bean, with no attributes.

Do the same for each <component-import> element in your plugin XML. Note that since version 0.2.0 of this helper library, you can optionally specify an LDAP filter, just as you could add a filter attribute to <component-import>. Here's an example that works with 0.3.1 and later:

1
2
@Bean
public FooService fooService() {
    return importOsgiService(FooService.class, ImportOptions.defaultOptions().withFilter("(some.key=some.value)"));
}

Here, the FooService will be imported only if it has a some.key property with the value some.value.

To import a collection of services as with osgi:list or osgi:set, since 0.6.0 the following approach may be used:

1
2
@Bean
public List<FooService> fooServices() {
    return importOsgiServiceCollection(list(FooService.class));
}

where importOsgiServiceCollection is statically imported from com.atlassian.plugins.osgi.javaconfig.OsgiServices and list is a static factory method for com.atlassian.plugins.osgi.javaconfig.ServiceCollection. As opposed to importOsgiService, the default "availability" for this method is "optional".

Exporting services to OSGi

Replace each <component … public=”true”> element in your plugin XML with a pair of methods like this in your Spring config class:

1
2

@Bean
public BarService barService() {
    // TODO instantiate and return your BarService implementation
}

@Bean
public FactoryBean<ServiceRegistration> exportBarService(
        final BarService barService) {
    return exportOsgiService(barService, ExportOptions.as(BarService.class));
}

… where the exportOsgiService method is statically imported from com.atlassian.plugins.osgi.javaconfig.OsgiServices.

You can also remove any @Named or @Component annotations from the class that implements BarService (since you’re now instantiating it programmatically).

Defining plugin module types

Replace each <module-type> element in your plugin XML with a pair of methods like this in your Spring config class:

1
2
@Bean
public ListableModuleDescriptorFactory myModuleDescriptorFactory() {
    return new MyModuleDescriptorFactory();
}

@Bean
public FactoryBean<ServiceRegistration> exportMyModuleType(
        final ListableModuleDescriptorFactory moduleDescriptorFactory) {
    return exportAsModuleType(moduleDescriptorFactory);
}

… where the exportAsModuleType method is statically imported from com.atlassian.plugins.osgi.javaconfig.OsgiServices.

Decomposing your config classes [optional]

If your @Configuration class has become too big or messy, you can easily split it up as follows:

  1. Pick one of your config classes (or create a new config class) to be the “main” config class.
  2. Move some/all of its beans to one or more new @Configuration classes, according to whatever categorisation makes sense (for example, put all your web-related beans into MyWebBeans.class, or split up the beans by feature, etc).
  3. At the top of the main config class, add a Spring @Import annotation that lists these subsidiary config classes, for example:
1
2
@Configuration
@Import({
    MyPersistenceBeans.class,
    MyServiceBeans.class,
    MyWebBeans.class
})
public class MainSpringConfig {}

Rate this page: