You also have a couple of other mistakes:
data: "$pageProperties",
will render something like data: "class.instanceobject"
and not actual data. Even if you serialize the data then you get something like {"id":"92078504","spacekey":"UADCE725"}
which you will have to manually deserialize. That would mean you are posting string.
I took the initiative to spare you from figuring out what is going on when rendering a json object to velocity and provide you a way to post JSON object.
The macro
package yourpackage;
import com.atlassian.confluence.content.render.xhtml.ConversionContext;
import com.atlassian.confluence.macro.Macro;
import com.atlassian.confluence.macro.MacroExecutionException;
import com.atlassian.confluence.renderer.radeox.macros.MacroUtils;
import com.atlassian.confluence.util.velocity.VelocityUtils;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.util.HashMap;
import java.util.Map;
public class CreateInitiative implements Macro {
private Map<String,String> pageProperties;
@Override
public String execute(Map<String, String> map, String s, ConversionContext conversionContext) throws MacroExecutionException {
Map<String, Object> contextMap = MacroUtils.defaultVelocityContext();
pageProperties=new HashMap<>();
pageProperties.put("id",conversionContext.getPageContext().getEntity().getIdAsString());
pageProperties.put("spacekey", conversionContext.getSpaceKey());
Gson gson = new Gson();
contextMap.put("pageProperties", gson.toJson(pageProperties));
return VelocityUtils.getRenderedTemplate("layouts/createInitiative.vm", contextMap);
}
@Override
public BodyType getBodyType() {
return BodyType.RICH_TEXT;
}
@Override
public OutputType getOutputType() {
return OutputType.BLOCK;
}
}
The rest endpoint
@Path("/create")
public class MyRestResource {
@Path("/initiative")
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces({MediaType.APPLICATION_JSON})
public Response createInitiative(MyRestResourceModel id) {
System.out.println("In REST response with: " + id.getId());
return Response.ok(id.getId()).build();
}
}
The json object:
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
public class MyRestResourceModel {
@XmlElement(name = "id")
private String id;
@XmlElement(name = "spacekey")
private String spacekey;
public MyRestResourceModel() {
}
public MyRestResourceModel(String id, String spacekey) {
this.id = id;
this.spacekey = spacekey;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getSpacekey() {
return spacekey;
}
public void setSpacekey(String spacekey) {
this.spacekey = spacekey;
}
}
And finally but most importantly:
<input id="createinitiative" class="aui" type="button" value="Create Initiative" onclick="createInitiative()" >
#set($propertiesHtml=$pageProperties)
<script type="text/javascript">
function createInitiative() {
AJS.toInit(function() {
jQuery0.ajax({
type: "POST",
contentType: "application/json",
url: AJS.contextPath() + "/rest/myrestresource/1.0/create/initiative",
data: '${propertiesHtml}',
dataType: "json",
success: function(response, textStatus) { AJS.log("Success: " + response); },
error: function (xhr, textStatus, errorThrown) { AJS.log("Error: " + xhr); }
});
});
}
</script>
Notice here that jQuery0 is my noConflict jquery. Use yours. Take a look at second line
#set($propertiesHtml=$pageProperties)
this is the trick. Atlassian is escaping any variable that doesn’t end in Html.
Data line also is explaining a bit why AJS.$. is not working, velocity is marking variables with $var or with ${var}. When you have AJS.$.ajax then it expects variable. It is generally advised not to use inline javascript to avoid just that problem