Last updatedMar 30, 2018

What is the best way to load a class or resource from a plugin?

Because of different ways that application servers deal with class loading, just calling this.getClass().getResourceAsStream()  might not work the same everywhere Confluence is deployed. To help, we have a utility method that checks the various class loaders in a predictable order:

1
InputStream in = com.atlassian.core.util.ClassLoaderUtils.getResourceAsStream(filename, this.getClass());

Loading inside plugins

Because plugins may be dynamically loaded, each plugin may have its own class loader, separate from the main Confluence application. This makes loading resources (for example, properties files) from inside a plugin JAR a little tricky.

If the class that you load the resource from is in the same jar as the resource file itself (that is, all are part of the same plugin), you can use ClassLoaderUtils as in the previous example, and everything will work fine.

However, if you are trying to load the file from a different plugin, or from the main application code, you'll need an instance of the PluginAccessor from spring (see how to retrieve it):

1
InputStream in = pluginAccessor.getDynamicResourceAsStream(filename);

An example of modules and resources

When writing your own ModuleDescriptor you might want developers that depend on your ModuleDescriptor to write in their atlassian-plugin.xml files something that looks like this :

atlassian-plugin.xml example definition

1
2
3
<swagger-enforcer key="meRestSwaggerEnforcer">
    <resource name="my-rest-swagger" type="swagger" location="swagger/swagger.json" />
</swagger-enforcer>

They would then have a ModuleDescriptor with an init() method that looks something like this:

ModuleDescriptor#init

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public void init(@Nonnull Plugin plugin, @Nonnull Element element) throws PluginParseException {
    super.init(plugin, element);
 
    for (ResourceDescriptor resourceDescriptor : getResourceDescriptors(RESOURCE_DESCRIPTOR_TYPE)) {
        final InputStream potentialResource = plugin.getClassLoader().getResourceAsStream(resourceDescriptor.getLocation());
        Preconditions.checkState(potentialResource != null, "Could not find the swagger resource: " + resourceDescriptor.getLocation());


        // DO SOMETHING HERE
    }
}

There are two important function invocations in this example:

  • AbstractModuleDescriptor\#getResourceDescriptors(java.lang.String)
    This method makes it easy to extract resource declarations from Atlassian Plugins 2 Module Descriptor XML definitions. You should use this for your own resource declarations.
  • plugin.getClassLoader().getResourceAsStream(resourceDescriptor.getLocation()); This is the preferred method of extracting a resource from another plugin.

Use the given examples to load resources from other plugins that are defined inside atlassian-plugin.xml files.