module

MessagePack::Serializable

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

Example

require "msgpack"

class Location
  include MessagePack::Serializable

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

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

class House
  include MessagePack::Serializable
  property address : String
  property location : Location?
end

house = House.from_msgpack({address: "Crystal Road 1234", location: {"lat": 12.3, "lng": 34.5}}.to_msgpack)
house.address    # => "Crystal Road 1234"
house.location   # => #<Location:0x10cd93d80 @latitude=12.3, @longitude=34.5>
house.to_msgpack # => Bytes[130, 167, 97, 100, 100, 114, 101, 115, ...

houses = Array(House).from_msgpack([{address: "Crystal Road 1234", location: {"lat": 12.3, "lng": 34.5}}].to_msgpack)
houses.size       # => 1
houses.to_msgpack # => Bytes[145, 130, 167, 97, 100, 100, 114, 101, ...

Usage

Including MessagePack::Serializable will create #to_msgpack and self.from_msgpack methods on the current object, and a constructor which accepts a MessagePack::Unpacker. By default, the object serializes into a msgpack object containing values of every instance variable, with keys equal to the variable name. Most primitives and collections supported as instance variable values (String, Number, Array, Hash etc.), along with objects which define #to_msgpack and a constructor accepting a MessagePack::Unpacker. 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 MessagePack::Field can be applied to an instance variable. Annotating property, getter and setter macros is also allowed.

class A
  include MessagePack::Serializable

  @[MessagePack::Field(key: "my_key", emit_null: true)]
  getter a : Int32?
end

MessagePack::Field properties:

  • ignore: skip this field on seriazation and deserialization if ignore is true
  • key: value of the key in the msgpack object (the name of the instance variable by default)
  • root: assume that the value is inside a MessagePack object with a given key (see Object.from_msgpack(string_or_io, root))
  • converter: specify an alternate type for parsing and generation. The converter must define .from_msgpack(MessagePack::Unpacker) and .to_msgpack(value, MessagePack::Packer) as class methods. Example converters are Time::Format and Time::EpochConverter
  • emit_null: emit Null value for this field if it is nil and emit_null is true. Nulls are not emitted by default

Deserialization also respects default values of variables:

struct A
  include MessagePack::Serializable

  @a : Int32
  @b : Float64 = 1.0
end

A.from_msgpack({a: 1}.to_msgpack) # => A(@a=1, @b=1.0)

Extensions: MessagePack::Serializable::Strict, MessagePack::Serializable::Unmapped and MessagePack::Serializable::Presence.

If the MessagePack::Serializable::Strict module is included, then unknown properties in a msgpack object would raise a parse exception on deserialization. Unknown properties are silently ignored by default.

If the MessagePack::Serializable::Unmapped module is included, then all unknown properties in a msgpack object would be put into the @msgpack_unmapped : Hash(String, MessagePack::Any) variable. Upon serialization, all keys inside @msgpack_unmapped would be serialized and appended to the current msgpack object.

struct A
  include MessagePack::Serializable
  include MessagePack::Serializable::Unmapped

  @a : Int32
end

a = A.from_msgpack({a: 1, b: 2}.to_msgpack)                # => A(@msgpack_unmapped={"b" => 2_i64}, @a=1)
Hash(String, MessagePack::Type).from_msgpack(a.to_msgpack) # => {"a" => 1_u8, "b" => 2_u8}

If the MessagePack::Serializable::Presence module is included, then the method #key_present? is defined, which allows to check if a key is present in the original msgpack object.

struct A
  include MessagePack::Serializable
  include MessagePack::Serializable::Presence

  @a : Int32?
end

A.from_msgpack({a: 1}.to_msgpack).key_present?(:a) # => true
A.from_msgpack({b: 1}.to_msgpack).key_present?(:a) # => false

Class annotation MessagePack::Serializable::Options

supported properties:

  • emit_nulls: emit Null value for nilable instance variables if emit_null is true. Nulls are not emitted by default
@[MessagePack::Serializable::Options(emit_nulls: true)]
class A
  include MessagePack::Serializable

  @a : Int32?
end

Constructors

new(*, __pull_for_msgpack_serializable pull : MessagePack::Unpacker)
Source

Instance methods

to_msgpack(packer : MessagePack::Packer)
Source

Macros

use_msgpack_discriminator(field, mapping)
Source

Nested types