Serialise BigDecimal, BigNumber, BigInt etc. to and from JSON










1















What types, and what serialisation pattern, can I use to ensure I have arbitrary-precision numbers in my JavaScript program while it's running, but the state is serialised to / deserialised from JSON with a minimum of pain?



I am writing an application that makes heavy use of numbers with higher precision than allowed by the ECMAScript native Number type. So I need to use a custom type (currently BigNumber) to represent those values.



I am looking hungrily at the proposed BigInt type, which when implemented as standard will be an improvement for many applications including the one I'm writing. However that won't help at all with JSON, which knows nothing about BigInt any more than BigNumber.



Whichever custom type I choose, there are many values of this type throughout the application state. So much that it's worth considering a custom hook in the serialisation / deserialisation layer that will handle transforming it to / from JSON.



Presumably the JSON document will have to represent the values as JSON native types (e.g. Object or String instances). How then, when de-serialising the entire complex application state, to reliably recognise and de-serialise those instances among all the others, to the correct value of the correct BigInt or BigNumber type?



How can I serialise that state, such that any BigNumber (or insert some other arbitrary-precision number type) value reliably survives the serialisation / de-serialisation process, to correct values of the correct type?










share|improve this question




























    1















    What types, and what serialisation pattern, can I use to ensure I have arbitrary-precision numbers in my JavaScript program while it's running, but the state is serialised to / deserialised from JSON with a minimum of pain?



    I am writing an application that makes heavy use of numbers with higher precision than allowed by the ECMAScript native Number type. So I need to use a custom type (currently BigNumber) to represent those values.



    I am looking hungrily at the proposed BigInt type, which when implemented as standard will be an improvement for many applications including the one I'm writing. However that won't help at all with JSON, which knows nothing about BigInt any more than BigNumber.



    Whichever custom type I choose, there are many values of this type throughout the application state. So much that it's worth considering a custom hook in the serialisation / deserialisation layer that will handle transforming it to / from JSON.



    Presumably the JSON document will have to represent the values as JSON native types (e.g. Object or String instances). How then, when de-serialising the entire complex application state, to reliably recognise and de-serialise those instances among all the others, to the correct value of the correct BigInt or BigNumber type?



    How can I serialise that state, such that any BigNumber (or insert some other arbitrary-precision number type) value reliably survives the serialisation / de-serialisation process, to correct values of the correct type?










    share|improve this question


























      1












      1








      1








      What types, and what serialisation pattern, can I use to ensure I have arbitrary-precision numbers in my JavaScript program while it's running, but the state is serialised to / deserialised from JSON with a minimum of pain?



      I am writing an application that makes heavy use of numbers with higher precision than allowed by the ECMAScript native Number type. So I need to use a custom type (currently BigNumber) to represent those values.



      I am looking hungrily at the proposed BigInt type, which when implemented as standard will be an improvement for many applications including the one I'm writing. However that won't help at all with JSON, which knows nothing about BigInt any more than BigNumber.



      Whichever custom type I choose, there are many values of this type throughout the application state. So much that it's worth considering a custom hook in the serialisation / deserialisation layer that will handle transforming it to / from JSON.



      Presumably the JSON document will have to represent the values as JSON native types (e.g. Object or String instances). How then, when de-serialising the entire complex application state, to reliably recognise and de-serialise those instances among all the others, to the correct value of the correct BigInt or BigNumber type?



      How can I serialise that state, such that any BigNumber (or insert some other arbitrary-precision number type) value reliably survives the serialisation / de-serialisation process, to correct values of the correct type?










      share|improve this question
















      What types, and what serialisation pattern, can I use to ensure I have arbitrary-precision numbers in my JavaScript program while it's running, but the state is serialised to / deserialised from JSON with a minimum of pain?



      I am writing an application that makes heavy use of numbers with higher precision than allowed by the ECMAScript native Number type. So I need to use a custom type (currently BigNumber) to represent those values.



      I am looking hungrily at the proposed BigInt type, which when implemented as standard will be an improvement for many applications including the one I'm writing. However that won't help at all with JSON, which knows nothing about BigInt any more than BigNumber.



      Whichever custom type I choose, there are many values of this type throughout the application state. So much that it's worth considering a custom hook in the serialisation / deserialisation layer that will handle transforming it to / from JSON.



      Presumably the JSON document will have to represent the values as JSON native types (e.g. Object or String instances). How then, when de-serialising the entire complex application state, to reliably recognise and de-serialise those instances among all the others, to the correct value of the correct BigInt or BigNumber type?



      How can I serialise that state, such that any BigNumber (or insert some other arbitrary-precision number type) value reliably survives the serialisation / de-serialisation process, to correct values of the correct type?







      javascript types json-deserialization






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 12 '18 at 5:23







      bignose

















      asked Nov 12 '18 at 4:57









      bignosebignose

      15.9k114976




      15.9k114976






















          2 Answers
          2






          active

          oldest

          votes


















          0














          One potential solution is the Granola library for Node.js.




          granola provides a JSON compatible stringifier and parser with support for modern language and object primitives.




          This would require:



          • Convert the application from using BigNumber values to BigInt values.

          • Wait for tools to support BigInt in the entire build tool chain.





          share|improve this answer






























            0














            If modifying the type (by adding a property to the prototype) is feasible, there is a toJSON hook from JSON.stringify, designed specifically to help custom types collaborate with JSON serialisation.




            If an object being stringified has a property named toJSON whose value is a function, then the toJSON() method customizes JSON stringification behavior: instead of the object being serialized, the value returned by the toJSON() method when called will be serialized.




            So you could add a new method to the BigNumber class:



            BigNumber.prototype.toJSON = function toJSON(key) 
            return
            _type: 'BigNumber',
            _data: Object.assign(, this),
            ;
            ;

            state =
            lorem: true,
            ipsum: "Consecteur non dibale",
            dolor: new BigNumber(107.58),
            sit: spam: 5, eggs: 6, beans: 7 ,
            amet: false,
            ;
            serialisedState = JSON.stringify(state);
            console.debug("serialisedState:", serialisedState);
            // → '"lorem":true,"ipsum":"Consecteur non dibale","dolor":"_type":"BigNumber","_data":"s":1,"e":2,"c":[1,0,7,5,8],"sit":"spam":5,"eggs":6,"beans":7,"amet":false'


            You can then recognise those specific objects when de-serialising, using the reviver parameter of JSON.parse:




            If a reviver is specified, the value computed by parsing is transformed before being returned. Specifically, the computed value and all its properties (beginning with the most nested properties and proceeding to the original value itself) are individually run through the reviver. Then it is called, with the object containing the property being processed as this, and with the property name as a string, and the property value as arguments. [If the return value is not undefined], the property is redefined to be the return value.




            function reviveFromJSON(key, value) 
            let result = value;
            if (
            (typeof value === 'object' && value !== null)
            && (value.hasOwnProperty('_type')))
            switch (value._type)
            case 'BigNumber':
            result = Object.assign(new BigNumber(0), value._data);


            return result;


            state = JSON.parse(serialisedState, reviveFromJSON);
            console.debug("state:", state);
            // → … dolor: BigNumber s: 1, e: 2, c: [ 1, 0, 7, 5, 8 ] , …





            share|improve this answer
























              Your Answer






              StackExchange.ifUsing("editor", function ()
              StackExchange.using("externalEditor", function ()
              StackExchange.using("snippets", function ()
              StackExchange.snippets.init();
              );
              );
              , "code-snippets");

              StackExchange.ready(function()
              var channelOptions =
              tags: "".split(" "),
              id: "1"
              ;
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function()
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled)
              StackExchange.using("snippets", function()
              createEditor();
              );

              else
              createEditor();

              );

              function createEditor()
              StackExchange.prepareEditor(
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader:
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              ,
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              );



              );













              draft saved

              draft discarded


















              StackExchange.ready(
              function ()
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53256165%2fserialise-bigdecimal-bignumber-bigint-etc-to-and-from-json%23new-answer', 'question_page');

              );

              Post as a guest















              Required, but never shown

























              2 Answers
              2






              active

              oldest

              votes








              2 Answers
              2






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              0














              One potential solution is the Granola library for Node.js.




              granola provides a JSON compatible stringifier and parser with support for modern language and object primitives.




              This would require:



              • Convert the application from using BigNumber values to BigInt values.

              • Wait for tools to support BigInt in the entire build tool chain.





              share|improve this answer



























                0














                One potential solution is the Granola library for Node.js.




                granola provides a JSON compatible stringifier and parser with support for modern language and object primitives.




                This would require:



                • Convert the application from using BigNumber values to BigInt values.

                • Wait for tools to support BigInt in the entire build tool chain.





                share|improve this answer

























                  0












                  0








                  0







                  One potential solution is the Granola library for Node.js.




                  granola provides a JSON compatible stringifier and parser with support for modern language and object primitives.




                  This would require:



                  • Convert the application from using BigNumber values to BigInt values.

                  • Wait for tools to support BigInt in the entire build tool chain.





                  share|improve this answer













                  One potential solution is the Granola library for Node.js.




                  granola provides a JSON compatible stringifier and parser with support for modern language and object primitives.




                  This would require:



                  • Convert the application from using BigNumber values to BigInt values.

                  • Wait for tools to support BigInt in the entire build tool chain.






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 12 '18 at 5:16









                  bignosebignose

                  15.9k114976




                  15.9k114976























                      0














                      If modifying the type (by adding a property to the prototype) is feasible, there is a toJSON hook from JSON.stringify, designed specifically to help custom types collaborate with JSON serialisation.




                      If an object being stringified has a property named toJSON whose value is a function, then the toJSON() method customizes JSON stringification behavior: instead of the object being serialized, the value returned by the toJSON() method when called will be serialized.




                      So you could add a new method to the BigNumber class:



                      BigNumber.prototype.toJSON = function toJSON(key) 
                      return
                      _type: 'BigNumber',
                      _data: Object.assign(, this),
                      ;
                      ;

                      state =
                      lorem: true,
                      ipsum: "Consecteur non dibale",
                      dolor: new BigNumber(107.58),
                      sit: spam: 5, eggs: 6, beans: 7 ,
                      amet: false,
                      ;
                      serialisedState = JSON.stringify(state);
                      console.debug("serialisedState:", serialisedState);
                      // → '"lorem":true,"ipsum":"Consecteur non dibale","dolor":"_type":"BigNumber","_data":"s":1,"e":2,"c":[1,0,7,5,8],"sit":"spam":5,"eggs":6,"beans":7,"amet":false'


                      You can then recognise those specific objects when de-serialising, using the reviver parameter of JSON.parse:




                      If a reviver is specified, the value computed by parsing is transformed before being returned. Specifically, the computed value and all its properties (beginning with the most nested properties and proceeding to the original value itself) are individually run through the reviver. Then it is called, with the object containing the property being processed as this, and with the property name as a string, and the property value as arguments. [If the return value is not undefined], the property is redefined to be the return value.




                      function reviveFromJSON(key, value) 
                      let result = value;
                      if (
                      (typeof value === 'object' && value !== null)
                      && (value.hasOwnProperty('_type')))
                      switch (value._type)
                      case 'BigNumber':
                      result = Object.assign(new BigNumber(0), value._data);


                      return result;


                      state = JSON.parse(serialisedState, reviveFromJSON);
                      console.debug("state:", state);
                      // → … dolor: BigNumber s: 1, e: 2, c: [ 1, 0, 7, 5, 8 ] , …





                      share|improve this answer





























                        0














                        If modifying the type (by adding a property to the prototype) is feasible, there is a toJSON hook from JSON.stringify, designed specifically to help custom types collaborate with JSON serialisation.




                        If an object being stringified has a property named toJSON whose value is a function, then the toJSON() method customizes JSON stringification behavior: instead of the object being serialized, the value returned by the toJSON() method when called will be serialized.




                        So you could add a new method to the BigNumber class:



                        BigNumber.prototype.toJSON = function toJSON(key) 
                        return
                        _type: 'BigNumber',
                        _data: Object.assign(, this),
                        ;
                        ;

                        state =
                        lorem: true,
                        ipsum: "Consecteur non dibale",
                        dolor: new BigNumber(107.58),
                        sit: spam: 5, eggs: 6, beans: 7 ,
                        amet: false,
                        ;
                        serialisedState = JSON.stringify(state);
                        console.debug("serialisedState:", serialisedState);
                        // → '"lorem":true,"ipsum":"Consecteur non dibale","dolor":"_type":"BigNumber","_data":"s":1,"e":2,"c":[1,0,7,5,8],"sit":"spam":5,"eggs":6,"beans":7,"amet":false'


                        You can then recognise those specific objects when de-serialising, using the reviver parameter of JSON.parse:




                        If a reviver is specified, the value computed by parsing is transformed before being returned. Specifically, the computed value and all its properties (beginning with the most nested properties and proceeding to the original value itself) are individually run through the reviver. Then it is called, with the object containing the property being processed as this, and with the property name as a string, and the property value as arguments. [If the return value is not undefined], the property is redefined to be the return value.




                        function reviveFromJSON(key, value) 
                        let result = value;
                        if (
                        (typeof value === 'object' && value !== null)
                        && (value.hasOwnProperty('_type')))
                        switch (value._type)
                        case 'BigNumber':
                        result = Object.assign(new BigNumber(0), value._data);


                        return result;


                        state = JSON.parse(serialisedState, reviveFromJSON);
                        console.debug("state:", state);
                        // → … dolor: BigNumber s: 1, e: 2, c: [ 1, 0, 7, 5, 8 ] , …





                        share|improve this answer



























                          0












                          0








                          0







                          If modifying the type (by adding a property to the prototype) is feasible, there is a toJSON hook from JSON.stringify, designed specifically to help custom types collaborate with JSON serialisation.




                          If an object being stringified has a property named toJSON whose value is a function, then the toJSON() method customizes JSON stringification behavior: instead of the object being serialized, the value returned by the toJSON() method when called will be serialized.




                          So you could add a new method to the BigNumber class:



                          BigNumber.prototype.toJSON = function toJSON(key) 
                          return
                          _type: 'BigNumber',
                          _data: Object.assign(, this),
                          ;
                          ;

                          state =
                          lorem: true,
                          ipsum: "Consecteur non dibale",
                          dolor: new BigNumber(107.58),
                          sit: spam: 5, eggs: 6, beans: 7 ,
                          amet: false,
                          ;
                          serialisedState = JSON.stringify(state);
                          console.debug("serialisedState:", serialisedState);
                          // → '"lorem":true,"ipsum":"Consecteur non dibale","dolor":"_type":"BigNumber","_data":"s":1,"e":2,"c":[1,0,7,5,8],"sit":"spam":5,"eggs":6,"beans":7,"amet":false'


                          You can then recognise those specific objects when de-serialising, using the reviver parameter of JSON.parse:




                          If a reviver is specified, the value computed by parsing is transformed before being returned. Specifically, the computed value and all its properties (beginning with the most nested properties and proceeding to the original value itself) are individually run through the reviver. Then it is called, with the object containing the property being processed as this, and with the property name as a string, and the property value as arguments. [If the return value is not undefined], the property is redefined to be the return value.




                          function reviveFromJSON(key, value) 
                          let result = value;
                          if (
                          (typeof value === 'object' && value !== null)
                          && (value.hasOwnProperty('_type')))
                          switch (value._type)
                          case 'BigNumber':
                          result = Object.assign(new BigNumber(0), value._data);


                          return result;


                          state = JSON.parse(serialisedState, reviveFromJSON);
                          console.debug("state:", state);
                          // → … dolor: BigNumber s: 1, e: 2, c: [ 1, 0, 7, 5, 8 ] , …





                          share|improve this answer















                          If modifying the type (by adding a property to the prototype) is feasible, there is a toJSON hook from JSON.stringify, designed specifically to help custom types collaborate with JSON serialisation.




                          If an object being stringified has a property named toJSON whose value is a function, then the toJSON() method customizes JSON stringification behavior: instead of the object being serialized, the value returned by the toJSON() method when called will be serialized.




                          So you could add a new method to the BigNumber class:



                          BigNumber.prototype.toJSON = function toJSON(key) 
                          return
                          _type: 'BigNumber',
                          _data: Object.assign(, this),
                          ;
                          ;

                          state =
                          lorem: true,
                          ipsum: "Consecteur non dibale",
                          dolor: new BigNumber(107.58),
                          sit: spam: 5, eggs: 6, beans: 7 ,
                          amet: false,
                          ;
                          serialisedState = JSON.stringify(state);
                          console.debug("serialisedState:", serialisedState);
                          // → '"lorem":true,"ipsum":"Consecteur non dibale","dolor":"_type":"BigNumber","_data":"s":1,"e":2,"c":[1,0,7,5,8],"sit":"spam":5,"eggs":6,"beans":7,"amet":false'


                          You can then recognise those specific objects when de-serialising, using the reviver parameter of JSON.parse:




                          If a reviver is specified, the value computed by parsing is transformed before being returned. Specifically, the computed value and all its properties (beginning with the most nested properties and proceeding to the original value itself) are individually run through the reviver. Then it is called, with the object containing the property being processed as this, and with the property name as a string, and the property value as arguments. [If the return value is not undefined], the property is redefined to be the return value.




                          function reviveFromJSON(key, value) 
                          let result = value;
                          if (
                          (typeof value === 'object' && value !== null)
                          && (value.hasOwnProperty('_type')))
                          switch (value._type)
                          case 'BigNumber':
                          result = Object.assign(new BigNumber(0), value._data);


                          return result;


                          state = JSON.parse(serialisedState, reviveFromJSON);
                          console.debug("state:", state);
                          // → … dolor: BigNumber s: 1, e: 2, c: [ 1, 0, 7, 5, 8 ] , …






                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Nov 12 '18 at 7:03

























                          answered Nov 12 '18 at 6:16









                          bignosebignose

                          15.9k114976




                          15.9k114976



























                              draft saved

                              draft discarded
















































                              Thanks for contributing an answer to Stack Overflow!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid


                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.

                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function ()
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53256165%2fserialise-bigdecimal-bignumber-bigint-etc-to-and-from-json%23new-answer', 'question_page');

                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

                              Edmonton

                              Crossroads (UK TV series)