How to Build a Dynamic Content Macro for Atlassian Confluence Connect

Dennis arrived at Null Pointer Corporation’s brand new headquarters in Singarich City.  He was met by Winfred, the lead developer at Null Pointer Corporation.  “Hi, are you Dennis, our Confluence plug-in trainer? Are you going to teach us about building a Dynamic Content Macro?” Winfred asked as they shook hands.  “Yes I am.  Nice to meet you Winfred.” said Dennis as he read Winfred’s ID.  “Come on.  Please follow me to the conference room.  We are all set up and ready.” Winfred said.

At the conference room, Winfred introduced Dennis to the trainees.  After a few jokes and ice breakers, “Ok class, let’s begin.” Dennis said.

1. Tools

You must have the following tools installed:

  1. Atlassian SDK or Apache Maven
  2. Mars Eclipse

2. Create the Project

“Have you chosen a directory for your project?” Dennis asked. “Yes.” the trainees answered back. “If you are using the Atlassian SDK, replace mvn with the atlas-mvn command. For this example I will user mvn.” Dennis explained.

Execute the following command in your chosen directory:

mvn archetype:generate -DarchetypeGroupId=com.atlassian.connect -DarchetypeArtifactId=atlassian-connect-spring-boot-archetype -DarchetypeVersion=1.1.0

You will then be prompted to input a groupId (type in com.javacodegeeks.example), artifactId (dynamic-macro), version and package (choose the provided default by pressing ENTER). Confirm by pressing “Y” for yes.

You should now have a directory named “dynamic-macro” with skeleton code. The following files should be under the project directory.

Under “src/main/resources”:

  1. application.yml – for specifying Spring properties
  2. atlassian-connect.json – the JSON add-on descriptor

Under “src/main/resources/templates” (to be created later):

  1. messages.htmlThymeleaf template

Under “src/main/java/com/javacodegeeks/example”:


Under “dynamic-macro”:

  1. pom.xml – contains the default dependencies, plugins, properties, etc.

Import the project to Eclipse by running mvn eclipse:eclipse. This command will generate “.classpath” and “.project” which is used by Eclipse to import the project.

3. Add Plug-in Logic

Modify the code like so:

package com.javacodegeeks.example;

import java.util.ArrayList;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

public class AddonApplication {
	private final ArrayList quotes;
	private static int index = 0;
	public AddonApplication() {
		quotes = new ArrayList();
		quotes.add("No guts, no glory!");
		quotes.add("When you're cool, the sun always shines!");
		quotes.add("It doesn't matter where we roam, it's always nice to be back home!");
	@RequestMapping(value = "/inspirational-messages")
	public String getInspirationalMessages(Model model) {
	    model.addAttribute("quote", quotes.get(index));
	    if (++index >= quotes.size()) {
	    	index = 0;
	    return "messages";

    public static void main(String[] args) throws Exception {
        new SpringApplication(AddonApplication.class).run(args);

Dennis asked “Can anybody tell me what this code will do?” Wanting to show why he is the lead developer, Winfred answered “That is a Spring Boot application. That app replies a new inspirational message in messages.html every time an HTTP GET request is received by the /inspirational-messages resource endpoint.” “Wow! That’s correct. Plus this app also uses Atlassian Connect Spring Boot API. Any programmer can write code that a machine can understand. Good programmers write code that other developers can understand.” Dennis added.

4. Edit the Plug-in Descriptor

Modify the plug-in descriptor like so:


  "key": "dynamic-macro",
  "baseUrl": "http://localhost:8080",
  "name": "Luminary Add-on",
  "authentication": {
    "type": "jwt"
  "lifecycle": {
    "installed": "/installed",
    "uninstalled": "/uninstalled"
  "modules": {
    "dynamicContentMacros": [
      	"key": "dynamic-macro-example",
        "name": {
          "value": "Luminary Plugin"
        "url": "/inspirational-messages",
        "description": {
          "value": "Provide inspirational messages."
        "outputType": "block",
        "bodyType": "none"

See Add-Descriptor to learn more. The key, baseUrl, and authentication are required properties. The key is unique and is used to identify the plug-in. The baseUrl is the URL of the add-on. The authentication defines the type of authentication to use when signing requests between the host application and the connect add-on.

See Dyanimic Content Macro Module Descriptor to learn more. The key, name, and url are required properties. The key identifies the macro. The name is the human readable name of the macro. The url is the link to the add-on resource that provides the macro content.

5. Create the Template

Create the template file like so:


<!DOCTYPE html>
  <title>Inspirational Message</title>
  <meta charset="utf-8"></meta>
  <meta name="viewport" content="width=device-width, initial-scale=1"></meta>
  <link rel="stylesheet" href=""></link>
  <link rel="stylesheet" href="//" media="all"></link>
  <script src=""></script>
  <script src=""></script>
  <script src="http://localhost:1990/confluence/atlassian-connect/all.js" type="text/javascript"></script>
<div class="container">
  <div class="row">
	<h3 class="text-center"><span class="label label-success" th:utext="${quote}">Quote</span></h3>

Line number 11 is highlighted because it is important. all.js establishes a cross-domain messaging bridge between an Atlassian Connect iframe and the host product. Without all.js, served from the product, the macro will not be displayed. See Atlassian Connect JavaScript client library for more details. This HTML page also uses Bootstrap.

Don’t forget to add the Thymeleaf dependency in your pom.xml like so:


6. Install the Plug-in

Install the Macro on a local Atlassian Confluence Cloud instance. Open another terminal and run:

atlas-run-standalone --container tomcat7x --product confluence --version 6.0.0-OD-2016.14.1-0054 --data-version 6.0.0-OD-2016.14.1-0054 --bundled-plugins com.atlassian.bundles:json-schema-validator-atlassian-bundle:1.0.4,com.atlassian.jwt:jwt-plugin:1.5.10-0021,com.atlassian.upm:atlassian-universal-plugin-manager-plugin:,com.atlassian.plugins:atlassian-connect-plugin:1.1.84 --jvmargs -Datlassian.upm.on.demand=true

You should be able to access Confluence in your browser at http://localhost:1990/confluence. Use admin as your username and password.

On the right hand corner, there is a cog icon, click on it and go to “Add-ons“. There should be an “Upload add-on” link. If there is none, click on “Settings” and enable private listings. Paste the link (http://localhost:8080) to your Macro server in the Upload add-on dialog box. Upon installing the add-on, you might get an error “An unexpected error occurred. Refer to the logs for more information.” Don’t mind it. Try reloading the page and check if the plugin was installed.

Before you can add the Macro add-on, you need to start your server. Run “mvn spring-boot:run” on another terminal to start it. Open http://localhost:8080 in your browser to check if your Macro add-on is ready. It should display the atlassian-connect.json contents.

7. Output

Now that the Macro add-on is installed, it’s time to create a Confluence Page and add your Macro to the page. Click on “Create” at the top of the page to create a blank page. Type the title “Dennis Training Demo” and add some paragraphs. Press “Shift + {“ to open the Macro Browser Dialog. Type “lumina” in the search field to filter and display your Luminary Add-on. Choose it and then click Save. The final output should look something like this:

dynamic content macro for atlassian confluence connect
Final Output

“Did everybody understand? Any questions?” Dennis asked.

8. Summary on Building a Dynamic Content Macro

“How do you build a dynamic macro?” Dennis asked. The trainees answered in unison. First, gather your tools then create the project. Second, add the plug-in logic and edit the plug-in descriptor. Third, install the plug-in. Finally, create a page to try out the app. Check out the Dynamic Macro Confluence Module for more details.

9. Download the Source Code

This is an example of building a Dynamic Content Macro for Atlassian Confluence Connect.

You can download the source code of this example here:

Joel Patrick Llosa

I graduated from Silliman University in Dumaguete City with a degree in Bachelor of Science in Business Computer Application. I have contributed to many Java related projects at Neural Technologies Ltd., University of Southampton (iSolutions), Predictive Technologies, LLC., Confluence Service, North Concepts, Inc., NEC Telecom Software Philippines, Inc., and NEC Technologies Philippines, Inc. You can also find me in Upwork freelancing as a Java Developer.
Notify of

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Inline Feedbacks
View all comments
Back to top button