Cannot push existing Map containing key 'context'

Hello,
I’m looking for some guidance on how to best handle a reserved parameter name in Moqui.

I recently had to implement an API where one of the required request parameters was named context. However, this resulted in the following exception:

Internal error processing request: java.lang.IllegalArgumentException: Cannot push existing Map containing key ‘context’, reserved key

I was eventually able to work around the issue by modifying WebFacadeImpl (around lines 144–145). Before the parameters are pushed into the execution context, I check for the context key and rename it to parameterContext:

if ((contentType.contains(“application/json”) || contentType.contains(“text/json”))) {
try {
JsonNode jsonNode = ContextJavaUtil.jacksonMapper.readTree(bodyString)
if (jsonNode.isObject()) {
jsonParameters = ContextJavaUtil.jacksonMapper.treeToValue(jsonNode, Map.class)
} else if (jsonNode.isArray()) {
jsonParameters = [_requestBodyJsonList:ContextJavaUtil.jacksonMapper.treeToValue(jsonNode, List.class)] as Map<String, Object>
}

if (jsonParameters.containsKey(“context”)) { jsonParameters.put(“parameterContext”, jsonParameters.remove(“context”))
}
} catch (Throwable t) {
logger.error(“Error parsing HTTP request body JSON: ${t.toString()}”, t)
jsonParameters = [_requestBodyJsonParseError:t.getMessage()] as Map<String, Object>
}
// logger.warn(“=========== Got JSON HTTP request body: ${jsonParameters}”)
}

The workaround solved my problem by allowing the API to accept the incoming context parameter and replacing it to parameterContext internally before the body is added to the context stack.

My question is, Is there a cleaner way to handle this? I suspect I may have overlooked an existing solution for dealing with reserved parameter names, and I’d appreciate any suggestions or best practices if you have encountered a similar situation.

Thank you.

There is a reason context is protected, it’s like a “self” reference used everywhere in groovy scripts, freemarker templates and so on. So having context under context invites trouble. For example, if you look at ContextStack.java in the function getByString(String key) you will notice an important line:

if (includeContext && "context".equals(key)) return this;

There are trivial ways to fix this instead of fighting with the framework. For example, why not simply wrap with a map. Imagine something like { "data": { "context": ... } }, so you can have at a top level a “data” key holding all the information you want including “context”.

Pretty much many solutions, but the last thing I would do is touch and change core, critical framework code, which may introduce many more problems for you.

Thank you for your response.

Unfortunately, in our case, this API is used for callback requests, and the other party will not do any changes on their side.

However, while revisiting the MoquiConf options, I found that I can add a filter at the webapp:

<webapp-list>
    <webapp name="webroot">
        <filter name="" class="">
            <url-pattern></url-pattern>
        </filter>
    </webapp>
</webapp-list>

I created filter and I was able to intercept the incoming request and apply the required transformation (wrapping or renaming the parameter).
And I was able to get the same result as the changes I made in the WebFacadeImpl.

Yes that’s another good alternative and does the job nicely. Much less intrusive to core moqui APIs and does the job. Nice work on finding this fix.

1 Like