benhaney/Jsonrs

Inner structs don't obey defimpl Encoder rules

louiscb opened this issue · 3 comments

Description of problem

When a struct contains an inner struct, both with Jsonrs.Encoder definitions, the Jsonrs.encode function will not pick up on the inner struct's definition.

Test recreating problem

This test fails when it should pass. The inner structs defimpl is not

  defmodule SomeStruct do
    defstruct [:field, :inner_struct]
  end

  defmodule InnerStruct do
    defstruct [:field, :ignored_field]
  end

  defimpl Jsonrs.Encoder, for: SomeStruct do
    def encode(%{field: f, inner_struct: is}) do
      %{f: f, is: is}
    end
  end

  defimpl Jsonrs.Encoder, for: InnerStruct do
    def encode(%{field: f}) do
      %{f: f}
    end
  end

  test "protocols" do
    is = %InnerStruct{field: "a", ignored_field: "b"}

    val = %SomeStruct{
      field: "a",
      inner_struct: is
    }

    assert ~s({"f":"a"}) == Jsonrs.encode!(is)

    assert ~s({"f":"a","is":{"f":"a"}}) ==
             Jsonrs.encode!(val)
  end

Related to this older issue #5

To me, this is expected behavior. If you want custom encoding to continue descending through the return value of your custom encoder, your Encoder impl for SomeStruct would need to look something like

defimpl Jsonrs.Encoder, for: SomeStruct do
  def encode(%{field: f, inner_struct: is}) do
    %{f: f, is: is} |> Jsonrs.Encoder.encode()
  end
end

which I believe is conceptually similar to what would be required with Jason or Poison.

I see, makes sense.