JsonBuilder can be used to construct JSON objects, serialize as JSON string etc. A call() method is executed depending on the type of parameter used, and the results vary accordingly, which can be better demonstrated using examples.

import groovy.json.JsonBuilder
 
long userId = 12
def json = new JsonBuilder()
def result = json {   // args as block
    userId userId
}
json.toString()       // produces error
groovy.lang.MissingMethodException: No signature of method: java.lang.Integer.call() is applicable for argument types: (java.lang.Integer) values: [12] Possible solutions: wait(), any(), abs(), wait(long), wait(long, int), and(java.lang.Number)

The above example does not work even if the key is given as a string. Using a map as the argument to the call() method of the JsonBuilder class gives us the correct result. As we can see the above method uses a block, which can be used if the name of keys are different from any variable names in the scope.

long userId = 12
long abc = 123
long z = 987
def json = new JsonBuilder()
json userId: userId,   // args as map
     abc: abc,
     z: z
json.toString()        // {"userId":12,"abc",123,"z": 987}

It is better to use as a map instead of a block (closure), which gives the intended result in most of the cases.

In JavaScript it is pretty straight forward.

var a = 1
JSON.stringify({a: a})    // "{"a": 1}"

Below are examples where key contains the value in the variable.

// Groovy
json "${userId}": userId, z: z
json.toString()    // {"12":12,"z",987}
// JavaScript
var a = 1, j = {}
j[a] = a
JSON.stringify(a)    // "{"1":1}"