module SBAN::Serializable
Overview
The SBAN::Serializable
module automatically generates methods for SBAN serialization when included.
Example
require "sban"
class Location
include SBAN::Serializable
@[SBAN::Field(key: "lat")]
property latitude : Float64
@[SBAN::Field(key: "lng")]
property longitude : Float64
end
class House
include SBAN::Serializable
property address : String
property location : Location?
end
house = House.from_sban({"address" => "Crystal Road 1234", "location" => {"lat" => 12.3, "lng" => 34.5}}.to_sban)
house.address # => "Crystal Road 1234"
house.location # => #<Location:0x10cd93d80 @latitude=12.3, @longitude=34.5>
house.to_sban # => Bytes[...]
houses = Array(House).from_sban([{"address" => "Crystal Road 1234", "location" => {"lat" => 12.3, "lng" => 34.5}}].to_sban)
houses.size # => 1
houses.to_sban # Bytes[...]
Usage
Including SBAN::Serializable
will create #to_sban
and self.from_sban
methods on the current class,
and a constructor which takes a SBAN::Decoder
. By default, these methods serialize into a sban
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_sban and a constructor taking a SBAN::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 SBAN::Field
can be placed on the instance variable. Annotating property, getter and setter macros is also allowed.
require "sban"
class A
include SBAN::Serializable
@[SBAN::Field(key: "my_key")]
getter a : Int32?
end
SBAN::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_sban(SBAN::Decoder)
andto_sban(value, SBAN::Builder)
as class methods. Examples of converters areTime::Format
andTime::EpochConverter
forTime
. - emit_null: if
true
, emits anull
value for nilable property (by default nulls are not emitted) - nil_as_undefined: if
true
, when the value isnil
, it is emitted asundefined
(by defaultnil
are encoded asnull
)
Deserialization also respects default values of variables:
require "sban"
struct A
include SBAN::Serializable
@a : Int32
@b : Float64 = 1.0
end
A.from_sban({"a" => 1}.to_sban) # => A(@a=1, @b=1.0)
Extensions: SBAN::Serializable::Unmapped
.
If the SBAN::Serializable::Unmapped
module is included, unknown properties in the SBAN
document will be stored in a Hash(String, SBAN::Type)
. On serialization, any keys inside sban_unmapped
will be serialized and appended to the current json object.
require "sban"
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 SBAN::Serializable::Options
supported properties:
- emit_nulls: if
true
, emits anull
value for all nilable properties (by default nulls are not emitted) - nil_as_undefined: if
true
, emits anil
value as undefined (by default nil emitsnull
)
require "json"
@[SBAN::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.