Article
· Aug 14, 2023 8m read

Working with %JSON.Adaptor

In this article,  I walk through the %JSON.Adaptor class. This class is extremely useful in exporting data into serialized JSON and importing the JSON objects and saves into class object.

I'll start with the %JSON. Adaptor parameters. The parameters are crucial part of the JSON import and export operations.

If your property name is not the same as the actual JSON key name for export to external or load the data’s into object through import, you should use the %JSONFIELDNAME parameter to define the alias name. If it doesn't, it produces an 'unexpected field' in the input error at the time of import.

Class Samples.TestJSONAdaptor Extends (%Persistent, %JSON.Adaptor)
{
    Property Name As %String(%JSONFIELDNAME = "First_Name");
ClassMethod ExportToJSON()
{
    Set obj = ##class(Samples.TestJSONAdaptor).%OpenId(1)
    Do obj.%JSONExport() 
}
}
Output
LEARNING>Do ##class(Samples.TestJSONAdaptor).ExportToJSON()
{"First_Name":"myFirstName"}

In certain situations, you may not want to expose or skip certain properties and internal keyword defined properties (Note: Property will expose in JSON even though if it’s defined as an internal keyword) in the JSON output. In order to prevent the field from being exposed to the outside world, you could mention this parameter %JSONINCLUDE
. Default value is INOUT

    1. INPUTONLY - It will only accept input and not export data to the outside world.
    2. OUTPUTONLY - It shows the values in the outside world. However, Null values can only be stored if this parameter was mentioned to this property. Be cautious when utilizing this parameter.
    3. NONE - JSON output or input should never be stored and retrieved.
Class Samples.TestJSONAdaptor Extends (%Persistent, %JSON.Adaptor)
{
    Property Name As %String(%JSONFIELDNAME = "First_Name");
    Property Phone As %Integer(%JSONINCLUDE = "INPUTONLY");
    Property IsActive As %Boolean(%JSONINCLUDE = "OUTPUTONLY");
ClassMethod ExportToJSON()
{
    #; JSON Export ouput
    Set obj = ##class(Samples.TestJSONAdaptor).%OpenId(1)
    Do obj.%JSONExport() 
    #; output >> {"First_Name":"myFirstName","IsActive":true}
    #; Object ouput
    Write obj.Phone 
    #; output >> 9639639636
}

Output
LEARNING>Do ##class(Samples.TestJSONAdaptor).ExportToJSON()
 {"First_Name":"myFirstName","IsActive":true} 
9639639636

Generally, the instance doesn't have any values in the properties that are not part of the JSON export. In order to include those properties in JSON export, it is necessary to include the %JSONNULL parameter. The output will have the default value of null. Furthermore, you could define this parameter option globally within your specific class definition instead of a specific field.  This will be applicable to all fields.

Class Samples.TestJSONAdaptor Extends (%Persistent, %JSON.Adaptor)
{

    Property Name As %String(%JSONFIELDNAME = "First_Name");
    Property Phone As %Integer(%JSONINCLUDE = "INPUTONLY");
    Property IsActive As %Boolean(%JSONINCLUDE = "OUTPUTONLY");
    /// This field is available in JSON export
    Property JSONNULLDeclared As %String(%JSONNULL = 1);
    /// This field is not available in JSON export
    Property JSONNULLNotDeclared As %String;
ClassMethod ExportToJSON()
{
    #; JSON Export 
    #; JSONNULLDeclared and JSONNULLDeclared - values are empty in object
    Set obj = ##class(Samples.TestJSONAdaptor).%OpenId(1)
    Do obj.%JSONExport() 
    #; output >> {"First_Name":myFirstName"","IsActive":true,"JSONNULLDeclared":null}
}
}
Output
LEARNING>Do ##class(Samples.TestJSONAdaptor).ExportToJSON()
{"First_Name":myFirstName"","IsActive":true,"JSONNULLDeclared":null}

 Basically, empty strings in the JSON input are stored as $c(0). If there are objects script "" values in the property, they won't be displayed in the JSON because %JSONIGNORENULL. Verify that the empty string conditions are met and export the data by enabling the %JSONIGNORENULL = 1. Furthermore, you could define and utilize this parameter option globally.

Class Samples.TestJSONAdaptor Extends (%Persistent, %JSON.Adaptor)
{

    Parameter %JSONNULL = 1; ///declared globally
    Property Name As %String(%JSONFIELDNAME = "First_Name");
    Property Phone As %Integer(%JSONINCLUDE = "INPUTONLY");
    Property IsActive As %Boolean(%JSONINCLUDE = "OUTPUTONLY");
    Property JSONNULLDeclared As %String(%JSONNULL = 1);
    Property JSONNULLNotDeclared As %String(%JSONIGNORENULL = 1);
ClassMethod ExportToJSON()
{
    Set obj = ##class(Samples.TestJSONAdaptor).%OpenId(1)
    Do obj.%JSONExport() 
}
}
Output
LEARNING>Do ##class(Samples.TestJSONAdaptor).ExportToJSON()
{"First_Name":"myFirstName","IsActive":true,"JSONNULLDeclared":null,"JSONNULLDeclared":null,"JSONNULLNotDeclared":""}

A lot of reference persistent or serial classes are linked in a class definition. So if you're exporting the class into JSON, it exports all the reference class fields as well into the JSON. If you prefer to export only ids instead of the entire value, you can use %JSONREFERENCE.

Class Samples.TestJSONAdaptor Extends (%Persistent, %JSON.Adaptor)
{

    Parameter %JSONNULL = 1;
    Property Name As %String(%JSONFIELDNAME = "First_Name");
    Property Phone As %Integer(%JSONINCLUDE = "INPUTONLY");
    Property IsActive As %Boolean(%JSONINCLUDE = "OUTPUTONLY");
    Property JSONNULLDeclared As %String(%JSONNULL = 1);
    Property JSONNULLNotDeclared As %String(%JSONIGNORENULL = 1);
    Property SubClass As Samples.TestJSONAdaptor.SubClass(%JSONREFERENCE = "ID");
ClassMethod ExportToJSON()
{
    #; JSON Export 
    Set obj = ##class(Samples.TestJSONAdaptor).%OpenId(1)
    Do obj.%JSONExport() 
}
}

output
LEARNING>d ##class(Samples.TestJSONAdaptor).ExportToJSON()
   {"First_Name":"Ashok","IsActive":true,"JSONNULLDeclared":null,"JSONNULLNotDeclared":"","SubClass":{"RefId":"a3295","TestProperty":"Test1"}} ; %JSONREFERENCE = "OBJECT"
LEARNING>d ##class(Samples.TestJSONAdaptor).ExportToJSON()
    {"First_Name":"myFirstName","IsActive":true,"JSONNULLDeclared":null,"JSONNULLDeclared":null,"JSONNULLNotDeclared":"","SubClass":"a321"} ; %JSONREFERENCE = "ID"

One of the most crucial parameters. When you load the JSON object into a class object, there may be a change that causes unexpected fields to be added to the JSON. An error is thrown if the parameter %JSONIGNOREINVALIDFIELD is not added. Enabling this parameter in your class definition is highly beneficial.

///Before enabling %JSONIGNOREINVALIDFIELD
Class Samples.TestJSONAdaptor1 Extends (%Persistent, %JSON.Adaptor)
{
    Property Name As %String(%JSONFIELDNAME = "First_Name");
    Property IsActive As %Boolean;
ClassMethod TestJSONImport()
{
    Set json = {"Name":"MytestNewName","IsActive":true}
    Set obj = ..%New()
    Set st = obj.%JSONImport(json)
    If $$$ISERR(st) w $SYSTEM.OBJ.DisplayError(st)
    Write obj.%Save()
}
}
output
LEARNING>Do ##class(Samples.TestJSONAdaptor1).TestJSONImport()
 
ERROR #9404: Unexpected field in input, Name, using class base mapping.11{"First_Name":null}
LEARNING>

///After enabling %JSONIGNOREINVALIDFIELD
Class Samples.TestJSONAdaptor1 Extends (%Persistent, %JSON.Adaptor)
{
    Parameter %JSONIGNOREINVALIDFIELD As BOOLEAN = 1;
    Property Name As %String(%JSONFIELDNAME = "First_Name");
    Property IsActive As %Boolean;
ClassMethod TestJSONImport()
{
    Set json = {"Name":"MytestNewName", "Phone":9639631236, "IsActive":true, "unspecified":"" }
    Set obj = ..%New()
    Set st = obj.%JSONImport(json)
    If $$$ISERR(st) w $SYSTEM.OBJ.DisplayError(st)
    Write "Save : ",obj.%Save(),!
    Do obj.%JSONExport()
}
}
LEARNING>Do ##class(Samples.TestJSONAdaptor).TestJSONImport()
Save : 1
{"First_Name":null,"IsActive":null,"JSONNULLDeclared":null,"JSONNULLNotDeclared":"","SubClass":null,"GblCharStrm":null,"GblBinStrm":null,"Decimal":null}
 

 

In addition, Some of the rarely used parameter is '%JSONENABLED. If you don’t want to generate the JSON, Adaptor-class method generators do not produce a runnable method. Set the parameter to 0. Unless otherwise specified, the default value is 1.

Native API methods for JSON adaptor

%JSONImport

This is actual method to importing the JSON object into the current class object. This method is verifying all the properties data type with the JSON key-value data type and declare the value to the property. You can refer the above sample codes for JSON import.

  • Remember that the JSON data type must be the same as the property data type when importing data. Otherwise it will throw and error
  • Boolean data type values 0 or 1 not same as JSON data type Boolean true or false. So, JSON must have true/false instead of 0 or 1
  • Always Use JSONFIELDNAME or XDataMapping block to avoid unexpected field mismatch error.
  • Better to use %JSONIGNOREINVALIDFIELD parameter to avoid unexpected field error.

%JSONExport

A typical method for writing the serialized JSON to the current device. Whenever you’re exporting and importing the floating point number with trailing zeros those are not part of the JSON output. Because The ObjectScript Decimal and the IEEE Binary numeric types do not keep track of trailing zeroes. you can refer the above sample codes for JSON Export.

%JSONExportToStream

Additional export options are available in %JSON.Adaptor. You can export your JSON as a stream object, using %JSONExportToStream.

ClassMethod TestEXportToStream()
{
    Set obj = ##class(Samples.TestJSONAdaptor).%OpenId(12)
    Do obj.%JSONExportToStream(.stream) 
    Write stream,!
    If $IsObject(stream) {
        Write stream.Read($$$MaxLocalLength)
    }
    Return
}

Output
EARNING>d ##class(Samples.TestJSONAdaptor).TestEXportToStream()
3@%Library.FileCharacterStream
{"First_Name":"TestNameSetMethod","IsActive":true,"JSONNULLDeclared":null,"JSONNULLNotDeclared":"","SubClass":"a3256","GblCharStrm":"Test string added as the global character stream","Decimal":12}

%JSONExportToString 

You can export the JSON object as a string by using %JSONExportToString method.

ClassMethod TestEXportToString()
{
    Set obj = ##class(Samples.TestJSONAdaptor).%OpenId(12)
    Do obj.%JSONExportToString(.string) 
    Write string
    Return
}
output
LEARNING>d ##class(Samples.TestJSONAdaptor).TestEXportToString()
{"First_Name":"TestSetMethod","IsActive":true,"JSONNULLDeclared":null,"JSONNULLNotDeclared":"","SubClass":"a3256","GblCharStrm":"Test string added as the global character stream","Decimal":12}
Discussion (2)1
Log in or sign up to continue