diff --git a/lib/elixir/lib/json.ex b/lib/elixir/lib/json.ex index 7d755ef8be..4b58bd2b58 100644 --- a/lib/elixir/lib/json.ex +++ b/lib/elixir/lib/json.ex @@ -149,8 +149,28 @@ end defimpl JSON.Encoder, for: Map do def encode(value, encoder) do - :elixir_json.encode_map(value, encoder) + case :maps.next(:maps.iterator(value)) do + :none -> + "{}" + + {key, value, iterator} -> + [?{, key(key, encoder), ?:, encoder.(value, encoder) | next(iterator, encoder)] + end end + + defp next(iterator, encoder) do + case :maps.next(iterator) do + :none -> + "}" + + {key, value, iterator} -> + [?,, key(key, encoder), ?:, encoder.(value, encoder) | next(iterator, encoder)] + end + end + + defp key(key, encoder) when is_atom(key), do: encoder.(Atom.to_string(key), encoder) + defp key(key, encoder) when is_binary(key), do: encoder.(key, encoder) + defp key(key, encoder), do: encoder.(String.Chars.to_string(key), encoder) end defimpl JSON.Encoder, for: Duration do @@ -262,17 +282,15 @@ defmodule JSON do Elixir primitive types are encoded to JSON as follows: - | **Elixir** | **JSON** | - |------------------------|----------| - | `integer() \| float()` | Number | - | `true \| false ` | Boolean | - | `nil` | Null | - | `binary()` | String | - | `atom()` | String | - | `list()` | Array | - | `%{binary() => _}` | Object | - | `%{atom() => _}` | Object | - | `%{integer() => _}` | Object | + | **Elixir** | **JSON** | + |----------------------------|----------| + | `integer() \| float()` | Number | + | `true \| false ` | Boolean | + | `nil` | Null | + | `binary()` | String | + | `atom()` | String | + | `list()` | Array | + | `%{String.Chars.t() => _}` | Object | You may also implement the `JSON.Encoder` protocol for custom data structures. Some built-in data-structures already derive the `JSON.Encoder` protocol: @@ -499,7 +517,7 @@ defmodule JSON do do: :elixir_json.encode_list(value, encoder) def protocol_encode(%{} = value, encoder) when not is_map_key(value, :__struct__), - do: :elixir_json.encode_map(value, encoder) + do: JSON.Encoder.Map.encode(value, encoder) def protocol_encode(value, encoder), do: JSON.Encoder.encode(value, encoder) diff --git a/lib/elixir/test/elixir/json_test.exs b/lib/elixir/test/elixir/json_test.exs index 2883e6647d..2a0a8c61d6 100644 --- a/lib/elixir/test/elixir/json_test.exs +++ b/lib/elixir/test/elixir/json_test.exs @@ -36,8 +36,8 @@ defmodule JSONTest do end test "maps" do - assert JSON.encode!(%{1 => 2, 3.0 => 4.0, key: :bar}) == - "{\"1\":2,\"3.0\":4.0,\"key\":\"bar\"}" + assert JSON.encode!(%{1 => 2, 3.0 => 4.0, ~c"list" => ~c"list", key: :bar}) == + "{\"1\":2,\"3.0\":4.0,\"key\":\"bar\",\"list\":[108,105,115,116]}" end test "lists" do @@ -83,8 +83,8 @@ defmodule JSONTest do end test "maps" do - assert protocol_encode(%{1 => 2, 3.0 => 4.0, key: :bar}) == - "{\"1\":2,\"3.0\":4.0,\"key\":\"bar\"}" + assert protocol_encode(%{1 => 2, 3.0 => 4.0, ~c"list" => ~c"list", key: :bar}) == + "{\"1\":2,\"3.0\":4.0,\"key\":\"bar\",\"list\":[108,105,115,116]}" end test "lists" do