talentdeficit / jsx

an erlang application for consuming, producing and manipulating json. inspired by yajl
MIT License
695 stars 218 forks source link

why record can not encode and decode by jsx #99

Open lcwxz1989 opened 8 years ago

lcwxz1989 commented 8 years ago

I have a record type need to encode and decode, but I find jsx did not support demo (push@demo)1> rd(message1, {expire, num}). message1 (push@demo)2> jsx:encode(#{a => #message1{expire=1,num=2}}). \ exception error: bad argument in function jsx_parser:value/4 (src/jsx_parser.erl, line 129)

talentdeficit commented 8 years ago

there's no reasonable way for jsx to get a record's fields at runtime, so the best possible encoding would probably be just a list of the values. that wouldn't allow decoding to a record though

you can write your own encoder that supports records though:

-module(recordizer).
-export([encode/1]).
%% custom encoder callback
-export([encode/2]).

-record(message1, {
  expire,
  num
}).

%% the parser is unmodified but the term passed to the parser instance is
%% preencoded by the custom `encode/2` function below
encode(Term) ->
    (jsx:parser(jsx_to_json, [], [escaped_strings]))(encode(Term, ?MODULE) ++ [end_json]).

%% this captures any instance that matches the record as a top level term, the value
%% for a map or proplist entry or a member of a list and returns a map to the parser
%% instead. anything else is handled by the default parser in `jsx_encoder`
encode(Message, _EntryPoint) when is_record(Message, message1) ->
    [#{expire => Message#message1.expire, num => Message#message1.num}];
encode(Term, EntryPoint) ->
    jsx_encoder:encode(Term, EntryPoint).
okeuday commented 8 years ago

@lcwxz1989 records only exist during preprocessing, so if you want them to automatically go to/from json with jsx, you will need a parse transform. I have one at https://github.com/okeuday/record_info_runtime/ which can provide the record field names based on the record name with the function record_info_fields/1. With that, you can make code automatically go to/from json.

However, the reason to not make it automatic is to have better type checking on the record types. That approach argues for manually creating the json based on the record fields and not using a parse transform.

paulo-ferraz-oliveira commented 4 years ago

Is this an actual issue? Back in 2016, probably, but now with all the map support and so...