Adaptive Notation for JSON

# Anders Rundgren (6 years ago)

Trying again...

It turned out that the Oracle/Java JSON API actually is I-JSON compatible by default through a method which I have coined "Adaptive Notation":

{   "BigDecimal.large": "1E+999",   "BigDecimal.small": 1,   "BigInteger.large": "240777489003222785532321",   "BigInteger.small": 1,   "Long.large": "9223372036854775807",   "Long.small": 1 }

Personally I prefer schemes where you either use JSON Number or JSON String, rather than mixing these depending on the actual value.

However, the most important is finding a common solution.

WDYT?

Anders

# Andrea Giammarchi (6 years ago)

My 2 cents.

For classes with a reachable namespace from the window / global and serializable arguments, you could use an ad-hoc structure to define complex values:

// the converter
const toJSONStruct = value =>
  Object.defineProperty(
    {
      "arguments": Symbol.iterator in value ?
                    [[...value]] :
                    [value.valueOf()]
    },
    "__proto__",
    {
      enumerable: true,
      value: value.constructor.name
    }
  );

// the replacer (basic example)
const replacer = (key, value) => {
  if (
    typeof value === 'object' &&
    value &&
    !/^(?:Array|Object)$/.test(value.constructor.name)
  ) return toJSONStruct(value);
  return value;
};

Here how you can produce some JSON

// example of a complex value
JSON.stringify(
  {
    property: new Uint8Array([10, 20, 30])
  },
  replacer,
  '  '
);

/*
{
  "property": {
    "arguments": [
      [
        10,
        20,
        30
      ]
    ],
    "__proto__": "Uint8Array"
  }
}
*/

A revirer example:

const reviver = (key, value) => {
  if (
    typeof value === 'object' &&
    value !== null &&
    value.hasOwnProperty('__proto__')
  ) {
    const Class = value.__proto__
                        .split('.')
                        .reduce((O, K) => O[K], window);
    return new Class(...value.arguments);
  }
  return value;
};

and a quick proof of the demo:

console.log(
  JSON.parse(
    `{
      "property": {
        "arguments": [
          [
            10,
            20,
            30
          ]
        ],
        "__proto__": "Uint8Array"
      }
    }`,
    reviver
  )
);

Having this standardized, since it's very unlikely anyone would use __proto__ key for a different reason, seems like an easier way to reason about complex serialized values.

Having toJSON and or toJSONConstructor able to return such struct instead of needing toJSONStruct would be even better.

Best