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?

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
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...
New
New
mafinar
A friend and I implemented a few algorithms in Dart and set them up in a repository. Thought I’d share it here.
New
CinderellaMan
Create a cryptocurrency trading bot in Elixir (YouTube videos, ebook pay what you want) <span class="hashtag-icon-placeholder"></span>eli...
New
PragmaticBookshelf
This hands-on book will quickly get you building, querying, and comparing graph data models using a robust, concurrent programming langua...
New
mafinar
I did not add this to a “this weekend I’ll learn” like my few other journals as I am decided on using this in the long term. Last I work...
New
JimmyCarterSon
I am following this tutorial . I have followed carefully correcting errors as I go. The app allows you to create a blog post and add comm...
New
JimmyCarterSon
Hello, I am working on a new application with Elixir, Dish_out. I want to see Data I follow this tutorial with Elixir Casts. However, I ...
New
New
PragmaticBookshelf
Programming Ruby is the most complete book on Ruby, covering both the language itself and the standard library as well as commonly used t...
New

Other popular topics Top

Devtalk
Reading something? Working on something? Planning something? Changing jobs even!? If you’re up for sharing, please let us know what you’...
1016 16828 371
New
AstonJ
Or looking forward to? :nerd_face:
New
gagan7995
API 4 Path: /user/following/ Method: GET Description: Returns the list of all names of people whom the user follows Response [ { ...
New
PragmaticBookshelf
Author Spotlight Jamis Buck @jamis This month, we have the pleasure of spotlighting author Jamis Buck, who has written Mazes for Prog...
New
First poster: bot
The overengineered Solution to my Pigeon Problem. TL;DR: I built a wifi-equipped water gun to shoot the pigeons on my balcony, controlle...
New
PragmaticBookshelf
Author Spotlight Erin Dees @undees Welcome to our new author spotlight! We had the pleasure of chatting with Erin Dees, co-author of ...
New
New
AstonJ
Chris Seaton, the creator of TruffleRuby has died. It appears from suicide :cry: He left this note on Twitter on the weekend: And one...
New
PragmaticBookshelf
Author Spotlight: Peter Ullrich @PJUllrich Data is at the core of every business, but it is useless if nobody can access and analyze ...
New
CommunityNews
A Brief Review of the Minisforum V3 AMD Tablet. Update: I have created an awesome-minisforum-v3 GitHub repository to list information fo...
New