The latest version of IRIS will have improved %DynamicObject (and the %DynamicArray) class objects.  They will support a method call like obj.%Get(key,,”stream”) which will return a %Stream.DynamicCharacter oref and this %Stream can contain a very large number of characters.  This can be copied into a %Stream.GlobalCharacter or a %Stream.FileCharacter if you want to save those characters in a persistent object.

This new form of %Get will also be able to include encoding/decoding using Base64 representation.  Similar extensions have been added to the %Set method.

The JSON classes in Ens.Util.JSON,  %ZEN.Auxiliary.json* and %JSON.* all contain methods that convert JSON representation to/from ObjectScript classes.  Once you have an ordinary ObjectScript Class then you are using ObjectScript data types for Property values.  The JSON null is usually converted to "" (null string).  Also, ordinary Property variables of an ObjectScript Class are never undefined but are automatically initialized to "" (the null string).  [[ An exception is [MULTIDIMENSIONAL] Properties which can be undefined but by default such Property variables do not participate in %Save() and JSON/XML export/import operations. ]]  SQL operations involving Class properties treat "" (the null string) as the SQL NULL value and SQL assumes a Class Property containing the ObjectScript string $C(0) is the empty string.

[[ Although the original question involved Caché and not IRIS, IRIS has signifcantly more complete support for the %DynamicAbstractObject classes so my examples will use IRIS.  If possible, I recommend upgrading to IRIS. ]]

There is the class %Library.DynamicAbstractObject and its subclasses %DynamicArray and %DynamicObject that can contain elements which can either be JSON values or ObjectScript values.  The ObjectScript statement:

USER>SET x={"a":null,"b":"","e":1.0,"f":"1.0","g":(00.1),"h":($c(0))}

makes x be a %DynamicObject oref where element a is a JSON null and where element "g" is the ObjectScript number .1 and element "h" is the ObjectScript string $c(0).  Note that if an ObjectScript expression is a %DynamicObject constructor then ObjectScript parses the elements of that constructor using JSON syntax except for the extension to constructor syntax where an element inside round parentheses is parsed as an ObjectScript run-time expression generating an ObjectScript value.

You can convert a %DynamicObject to JSON string representation and any ObjectScript valued element will be converted to JSON representation.

[[ Note that JSON does not support certain ObjectScript values: $double("NAN"), $double("INFINITY") and orefs that are not a subclass of %DynamicAbstractObject.  A %DynamicAbstractObject containing such an ObjectScript element cannot be converted to JSON. ]]

USER>WRITE x.%ToJSON()
{"a":null,"b":"","e":1.0,"f":"1.0","g":0.1,"h":"\u0000"}

Evaluating a %DynamicObject element in an ObjectScript expression converts that element to an ObjectScript value.

USER>ZWRITE x.a, x.b, x.c, x.e, x.f, x.g, x.h
""
""
""
1
"1.0"
.1
$c(0)

Notice that the undefined element x.c is converted to the ObjectScript null string.  You never get an error evaluating x.%Get(key) for any value of the expression key as every undefined element in a %DynamicObject has the value of the null string.  Also, x.a, which contains a JSON null, is converted to the ObjectScript null string.  The JSON treatment of undefined elements and the ObjectScript treatment of undefined Properties means that when we convert an ordinary ObjectScript class to either XML or JSON then we can skip converting a Property with the null string value as converting JSON or XML back to an ordinary class object will result in all unrepresented properties getting the value of the null string.

If you need to know if a %DynamicObject element is JSON null, null string or undefined then evaluating the %GetTypeOf(key) will tell you that.

USER>ZWRITE x.%GetTypeOf("a"),x.%GetTypeOf("b"),x.%GetTypeOf("c"),x.%GetTypeOf("e")
"null"
"string"
"unassigned"
"number"

The %FromJSON(stream)/%ToJSON(stream) methods will let you read/write JSON representation from/to a %Stream.

[[ Things that only work in IRIS follows. ]]

The size of the %DynamicArray/%DynamicObject class objects is limited only by the amount of memory available to your process.  A string valued %DynamicObject element can be significantly longer than the maximum length supported by ObjectScript string values.  If you have such a long string element then you will have convert that element to an ObjectScript %Stream in order to manipulate it in ObjectScript.

USER>SET stream=x.%Get(key,,"stream")  ;; Note 3 arguments with 2nd argument missing

will generate an in-memory, readonly %Stream that can be copied to a Global or File %Stream or can be examined by reading that string in small pieces.

In recent IRIS releases you can do

USER>SET binarystream=x.%Get(key,,"stream<base64")

which will convert a base64 encoded element into a readonly binary %Stream.  You can do the reverse conversion by evaluating x.%Set(key,binarystream,"stream>base64").  See the the Class Reference documentation pages for the %Library.%DyanmicAbstractObject class and its %DynamicArray and %DynamicObject subclasses for more details.

By the looks of it, the original question applied $DATA to an element of the %DynamicAbstractObject classes.  The $DATA and $GET functions can only be applied to Multidimensional variables.  All ObjectScript local and global variables are Multidimensional.  By default a property variable of a class object is not multidimensional unless the property default is over ridden with the [ Multidimensional ] attribute.  The %DynamicAbstractObject classes provide no way of supporting elements which are Multidimensional.  If dynobj is an object reference to a %DynamicObject then dynobj.%Get(key) is defined for all possible string values of 'key'.  If dynobj.%GetTypeOf(key) returns "unassigned", or "null", then dynobj.%Get(key) will return the empty string value.

Currently, $DATA(dynobj.keyname) signals <PROPERTY DOES NOT EXIST> which is what is signaled for by all classes if the Property 'keyname' does not exist.  In a future IRIS release it will report

<INVALID CLASS> *Class '%Library.DynamicObject' does not support MultiDimensional operations

The correct way to see if keyname "test" exists in a %DynamicObject is to evaluate (dynobj.%GetTypeOf("test") '= "undefined") .

You are using a 5 year old version of Ensemble that is using an experimental release of JSON support with classes named %Library.AbstractObject, %Library.Object and %Library.Array.  When you upgrade to any version after 2016.1 you will find the JSON support classes are now named %Library.DynamicAbstractObject, %Library.DynamicObject and %Library.DynamicArray.  All of the method names will change because support for system methods with names that start with $ has been removed.  Method names like  $getIterator, $fromJSON and $getNext will become %GetIterator, %FromJSON and %GetNext.  Other than the extensive name changes, most of features of the experimental JSON classes has remained unchanged.

There are additional new features added during future releases. For example, the ObjectScript language will accept JSON object and array constructor syntax as part of the ObjectScript expression syntax.  If an element which is part of an object/array constructor inside an ObectScript program is enclosed in round parentheses then that element is evaluated using ObjectScript expression syntax instead using JSON literal syntax.  There will also be some additional ways to control the conversions between JSON types and ObjectScript types.

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.

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.

The ClassMethod IsNumeric(...) seems to contain three SET statements that do nothing more than copy data around.  The following is equivalent (without data copies)

ClassMethod IsNumeric(value As %StringAs %Boolean
 { QUIT $ISVALIDNUM(value)  }

And this implementation of IsNumeric is equivalent to the first answer, ClassMethod  IsValidNumber(...) by  Eduard Lebedyuk except the IsNumeric ClassMethod does not have the [ FINAL ] attribute.

In regard to:  "Calculating what day of the week Columbus reached on  Oktober 12, 1492 in America might be incorrect."  Columbus would have been using the "Julian Calendar", which reckons dates quite differently than using the "Julian Day Number", despite the similarity of the names.  Note that Julian Day number changes at Noon UTC rather than changing at Midnight local time where the Gregorian calendar and Julian Calendar assume the date changes.  October 12, 1492 (Julian Calendar) is October 21, 1492 (Gregorian), a 9 day difference, since there was a 10 day difference when the Gregorian calendar started on October 15, 1582 (October 5, 1582 Julian Calendar) and February, 1500 was a leap year in Julian Calendar but not in the Gregorian Calendar.  Both the Julian Calendar and the Gregorian Calendar (and the Islamic and Hebrew calendars) would agree that the first Columbus day was a Friday.  I.e., whenever any calendar adds a leap day/month or skips/adds days to switch between calendars, the days of the week just change by 1 normal day when we switch from one sunrise to the next.  Religions and countries may argue over what year of the calendar it is and what month of the year it is and what day of the month it is but there is much less argument over which day of the week it is.