Fl4m3Ph03n1x

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:
https://hexdocs.pm/jason/Jason.Encoder.html

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

  1. Is my objective possible using the Jason library, or is this a limitation?
  2. Am I miss understanding the documentation and doing something incorrect?
6 2289 2

Marked As Solved

Fl4m3Ph03n1x

Fl4m3Ph03n1x

Answer

Turns out there is nothing wrong with the code itself.

The issue here is that I was trying these examples in the iex shell. Due to Protocol Consolidation this means that the protocol will be consolidated at compile time. Therefore, because when I launch iex there is nothing regarding the Jason.Encoder protocol compiled, I loose the chance to do it runtime (and iex is runtime).

This also affects tests in an interesting way, to fix them you can either disable Protocol Consolidation wen running under Mix.env() == :test (but it will absolutely hammer your test’s performance) or you can do it at compile time with some extra options.

A very good answer was also given by the community:

And I recommend you read the full thread if you want all the juicy details that I have quickly summarized here.

Popular Backend topics Top

PragmaticBookshelf
Don’t accept the compromise between fast and beautiful: you can have it all. Phoenix creator Chris McCord, Elixir creator José Valim, and...
16 1423 3
New
PragmaticBookshelf
TDD is a modern programming practice that all C developers need to know. It’s a different way to program—unit tests are written in a tigh...
3 1426 1
New
PragmaticBookshelf
Write Elixir tests that you can be proud of. Dive into Elixir’s test philosophy and gain mastery over the terminology and concepts that u...
33 2317 8
New
DevotionGeo
For me it’s the semicolon, because I stopped using a semicolon in JavaScript, two other of my favorite languages, Elixir and Go don’t hav...
49 2259 25
New
CinderellaMan
Create a cryptocurrency trading bot in Elixir (YouTube videos, ebook pay what you want) <span class="hashtag-icon-placeholder"></span>eli...
32 2135 13
New
ManningBooks
Deep Learning with Python, Second Edition is a comprehensive introduction to the field of deep learning using Python and the powerful Ker...
3 1538 1
New
PragmaticBookshelf
This project based book gets you up to speed on building and deploying Elixir IoT applications using Nerves, as you develop a real-world ...
33 1781 11
New
Cellane
Phoenix 1.6.0 got released last week, with built-in authentication and mailer generators, a whole new HEEx (HTML-aware Embedded Elixir) e...
87 1936 29
New
mafinar
Hello folks! We had a pretty fun thread here around the same time last year - talking about Advent of Code problems. That also happened t...
107 2741 40
New
ManningBooks
Dodge the common mistakes that even senior developers make, take full advantage of static analysis tools, and deliver robust and error-fr...
2 1308 1
New

Other popular topics Top

foxtrottwist
Here’s our thread for the Keyboardio Atreus. It is a mechanical keyboard based on and a slight update of the original Atreus (Keyboardio ...
9 3076 7
New
AstonJ
This looks like a stunning keycap set :orange_heart: A LEGENDARY KEYBOARD LIVES ON When you bought an Apple Macintosh computer in the e...
14 5750 7
New
New
New
New
PragmaticBookshelf
Author Spotlight: Karl Stolley @karlstolley Logic! Rhetoric! Prag! Wow, what a combination. In this spotlight, we sit down with Karl ...
31 3516 17
New
PragmaticBookshelf
Author Spotlight: Sophie DeBenedetto @SophieDeBenedetto The days of the traditional request-response web application are long gone, b...
37 2987 15
New
PragmaticBookshelf
Author Spotlight: Bruce Tate @redrapids Programming languages always emerge out of need, and if that’s not always true, they’re defin...
54 4266 23
New
CommunityNews
Will Swifties’ war on AI fakes spark a deepfake porn reckoning?
0 5638 0
New
AstonJ
This is a very quick guide, you just need to: Download LM Studio: https://lmstudio.ai/ Click on search Type DeepSeek, then select the o...
13 2398 10
New