Crystal: auto pack-unpack json methods for structs, and classes

Created on 7 Oct 2016  路  15Comments  路  Source: crystal-lang/crystal

why to_json not added to any record? class?, by default, just like inspect

require "json"

record Bla, a : Int32, b : String

bla = Bla.new 1, "2"
puts bla.inspect # => Bla(@a=1, @b="2")
puts bla.to_json # => wrong number of arguments for 'Bla#to_json' (given 1, expected 0)

instead of

record Bla, a : Int32, b : String do
  JSON.mapping({a: Int32, b: String})
end

Most helpful comment

From a security point of view, it can be dangerous to automatically generate JSON mappings. It may end up leaking secret tokens if one isn't careful enough.

All 15 comments

I _think_ we can try to do it... The main reason it's not done automatically is because:

  • Sometimes a type might have other variables that must not be serialized
  • Sometimes the serialization is a bit different than just all ivars (for example different names, or converters)

We can either provide automatic to_json/from_json to all types, or maybe have a JSON.automapping macro that does it only for types where you invoke it. I'll try both approaches later and see what happens :-)

if user need custom serialize, he just define method to_json, or add mapping by hands
most record cases, it just convert from json and to json

i can write:

record Bla do; JSON.mapping({a : Int32, b : String}); end

but this ugly in case:
https://github.com/crystal-lang/crystal/issues/2787

From a security point of view, it can be dangerous to automatically generate JSON mappings. It may end up leaking secret tokens if one isn't careful enough.

I think adding JSON.mapping to record types is fine, but not class, struct by default.

@asterite If there is not going to be a default to_json method (and I can see why it might not be needed) perhaps there could be some sort of an internally accessible enumerable of all the struct or class members so it would be easy to write a custom one. For example:

json = ""
attributes.each do | attr | 
  json << "\"#{attr.name}\": #{attr.value if attr.type == String}"
end

It's a bit silly example but you get the picture.

Prefer to(JSON).

@kostya That's awesome, I definitely need more schooling on macros. What does this line do?

if var = @{{var.name}}

Also Is there a way to get the type of the instance var?

if var = @{{var.name}} removes nils.

types
https://play.crystal-lang.org/#/r/1d25

Why would the instance_vars iterator yield a nil for the name?

not nil for the name, check nil for variable value.
code outside of {{}}, {%%} is not a macro, this is part of generated program.

Oh got it now.

Thanks.

to learn macro, i think this is best place: https://github.com/mperham/sidekiq.cr/blob/master/src/sidekiq/worker.cr, here it used on expert mode :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

oprypin picture oprypin  路  3Comments

cjgajard picture cjgajard  路  3Comments

asterite picture asterite  路  3Comments

jhass picture jhass  路  3Comments

nabeelomer picture nabeelomer  路  3Comments