jit-cjson


Table of Contents

Name

JIT-cjson - Fast JSON encoding/parsing library develop by OpenResty Inc.

Description

This is a high-performance JSON encoding/decoding module developed by OpenResty Inc.

The encoding performance can reach up to 18 times faster than other open-source Lua-cjson modules, while the decoding performance can be up to 6 times faster. It also adds new features including support for JSON comments, and allowing trailing commas in arrays and objects.

Back to TOC

Synopsis

-- Module instantiation
local cjson = require "jit.cjson"
local cjson2 = cjson.new()
local cjson_safe = require "jit.cjson.safe"

-- Translate Lua value to/from JSON
text = cjson.encode(value)
value = cjson.decode(text)

-- Get and/or set JIT CJSON configuration
setting = cjson.decode_invalid_numbers([setting])
setting = cjson.encode_invalid_numbers([setting])
keep = cjson.encode_keep_buffer([keep])
depth = cjson.encode_max_depth([depth])
depth = cjson.decode_max_depth([depth])
convert, ratio, safe = cjson.encode_sparse_array([convert[, ratio[, safe]]])

Import JIT-CJSON via the Lua require function.

The JIT-CJSON module will throw an error during JSON conversion if any invalid data is encountered. Refer to cjson.encode and cjson.decode for details.

The cjson.safe module behaves identically to the cjson module, except when errors are encountered during JSON conversion. On error, the cjson_safe.encode and cjson_safe.decode functions will return nil followed by the error message.

cjson.new can be used to instantiate an independent copy of the JIT CJSON module. The new module has a separate persistent encoding buffer, and default settings.

Ensuring each thread calls cjson.encode separately (ie, treat cjson.encode as non-reentrant).

APIs

decode

syntax: value = cjson.decode(json_text)

Deserializes a UTF-8 JSON string into a Lua value or table.

Note: Only UTF-8 encoding is supported. UTF-16 and UTF-32 JSON strings are not supported.

Important:

  • NULL (ASCII 0) and double quote (ASCII 34) characters must be escaped within strings
  • All escape codes will be decoded; other bytes pass through transparently
  • UTF-8 characters are not validated during decoding
  • JSON null is converted to a NULL lightuserdata value (can be compared with cjson.null)
  • By default, non-standard JSON numbers (infinity, NaN, hexadecimal) can be decoded
    • This behavior can be changed with decode_invalid_numbers()

Example:

local json_text = '[ true, { "foo": "bar" } ]'
local value = cjson.decode(json_text)
-- Returns: { true, { foo = "bar" } }

Back to TOC

decode_invalid_numbers

syntax: setting = cjson.decode_invalid_numbers([setting])

default: true

The setting argument must be a boolean.

JIT CJSON may generate an error when decoding numbers that are not supported by the JSON specification. Invalid numbers are defined as follows:

  • infinity
  • not-a-number (NaN)
  • hexadecimal

Available settings:

  • true: Accept and decode invalid numbers. This is the default setting.
  • false: Throw an error when invalid numbers are encountered.

The current setting is always returned, and is only updated when an argument is provided.

Back to TOC

decode_max_depth

syntax: depth = cjson.decode_max_depth([depth])

default: 1000

The depth argument must be a positive integer.

JIT CJSON will generate an error when parsing deeply nested JSON once the maximum array/object depth has been exceeded. This check prevents unnecessarily complicated JSON from slowing down the application, or crashing the application due to lack of process stack space.

An error may be generated before the depth limit is hit if Lua is unable to allocate more objects on the Lua stack.

By default, JIT CJSON will reject JSON with arrays and/or objects nested more than 1000 levels deep.

The current setting is always returned, and is only updated when an argument is provided.

Back to TOC

decode_array_with_array_mt

syntax: cjson.decode_array_with_array_mt(enabled)

default: false

If enabled, JSON Arrays decoded by cjson.decode will result in Lua tables with the array_mt metatable. This can ensure a 1-to-1 relationship between arrays upon multiple encoding/decoding of your JSON data with this module.

If disabled, JSON Arrays will be decoded to plain Lua tables, without the array_mt metatable.

The enabled argument is a boolean.

Example:

local cjson = require "jit.cjson"

-- default behavior
local my_json = [[{"my_array":[]}]]
local t = cjson.decode(my_json)
cjson.encode(t) -- {"my_array":{}} back to an object

-- now, if this behavior is enabled
cjson.decode_array_with_array_mt(true)

local my_json = [[{"my_array":[]}]]
local t = cjson.decode(my_json)
cjson.encode(t) -- {"my_array":[]} properly re-encoded as an array

Back to TOC

decode_allow_trailing_comma

syntax: cjson.decode_allow_trailing_comma(enabled)

default: false

The enabled argument is a boolean.

When enabled, trailing commas in JSON arrays and objects are allowed during decoding. When disabled (default), trailing commas will cause a parse error.

Example:

local cjson = require "jit.cjson"

-- with trailing commas enabled
cjson.decode_allow_trailing_comma(true)
local t = cjson.decode('[1,2,3,]')     -- ok
local t2 = cjson.decode('{"a":1,"b":2,}')  -- ok

-- with trailing commas disabled
cjson.decode_allow_trailing_comma(false)
local t = cjson.decode('[1,2,3,]')     -- error
local t2 = cjson.decode('{"a":1,"b":2,}')  -- error

Back to TOC

decode_allow_comment

syntax: cjson.decode_allow_comment(enabled)

default: false

The enabled argument is a boolean.

When enabled, comments in JSON are allowed during decoding. When disabled (default), comments will cause a parse error.

Example:

local cjson = require "jit.cjson"

-- with comments enabled
cjson.decode_allow_comment(true)
local t = cjson.decode([[{
    //This line is comment
    "a": "Hello"
}]])  -- ok

-- with comments disabled
cjson.decode_allow_comment(false)
local t = cjson.decode([[{
    //This line is comment
    "a": "Hello"
}]])  -- error

Back to TOC

encode

syntax: json_text = cjson.encode(value)

Serializes a Lua value into a string containing the JSON representation.

Supported Lua types:

  • boolean
  • lightuserdata (NULL value only)
  • nil
  • number
  • string
  • table

Unsupported Lua types (will generate an error):

  • function
  • lightuserdata (non-NULL values)
  • thread
  • userdata

Note: By default, numbers are encoded with 14 significant digits. See encode_number_precision for details.

The following characters will be escaped within UTF-8 strings:

  • Control characters (ASCII 0 - 31)
  • Double quote (ASCII 34)
  • Backslash (ASCII 92)
  • Delete (ASCII 127)

All other bytes are passed transparently.

Lua arrays with missing entries (sparse arrays) may optionally be encoded in several different ways. Refer to cjson.encode_sparse_array for details.

JSON object keys are always strings. Hence cjson.encode only supports table keys which are type number or string. All other types will generate an error.

By default, encoding the following Lua values will generate errors:

  • Numbers incompatible with the JSON specification (infinity, NaN)
  • Tables nested more than 1000 levels deep
  • Excessively sparse Lua arrays

These defaults can be changed with:

  • cjson.encode_invalid_numbers
  • cjson.encode_max_depth
  • cjson.encode_sparse_array

Back to TOC

encode_invalid_numbers

syntax: setting = cjson.encode_invalid_numbers([setting])

default: false

The setting argument must be a boolean or string "null".

JIT CJSON may generate an error when encoding floating point numbers not supported by the JSON specification (invalid numbers):

  • infinity
  • not-a-number (NaN)

Available settings:

  • true: Allow invalid numbers to be encoded. This will generate non-standard JSON, but this output is supported by some libraries.
  • "null": Encode invalid numbers as a JSON null value. This allows infinity and NaN to be encoded into valid JSON.
  • false: Throw an error when attempting to encode invalid numbers. This is the default setting.

The current setting is always returned, and is only updated when an argument is provided.

Back to TOC

encode_keep_buffer

syntax: keep = cjson.encode_keep_buffer([keep])

This API exists only for compatibility with the open-source lua-cjson module. It has no actual effect in this implementation.

Back to TOC

encode_max_depth

syntax: depth = cjson.encode_max_depth([depth])

default: 1000

The depth argument must be a positive integer.

Once the maximum table depth has been exceeded JIT CJSON will generate an error. This prevents a deeply nested or recursive data structure from crashing the application.

By default, JIT CJSON will generate an error when trying to encode data structures with more than 1000 nested tables.

The current setting is always returned, and is only updated when an argument is provided.

Example:

-- Recursive Lua table
local a = {}
a[1] = a

Back to TOC

encode_number_precision

syntax: precision = cjson.encode_number_precision([precision])

default: 14

The precision argument must be an integer between 1 and 16.

The number of significant digits returned by JIT CJSON when encoding numbers can be changed to balance accuracy versus performance. For data structures containing many numbers, setting cjson.encode_number_precision to a smaller integer (for example 3) can improve encoding performance by up to 50%.

By default, JIT CJSON will output 16 significant digits when converting a number to text.

The current setting is always returned, and is only updated when an argument is provided.

Back to TOC

encode_skip_unsupported_value_types

syntax: cjson.encode_skip_unsupported_value_types(enabled)

default: false

The enabled argument is a boolean.

If enabled, cjson will not throw an exception when encountering unsupported types in the Lua table.

Example:

local ffi = require "ffi"
local cjson = require "jit.cjson"
cjson.encode_skip_unsupported_value_types(true)
local t = {key = "val"}

t.cdata = ffi.new("char[?]", 100)
print(cjson.encode(t))
-- Returns: {"key":"val"}

encode_sparse_array

syntax: convert, ratio, safe = cjson.encode_sparse_array([convert[, ratio[, safe]]])

default:

  • convert: false (boolean)
  • ratio: 2 (positive integer)
  • safe: 10 (positive integer) JIT CJSON classifies a Lua table into one of three kinds when encoding a JSON array. This is determined by the number of values missing from the Lua array as follows:

Normal All values are available.

Sparse At least 1 value is missing.

Excessively sparse The number of values missing exceeds the configured ratio.

JIT CJSON encodes sparse Lua arrays as JSON arrays using JSON null for the missing entries.

An array is excessively sparse when all the following conditions are met:

ratio > 0

maximum_index > safe

maximum_index > item_count * ratio

JIT CJSON will never consider an array to be excessively sparse when ratio = 0. The safe limit ensures that small Lua arrays are always encoded as sparse arrays.

By default, attempting to encode an excessively sparse array will generate an error. If convert is set to true, excessively sparse arrays will be converted to a JSON object.

The current settings are always returned. A particular setting is only changed when the argument is provided (non-nil).

Example: Encoding a sparse array cjson.encode({ [3] = “data” }) – Returns: ‘[null,null,“data”]’ Example: Enabling conversion to a JSON object cjson.encode_sparse_array(true) cjson.encode({ [1000] = “excessively sparse” }) – Returns: ‘{“1000”:“excessively sparse”}’

Back to TOC

encode_empty_table_as_object

syntax: cjson.encode_empty_table_as_object(true|false|"on"|"off")

Change the default behavior when encoding an empty Lua table.

By default, empty Lua tables are encoded as empty JSON Objects ({}). If this is set to false, empty Lua tables will be encoded as empty JSON Arrays instead ([]).

This method either accepts a boolean or a string ("on", "off").

Back to TOC

empty_array

syntax: cjson.empty_array

A lightuserdata, similar to cjson.null, which will be encoded as an empty JSON Array by cjson.encode().

For example, since encode_empty_table_as_object is true by default:

local cjson = require "jit.cjson"

local json = cjson.encode({
    foo = "bar",
    some_object = {},
    some_array = cjson.empty_array
})

This will generate:

{
    "foo": "bar",
    "some_object": {},
    "some_array": []
}

Back to TOC

encode_number_precision

syntax: cjson.encode_number_precision(precision)

This fork allows encoding numbers with a precision of up to 16 decimals.

Back to TOC

encode_escape_forward_slash

syntax: cjson.encode_escape_forward_slash(enabled)

default: true

This API exists only for compatibility with the open-source lua-cjson module. It has no actual effect in this implementation.

Back to TOC

API (Variables)

null

JIT CJSON decodes JSON null as a Lua lightuserdata NULL pointer. cjson.null is provided for comparison.

Back to TOC

array_mt

syntax: setmetatable({}, cjson.array_mt)

When jit-cjson encodes a table with this metatable, it will systematically encode it as a JSON Array. The resulting, encoded Array will contain the array part of the table, and will be of the same length as the # operator on that table. Holes in the table will be encoded with the null JSON value.

Example:

local t = { "hello", "world" }
setmetatable(t, cjson.array_mt)
cjson.encode(t) -- ["hello","world"]

Or:

local t = {}
t[1] = "one"
t[2] = "two"
t[4] = "three"
t.foo = "bar"
setmetatable(t, cjson.array_mt)
cjson.encode(t) -- ["one","two",null,"three"]

This value was introduced in the 2.1.0.5 release of this module.

Back to TOC

empty_array_mt

syntax: setmetatable({}, cjson.empty_array_mt)

A metatable which can “tag” a table as a JSON Array in case it is empty (that is, if the table has no elements, cjson.encode() will encode it as an empty JSON Array).

Instead of:

local function serialize(arr)
    if #arr < 1 then
        arr = cjson.empty_array
    end

    return cjson.encode({some_array = arr})
end

This is more concise:

local function serialize(arr)
    setmetatable(arr, cjson.empty_array_mt)

    return cjson.encode({some_array = arr})
end

Both will generate:

{
    "some_array": []
}

Back to TOC

Replacing the Open Source lua-cjson Module

If you want to replace lua-cjson without modifying existing code, you can create a wrapper for the jit-cjson module.

Create file cjson.lua in your Lua search path:

local cjson = require "jit.cjson"

-- write this log to make sure you use the right module.
ngx.log(ngx.INFO, "jit.cjson is loaded")

return cjson

Create file cjson/safe.lua in your Lua search path:

local cjson = require "jit.cjson.safe"

-- write this log to make sure you use the right module.
ngx.log(ngx.INFO, "jit.cjson.safe is loaded")

return cjson