Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Empty object encodes as array #23

Open
tmpgnh opened this issue Apr 7, 2020 · 2 comments
Open

Empty object encodes as array #23

tmpgnh opened this issue Apr 7, 2020 · 2 comments

Comments

@tmpgnh
Copy link

tmpgnh commented Apr 7, 2020

% 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 #19)

Thanks,

@rxi
Copy link
Owner

rxi commented Apr 7, 2020

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}

@tmpgnh
Copy link
Author

tmpgnh commented Apr 7, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants