-
-
Notifications
You must be signed in to change notification settings - Fork 4
Home
Yet another Nth JSON Erlang project, while there are already good ones ?
Yes, jason
offer features mainly for Erlang records handling, which are not widely proposed in other projects.
jason
do not use NIF, so if performance is your main interest, see other well known projects using NIFs. However see Benchmark.
So what makes jason
usefull for me, then ?
-
jason
's bias is to be able to encode and decode records at runtime, without any code manipulation at compile time. This makejason
easy to use, with a minimal footprint in your own source code. -
jason
let you easily convert JSON object to record specification, and create for you ad-hoc modules to handle records. Even with deeply nested JSON objects. -
jason
allow you to use JSON to records translation when source is not stable and JSON object can change without any warning. This is particulary interesting when JSON source is coming from third party. - Float are converted with automatic precision without need to set a precision depth.
-
Pretty printing JSON in several indentation format is another rare feature that
jason
gives you, among others. - Only very few options to be user friendly.
Some important things are to be known before using jason
. Please read carefully below chapters.
Keys, if no mode
is set, or if {mode, struct}
is used, are utf8 binaries.
For all other modes, unless option {binary, k}
or {binary, kv}
is set, keys will be converted to atoms.
However, if key length is more than 255 characters, or containing utf8 characters and local Erlang release < 20.0, key will be converted to binary. This will not be possible for {mode, record}
for which key must be atoms, and will raise an error in such case. This case should be rare fortunately.
Values, if no mode
is set, or if {mode, struct}
is used are utf8 binaries.
For all other modes, unless option {binary, v}
or {binary, kv}
is set, values will be converted to string if printable, otherwise kept in utf8 binary.
{binary, v}
or {binary, kv}
with {mode, record}
as it can result in badarg
errors, especially with nested records where v
part is a record and not convertible to binary.
jason
was created initially to handle easily Erlang records from and to JSON.
Erlang records are, finally, only tuples with an atom name as first element. This first element is lost while encoded in JSON, as JSON object are 'anonymous' (except by declaring object name in object itself). The problem is to affect the keys (left side) of JSON entries.
There is two ways to do this :
- By passing record's key list as option :
{records, [{RecordName1, [Field1, ...]}, ...]}
- By asking
jason
to extract record info from module(s) abstract code :{records, [ModName, ...]}
First way is easy by using built-in record_info(fields, RecordName)
.
First way is recommended when possible for obvious performance reason.
Second way is slower, but is handy when many record definitions has to be passed to encoding. This make the code also easy for records declared locally :
jason:encode(Something, [{records, [?MODULE]}]).
Make sure however that abstract code will be available after compilation. Compile native is not the case...
Counterpart of the fact that JSON objects are 'anonymous', i.e without name declaration, is that we cannot give a meaningful name (first element of tuple) to generated Erlang records, without magic.
jason
decode JSON object by creating dynamically named records based on a portable hash (phash2
) on keys and value type.
For instance {"k1": 1,"k2": "ab"}
creates a record {'8056669',1,"ab"}
(i.e '8056669'#{'k1'=1, 'k2'="ab"}
). Record name is phash2([{k1, integer},{k2,list}])
casted to atom.
Note : hash collision is possible in theory but very unlikely in real life usage.
jason
create for you dynamically compiled module, called with same name than record, to handle easily those records.
Deeply nested JSON object are cleanly handled bottom up, so that each parent record use child record types.
Note : using option {binary, v}
or {binary, kv}
will create a module with a different hash than without option,
and also a different record definition (value is expected to be binary and not list).