JSON::Serializable works with Enum?

I am reading the Crystal Release Notes from back(0.1.0) to front this week end.

Really lots of interesting histories and stories.

I saw some code like this in 0.16.0 release note

require "json"
require "big"
require "big/json"

enum Color
  Red   = 1
  Green = 2
  Blue  = 3
end

class Lollipop
  JSON.mapping({
    color:    Color,
    diameter: BigFloat,
  })
end

json = %({"color": 2, "diameter": 12.3456789123456789})
lollipop = Lollipop.from_json(json)
p lollipop # => #<Lollipop:0x10c962f30 @color=Green, @diameter=12.34567

Sure above code not works anymore because JSON.mapping was replaced by JSON::Serializable, right?

But, the issue is, i could not write the code for the equivalent of the above code use 1.5.0.

Following code raise error.

Unhandled exception: Expected String but was Int at line 1, column 12
  parsing Lollipop#color at line 1, column 2 (JSON::SerializableError)
enum Color
  Red   = 1
  Green = 2
  Blue  = 3
end

class Lollipop
  include JSON::Serializable

  property color : Color
  property diameter : BigFloat
end

json = %({"color": 2, "diameter": 12.3456789123456789})
lollipop = Lollipop.from_json(json)
pp! lollipop

So, how to fix that?

Thank you.

This was changed in as part of Serialize Enum to underscored String by default by straight-shoota · Pull Request #10431 · crystal-lang/crystal · GitHub. Tl;dr you should use string representation instead of the integer value in your JSON. E.g."color": "red". Alternatively there is also Enum::ValueConverter(T) - Crystal 1.5.0 if you wanted to keep using the integer value.

1 Like

Thanks you very much, both solution works!

require "json"
require "big"
require "big/json"

enum Color
  Red   = 1
  Green = 2
  Blue  = 3
end

class Lollipop
  include JSON::Serializable

  @[JSON::Field(converter: Enum::ValueConverter(Color))]
  property color : Color
  property diameter : BigFloat
end

json = %({"color": 1, "diameter": 12.3456789123456789})
lollipop = Lollipop.from_json(json)
pp! lollipop

Or

enum Color
  Red   = 1
  Green = 2
  Blue  = 3
end

class Lollipop
  include JSON::Serializable

  property color : Color
  property diameter : BigFloat
end

json = %({"color": "red", "diameter": 12.3456789123456789})
lollipop = Lollipop.from_json(json)
pp! lollipop
1 Like