Fl4m3Ph03n1x
How to have custom enconding for struct using Jason?
Background
I am trying to encode a structure into json format using the Jason library. However, this is not working as expected.
Code
Let’s assume I have this struct:
defmodule Test do
defstruct [:foo, :bar, :baz]
end
And that when using Jason.enconde(%Test{foo: 1, bar: 2, baz:3 }) I want this json to be created:
%{"foo" => 1, "banana" => 5}
Error
It is my understanding that to achieve this I need to implement the Jason.Enconder protocol in my struct:
defmodule Test do
defstruct [:foo, :bar, :baz]
defimpl Jason.Encoder do
@impl Jason.Encoder
def encode(value, opts) do
Jason.Encode.map(%{foo: Map.get(value, :foo), banana: Map.get(value, :bar, 0) + Map.get(value, :baz, 0)}, opts)
end
end
end
However, this will not work:
Jason.encode(%Test{foo: 1, bar: 2, baz: 3})
{:error,
%Protocol.UndefinedError{
description: "Jason.Encoder protocol must always be explicitly implemented.\n\nIf you own the struct, you can derive the implementation specifying which fields should be encoded to JSON:\n\n @derive {Jason.Encoder, only: [....]}\n defstruct ...\n\nIt is also possible to encode all fields, although this should be used carefully to avoid accidentally leaking private information when new fields are added:\n\n @derive Jason.Encoder\n defstruct ...\n\nFinally, if you don't own the struct you want to encode to JSON, you may use Protocol.derive/3 placed outside of any module:\n\n Protocol.derive(Jason.Encoder, NameOfTheStruct, only: [...])\n Protocol.derive(Jason.Encoder, NameOfTheStruct)\n",
protocol: Jason.Encoder,
value: %Test{bar: 2, baz: 3, foo: 1}
}}
From what I understand, it looks like I can only select/exclude keys to serialize, I cannot transform/add new keys.
Since I own the structure in question, using Protocol.derive is not necessary.
However I fail to understand how I can leverage the Jason.Encoder protocol to achieve what I want.
Questions
- Is my objective possible using the Jason library, or is this a limitation?
- Am I miss understanding the documentation and doing something incorrect?
Marked As Solved
kartheek
Docs state advantage of protocol consolidation as below:
Consolidation directly links protocols to their implementations in a way that invoking a function from a consolidated protocol is equivalent to invoking two remote functions.
For solving the problem in original post - you have to create the module and encoder in a file say test.ex in lib folder and it will work.
Also Liked
kartheek
You can read about Protocol Consolidation.
Protocol consolidation happens at compile time. You can disable or enable from mix config as mentioned in docs.
When it is enabled (by default) - it will link protocols with their implementations at compile time to optimise invocations. So when you are trying it in iex - it has no effect as protocol consolidation already happened.
Two solutions:
- disable protocol consolidation using mix config (not recommended) - Section 16.6 don’t go by title read the content in linked section in this book - https://www.elixircryptobot.com/.
- define all these encoders in files and compile the project (recommended)
No problem with the code or library or project - its working as it is supposed to be.
LostKobrakai
That’s not required if the implementation is nested within the module the implementation is for.
sneako
I stand corrected, thanks @LostKobrakai !
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








