json.lua
json.lua copied to clipboard
Empty object encodes as array
% lua
Lua 5.3.3 Copyright (C) 1994-2016 Lua.org, PUC-Rio
> json=require'json'
> json.encode(json.decode('{}'))
[]
Why doesn't return '{}'? (Maybe related to https://github.com/rxi/json.lua/issues/19)
Thanks,
This is expected behaviour, there's a few reasons this choice was made though:
In Lua there's no distinction between an "array" and a "map". When json.lua
encounters a table it tries to determine first if it's a valid array -- it does so by checking to make sure it doesn't contain any non-numerical keys, and that it contains the keys in the inclusive range 1
to n
without any gaps -- by this definition an empty table is considered an array.
This behaviour was chosen as in typical cases you won't be encoding an empty object, and, if you are, in many cases that object can be stored as an array and treated like an object once loaded (lua, javascript). Typically if you have an empty table you're writing to JSON in lua it's a table that you're using as an array.
The library makes only the following guarantees: that valid JSON will decode correctly, that encoded JSON will be valid, and that data encoded with json.encode()
will result in the same data when json.decode()
is used.
If you want to force your empty table to be encoded as an object, a simple work around might be to add a dummy value to it, for example:
json.encode { _ = false } -- => {"_":false}
Thank you for the explanation. I actually felt that the second guarantee
data encoded with json.encode() will result in the same data when json.decode() is used
is being violated---cf. the empty JSON object '{}'. For my use case which parses and then returns JSON I'm thinking to patch json.lua along these lines:
@@ -56,6 +56,9 @@
end
+local json_object_tag = {}
+
+
local function encode_table(val, stack)
local res = {}
stack = stack or {}
@@ -65,7 +68,7 @@
stack[val] = true
- if rawget(val, 1) ~= nil or next(val) == nil then
+ if getmetatable(val) ~= json_object_tag and (rawget(val, 1) ~= nil or next(val) == nil) then
-- Treat as array -- check keys are valid and it is not sparse
local n = 0
for k in pairs(val) do
@@ -337,6 +340,7 @@
if chr == "}" then break end
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
end
+ setmetatable(res, json_object_tag)
return res, i
end