Skip to end of metadata
Go to start of metadata

Some very rough notes I took while learning to create an Atlassian Confluence plugin. Perhaps, I'm in the process of cleaning these notes up now, while building another plugin. Please consider this a somewhat sloppy WORK-IN-PROGRESS for now.


Install the Atlassian SDK

See: Set up the Atlassian Plugin SDK and Build a Project

Create the Plugin Skeleton

Navigate to the directory on your system where you'd like to create your plugin.  The command we are about to run will create a folder with the plugin directories inside.

mkdir confluence-code-mojo

Change into the directory...

cd confluence-code-mojo

Execute the following command to generate the plugin skeleton...


The first time, Maven will download a bunch of packages.

Now you need to define some things:

Define value for groupId: : com.codyburleson.confluence
Define value for artifactId: : codemojo
Define value for version: 1.0.0-SNAPSHOT: (press ENTER)
Define value for package: com.codyburleson.test: : com.codyburleson.confluence.codemojo

You will then be prompted to confirm

Confirm properties configuration:
groupId: com.codyburleson.confluence
artifactId: codemojo
version: 1.0.0-SNAPSHOT
package: com.codyburleson.confluence.codemojo
 Y: : (press ENTER)

Maven will do its thing. If everything goes well, you should then get a BUILD SUCCESS message...

[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 02:23 min
[INFO] Finished at: 2017-06-23T14:55:21-06:00
[INFO] Final Memory: 13M/160M
[INFO] ------------------------------------------------------------------------

Now, we should have the basic plugin skeleton within the initial directory as follows:

  • confluence-code-mojo/
    • codemojo/
      • LICENSE
      • pom.xml
      • README
      • src/
        • etc...

I'm using IntelliJ IDEA as my IDE, so, at this point, I can choose to import the project in IntelliJ (selecting the pom.xml file within the codemojo/ directory.)

It's a good idea to establish this starting point as a baseline from which to build a source code history. I'll track with Git, so cd into the confluence-code-mojo folder and execute the following command to initialize the containing directory as a Git repository.

git init

Now, you can open the local repository in Atlassian SourceTree (Git client) or use the command line; whatever you prefer to manage and track your source code changes. Personally, I prefer to use SourceTree. In SourceTree, I select  New... > Add Existing Local Repository and then choose the confluence-code-mojo folder. I select all files in the File status view, enter the Commit message, "Initial commit" and then press Commit and OK.

Now we're ready to start customizing the plugin, but before we do that, let's just do a little acid test.

Install and test the plugin skeleton

Change into the plugin directory (in my case, codemojo) and enter the following command: 


The Atlas CLI and Maven will do their thing - bringing down required dependencies and then firing up developer instance of Confluence with your plugin installed for testing purposes.

Wait patiently, this process takes quite a while to complete.

When it's ready, you should see something like the following in the terminal:

[INFO] [talledLocalContainer] Jun 23, 2017 3:21:35 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
[INFO] [talledLocalContainer] INFO: Initiating Jersey application, version 'Jersey: 1.8-atlassian-16 03/23/2015 10:20 PM'

Navigate to:


Login with admin | admin

Go find your plugin in the manage page...



After executing the atlas-run command, use CTRL + D in the console to shut down gracefully! But, let's not shut it down just yet. We need to make changes to the plugin and redeploy.

Customize the plugin

Open the src/main/resources/atlassian-plugin.xml file in your editor. It should look something like this:

<atlassian-plugin key="${atlassian.plugin.key}" name="${}" plugins-version="2">
        <vendor name="${}" url="${project.organization.url}" />
        <param name="plugin-icon">images/pluginIcon.png</param>
        <param name="plugin-logo">images/pluginLogo.png</param>

    <!-- add our i18n resource -->
    <resource type="i18n" name="i18n" location="codemojo"/>
    <!-- add our web resources -->
    <web-resource key="codemojo-resources" name="codemojo Web Resources">
        <resource type="download" name="codemojo.css" location="/css/codemojo.css"/>
        <resource type="download" name="codemojo.js" location="/js/codemojo.js"/>
        <resource type="download" name="images/" location="/images"/>


After the <web-resource>...</web-resource> section in the file, enter the following to setup macro plugin type.

<xhtml-macro name="codemojo" class="com.codyburleson.confluence.codemojo.macro.Plugin" key='codemojo'>
    <description key="my.plugin.desc"/>
    <category name="formatting"/>

Open the file /src/main/resources/ and add edit similar to the following:

#put any key/value pairs here Macro
my.plugin.desc=A source code formatting macro that uses Codemirror for advanced formatting.

Also, change the <description> item in the pom.xml; this is what will display as a description in the Add-ons management area of Confluence. For example:

<description>Macro and formatters for pretty-printing source code in a wiki page using Codemirror.</description>

Create the com.codyburleson.confluence.codemojo.macro java package.

Next, create the Java class file,, in that package...
package com.codyburleson.confluence.macro;

import com.atlassian.confluence.content.render.xhtml.ConversionContext;
import com.atlassian.confluence.macro.Macro;
import com.atlassian.confluence.macro.MacroExecutionException;

import java.util.Map;

public class Panel implements Macro {

    public String execute(Map<String, String> map, String s, ConversionContext conversionContext) throws MacroExecutionException {
        return "<h1>Hello World</h1>";

    public BodyType getBodyType() { return BodyType.NONE; }

    public OutputType getOutputType() { return OutputType.BLOCK; }

This is the minimum skeleton your Macro will require to implement the confluence Macro class and display a Macro object in Confluence. 

In your terminal window, change directory back to the top directory for your plugin (eg cd /Users/cburleson/repos/confluence-code-mojo/codemojo)

Run the command:

atlas-mvn package

You should see a confirmation message 

[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.656 s
[INFO] Finished at: 2016-10-10T18:33:09+10:00
[INFO] Final Memory: 37M/433M
[INFO] ------------------------------------------------------------------------

I, on the other hand, got an error message on the attempt to redeploy in the atlas-run session:

[INFO] [talledLocalContainer] Caused by: com.atlassian.plugin.IllegalPluginStateException: Cannot getResourceAsStream( This operation must occur before the plugin 'com.codyburleson.confluence.codemojo' is uninstalled

I created a file right next to the file. But since the file wasn't there initially, I need to stop the atlas-run session and restart it. From then on, redeploying with the atlas-mvn package command should work. 

That is, press CTRL + D to shut down the former atlas-run session. 

Run atlas-mvn package to build the plugin.

Typically, when you run the atlas-mvn package command, you can monitor the terminal where confluence was run originally using atlas-run and confirm that QuickReload finished loading. You should see a confirmation message. That's what we'll do to keep deploying changes to our plugin (once passing the above little quirk).


I should consult with Atlassian about this little quirk.

Now you can try adding the Macro to a test page in Confluence (you'll need to make a new Confluence Space and Page before you can test it out so go ahead and do that first).

Now, we will continue to customize the plugin. We'll add a macro parameter to learn about how parameters can be set, and used.

Note to Self (and potential readers)

In my second plugin development, through which I am editing this page to try to make it more accurate and useful, I left off here. Going forward from this point, it could get confusing; sorry. I'll be back to finish up soon!

Open the atlassian-plugin.xml file in your editor.

Locate the <parameters/> element within the <xhtml-macro> element you created.  

Replace the <parameters/> element with the following:

    <parameter name="Title" type="string" />

This specifies that the parameter is called 'Title' and is of type 'string'.  You can find the full list of types under the Parameters heading in the macro module documentation

Now modify the execute method in the Java class so it looks like this:

public String execute(Map<String, String> map, String s, ConversionContext conversionContext) throws MacroExecutionException {
    if (map.get("Title") != null) {

		StringBuilder sb = new StringBuilder();
   		sb.append("<div class=\"codemojo\">");
   		return sb.toString();
	} else {
   		return "<h1>Hello World!<h1>";


Execute atlas-mvn package.

Write a comment…