jit-cjson
Table of Contents
- Name
- Description
- Synopsis
- APIs
- API (Variables)
- Replacing the Open Source lua-cjson Module
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.
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 withcjson.null
) - By default, non-standard JSON numbers (infinity, NaN, hexadecimal) can be decoded
- This behavior can be changed with
decode_invalid_numbers()
- This behavior can be changed with
Example:
local json_text = '[ true, { "foo": "bar" } ]'
local value = cjson.decode(json_text)
-- Returns: { true, { foo = "bar" } }
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.
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.
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
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
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
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
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.
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.
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
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.
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”}’
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"
).
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": []
}
encode_number_precision
syntax: cjson.encode_number_precision(precision)
This fork allows encoding numbers with a precision
of up to 16 decimals.
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.
API (Variables)
null
JIT CJSON decodes JSON null as a Lua lightuserdata NULL pointer. cjson.null is provided for comparison.
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.
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": []
}
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