Writing a Macro Using JSON
This tutorial applies to Confluence 4.x and later
Level of experience:
This is an intermediate tutorial. You should have completed at least one beginner tutorial before working through this tutorial. See the list of tutorials in DAC.
It should take you approximately 1 hour to complete this tutorial.
On this page:
Overview of the tutorial
In this tutorial, you create a Confluence macro that prints out the days of the week starting on a given date. If a user supplies a date as a macro parameter, the macro prints the days of the week starting on that date. Otherwise, it shows the the days of the week starting with the current date.
While the calendar itself isn't very useful, it will demonstrate how to use the Confluence JSON APIs from the plugin Java code. Our calendar will be composed by JSON data.
To get the most out of this tutorial, you should be familiar with:
- The basics of Java development: classes, interfaces, methods, how to use the compiler, and so on.
- How to create an Atlassian plugin project using the Atlassian Plugin SDK.
- How to use and administer Atlassian Confluence.
Also, while this tutorial demonstrates how to work with JSON data in a plugin, it does not discuss JSON itself. For more information on JSON, see http://www.json.org/.
We encourage you to work through this tutorial. If you want to skip ahead or check your work when you have finished, you can find the plugin source code on Atlassian Bitbucket. Bitbucket serves a public Git repository containing the tutorial's code. To clone the repository, issue the following command:
Alternatively, you can download the source as a ZIP archive by choosing download here: https://bitbucket.org/atlassian_tutorial/writing-a-macro-using-json
Step 1. Create the plugin project
In this step, you'll use the Atlassian Plugin SDK to generate the scaffolding for your plugin project. The Atlassian Plugin SDK automates much of the work of plugin development for you.
- If you have not already set up the Atlassian Plugin SDK, do that now: Set up the Atlassian Plugin SDK and Build a Project.
- Open a terminal and navigate to your Eclipse workspace directory.
Enter the following command to create the project files for the plugin:
As prompted, enter the following project parameters:
- Confirm your entries when prompted.
Step 2. Review the POM
The SDK generated a project directory with most of the artifacts our plugin needs, including a POM (Project Object Model) file. The POM describes your project and declares your plugin build dependencies. It's a good idea to open and review the POM after generating a new project. Let's do that now, making a few changes to the generated content as we go.
- Change to the
examplemacrodirectory created by the SDK in the previous step and open the file
Add your company or organisation name and your website to the
- Save the file.
Step 3. Tweak the plugin descriptor
Next we'll make a few changes to the plugin descriptor file. Among other things, the descriptor tells Confluence what UI elements the macro wants to extend or implement. In the Atlassian plugin framework, a unit of functionality is encapsulated by a module. For our plugin, we'll modify the Web Resource module that the SDK gave us and add a type of Macro Module,
Open the plugin descriptor file,
atlassian-plugin.xml, for editing. It is located in the
src/main/resourcesdirectory of your project home.
Notice that the SDK added a few module for our plugin already. For one, it added a
web-resourceelement with a few resources that plugins typically require. We won't use all of them, but we will use one or two and add another.
Add the following resource element to the
web-resourceelement in the descriptor:
This is the Velocity template that we'll create in a bit.
Add the following as a child of
This is the module declaration for our macro. Notice that it's going to take a single parameter,
- Save your changes.
Step 4. Add presentation resources
- Navigate to the resources directory,
src/main/resources, and create a new directory there named
templatesdirectory you just created, create a file named
examplemacro.vmand add the following content to the file:
Notice that our Velocity template consists of resource statements and a
divwith a single
fieldsetelement. The element contains a hidden
inputelement, to which we assign the output of our macro's
executemethod (that is, the URL-encoded, serialized JSON object string). The
Open the properties file in the
examplemacro.properties, and add the following properties to the file:
These will provide the label and description for the parameter in the macro browser, as shown here:
src/main/resources/js/examplemacro.jsand add the following content:
- Retrieves the URL-encoded, serialized JSON string from the hidden
- Creates a JSON object from that string using jQuery.parseJSON, replacing any spaces with non-breaking spaces in the process.
- Creates HTML for a table with a row for each of the seven dates and two columns for the dates and days, populating each cell with the relevant values from the JSON object
- Inserts the HTML into the page.
Step 5. Create the macro class
Let's add the Java class that implements our macro logic. We'll start simple, creating a macro that just generates placeholder text for now.
- Create a file named
ExampleMacro.java. in the
Add the following skeleton code:
When a macro is invoked, Confluence calls its
execute()method, so that's where we'll need to do the heavy lifting for our macro. Confluence passes parameters as strings in the
execute. As implied by our variable declarations, our parameter will be a date. The class specifies the body type of
NONEand an output type
BLOCKfor our macro. This tells Confluence what kind of content it should expect our macro to generate.
Step 6. Start up Confluence
We're not done yet, but let's start up Confluence and see what our macro does so far:
- Make sure you have saved all your code changes to this point.
- In a terminal window, navigate to the plugin root folder (where the
Run the following command:
This command builds your plugin code, starts a Confluence instance, and installs your plugin. This may take a minute or two. When it's done, you will see many status lines on your screen concluding with something like this:
- Open your browser and open Confluence at the address indicated in the output.
- At the login screen, enter the default credentials for an administrator user,
- Create a new page in the Demonstration Space by clicking the Create button from the header.
- In the edit page screen, click Insert > Other Macros.
- Browsing to the macro in the Select Macro dialog. You can do so quickly by typing the first few letters of the macro name, such as Exa.
- Select the macro and insert it into your page.
As you saw in the preview pane and on the page after saving your changes, so far the macro generates our placeholder text, "Only a test". We'll make it do more next.
You can keep Confluence running at this point, QuickReload will automatically redeploy any changes you build.
Step 7. Make your macro do more
Let's add the logic for generating our JSON-based calendar. We'll take this task piece by piece, so that we can examine and discuss each part of the code as we go.
ExampleMacro.javafor editing once again.
Replace the body of the
execute()method with this:
startDateobject by calling a new method,
getStartDateFromParams(), passing it the
paramsargument. It will be the job of
getStartDateFromParams()to determine the start date and return it as a string into a
Populates the array by taking the parameter as the starting date and looping seven times, each time incrementing the date by one. On each loop, the date is formatted by name and date, with the results stored in the JSON array (with the help of a method we'll create in a bit).
It sets the array as a
daysdatesproperty of the JSON object.
getStartDateFromParams()method called from
paramsargument always contains a
RAW_PARAMS_KEYkey containing the raw parameter string, so we'll only parse parameters when
params.sizeis greater than 1. Also note that if the user doesn't provide a date, the
startDateis initialized to the current date, which serves as our default.
Add the other method we added to
This method simply populates a JSON object with the day and date for each cycle of the
So far, we stored the days and dates information as a JSON object. We still need to output the results. Replace the existing return statement (
return "Only a test";) with these lines:
Notice our new return value. More realistically, you'd likely want to make your JSON available via REST, but REST is a topic for its own tutorial. To keep this simple, our plugin uses a Velocity template to render output as markup.
Notice the call to
contextMap.put(). This function:
- Serializes the
dayDateJsonObjectJSON object into a string.
- URL encodes it.
- Puts it into a
This is then rendered into a
String containing markup according to the Velocity template we already created.
Step 8. Check your code
You macro plugin class is now complete. To review, our
execute() method now:
- Creates a JSON object containing two name/value pairs (one for the date and one for the day). This is what
nextDayDateJsonObjectin the for loop of
executeso that a JSON object is created for each of the seven dates.
- Adds each of these objects to a JSON array named
- Adds the JSON array filled with all seven JSON objects, as the value to the only property of another JSON object,
The end result being a single JSON object,
dayDateJsonObject, that contains an array of seven JSON objects, each of which is a set of day and date name/value pairs.
You can check your completed class against the following:
We're ready to try the macro again.
Step 9. Test the completed macro
To see your new macro in action:
- Make sure you have saved all your file changes.
- Rebuild your plugin and QuickReload will automatically reinstall it.
- Back in the Confluence browser window, try adding your macro again. This time, you should get the default calendar in the preview pane.
- Enter a date in the Date field using the dd/mm/yyyy format, such as 22/09/2014 for September 22, 2014.
- Click Insert.
- Click Save to view your macro output.