Sergio Martinez · Aug 6, 2019

Preserving default value of a method parameter when passing a non existing property of a JSON object


I have a method that has multiple parameters and is normally used from other classes in ObjectScript. Most of the parameters have default values. Withing the server code that's perfect. In some areas I can call myMethod(,,"sometext") or myMethod(tVariab) and thats fine... I use it as it's required in each place.

But now I want to expose it as a REST service so I need to buld a kind of wrapper., another method in a REST dispatcher class that will receive the parameters in a JSON object and will call the server method already implemented. Something like:

{"par1":1111, "par2":"sample text", "par3":0}

that is transformed to a tJSON %DynamicObject that later will be used to call the method: myMethod(tJSON.par1,tJSON.par2,tJSON.par3) ... so far so good.

BUT, I hoped that it would be posible to receive:

{"par1:2222} and then run myMethod(tJSON.par1,tJSON.par2,tJSON.par3)... and, as par2 and par3 really don't exist this time, I expected myMethod assume default values for par2 and par3 parameters. But, in the end, IRIS assumes that I'm passing "" in those positions as if call statement was: myMethod(2222,"","") instead of myMethod(2222).

I want to avoid to implement in the wrapper all possible combinations of input parameters... which would be the best approach?

3 0 3 282
Log in or sign up to continue

Hi Sergio,

I have the following code that will do what you need, but i don't see this as the best approach since it is more complicated than a bunch of If's. 

But it works, and it shows that you do anything in ObjectScript!

Class MyPackage.MyClass

ClassMethod MyMethod(p1 = 1, p2 = 2, p3 = 3)
Write p1,"-",p2,"-",p3,!

ClassMethod Test()
Do ..FromJson({})
Do ..FromJson({"P1":"first value""P2":"second value"})
Do ..FromJson({"P1":"first value""P3":"third value"})
Do ..FromJson({"P2":"second value"})

ClassMethod FromJson(json)
Set call="(json) Do ##class(MyPackage.MyClass).MyMethod("  //we need to pass json as input param to xecute
Set first = 1
For jsonProp = "P1","P2","P3" {
If 'first Set call=call_","
//Set call=call_$Select(json.%IsDefined(jsonProp):"json."_jsonProp,1:"") //same as $Property, but doc mentions to use $Property instead
Set call=call_$Select(json.%IsDefined(jsonProp):"$Property(json,"""_jsonProp_""")",1:"")
Set first = 0
Set call=call_")"
Xecute (call,json) //pass json as input parameter


Here's a way without indirection:

Class MyPackage.MyClass

ClassMethod MyMethod(p1 = 1, p2 = 2, p3 = 3)
    Write p1,"-",p2,"-",p3,!

/// do ##class(MyPackage.MyClass).Test()
ClassMethod Test()
    Do ..FromJson({})
    Do ..FromJson({"p1":"first value", "p2":"second value"})
    Do ..FromJson({"p1":"first value", "p3":"third value"})
    Do ..FromJson({"p2":"second value"})

/// do ##class(MyPackage.MyClass).ArgPosMapping("MyPackage.MyClass", "MyMethod")
ClassMethod ArgPosMapping(class, method, Output map)
    kill map
    set formalspec = $$$comMemberKeyGet(class,$$$cCLASSmethod,method,$$$cMETHformalspecparsed)
    for i=1:1:$ll(formalspec) {
        set arg = $lg(formalspec, i)
        set map($lg(arg, 1)) =  i
    set map = $ll(formalspec)

ClassMethod FromJson(json)
    Do ..ArgPosMapping($classname(), "MyMethod", .map)
    Set iterator = json.%GetIterator()
    Set position = 0
    While iterator.%GetNext(.key, .value) {
        Set position = position + 1
        Set arguments(map(key)) = value
    Set arguments = map

    Do ..MyMethod(arguments...)


You're running into the fact that calling %Get on a dynamic object doesn't return an undefined when data at the index you specify doesn't exist.  Instead, it returns "".

Both the answers you have here are great if you need a generalized solution.  If all you're looking for is a simple work around in a non-general case, all you need to do is check if your %Get returned "",  and if so, kill the value before you pass it in:

ClassMethod passIncompleteJSON()
  set json = ["arg1 val", "arg2 val"]
  set arg1 = json.%Get(0)
  kill:(arg1="") arg1
  set arg2 = json.%Get(1)
  kill:(arg2="") arg2
  set arg3 = json.%Get(2)
  kill:(arg3="") arg3
  write ..threeArgs(.arg1, .arg2, .arg3)

ClassMethod threeArgs(a, b, c)
  set:($get(c)="") c = "default"
  return a_"."_b_"."_c

Just be sure to pass in the parameters by reference since you're going to be passing in undefined variables.

(This does remove the distinction between undefined and "" though; you wouldn't be able to intentionally pass "" with this solution)