Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

why record can not encode and decode by jsx #99

Open
lcwxz1989 opened this issue Aug 16, 2016 · 3 comments
Open

why record can not encode and decode by jsx #99

lcwxz1989 opened this issue Aug 16, 2016 · 3 comments

Comments

@lcwxz1989
Copy link

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
Copy link
Owner

talentdeficit commented Aug 17, 2016

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
Copy link
Contributor

okeuday commented Aug 17, 2016

@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
Copy link
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants