Manage data types with %ZEN.proxyObject and Ens.Util.JSON.ObjectToJSONStream()

Hello,

I am trying to use %ZEN.proxyObject to send out in JSON format so I do:

    set tProxyRequest = ##class(%ZEN.proxyObject).%New()
    set tProxyRequest.notanumber = "28001"
    set tProxyRequest.aboolean = "true"
    
    set tBody = ##class(%GlobalCharacterStream).%New()
    do ##class(Ens.Util.JSON).ObjectToJSONStream(tProxyRequest,.tBody,"aelotwu")
    w tBody.Read()

and I get:

{
        "aboolean":"true",
        "notanumber":28001
}

But I want this:

{
        "aboolean":true,
        "notanumber":"28001"
}

 

Help please !

  • 0
  • 0
  • 617
  • 9
  • 0

Comments

It can be done in 2016.1 FT, see this post. To do it in older versions, inherit from system classes.

 

Alternatively you can define a persistent class with properties of required types and transform it into json.

 

P.S. As a hack: JSON consumer can sometimes accept 1/0 in place of true/false, so you can try to use this values.

What Eduard means is that you can create a registered class, with typed properties (a boolean and a numeric in your case), populate it and then transform to JSON using the jsonProvider.

That is the only valid approach to control JSON types in versions before 2016.1. Everything else is a hack.

Stefan. I used a registered class with typed properties and doesn't works frown

I made this test class:

Class test.DummyClass Extends %RegisteredObject
{

Property notanumber As %String;

Property aboolean As %Boolean;

Method outout2JSON()
{
    set tProxyRequest = ##class(%ZEN.proxyObject).%New()
    set tProxyRequest.notanumber = ..notanumber
    set tProxyRequest.aboolean = ..aboolean
    
    set tBody = ##class(%GlobalCharacterStream).%New()
    do ##class(Ens.Util.JSON).ObjectToJSONStream(tProxyRequest,.tBody,"aelotwu")
    w tBody.Read()
}

ClassMethod Test()
{
    set dummy = ##class(test.DummyClass).%New()
    set dummy.notanumber = "28001"
    set dummy.aboolean = 1
    do dummy.outout2JSON()
}

}

And this is the result sad:

USER>do ##class(test.DummyClass).Test()
{
        "aboolean":1,
        "notanumber":28001
}
USER>w $zv
Cache for Windows (x86-64) 2015.2.1 (Build 705U) Mon Aug 31 2015 16:45:59 EDT

 

What's wrong?

Thanks

I modified your code like this:

Class test.DummyClass Extends %RegisteredObject
{

Property notanumber As %String;

Property aboolean As %Boolean;

/// do ##class(test.DummyClass).Test()
ClassMethod Test()
{
    
    set dummy = ..%New()
    set dummy.notanumber = "28001"
    set dummy.aboolean = 1
    do ##class(%ZEN.Auxiliary.jsonProvider).%ObjectToJSON(dummy,,,"aelotw")
}
}

Terminal output:

>do ##class(test.DummyClass).Test()
{
        "notanumber":"28001",
        "aboolean":true
}

 

Thanks Eduard for posting the working solution. The reason why this works is that you actually create an object of your registered class and assign the values. The jsonProvider API can now walk the object and project the types properly.

In the non-working example, you created a zenProxyObject and assigned the values on your own. The zenProxyObject just deals with auto-types and guesses the best possible type fit. As you see, this guess can't be correct all the time as in this case.

If you want to create a JSON structure with specific types, either use a) the new JSON support in 2016.1 (recommended if 2016.1 is available) or b) create a subclass from %RegisteredObject and use the jsonProvider API.

PERFECT !!

I see now my mistake smiley

I fixed the code like this:

Class test.DummyClass Extends %RegisteredObject
{
Property notanumber As %String;
Property aboolean As %Boolean;
Method outout2JSON()
{
    set tBody = ##class(%GlobalCharacterStream).%New()
    do ##class(Ens.Util.JSON).ObjectToJSONStream(##this,.tBody,"aelotw")
    w tBody.Read()
}
ClassMethod Test()
{
    set dummy = ##class(test.DummyClass).%New()
    set dummy.notanumber = "28001"
    set dummy.aboolean = 1
    do dummy.outout2JSON()
}
}
 

And now:

USER>do ##class(test.DummyClass).Test()
{
        "notanumber":"28001",
        "aboolean":true
}

 

Small comment: use $this instead of ##this, even though they compile to the same thing.

But ... another problem...

What if a need to send a JSON object with properties with underscore characters like "not_a_number"?

Is because that I used %ZEN.proxyObject...

You can define quoted property names, e.g.:

Property "not_a_number" As %String;

same for runtime properties:

set object."not_a_number" = "28456"