Recent posts:
Recent replies:

Standard class object properties have a limited string length but a property can contain a %Stream.GlobalCharacter oref which %JSON.Adaptor can export as a JSON string.

Another option is to create a %DynamicObject (%Library.DynamicObject) class object or a %DynamicArray (%Library.DynamicArray) class object instead of using a subclass of %JSON.Adaptor.  You can create a %DynamicObject/%DynamicArray is ObjectScript by using a JSON object/array literal as an ObjectScript literal.  The %FromJSON class method will create a %DynamicObject/%DynamicArray by importing JSON from a %Stream, file or device and the %ToJSON class method will export a %DynamicObject/%DynamicArray to a %Stream, file or device.

On IRIS, the %Set and %Get methods in %DynamicObject-s/%DynamicArray-s have been extended to take type keywords of the form "stream", "stream>base64", "stream<base64" which can transfer %DynamicObject string elements between unlimited length %Stream-s and include the ability to encode or decode Base64 during the transfer.  There are also type key words "string", "string>base64", "string<base64" which can set/get ObjectScript string values into/from %DynamicObject elements but ObjectScript strings are currently limited to a length of 3,641,144 characters.

So on IRIS you can do something like:
   Set DynObj = {"ID":23, "Name":"John Doe", "BirthDay":"1974-12-15"}
   Do DynObj.%Set("DataFile",DataOref,"stream>base64")
   Do DynObj.%ToJSON(OutputOref)
where DataOref is a class reference to a %Stream.FileBinary referencing the binary file containing data related to John Doe and where OutputOref is a %Stream.FileCharacter referencing the file that will contain JSON text.

Although the replies have already answered the question about creating JSON on Caché, I would look to add some discussion about additional features that support the %Library.DynamicArray and %Library.DynamicObject classes.  I am running my examples on IRIS Version 2020.2 (Build 199U) so a few of the features will not be available in older Caché versions.

You asked how does a programmer generate the following JSON:  { "MyProperty":"1"}.  If you are writing an ObjectScript program then just execute the statement:

SET x = { "MyProperty":"1"}

Whenever an ObjectScript expression contains language syntax which is enclosed either in nested curly brackets, { ... }, or in nested square brackets, [ ... ], then the ObjectScript compiler  will parse the contents of the bracketed expression using the rules for a JSON object or a JSON array respectively.  The strings and numbers and identifiers inside the bracketed syntax will be JSON literal values with one exception.  If a value inside the bracketed expression is enclosed in round parentheses, ( ... ) then the contents of the parenthesized value will have the syntax of an ObjectScript expression which will be evaluated at run time.

The %DynamicArray and %DynamicObject class objects can contain property values using JSON syntax for their representation as well as containing property values which are ObjectScript values.  Details of all the methods that can be applied to a %DynamicArray/%DynamicObject class object can be found in Class Reference web pages for the %Libraray.DynamicArray, %Library.DynamicObject and %Library.DynamicAbstractObject classes.

When you use the %ToJSON( ) method on a %DynamicArray/%DynamicObject then all the properties containing ObjectScript values will be translated to the appropriate JSON literal representation.  Certain ObjectScript values, such as an oref or $DOUBLE("NaN"), do not have a JSON representation and their occurrence will cause %ToJSON to generate an <ILLEGAL VALUE> signal.  When you use  the %Get(key) method to evaluate a property containing JSON representation then that JSON representation will first be converted into an ObjectScript value.  When you use the %Set(key,value) to modify a property then value is computed as a run-time ObjectScript expression and that ObjectScript computation becomes the value of the property.

The %Get(key,default,type) method call has two optional parameters.  The value of the default argument is returned (without any type conversions) if there is no property with the specified key argument.  If there is no default argument then an unassigned key argument will return the ObjectScript empty string.  The type argument contains a string that specifies what type conversion should be applied to the element with the specified key.  An empty string type argument or a missing type argument does the normal default conversion to ObjectScript.  The %Set(key,value,type) takes an optional type argument which is a string which specifies how the ObjectScript value argument is converted to a property element.  Th supported type arguments have changed over time so check the Class Reference web pages for documentation on what the possible type strings mean.


USER>set x=["0.1230",12.30E-2,(.12300),("0.1230")]   ;; JSON string, JSON number, ObjScr number, ObjScr string              

USER>write x.%ToJSON()                                             
["0.1230",12.30E-2,0.123,"0.1230"]  ;; Everything converts to JSON representation (strings are the same)

USER>write x.%Get(0),",",x.%Get(1),",",x.%Get(2),",",x.%Get(3),","  ;; Everything converts to ObjectScript

;; Newly added "json" type argument.
;; The 6-char string 0.1230 becomes 8 chars with leading/trailing double-quotes in JSON literal representation
;; The JSON number is not changed
;; The ObjectScript number picks up the leading zero required by JSON representation
USER>write x.%Get(0,,"json"),",",x.%Get(1,,"json"),",",x.%Get(2,,"json"),","
USER>set y=["null",null,""]    ;; JSON 4-char string null, JSON null value, JSON empty string                                    

USER>write y.%ToJSON( )   ;; JSON array printed as a %String                          
USER>write y.%Get(0),",",y.%Get(1),",",y.%Get(2),",",y.%Get(3),","   ;; Convert to ObjectScript 4 elements of 3-element array      
null,,,,  ;; Note that null, "" and unassigned all convert to empty string in ObjectScript
USER>write y.%Get(0,,"json"),",",y.%Get(1,,"json"),",",y.%Get(2,,"json"),",",y.%Get(3,,"json"),","  ;; Convert 4 elements to JSON
;; Note: 4-char string null now is 6 chars with 2 "-chars, null identifier, empty string with only 2 "-chars,
;; and ObjectScript default null string for unassigned value (there is no legal JSON representation)

Unfortunately %Set does not yet support the "json" type argument but maybe that will happen in a future IRIS release.

There are actually two (maybe more) levels of ObjectScript.  There is basic ObjectScript, which is an very extended version of the ANSI M language.  [ footnote [ANSI M is the successor of the ANSI MUMPS language and that language, without the large number of extensions supported by basic ObjectScript, could be considered to be a third language level although no modern programmer would restrict their code to this much older language definition.] ]  And there is the Class Language ObjectScript, which includes things like type-name classes:  %Library.String (can be abbreviated %String), %Library.Integer (can be abbreviated %Integer), etc.  It also includes Class Methods (with syntax like ##class(Class.Name).ClassMethodName(arg1,arg2)) and there are Object Methods (which look like oref.ObjectMethodName(arg1,arg2), where oref must contains an extended ObjectScript object reference) and there are Object Properties (which look like oref.PropName, where oref must contain an extended ObjectScript object reference.)

An example of a basic ObjectScript statement is SET var1=42,var2="42"  Almost every operation in basic ObjectScript thinks var1 and var2 contain identical values.  So the string equality operation var1=var2 returns 1 because var1 is converted to a string and "42" equals "42".  The numeric comparison operations var1<var2 and var1'<var2 return 0 and 1 because var2 is converted to a numeric and 42<42 is false while 42'<42 is true.  We could also evaluate var1+var2 and the result will be 84 (or is that result "84"--who can tell?).

In Class Language ObjectScript you can declare
          property LimitedInt : %Integer(MAXVAL=10);
and if you (directly or indirectly) call the %ValidateObject() method on a class object containing the property LimitedInt then the contents of LimitedInt may be checked to make sure they look like an integer with a value not greater than 10.  However, only Class Language methods like %SerializeObject, %ValidatObject, %Save, etc. make these checks on the value of LimitedInt.  If someone executes
          SET oref.LimitedInt=20.95
in basic ObjectScript, the basic ObjectScript execution will not signal an error despite the fact that 20.95 is larger than the MAXVAL and despite the fact that 20.95 is NOT a %Integer.  Only executing an appropriate Class Language method will detect that oref.LimitedInt does not contain a valid value.  The purpose of %Library.DataType subclasses is to make it possible that a %Save() method does not save invalid property values into a data base.

Certain ObjectScript conversions may change an ObjectScript value.  This can happen when changing a well-formed numeric string to be a decimal number because the decimal arithmetic implemented in ObjectScript mathematics supports no more than 19 decimal digits of precision.  Consider,

USER>set a="12345678901234567890123",b="12345678901234567890124",c="123456789012345678901230"
USER>write b>a," ",a>b," ",+a," ",+b
0 0 12345678901234567890000 12345678901234567890000

Because the > and < operators are arithmetic-comparison operators the string operands are converted to a numeric value with only 19 significant digits of precision and the resulting numeric values for a and b end up being equal so neither b>a nor a>b are true.  However, the sorts-after operator, ]], orders the canonical numeric strings before any non-empty string that does not have canonical numeric syntax.  The canonical numeric strings are sorted in numeric order while strings that do not have canonical numeric syntax are sorted in textual string order.  This is also the default rule for ordering subscript values in ObjectScript.  Operands of ]] are converted to strings before doing  this subscript ordering.  The values a, b and c are all canonical numeric strings and ObjectScript is perfectly capable of doing the sorts-after string comparisons on very long canonical numeric strings.  Consider,

USER>write a]]b," ",b]]a," ",b]]c," ",c]]b
0 1 0 1

Now a and b are both canonical numeric strings with 23 digits and their first 22 digits are equal but the b has a 23rd digit larger than the 23rd digit of a, so b sorts-after a.  But b does not sorts-after c because c has more significant digits so the canonical numeric value of c is greater than the canonical numeric value of b.

The basic ObjectScript language has a very small class of built-in types.

(1) There are the ObjectScript string values, which include the subclass of canonical numeric strings.

(2) There are the default decimal floating-point values which do not have more 19 digits of decimal precision (and may sometimes have less than 19 digits of precision because the implemented accuracy of ObjectScript decimal arithmetic operations is approximately 18.96 decimal digits.)  Every decimal floating-point value can be converted exactly to a canonical numeric string (but canonical numeric string values with more than 18 digit characters cannot always be converted exactly to a decimal floating-point numeric result but must instead be a decimal numeric value that is an approximation.

(3) Basic ObjectScript supports a third set of "$DOUBLE values" which contains the *binary* floating-point values specified by the IEEE 64-bit binary floating-type type.  The 64-bit binary floating-point arithmetic specified by the IEEE standard has approximately 15.95 decimal digits of precision but since the representation is binary, and not decimal, an exact conversion of a 64-bit IEEE binary floating-point value to a decimal string can have over 1000 digits.  Now every $DOUBLE binary floating-point value could be exactly converted to a canonical numeric string but it is not reasonable to have such a conversion produce such long strings.  The default conversion of a $DOUBLE value to a canonical numeric string will have no more than 20 significant digits, and the approximated 20th significant digit will never be a 5 or 0 (unless that 20th digit results in an exact conversion.)  Using a default canonical numeric string with 20 significant digits for $DOUBLE conversions means the ]], sorts-after, operator will correctly order a $DOUBLE binary floating-point value in-between the adjacent 19-digit decimal floating-point values of the ObjetScript default decimal numeric type.

(4) There are also the oref values which are the basic ObjectScript values created by Class Language ObjectScript.  Basic ObjectScript can do property evaluation, property assignment and method calls using the basic ObjectScript oref type.  Basic ObjectScript can convert oref values to the ObjectScript string type and the ObjectScript decimal arithmetic type but neither of these conversions is particularly useful unless you are debugging.

Steven has no followers yet.
Steven has not followed anybody yet.
Global Masters badges:
Steven has no Global Masters badges yet.