Replacing WikiMacro code with groovy fails because of wrong context type

I was adapting the very useful Bulk replace content in pages script to perform bulk changes on macro code stored in XWiki.WikiMacroClass objects.

Reading the macro code worked perfectly.
Replacing the content in memory also worked.
But every attempt to write the modified code back to the object failed :face_with_steam_from_nose:

All write attempts resulted in variations of:

No signature of method: <unknown>.null() is applicable for argument types: (null)
groovy.lang.MissingMethodException

I tried all obvious approaches without success:

codeProp.setValue(newContent)          // never worked
macroObj.set("code", newContent)       // never worked
document.save("Bulk Replace Code.")    // never worked

I also tried switching to the Core API, similar to patterns used here:

def pxwiki = xwiki.getXWiki()
def pxcontext = xcontext
def coreDoc = pxwiki.getDocument(document.getDocumentReference(), pxcontext)
def obj = coreDoc.getObject("XWiki.WikiMacroClass", macroObj.getNumber())
obj.set("code", newContent, pxcontext)
pxwiki.saveDocument(coreDoc, "Bulk Replace Code.", true, pxcontext)

This also failed, still producing the same MissingMethodException :roll_eyes:

The actual root cause

After adding more detailed logging outside the Job Macro Box, the error finally became visible to me:

No signature of method: com.xpn.xwiki.XWiki.getDocument()
is applicable for argument types:
(org.xwiki.model.reference.DocumentReference,
 com.xpn.xwiki.api.Context)

So the issue was a wrong context type.

The fix

xcontext in scripts is an API context but Core APIs expect a com.xpn.xwiki.XWikiContext

The correct solution is:

def pxcontext = xcontext.context

instead of:

def pxcontext = xcontext

It took quite a while to figure this out and it ended up being a surprisingly frustrating learning experience. But it paid of finally :wink:

After switching to the proper Core context, writing to XWiki.WikiMacroClass works perfectly.

So my learning is…

If you modify objects using the Core API:

  • Reading via xwiki.getDocument() may work

  • Writing requires:

    • Core document (XWikiDocument)

    • Core context (xcontext.context)

Otherwise you’ll get misleading MissingMethodException errors that look unrelated to the actual problem.

At that point I’m too happy (and tired) to continue investigating – but why is def pxcontext = xcontext working here, is it? @surli

I’m not sure… feels like a bug to me. Apparently was done by @tmortagne in XWIKI-15472: showInstalledCount is not taken into account · xwiki/xwiki-platform@0115ce0 · GitHub it probably use to work, maybe at a point it worked by mistake?

1 Like

It still does.

There is one problem with the schedulers system, an initial mistake we unfortunately cannot get rid anymore, or it will break all existing schedulers: xcontext is an XWikiContext, and not the more script oriented Context you find in a groovy macro and any other groovy code in XWiki.

2 Likes