Duplicated modules: 'Elixir.Poison.Encoder.Map' specified in poison `mix release`

259 Views Asked by At

I am working in an umbrella application that works with Poison to encode and decode Json. In order to encode my ecto models I write the following implementation:

def defimpl Poison.Encoder, for: Any do
def encode(%{__struct__: App.Models.Task} = struct, options) do
  struct =
    if struct.geom do
      {lon, lat} =  struct.geom.coordinates
      %{struct | lon: lon, lat: lat}
    else
      struct
    end
  enconde_model(struct, options)
end

def encode(%{__struct__: _} = struct, options) do
  enconde_model(struct, options)
end

def encode({lon, lat}, options) when is_float(lon) and is_float(lat) do
  %{lon: lon, lat: lat}
  |> sanitize_map()
  |> Poison.Encoder.Map.encode(options)
end

defp enconde_model(model, options) do
  model
  |> Map.from_struct()
  |> sanitize_map()
  |> Poison.Encoder.Map.encode(options)
end

defp sanitize_map(map) do
  map
  |> Enum.filter(
    fn({_, %Ecto.Association.NotLoaded{}}) -> false
      ({:__meta__, _}) -> false
      ({:__struct__, _}) -> false
      ({_, _}) -> true
    end)
  |> Map.new()
end

end

The think is that once I run mix release the program raises the error unless I comment out the code I just show above.

So, there is another way to achieve this same functionality without using the implementation?

1

There are 1 best solutions below

2
Dogbert On BEST ANSWER

You're getting that error because you're overriding the existing encoder implementations. The right way to do this is to implement Poison.Encoder for each struct you want to encode. With @derive, this is pretty straightforward:

@derive {Poison.Encoder, only: [:the, :field, :names, :you, :want, :in, :json]}
schema "tasks" do
  ...
end

For the tuple, you'll need to manually convert those to maps in the encoding for the structs which can contain those tuples:

defimpl Poison.Encoder, for: Something do
  def encode(%{a_tuple: {lat, lon}, something: else_}, options) do
    Poison.encode!(%{location: %{lat: lat, lon: lon}, something: else_}, options)
  end
end