Skip to main content

JSON module

The JSON module turns JSON text into JARU values (maps, lists, numbers, strings and booleans) and the other way round. Use it to read what an API answers through Http, to save a program's settings to a file with File or to send data over MQTT.

use JSON

JARU JSON module screenshot for parsing, creating, and serializing structured data

It works the same on Windows and on every board.

Functions​

FunctionWhat it doesReturns
JSON.parse(text)Reads a JSON textThe value: a map, a list, a number, a string or a boolean
JSON.stringify(value)Writes a value as JSON text, on one lineA string
JSON.stringify(value, indent)The same, with one line per element and indent spaces per levelA string

parse(text)​

Reads the JSON text text and returns what it represents. A JSON object becomes a map, and its values become the ones in this table:

In the JSONIn JARU
Object { … }A map, with the keys as strings
Array [ … ]A list
Number without decimalsAn integer
Number with decimals or an exponent (8.5, 3.0, 1e3)A decimal
StringA string. The escapes (\n, \", \u00e9…) come already converted.
true and falsetrue and false
nullnil

You read a map's values with square brackets, m["key"], and a list's, with their position, l[0] (see Lists, maps and arrays):

use JSON

var text = '{"name": "Ana", "age": 25, "marks": [7, 8.5], "address": {"street": "Main", "number": 3}}'
var person = JSON.parse(text)
println(person["name"]) // Ana
println(person["marks"][1]) // 8.5
println(person["address"]["street"]) // Main

var list = JSON.parse("[1, 2, 3]")
println(list.size()) // 3

The text can also be a single value: JSON.parse("42") returns the integer 42, and JSON.parse('"hello"'), the string hello.

It's strict JSON, with one exception: it accepts an extra comma at the end of a list or an object ([1, 2,] gives [1, 2]). It doesn't accept single quotes, unquoted keys or comments. If a key is repeated, the last value wins.

If the text can't be read, it throws an exception, which you catch with try (see Errors and exceptions):

ErrorMessageWhen
ERR_INVALID_VALUEString is not valid JSON.The text isn't valid JSON.
ERR_INVALID_VALUEArgument of parse() is an empty string.The text is empty.
ERR_INVALID_VALUEJSON object could not be processed.The text is just null.
ERR_TYPE_MISMATCHArgument of parse() must be a string.You don't pass a string.
ERR_INVALID_ARG_NUMBERparse() expects 1 argument, got 2.You don't pass one argument.
use JSON

try
var data = JSON.parse("{name: 1}")
catch (var e)
println(e) // ERR_INVALID_VALUE: String is not valid JSON.
end

stringify(value, indent)​

Writes value as JSON text and returns it in a string. indent is optional:

  • Without indent, everything goes on one line, with a space after each : and each ,.
  • With indent, an integer, each element goes on its own line, with indent more spaces for each level. With 0, one line per element and no indentation.
use JSON

var reading = {"sensor": "t1", "value": 21.5, "ok": true, "faults": nil}
println(JSON.stringify(reading))
println(JSON.stringify([1, 2.0, "two"])) // [1, 2, "two"]
{"value": 21.5, "sensor": "t1", "faults": null, "ok": true}
[1, 2, "two"]

With indentation, JSON.stringify({"list": [1, 2]}, 2) gives:

{
"list": [
1,
2
]
}

Each JARU value is written like this:

In JARUIn the JSON
MapAn object. Its keys are written as strings: an integer, such as 1, comes out "1" (and JSON.parse reads it as that string); true and false, "true" and "false"; and nil, "null". With another key, such as a decimal, it throws ERR_INVALID_VALUE.
ListAn array
IntegerA number
DecimalA number with 6 significant digits: 1 / 3 comes out as 0.333333, and 3000000000.0, as 3e+09. A decimal with no fractional part is written as an integer: 2.0 comes out as 2.
StringA string, with ", \ and line breaks and tabs written as escapes
true and falsetrue and false
nilnull

The order of an object's keys isn't the map's: in the example above, value comes before sensor.

Errors (exceptions):

ErrorMessageWhen
ERR_INVALID_VALUEObject is not serializable to JSON.The value, or one of those a list or a map holds, isn't one of those in the table: an instance of a class, an array {…}, a Bytes block, a function… Or a map has a key that isn't a string, an integer, a boolean or nil.
ERR_TYPE_MISMATCHArgument 2 of stringify() (indent) must be an integer.indent isn't an integer.
ERR_INVALID_ARG_NUMBERstringify() expects 1 or 2 arguments, got 0.You don't pass one or two arguments.

Complete example​

It saves a program's settings to a file and reads them back:

use JSON, File

// The default settings
var config = {"name": "Sensor 1", "interval": 30, "thresholds": [18, 26], "active": true}

// Save them to a file, indented so that they read well
var f = File.open("config.json", "w")
f.write(JSON.stringify(config, 2))
f.close()

// Read them back
var g = File.open("config.json", "r")
var loaded = JSON.parse(g.read())
g.close()

println(loaded["name"]) // Sensor 1
println(loaded["thresholds"][1]) // 26
loaded["interval"] = 60
println(JSON.stringify(loaded))

The last line prints:

{"interval": 60, "thresholds": [18, 26], "name": "Sensor 1", "active": true}

Pitfalls and known issues​

  • Values, with square brackets. A JSON object is a map: you read its value with m["name"], not with m.name.
  • Decimals that aren't equal. When a decimal is read, it can differ in the last digit from the same number written in the program: JSON.parse("1.68") == 1.68 is false. To compare decimals, check whether the difference is very small.
  • Decimals with 6 digits. stringify rounds decimals to 6 significant digits. If you need more, write the number as a string.
  • Large integers. JARU integers are 32-bit: a number without decimals above 2147483647 wraps around when it's read ([3000000000] gives [-1294967296]). Write it with decimals (3000000000.0) so that it arrives as a decimal.
  • A lone null can't be read. JSON.parse("null") gives an error. Inside an object or a list it can: it arrives as nil.

All the known issues of JARU, together, are in Known issues.