module

CBOR::Serializable

The CBOR::Serializable module automatically generates methods for CBOR serialization when included.

Example

require "cbor"

class Location
  include CBOR::Serializable

  @[CBOR::Field(key: "lat")]
  property latitude : Float64

  @[CBOR::Field(key: "lng")]
  property longitude : Float64
end

class House
  include CBOR::Serializable

  property address : String
  property location : Location?
end

house = House.from_cbor({"address" => "Crystal Road 1234", "location" => {"lat" => 12.3, "lng" => 34.5}}.to_cbor)
house.address  # => "Crystal Road 1234"
house.location # => #<Location:0x10cd93d80 @latitude=12.3, @longitude=34.5>
house.to_cbor  # => Bytes[...]

houses = Array(House).from_cbor([{"address" => "Crystal Road 1234", "location" => {"lat" => 12.3, "lng" => 34.5}}].to_cbor)
houses.size    # => 1
houses.to_cbor # Bytes[...]

Usage

Including CBOR::Serializable will create #to_cbor and self.from_cbor methods on the current class, and a constructor which takes a CBOR::Decoder. By default, these methods serialize into a cbor object containing the value of every instance variable, the keys being the instance variable name. Most primitives and collections supported as instance variable values (string, integer, array, hash, etc.), along with objects which define to_cbor and a constructor taking a CBOR::Decoder. Union types are also supported, including unions with nil. If multiple types in a union parse correctly, it is undefined which one will be chosen.

To change how individual instance variables are parsed and serialized, the annotation CBOR::Field can be placed on the instance variable. Annotating property, getter and setter macros is also allowed.

require "cbor"

class A
  include CBOR::Serializable

  @[CBOR::Field(key: "my_key")]
  getter a : Int32?
end

CBOR::Field properties:

  • ignore: if true skip this field in serialization and deserialization (by default false)
  • key: the value of the key in the json object (by default the name of the instance variable)
  • converter: specify an alternate type for parsing and generation. The converter must define from_cbor(CBOR::Decoder) and to_cbor(value, CBOR::Builder) as class methods. Examples of converters are Time::Format and Time::EpochConverter for Time.
  • presence: if true, a @{{key}}_present instance variable will be generated when the key was present (even if it has a null value), false by default
  • emit_null: if true, emits a null value for nilable property (by default nulls are not emitted)
  • nil_as_undefined: if true, when the value is nil, it is emitted as undefined (by default nil are encoded as null)

Deserialization also respects default values of variables:

require "cbor"

struct A
  include CBOR::Serializable
  @a : Int32
  @b : Float64 = 1.0
end

A.from_cbor({"a" => 1}.to_cbor) # => A(@a=1, @b=1.0)

Extensions: CBOR::Serializable::Unmapped.

If the CBOR::Serializable::Unmapped module is included, unknown properties in the CBOR document will be stored in a Hash(String, CBOR::Type). On serialization, any keys inside cbor_unmapped will be serialized and appended to the current json object.

require "cbor"

struct A
  include JSON::Serializable
  include JSON::Serializable::Unmapped
  @a : Int32
end

a = A.from_json(%({"a":1,"b":2})) # => A(@json_unmapped={"b" => 2_i64}, @a=1)
a.to_json                         # => {"a":1,"b":2}

Class annotation CBOR::Serializable::Options

supported properties:

  • emit_nulls: if true, emits a null value for all nilable properties (by default nulls are not emitted)
  • nil_as_undefined: if true, emits a nil value as undefined (by default nil emits null)
require "json"

@[CBOR::Serializable::Options(emit_nulls: true)]
class A
  include JSON::Serializable
  @a : Int32?
end

Discriminator field

A very common JSON serialization strategy for handling different objects under a same hierarchy is to use a discriminator field. For example in GeoJSON each object has a "type" field, and the rest of the fields, and their meaning, depend on its value.

You can use JSON::Serializable.use_json_discriminator for this use case.

Constructors

new(*, __decoder_for_cbor_serializable decoder : CBOR::Decoder)
Source

Instance methods

to_cbor(cbor : CBOR::Encoder)
Source

Nested types