Example of an ad hoc serializer that is tailored to transform business specific objects into customized representation.

In the following, we expose 3 business classes, E, A and B, and a specific business serializer RestrictedSerializer. The principle is that the custom serialization logic in enclosed into the RestrictedSerializer and that the standard serializer is unchanged.

The additional behaviors exposed are:

  • replace a full business object (see E::id): instead of serializing an attribute, the custom serializer uses a different representation.
  • inject a phantom attribute (see E::phantom): when serializing, the custom serializer injects new attributes.
  • hide a normally serialized attribute (see E::semi_private): when serializing, the custom serializer hides some specific attributes.

The advantage of the approach is that it is done programmatically so can be adapted to real complex use cases. Basically, this is half-way between the full automatic serialization and the full manual serialisation.

Introduced classes

class A

serialization :: A

A business object, with an integer information
class B

serialization :: B

A business object associated with an A.
abstract class E

serialization :: E

The root class of the business objects.
class RestrictedJsonSerializer

serialization :: RestrictedJsonSerializer

Extends JsonSerializer and adds specific business behaviors when dealing with business objects.
class RestrictedSerializer

serialization :: RestrictedSerializer

Extends Serializer and adds specific business behaviors when dealing with business objects.

Redefined classes

redef abstract class Deserializer

serialization :: custom_serialization $ Deserializer

Abstract deserialization service
redef class Sys

serialization :: custom_serialization $ Sys

The main class of the program.

All class definitions

class A

serialization $ A

A business object, with an integer information
class B

serialization $ B

A business object associated with an A.
redef abstract class Deserializer

serialization :: custom_serialization $ Deserializer

Abstract deserialization service
abstract class E

serialization $ E

The root class of the business objects.
class RestrictedJsonSerializer

serialization $ RestrictedJsonSerializer

Extends JsonSerializer and adds specific business behaviors when dealing with business objects.
class RestrictedSerializer

serialization $ RestrictedSerializer

Extends Serializer and adds specific business behaviors when dealing with business objects.
redef class Sys

serialization :: custom_serialization $ Sys

The main class of the program.
package_diagram serialization::custom_serialization custom_serialization serialization serialization serialization::custom_serialization->serialization json::serialization_write serialization_write serialization::custom_serialization->json::serialization_write poset poset serialization->poset meta meta serialization->meta json json serialization->json serialization::caching caching json::serialization_write->serialization::caching ...poset ... ...poset->poset ...meta ... ...meta->meta ...json ... ...json->json ...serialization::caching ... ...serialization::caching->serialization::caching a_star-m a_star-m a_star-m->serialization::custom_serialization

Ancestors

module abstract_collection

core :: abstract_collection

Abstract collection classes and services.
module abstract_text

core :: abstract_text

Abstract class for manipulation of sequences of characters
module array

core :: array

This module introduces the standard array structure.
module bitset

core :: bitset

Services to handle BitSet
module bytes

core :: bytes

Services for byte streams and arrays
module caching

serialization :: caching

Services for caching serialization engines
module circular_array

core :: circular_array

Efficient data structure to access both end of the sequence.
module codec_base

core :: codec_base

Base for codecs to use with streams
module codecs

core :: codecs

Group module for all codec-related manipulations
module collection

core :: collection

This module define several collection classes.
module core

core :: core

Standard classes and methods used by default by Nit programs and libraries.
module engine_tools

serialization :: engine_tools

Advanced services for serialization engines
module environ

core :: environ

Access to the environment variables of the process
module error

core :: error

Standard error-management infrastructure.
module exec

core :: exec

Invocation and management of operating system sub-processes.
module file

core :: file

File manipulations (create, read, write, etc.)
module fixed_ints

core :: fixed_ints

Basic integers of fixed-precision
module fixed_ints_text

core :: fixed_ints_text

Text services to complement fixed_ints
module flat

core :: flat

All the array-based text representations
module gc

core :: gc

Access to the Nit internal garbage collection mechanism
module hash_collection

core :: hash_collection

Introduce HashMap and HashSet.
module inspect

serialization :: inspect

Refine Serializable::inspect to show more useful information
module iso8859_1

core :: iso8859_1

Codec for ISO8859-1 I/O
module kernel

core :: kernel

Most basic classes and methods.
module list

core :: list

This module handle double linked lists
module math

core :: math

Mathematical operations
module meta

meta :: meta

Simple user-defined meta-level to manipulate types of instances as object.
module native

core :: native

Native structures for text and bytes
module numeric

core :: numeric

Advanced services for Numeric types
module protocol

core :: protocol

module queue

core :: queue

Queuing data structures and wrappers
module range

core :: range

Module for range of discrete objects.
module re

core :: re

Regular expression support for all services based on Pattern
module ropes

core :: ropes

Tree-based representation of a String.
module serialization_core

serialization :: serialization_core

Abstract services to serialize Nit objects to different formats
module sorter

core :: sorter

This module contains classes used to compare things and sorts arrays.
module stream

core :: stream

Input and output streams of characters
module text

core :: text

All the classes and methods related to the manipulation of text entities
module time

core :: time

Management of time and dates
module union_find

core :: union_find

union–find algorithm using an efficient disjoint-set data structure
module utf8

core :: utf8

Codec for UTF-8 I/O

Parents

module serialization

serialization :: serialization

General serialization services
module serialization_write

json :: serialization_write

Services to write Nit objects to JSON strings: serialize_to_json and JsonSerializer

Children

module a_star-m

a_star-m

# Example of an ad hoc serializer that is tailored to transform business specific objects into customized representation.
#
# In the following, we expose 3 business classes, `E`, `A` and `B`, and a specific business serializer `RestrictedSerializer`.
# The principle is that the custom serialization logic in enclosed into the `RestrictedSerializer` and that the
# standard serializer is unchanged.
#
# The additional behaviors exposed are:
#
# * replace a full business object (see `E::id`):
#   instead of serializing an attribute, the custom serializer uses a different representation.
# * inject a phantom attribute (see `E::phantom`):
#   when serializing, the custom serializer injects new attributes.
# * hide a normally serialized attribute (see `E::semi_private`):
#   when serializing, the custom serializer hides some specific attributes.
#
# The advantage of the approach is that it is done programmatically so can be adapted to real complex use cases.
# Basically, this is half-way between the full automatic serialization and the full manual serialisation.
module custom_serialization is example

import serialization
import json::serialization_write

# The root class of the business objects.
# This factorizes most services and domain knowledge used by the `RestrictedSerializer`
#
# In real enterprise-level code, the various specific behaviors can be specified in more semantic classifiers.
abstract class E
	serialize

	# The semantic business identifier.
	#
	# With the `RestrictedSerializer`, references to `E` objects will be replaced with `id`-based information.
	# This avoid to duplicate or enlarge the information cross-call wise.
	#
	# A future API/REST call can then request the _missing_ object from its identifier.
	var id: String

	# A phantom attribute to be serialized by the custom `RestrictedSerializer`.
	#
	# This can be used to inject constant or computed information that make little sense to have as a genuine attribute in
	# the Nit model.
	fun phantom: String do return "So Much Fun"

	# An attribute not to be serialized by the custom `RestrictedSerializer`.
	# e.g. we want it on the DB but not in API/REST JSON messages
	#
	# Note that the annotation `noserialize` hides the attribute for all serializers.
	# To hide the attribute only in the `RestrictedSerializer`, it will have to actively ignore it.
	var semi_private = "secret"

	# Test method that serializes `self` and prints with the standard JsonSerializer
	fun ser_json
	do
		var w = new StringWriter
		var js = new JsonSerializer(w)
		js.plain_json = true
		js.serialize(self)
		print w
	end

	# Test method that serializes `self` and prints with the custom RestrictedJsonSerializer.
	fun ser_json2
	do
		var w = new StringWriter
		var js = new RestrictedJsonSerializer(w)
		js.plain_json = true
		js.serialize(self)
		print w
	end
end

# Extends Serializer and adds specific business behaviors when dealing with business objects.
#
# As with standard Nit, additional level of customization can be achieved by adding more double-dispatching :)
# We can thus choose to locate the specific behavior in the serializer, or the serializees.
class RestrictedSerializer
	super Serializer

	# This method is called to generate the attributes of a serialized representation
	redef fun serialize_core(value)
	do
		super

		if value isa E then
			# Inject additional special domain-specific information
			serialize_attribute("more-data", value.phantom)
		end
	end

	# This method is called when trying to serialize a specific attribute
	redef fun serialize_attribute(name, value)
	do
		var recv = current_object
		if recv isa E then
			# do not serialize `E::semi_private`
			if name == "semi_private" then return
		end

		if value isa E then
			# Do not serialize references to `E`.
			# Just use a domain-specific value that make sense in the business logic.
			serialize_attribute(name, "ID:" + value.id)
			return
		end

		super
	end
end

# Extends JsonSerializer and adds specific business behaviors when dealing with business objects.
class RestrictedJsonSerializer
	super JsonSerializer
	super RestrictedSerializer
end

# A business object, with an integer information
class A
	super E
	serialize

	# A business information
	var i: Int
end

# A business object associated with an `A`.
class B
	super E
	serialize

	# A business association
	var a: A
end

# The business data to serialize
var a = new A("a", 1)
var b = new B("b", a)

a.ser_json
a.ser_json2
b.ser_json
b.ser_json2

lib/serialization/examples/custom_serialization.nit:15,1--155,11