Discussion
· Jul 8, 2020

%JSON.Adaptor with class that inherit from %ListOfObjects

I was trying the %JSON.Adapter backport to cache and try it also in IRIS and i found a kind of an issue regarding to export and object to json that is an inheritance of %ListOfObjects
If we have a list of elementtype of and object and then we try to export this to a json we get this json instead of a correct json.

exported json:

{
  "ElementType":"test.element",
  "Size":"1"
}

Json that we want:

[
  {
    "field1":"testField1",
    "field2":"testField2"
  }
]

Test classes:

Class test.elementList Extends (%ListOfObjects, %ZJSON.Adaptor)
{ 
 /// The type (class name) of the elements stored in the collection.
 Parameter ELEMENTTYPE = "test.element";
}
Class test.element Extends (%RegisteredObject, %ZJSON.Adaptor)
{ 
 Property field1 As %String [ InitialExpression = "testField1" ];
 Property field2 As %String [ InitialExpression = "testField2" ];
}

Class test.Main Extends %RegisteredObject
{ 
ClassMethod Run()
{
  Set elem = ##class(test.element).%New()
  Set elemList = ##class(test.elementList).%New()
  Do elemList.Insert(elem)
  Do elemList.%JSONExportToString(.json)
  Do ##class(%ZJSON.Formatter).%New().Format(json)
 } 
}

I could fix it overwritting the %JSONExportToString in the elementList class in order to loop over elements and so on...but can be possible to fix this in IRIS? or is there any other solution?

Thanks !

Discussion (3)0
Log in or sign up to continue

Just to verify if this is a %JSON specific problem I added also %XML.Adaptor to the classes.
And there is a similar problem: %ListOfObjects seems to be the bad guy. 

Do elemList.%JSONExport()
      {"ElementType":"Test.element","Size":1}
Do elemList.XMLExport()
     <elementList><ElementType>Test.element</ElementType><Size>1</Size></elementList>
zw elemList
elemList=2@Test.elementList  ; <OREF>
+----------------- general information ---------------
|      oref value: 2
|      class name: Test.elementList
| reference count: 2
+----------------- attribute values ------------------
|            Data(1) = ""
|        ElementType = "Test.element"
|            Oref(1) = "1@Test.element"
|               Size = 1  <Set>
+-----------------------------------------------------

With a small extension, you may get closer to your result.
What you expect is a JSON Array, but %JSONExport... works on data OBJECTS, not on data TYPES { same as XMLExport() }

So I have created a small wrapper object:

Class Test.javier Extends (%RegisteredObject, %JSON.Adaptor) 
{ Property wrap As Test.elementList(%JSONFIELDNAME = " "); }

extending Test.Main:

Class Test.Main Extends %RegisteredObject 
{ ClassMethod Run()  {
  Set elem = ##class(Test.element).%New()
  Set elemList = ##class(Test.elementList).%New()
  Do elemList.Insert(elem)
#; Do elemList.%JSONExportToString(.json)
#; Do ##class(%ZJSON.Formatter).%New().Format(json)
#;; extended
 set jav=##class(Test.javier).%New()
 set jav.wrap=elemList
 Do jav.%JSONExportToString(.json)

 set json=$e($p(json,":",2,*),1,*-1)  ;  a little bit dirty 
 Do ##class(%ZJSON.Formatter).%New().Format(json)
}

And here we go:

SAMPLES>do ##class(Test.Main).Run()
[
    {
      "field1":"testField1",
      "field2":"testField2"
    }
]
SAMPLES>

I don't know if i will prefer override the %JSONExportToString and %JSONExportToStream or  wrapping but that dirty trick..
 

Class test.elementList Extends (%ListOfObjects, %JSON.Adaptor)
{



/// The type (class name) of the elements stored in the collection.

Parameter ELEMENTTYPE = "test.element";



/// Returns this object as a JSON Stream
Method %JSONExportToStream(ByRef objStream As %Stream.Object, %mappingName As %String = "") As %Status
{

    #Dim objStream As %Stream.TmpCharacter = ##class(%Stream.TmpCharacter).%New()

    Do objStream.Write("[")

    For i=1:1:..Size
    {

        Do ..GetAt(i).%JSONExportToStream(.objStream, %mappingName)

        If (i<..Size)
        {

            Do objStream.Write(",")
        }
    }

    Do objStream.Write("]")

    Return $$$OK
}



/// Returns this object as a JSON string
Method %JSONExportToString(ByRef jsn As %String, %mappingName As %String = "") As %Status
{

    #Dim jsonElement As %String = ""

    Set jsn = "["

    For i=1:1:..Size
    {

        Set jsonElement = ""

        Do ..GetAt(i).%JSONExportToString(.jsonElement, %mappingName)

        Set jsn = jsn_jsonElement

        If (i<..Size)
        {
            Set jsn = jsn_","
        }
    }

    Set jsn = jsn_"]"

    Return $$$OK
}

}