
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
- 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

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










Other popular topics









Latest in Backend
Latest (all)
Categories:
Popular Portals
- /elixir
- /opensuse
- /rust
- /kotlin
- /ruby
- /erlang
- /python
- /clojure
- /react
- /quarkus
- /go
- /vapor
- /v
- /react-native
- /wasm
- /django
- /security
- /nodejs
- /centos
- /rails
- /haskell
- /fable
- /gleam
- /js
- /swift
- /deno
- /tailwind
- /assemblyscript
- /laravel
- /symfony
- /phoenix
- /crystal
- /typescript
- /debian
- /adonisjs
- /julia
- /arch-linux
- /svelte
- /spring
- /c-plus-plus
- /preact
- /flutter
- /actix
- /java
- /angular
- /ocaml
- /zig
- /scala
- /kubuntu
- /zotonic
- /vim
- /rocky
- /lisp
- /html
- /keyboards
- /emacs
- /vuejs
- /nim
- /nerves
- /elm