Preserving default value of a method parameter when passing a non existing property of a JSON object
Hi,
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?
Comments
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!
{
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)