Written by

Senior Startups and Community Programs Manager at InterSystems Corporation
Question Evgeny Shvarov · Apr 7

How to convert persistent object to dynamic object

Hi devs!

Suppose I have an instance of a persistent class:

Set person = ##class(dc.Sample.Person).%OpenId(1)

Class is an ancestor of %JSON.Adapter.

How can I convert it to dynamic object with the properties that person.%JSONExport() provides?

{"Name":"Elon Mask","Title":"Associate Accountant","Company":"InterSystems","Phone":"799-933-5569","DOB":"1926-12-11"}

Couldn't find a right method. 

set dynObj = ##class(%ZEN.Auxiliary.altJSONProvider).%ObjectToAET(person) works, but adds id and classname, which I don't want to be added:

zw dynObj
dynObj={"_class":"dc.Sample.Person","_id":1,"Name":"Elon Mask","Title":"Associate Accountant","Company":"InterSystems","Phone":"799-933-5569","DOB":31390}  ;

Thoughts?

Product version: IRIS 2025.1

Comments

Dean White · Apr 7
set dynObj = {}.%FromJSON(Person.%ToJSON())
0
Evgeny Shvarov  Apr 7 to Dean White

Looks very promising, but doesn't work for me:

USER>set dynObj = {}.%FromJSON(person.%ToJSON())

SET dynObj = {}.%FromJSON(person.%ToJSON())
^
<METHOD DOES NOT EXIST> *%ToJSON,dc.Sample.Person
USER>

0
Robert Cemper · Apr 7

not just Sample.Person but also Sample.Address,
or whatever serial class you refer to require %JSON Adaptor.
then

set person=##class(Sample.Person).%OpenId(3)
>set sc=person.%JSONExportToString(.Jperson)
set zjson={}.%FromJSON(Jperson)
ZWRITE
Jperson="{"LIMIT":103,"Name":"O'Rielly,Xavier E.","SSN":"331-77-5308","DOB":"1957-05-26","Home":{"Street":"8757 Elm Place","City":"Miami","State":"FL","Zip":"92027"},"Office":{"Street":"413 First Drive","City":"Miami","State":"NH","Zip":"83830"},"Age":67,"RowVer":0}"
person=<OBJECT REFERENCE>[2@Sample.Person]
sc=1
zjson=<OBJECT REFERENCE>[13@%Library.DynamicObject]

and there is your dynamic object

0
Evgeny Shvarov  Apr 8 to Robert Cemper

Wow, @Robert Cemper ! Thank you as usual! 

But 3 lines. Could it be a one command by any chance? :)

I compete with the following:

/// Get JSON for a person with a given idClassMethod personsidGET(messageRequest As dc.Sample.v3rest.requests.personsidGET) As%Status

{

 Set person = ##class(dc.Sample.Person).%OpenId(messageRequest.pathid)

 set stream=##class(%Stream.TmpCharacter).%New() 

 d person.%JSONExportToStream(.stream)

 return stream

}

This works, but with an unnecessary "to stream, out of stream" exercise IMHO.

0
Robert Cemper  Apr 8 to Evgeny Shvarov

OK

To Stream needs 1 line 2 statements
 

ClassMethod personsidGET(messageRequest As dc.Sample.v3rest.requests.personsidGET) As%Stream.Object
{
 set stream=##class(%Stream.TmpCharacter).%New(),sc=##class(dc.Sample.Person).%OpenId(messageRequest.pathid).%JSONExportToStream(.stream)
 return stream
 }

To String is shorter (just 1 statement) as you don't need to initialize %String)

ClassMethod personsidGET(messageRequest As dc.Sample.v3rest.requests.personsidGET) As%Stringdo##class(dc.Sample.Person).%OpenId(messageRequest.pathid).%JSONExportToString(.string)
 return string
{
0
Evgeny Shvarov  Apr 8 to Robert Cemper

Yes. But you cannot return String in this method - either dynamic object, or Stream object.

BTW, I’d even expect this functionality over %JSON.Adapter, as there is an option to import (construct) persistent from dynamic in it:

Set person=##class(dc.Sample.Person).%New()

do person.%JSONImport(dynamicPerson)

But person.%JSONExport() does JSON string into device. Would be wonderful to have:

D person.%JSONExport(.dynobj)

0
Robert Cemper  Apr 18 to Evgeny Shvarov

That's a typical case,
where I write my personal ZZanyname  function  into %ZLANGF00.mac
to hide the details

0

According to the documentation, there is a parameter "pFormat" that has default value acelo, where:

  • c - output the ObjectScript-specific "_class" and "_id" properties

So, if you just call the transform like this, it should work:

set dynObj = ##class(%ZEN.Auxiliary.altJSONProvider).%ObjectToAET(person, , , "aelo")
0
Evgeny Shvarov  Apr 8 to Laura Blázquez García

Thank you so much, @Laura Blázquez García ! This is a great catch! 

This does the job! The only concern is that I'd love to see something like:

set dynObj=$System.JSON.Persistent2Dynamic(person)

Especially since VSCode highlights %Zen as a deprecated package. (Are there any plans? calling @Timothy Leavitt )

0
Mario Sanchez Macias  Apr 15 to Laura Blázquez García

So the one-line non-deprecated way would be: 

Set sc=person.%JSONExportToString(.json), dynObj = {}.%FromJSON(json)
    
    // or if we have long objectsSet sc=person.%JSONExportToStream(.json), dynObj = {}.%FromJSON(json)

But I agree it would be nicer to have just one command!, like the one that @Laura Blázquez García pointed out. 

0
David Hockenbroch · Apr 16

I know this has already been answered several ways, but let's not overlook embedded SQL as an option.

&sql(select JSON_OBJECT('Name':Name,'Title':Title,'Company':Company,'Phone':Phone, 'DOB':DOB) INTO :person WHERE ID = 1)
set personobj = {}.%FromJSON(person)

This can get a little unruly for tables with a lot of columns, but if you're wanting to pick out certain specific columns or customize the JSON field names, this approach gives you that flexibility.

0
Robert Cemper  Apr 18 to Vitaliy Serdtsev

which version ?

I tried and failed.
CLASS DOES NOT EXIST>%FromOref+8^%Library.DynamicObject.1 *%Library.EntityProjectionUtil
SAMPLES>w $zv
IRIS for Windows (x86-64) 2024.3 (Build 217U) Thu Nov 14 2024 17:59:58 EST

0
Vitaliy Serdtsev  Apr 18 to Robert Cemper

IRIS 2025.1.CE: the error is the same.

Why the %Library.EntityProjectionUtil class is missing in the system is a good question for developers.

0