Skip to content

Commit ff628d0

Browse files
committed
Encode any JSON key to string, closes #14305
1 parent 71da1a2 commit ff628d0

File tree

2 files changed

+35
-17
lines changed

2 files changed

+35
-17
lines changed

lib/elixir/lib/json.ex

+31-13
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,28 @@ end
149149

150150
defimpl JSON.Encoder, for: Map do
151151
def encode(value, encoder) do
152-
:elixir_json.encode_map(value, encoder)
152+
case :maps.next(:maps.iterator(value)) do
153+
:none ->
154+
"{}"
155+
156+
{key, value, iterator} ->
157+
[?{, key(key, encoder), ?:, encoder.(value, encoder) | next(iterator, encoder)]
158+
end
153159
end
160+
161+
defp next(iterator, encoder) do
162+
case :maps.next(iterator) do
163+
:none ->
164+
"}"
165+
166+
{key, value, iterator} ->
167+
[?,, key(key, encoder), ?:, encoder.(value, encoder) | next(iterator, encoder)]
168+
end
169+
end
170+
171+
defp key(key, encoder) when is_atom(key), do: encoder.(Atom.to_string(key), encoder)
172+
defp key(key, encoder) when is_binary(key), do: encoder.(key, encoder)
173+
defp key(key, encoder), do: encoder.(String.Chars.to_string(key), encoder)
154174
end
155175

156176
defimpl JSON.Encoder, for: Duration do
@@ -262,17 +282,15 @@ defmodule JSON do
262282
263283
Elixir primitive types are encoded to JSON as follows:
264284
265-
| **Elixir** | **JSON** |
266-
|------------------------|----------|
267-
| `integer() \| float()` | Number |
268-
| `true \| false ` | Boolean |
269-
| `nil` | Null |
270-
| `binary()` | String |
271-
| `atom()` | String |
272-
| `list()` | Array |
273-
| `%{binary() => _}` | Object |
274-
| `%{atom() => _}` | Object |
275-
| `%{integer() => _}` | Object |
285+
| **Elixir** | **JSON** |
286+
|----------------------------|----------|
287+
| `integer() \| float()` | Number |
288+
| `true \| false ` | Boolean |
289+
| `nil` | Null |
290+
| `binary()` | String |
291+
| `atom()` | String |
292+
| `list()` | Array |
293+
| `%{String.Chars.t() => _}` | Object |
276294
277295
You may also implement the `JSON.Encoder` protocol for custom data structures.
278296
Some built-in data-structures already derive the `JSON.Encoder` protocol:
@@ -499,7 +517,7 @@ defmodule JSON do
499517
do: :elixir_json.encode_list(value, encoder)
500518

501519
def protocol_encode(%{} = value, encoder) when not is_map_key(value, :__struct__),
502-
do: :elixir_json.encode_map(value, encoder)
520+
do: JSON.Encoder.Map.encode(value, encoder)
503521

504522
def protocol_encode(value, encoder),
505523
do: JSON.Encoder.encode(value, encoder)

lib/elixir/test/elixir/json_test.exs

+4-4
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ defmodule JSONTest do
3636
end
3737

3838
test "maps" do
39-
assert JSON.encode!(%{1 => 2, 3.0 => 4.0, key: :bar}) ==
40-
"{\"1\":2,\"3.0\":4.0,\"key\":\"bar\"}"
39+
assert JSON.encode!(%{1 => 2, 3.0 => 4.0, ~c"list" => ~c"list", key: :bar}) ==
40+
"{\"1\":2,\"3.0\":4.0,\"key\":\"bar\",\"list\":[108,105,115,116]}"
4141
end
4242

4343
test "lists" do
@@ -83,8 +83,8 @@ defmodule JSONTest do
8383
end
8484

8585
test "maps" do
86-
assert protocol_encode(%{1 => 2, 3.0 => 4.0, key: :bar}) ==
87-
"{\"1\":2,\"3.0\":4.0,\"key\":\"bar\"}"
86+
assert protocol_encode(%{1 => 2, 3.0 => 4.0, ~c"list" => ~c"list", key: :bar}) ==
87+
"{\"1\":2,\"3.0\":4.0,\"key\":\"bar\",\"list\":[108,105,115,116]}"
8888
end
8989

9090
test "lists" do

0 commit comments

Comments
 (0)