defmodule Utilities.Serialize do def store_object(file_path, object) do json_string = Poison.encode!(object) File.write!(file_path, json_string) end def retrieve_object(file_path) do case File.read(file_path) do {:ok, json_string} -> Poison.DecodeWithStruct.decode!(json_string) {:error, reason} -> IO.inspect("Error reading file #{file_path}: #{reason}") nil end end end defmodule Poison.DecodeWithStruct do def decode!(json_string) do data_map = Poison.decode!(json_string) to_struct(data_map) end def to_struct(%{"__struct__" => module_name_str} = map_with_string_keys) do module = String.to_atom("Elixir." <> module_name_str) map_with_atom_keys_and_processed_values = map_with_string_keys |> Enum.map(fn {key_str, value} -> atom_key = String.to_atom(key_str) processed_value = cond do # Check if 'value' is a map AND it contains the "__struct__" string key is_map(value) and Map.has_key?(value, "__struct__") -> to_struct(value) # Recursively call to_struct is_list(value) -> Enum.map(value, &maybe_to_struct/1) # Process list elements true -> value # Otherwise, use the value as is end {atom_key, processed_value} end) |> Enum.into(%{}) struct_fields = Map.delete(map_with_atom_keys_and_processed_values, :__struct__) struct(module, struct_fields) end # Handles items that are not maps or don't have "__struct__" def to_struct(other), do: other # Helper for list processing defp maybe_to_struct(%{"__struct__" => _} = item_map), do: to_struct(item_map) defp maybe_to_struct(item), do: item end defimpl Poison.Encoder, for: Database.Entry do def encode(%Database.Entry{} = doc, opts) do doc |> Map.from_struct() |> Map.put("__struct__", inspect(doc.__struct__)) |> Poison.Encoder.Map.encode(opts) end end defimpl Poison.Encoder, for: Database.Topic do def encode(%Database.Topic{} = doc, opts) do doc |> Map.from_struct() |> Map.put("__struct__", inspect(doc.__struct__)) |> Poison.Encoder.Map.encode(opts) end end