Custom classes and native TypeScript/JavaScript classes serialization and deserialization with metadata into JSON compliant standard.
- Serialization of primitives and wrappers;
- Serialization of JavaScript built-ins types: Array, Date, Map and Set;
- Serialization of classes marked for serialization using a default serialization strategy;
- Serialization of objects metadata defined with Reflect library;
- Serialization of cyclic references;
- Custom serialization/deserialization transformers, allowing flexibility and default transformers override;
- Object serialization/deserialization customization per serializable class;
- Open/Closed principle allowing programmer to override basically everything;
- Minimal or no extra metadata on the output JSON object (configurable globally or per operation);
- Serialization groups;
- Custom types transformers, allowing almost anything to be serialized;
- Namespaces and custom names;
- IoC Container aware;
- Minification friendly.*
*Minification friendly requires special treatment. More on this on section Usage: Minification.
The following features are not supported, but may be added in the future. If you requires any of the following unsupported features, please ask and propose a solution. 😉
- Generics - Since TypeScript uses the concept of Type Erasure, its very hard to come up with some architecture and API that does not involve too much manual definitions or JSON pollution;
- Multiple Types (e.g.
Number
|MyClass
) - Despite it being relatively easy to implement, it is not a core feature since most of the serializable types have a well defined structure and multiple types normally is actived through inheritance, which is supported.
- ES2018+ JavaScript VM (e.g.: NodeJS 12.x LTS+, Chrome 78+)
- NodeJS 12.x LTS
- TypeScript 3.7.5
See serializer.spec.ts to see usage while this sections is not written yet 👍
This section describes the internal rules and design decisions used in this library.
Notice: The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as described in RFC 2119.
- MUST be friendly to IoC containers, such as Inversify;
- MUST only perform serialization/deserialization and type checking. JSON schema validation are other topic and have specific libraries for that (eg.: AJV);
- SHOULD respect JSON standards, unless explicitly said otherwise;
- SHOULD have minimal performance impact on applications.
Date
objects are serialized as ISO strings. (JavaScriptJSON
default);NaN
values are serialized as"NaN"
string. (JavaScriptJSON
usesnull
);-Infinity
/Infinity
are serialized as"-Infinity"
and"Infinity"
strings. (JavaScriptJSON
usesnull
);Map
objects are serialized as tuples <K,V> (eg.:[[1, "A"], [2, "B"], [3, {prop: "bar"}]]
). (JavaScriptJSON
does not serializeMap
objects, resulting in empty objects -{}
);Set
objects are serialized as arrays[key, value]
(e.g.:[[1, "A"], [2, "B"], [3, {prop: "bar"}]]
). (JavaScriptJSON
does not serializeSet
objects, resulting in empty objects -{}
);
- All types/classes not decorated with
@Serializable
MUST use a@Transformer
to perform serialization; - Global and per operation behavior configuration;
- To enforce wrappers, you MUST use the extra options of each built-in transformer;
- Possibility to serialize without creating any metadata;
- Possibility to deserialize without metadata. Requires the
expectedType
argument on theSerializer#deserialize
orSerializer#fromJson
method; - If a wrapper is used (Number, Boolean, String), but it was not enforced by
TypesEnum.WRAPPER
enum, then value MUST be serialized/deserialized as a primitive;
To serialize an object, an TOP -> BOTTOM strategy is used. In other words, this means that the object is first serialized from its top hierarchy (parent class) to the bottom hierarchy (subclass). Example:
class A {
// Serializable fields
}
class B extends A {
// Serializable fields
}
In this example, all the fields on the class A
marked to serialization will be serialized with the default strategy or, if the class implements the ISerializable
interface, the method writeJson
will be called with a JsonWriter service allowing the programmer to customize the process. After A
has its fields serialized, the Serializer
will move down the hierarchy, serializing B
with the same strategy as A
.
Note: inside writeJson
method you MUST use this
to reference the object being serialized. Also, if the class inherits other serializable classes, the JsonWriter.json
getter will contain the serialized fields declared on those classes.
To deserialize an object, an TOP -> BOTTOM strategy is also used. In other words, this means that the object is first deserialized from its top hierarchy (parent class) to the bottom hierarchy (subclass). Example:
class A {
// Serializable fields
}
class B extends A {
// Serializable fields
}
In this example, a B
instance will be created first, but the deserialization of the fields will begin from the A
class with the default strategy or, if the class implements the ISerializable
interface, the method readJson
will be called with a JsonReader service allowing the programmer to customize the process. After A
has its fields deserialized, the Serializer
will move down the hierarchy, deserializing B
fields with the same strategy as A
.
Note: inside readJson
method you MUST use this
to reference the object being deserialized. Also, if the class inherits other serializable classes, all the classes up on the hierarchy will be already deserialized and their fields MAY be safely used.
Describes method signatures to customize an object serialization/deserialization process for classes marked with @Serializable
decorator. When a class implements this interface and the default Serializer
is used, the methods writeJson
and readJson
will be called during serialization and deserialization with the object resulted from the default strategy in Serializer#writeJson
and Serializer#readJson
.
You MAY disable the default serialization/deserialization strategy for the class by setting the option defaultStrategy
in @Serializable
to false
.
Methods Summary | Description |
---|---|
public readJson<T>(defaultInstance: T, json: Json<T>): T |
Customize the deserialization operation. |
public writeJson<T>(defaultJson: Json<T>, instance: T): Json<T> |
Customize the serialization operation. |
This method is responsible for customizing the deserialization of the object, restoring it to the original state with the correct prototype. You MAY use this methods in two different ways: changing de default
or creating a brand new object from json
. In all cases you must return the restored object (T
).
Generic Types:
T
: (optional) The restored object type. MUST be the class itself or not set (inferred).
Parameters | Type | Description |
---|---|---|
default |
T |
The deserialized object using the default deserialization strategy. The object is an instance of T . |
json |
Json<T> |
The raw JSON object being deserialized. The object is an instance of Object with Json<T> format. |
Returns |
---|
The deserialized object as an instance of T . |
This method is responsible for customizing the serialization of the object, generating a Json<T>
version that can be converted into JSON. You MAY use this methods in two different ways: changing de default
or creating a brand new object from instance
. In all cases you must return the serialized object (Json<T>
).
Generic Types:
T
: (optional) The type of the object to be serialized. MUST be the class itself or not set (inferred).
Parameters | Type | Description |
---|---|---|
default |
Json<T> |
The serialized object using the default serialization strategy. The object is an instance of Object with Json<T> format. |
instance |
T |
The object instance to be serialized. The object is an instance of T . |
Returns |
---|
The serialized object as an instance of Object in Json<T> format. |
Marks a class as a serializable type, registering it on the SerializerRegistry
as a serializable type. Only non abstract classes can be marked as serializable.
Signatures:
@Serializable()
@Serializable(options: SerializableOptions)
Arguments | Type | Description |
---|---|---|
options |
SerializableOptions |
(optional) Configure registry options. |
SerializableOptions (Type) |
Type | Description |
---|---|---|
name |
string |
(optional) Name of the type. MAY be used to define a custom name. Default: constructor.name (class name) |
namespace |
string |
(optional) Namespace of the type. MAY be used to group related types. Default: "" (empty string, global namespace) |
version |
number |
(optional) Define the current version of the type (integer). MAY be used as a version control to prevent bugs of incompatible versions (i.e. client version <> server version). Default: 1 |
defaultStrategy |
boolean |
(optional) Flag to enable the default deserialization strategy used by Serializer . Default: true |
Marks a field for serialization. When marking custom types (i.e. programmer defined classes) be aware of the TDZ HELL (temporal dead zone) with cyclic dependencies (see TypeScript issue #14971), in which case the programmer MUST set the type
parameter (errors MAY be thrown if not set), otherwise its optional.
Generic Types:
E
: Theextra
type inSerializeOptions<E>
;
Signatures:
@Serialize<E = void>()
@Serialize<E = void>()
@Serialize<E = void>(type: () => Class|Function|TypesEnum|Array<Class|Function|TypesEnum>)
@Serialize<E = void>(options: SerializeOptions)
@Serialize<E = void>(type: () => Class|Function|TypesEnum|Array<Class|Function|TypesEnum>, options: SerializeOptions)
Arguments | Type | Description |
---|---|---|
type |
Class Function TypesEnum Array<Class Function TypesEnum> |
(optional) The type or a list of types that the field holds. Note: When using user defined classes with cyclic dependencies this MUST be set to prevent TDZ errors. Default: infered by reflection ("design:type" ). |
options |
SerializeOptions<E> |
(optional) Defines serialization options, such as groups. |
SerializeOptions<E> (Type) |
Type | Description |
---|---|---|
groups |
Array<string> |
(optional) A list of serialization groups to include the attribute during serialization/deserialization. |
extra |
E |
(optional) Some extra data to be passed to the Transformer during serialization/deserialization. An example of usage is for Array on the ArrayTransformer (ArrayExtra ). |
Marks a class a type transformer to be used during serialization/deserialization. The type is registered on the SerializerRegistry
. This decorator provides a declarative way to define a transformer instead of the direct use of SerializerRegistry#addTransformer
method. The class MUST implement the ITransformer<T, S, E>
interface.
The default behavior is to instantiate only once and cache the object for the rest of the application lifecycle. This can be changed by setting the parameter TransformerOptions.instatiationBehavior
.
Generic Types:
T
: The type to be transformed before serialization (input);S
: The transformed type after serialization (output);E
: (optional) Some extra data to be passed to the transformer in a per serializable field configuration. May be set in@Serialize
or directly inSerializerRegistry.addType
Signatures:
@Transformer<T = any, S = any>(type: Class)
@Transformer<T = any, S = any>(type: Class, options: TransformerOptions)
Arguments | Type | Description |
---|---|---|
type |
Class |
The type to be transformed in a JSON compatible format. |
options |
TransformerOptions |
(optional) Defines transformer options, such as instantiation policy. |
TransformerOptions (Type) |
Type | Description |
---|---|---|
instantiationPolicy |
InstantiationPolicyEnum |
(optional) The specific policy of this transformer instantiation. Overrides global policy in SerializerConfig . Default: InstantiationPolicyEnum.SINGLETON . |
The service that performs serialization and deserialization process. Can be configured globally or per operation to change the serialization and deserialization behaviors, such as including or not typeMetadata
and performing other operations.
Accessors Summary | Type | Description |
---|---|---|
config |
SerializerConfig |
Gets or sets the global configuration of the serializer service |
Methods Summary | Description |
---|---|
public serialize<T extends Object>(instance: T, options?: SerializationOptions): string |
Serializes object(s) into a JSON string . |
public deserialize<T extends Object>(json: string, options?: DeserializationOptions): T |
Deserializes a an JSON string into T . |
public deserialize<T extends Object>(json: string, clazz: Class<T> options?: DeserializationOptions): T |
Deserializes a an JSON string into T by using clazz as root type or type checking. |
public toJson<T extends Object>(instance: T, options?: SerializationOptions): Json<T> |
Converts a given instance or instances of a class to its "JSON object" version, including, if configured, the necessary metadata to convert it back to a instance of the class. |
public fromJson<T extends Object>(json: Json<T>, options?: DeserializationOptions): T |
Restores a given json object to its original instance of class, if possible. For the restoration process to work for some given classes, some metadata must be set. |
public fromJson<T extends Object>(json: Array<Json<T>>, options?: DeserializationOptions): Array<T> |
Restores a given array of json objects to its original instance of class, if possible. For the restoration process to work for some given classes, some metadata must be set. |
public fromJson<T extends Object>(json: Json<T>, clazz: Class<T>, options?: DeserializationOptions): T |
Restores a given json object to its original instance of class, if possible, using a specific class to validate or as the type of the root object. For the restoration process to work for some given classes, some metadata must be set. |
public fromJson<T extends Object>(json: Array<Json<T>>, clazz: Class<T>, options?: DeserializationOptions): Array<T> |
Restores a given array of json objects to its original instance of class, if possible, using a specific class to validate or as the type of the root object. For the restoration process to work for some given classes, some metadata must be set. |
protected readJson<T>(json: Json<T>): T |
protected Default deserialization strategy for @Serializable classes. Classes that implements ISerializable will receive the result of this method and can customize the operation per class. Override this method to customize the default deserialization process. |
protected writeJson<T>(instance: T): Json<T> |
protected Default serialization strategy for @Serializable classes. Classes that implements ISerializable will receive the result of this method and can customize the operation per class. Override this method to customize the default serialization process. |
SerializerConfig (Type) |
Type | Description |
---|---|---|
typeMetadata |
boolean |
(optional) Flag to include object type metadata. Including object type metadata allows transparent object deserialization (deserialization without expectedType ), in which case disables types checking but still allows full deserialization. Default: true |
objectMetadata |
boolean |
(optional) Flag to includes object metadata defined with Reflect.defineMetadata or @Reflect.metadata Default: true |
typeCheck |
boolean |
(optional) Flag to enable type checking upon deserialization (requires expectedType to validate root object). If a type is a subtype of the type being checked against, it will pass validation, otherwise it will throw TypeMismatchException . Default: true |
versionMismatchBehavior |
BehaviorEnum |
(optional) Configure the behavior of class version check upon deserialization. If configured to BehaviorEnum.ERROR , will throw VersionMismatchException . Default: BehaviorEnum.ERROR |
SerializationOptions (Type) |
Type | Description |
---|---|---|
typeMetadata |
boolean |
(optional) Overrides global configuration SerializerConfig.typeMetadata |
objectMetadata |
boolean |
(optional) Overrides global configuration SerializerConfig.objectMetadata |
groups |
Array<string> |
(optional) Groups to include in serialization process. By default if no group is passed, all attributes will be serialized. If a group is set, only non grouped attributes and attributes that belongs to any of the specified group will be serialized. You may exclude the ungrouped attributes by setting the flag excludeUngrouped . |
excludeUngrouped |
boolean |
(optional) Flag to exclude ungrouped attributes, keeping only attributes that belongs to any of the defined groups . Default: false |
DeserializationOptions (Type) |
Type | Description |
---|---|---|
typeCheck |
boolean |
(optional) Overrides global configuration SerializerConfig.typeCheck |
groups |
Array<string> |
(optional) Groups to include in deserialization process. By default if no group is passed, all attributes will be deserialized. If a group is set, only non grouped attributes and attributes that belongs to any of the specified group will be deserialized. You may exclude the ungrouped attributes by setting the flag excludeUngrouped . |
excludeUngrouped |
boolean |
(optional) Flag to exclude ungrouped attributes, keeping only attributes that belongs to any of the defined groups . Default: false |
# public deserialize<T extends Object>(json: string, clazz: Class<T> options?: DeserializationOptions): T
Converts a given instance of a class to its "JSON object" version, including, if configured, the necessary metadata to convert it back to a instance of the class.
Generic types:
T
: (optional) The object type (class) to be transformed intoJson<T>
. Default: inferred.
Parameters | Type | Description |
---|---|---|
instance |
T |
The object to be converted into Json<T> . |
options |
SerializerOptions |
(optional) Configure how the operation should be done. Default: Uses the global configuration. |
Throws | Description |
---|---|
ArrayDimensionsOutOfRangeException |
|
IheritanceNonSerializableException |
|
NonSerializableException |
|
TypeMismatchException |
|
VersionMismatchException |
Returns |
---|
The instance converted to "JSON object" (plain object) |
# public toJson<T extends Object>(instances: Array<T>, options?: SerializationOptions): Array<Json<T>>
Converts a given array of instances of a class to its "json object" version, including, if configured, the necessary metadata to convert it back to a instance of the class.
Generic types:
T
: (optional) The object type (class) to be transformed intoJson<T>
. Default: inferred.
Parameters | Type | Description |
---|---|---|
instances |
Array<T> |
The array of objects to be converted into Json<T> . |
options |
SerializerOptions |
(optional) Configure how the operation should be done. Default: Uses the global configuration. |
Throws | Description |
---|---|
ArrayDimensionsOutOfRangeException |
|
IheritanceNonSerializableException |
|
NonSerializableException |
|
TypeMismatchException |
|
VersionMismatchException |
Returns |
---|
The array converted to "JSON object" (plain object) |
# public fromJson<T extends Object>(json: Array<Json<T>>, options?: DeserializationOptions): Array<T>
# public fromJson<T extends Object>(json: Json<T>, clazz: Class<T>, options?: DeserializationOptions): T
# public fromJson<T extends Object>(json: Array<Json<T>>, clazz: Class<T>, options?: DeserializationOptions): Array<T>
static class Holds information for all registered types marked with @Serializable
decorator and all transformers marked with @Transformer
. Also provides methods to programmatically retrieve and add types and transformers.
Method Summary | Description |
---|---|
public static getTypes(): Map<string, RegisteredTypesMap> |
Gets the list of registered serializable types. |
public static addType(clazz: Class, name?: string, namespace?: string, version?: number): void |
Registers a type in the registry as a serializable type. Imperative way instead of @Serializable . |
public getTransformers(): Map<Class, ITransformer<any, any>>: void |
Gets the list of registered type transformers. |
public addTransformer<T = any, S = any>(clazz: Class, transformer: ITransformerStatic<T, S>): void |
Registers a type transformer in the registry. Imperative way of @Transformer |
# public static addTransformer<T = any, S = any>(clazz: Class, transformer: ITransformerStatic<T, S>)
Default Array
transformer.
Default Boolean
transformer.
Default Map
transformer.
Default Number
transformer.
Default Object
transformer.
Default Set
transformer.
Default String
transformer.
Used to define a type to configure a serializable attribute that cannot be expressed naturally in runtime, such as any
type.
Value | Description |
---|---|
ANY |
Accepts any type. Use when you do not want to type check. |
Used to customize behavior on some operations that MAY have different behaviors under certain circumstances or by programmer design choice.
Value | Description |
---|---|
WARNING |
Writes a warning on the console when a given situation happens. |
ERROR |
Throws an error when a given situation happens. You MAY want to try-catch theses exceptions. |
IGNORE |
Do nothing when a given situation happens. |
Used to customize object instantiation policy.
Value | Description |
---|---|
SINGLETON |
Instantiate only once and then cache. |
TRANSIENT |
Gets a new instance every time the object is required. |
Type alias for a abstract class definition. Accepts only abstract classes (non constructable classes, abstract classes).
Generic types:
T
: (optional) The type (class) being represented. Default:Object
Type alias for a class definition.
Generic types:
T
: The type (class) being represented.
Type alias for all the extra data that all the built-in transformers accept.
Type alias for a json version of a given class. Only the class attributes are keep, methods are excluded. Object
and Array
methods are kept.
Generic types:
T
: The type (class) of the object this JSON structure represents.
Represents serialization metadata to include in the JSON allowing transparent deserialization or correct inheritance deserialization.
Attributes Summary | Type | Description |
---|---|---|
versions |
Array<[string, number]> |
(optional) Array of tuples with fully qualified name (i.e. namespace plus names separated by "." - dots) with the class versions used to serialize the object. The order is from TOP to BOTTOM in the inheritance hierarchy (e.g. [A , B , C ] in a C extends B , B extends A inheritance chain). |
objectMetadata |
Array<[string, any]> |
(optional) Array of tuples of object metadata to restore. |
Type alias for a class definition. Accepts only newable classes (i.e. constructable classes, non abstract classes). Generic Types
T
: (optional) The type (class) being represented. Default:Object
Represents the configuration of a serializable field.
Generic Types
C
: (optional) The class the field belongs to. Default:any
E
: (optional) Extra data to be passed to transformers. Defaultvoid
Attributes Summary | Type | Description |
---|---|---|
name |
keyof C |
The name of the field. |
type |
() => Class TypesEnum |
The type of the field. Must be set as an arrow function to prevent TDZ errors. |
groups |
Array<string> |
(optional) List of context groups that this field must be included. |
extra |
E ExtraTypes |
(optional) Extra data to be passed to the transformers. |
Options of a serializable type.
Attributes Summary | Type | Description |
---|---|---|
name |
string |
(optional) Name of the type. MAY be used to define a custom name. Default: constructor.name (class name). |
namespace |
string |
(optional) Namespace of the type. MAY be used to group related types. Default: "global" . |
version |
number |
(optional) Define the current version of the type (integer). MAY be used as a version control to prevent bugs of incompatible versions (i.e. client version != server version). Default: 1 . |
Serialization options for a field marked with @Serialize
.
Attributes Summary | Type | Description |
---|---|---|
groups |
Array<string> |
(optional) A list of serialization groups to include the attribute during serialization/deserialization. |
extra |
E ExtraTypes |
(optional) Some extra data to be passed to the Transformer during serialization/deserialization. An example of usage is for Array on the ArrayTransformer (ArrayExtra ). |
Options to configure a ITransformer
.
Attributes Summary | Type | Description |
---|---|---|
instantiationPolicy |
InstantiationPolicyEnum |
(optional) The specific policy of this transformer instantiation. Overrides global policy in SerializerConfig. Default: InstantiationPolicyEnum.SINGLETON |
override |
boolean |
(optional) Flag to allow an existing type transformer to be overridden, otherwise an TransformerAlreadyDefinedException is thrown when trying to override an existing ITransformer definition for a given type. Default: false . |
Inherits: Exception
Inherits: Exception
Use my packages in your projects? You think they are awesome? So, help me give more time to develop them by becoming a sponsor. 😉