X-Git-Url: http://nitlanguage.org diff --git a/lib/serialization/serialization.nit b/lib/serialization/serialization.nit index e3ca6b3..cdbaed4 100644 --- a/lib/serialization/serialization.nit +++ b/lib/serialization/serialization.nit @@ -14,246 +14,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Abstract services to serialize Nit objects to different formats -# -# This module declares the `serialize` annotation to mark Nit classes as serializable. -# For an introduction to this service, refer to the documentation of the `serialization` group. -# This documentation provides more technical information on interesting entitie of this module. -# -# Interesting entities for end users of serializable classes: -# -# * Serialize an instance subclass of `Serializable` with either -# `Serializer::serializable` and `Serializable::serialize`. -# * Deserialize an object using `Deserializer::deserialize`. -# The object type must the be checked with an `assert` or otherwise. -# -# Interesting entities to create custom serializable classes: -# -# * Subclass `Serializable` to declare a class as serializable and to customize -# the serialization and deserialization behavior. -# * Redefine `Serializable::core_serialize_to` to customize the serialization -# of the receiver class. -# * Redefine `Deserializer::deserialize_class` to customize the deserialization -# of a specific class by name. -# -# Interesting entities for serialization format: -# -# * Subclass `Serializer` and `Deserializer` with custom serices. -# * In `Serializer`, `serialize` and `serialize_reference` must be redefined. -# * In `Deserializer`; `deserialize`, `deserialize_attribute and -# `notify_of_creation` must be redefined. -module serialization is - new_annotation auto_serializable - new_annotation serialize - new_annotation noserialize -end - -# Abstract serialization service to be sub-classed by specialized services. -interface Serializer - # Entry point method of this service, serialize the `object` - # - # This method, and refinements, should handle `null` and probably - # use double dispatch to customize the bahavior per serializable objects. - fun serialize(object: nullable Serializable) is abstract - - # Serialize an object, with full serialization or a simple reference - protected fun serialize_reference(object: Serializable) is abstract - - # Serialize an attribute to compose a serializable object - # - # This method should be called from `Serializable::core_serialize_to`. - fun serialize_attribute(name: String, value: nullable Object) - do - if not try_to_serialize(value) then - warn("argument {name} of type {value.class_name} is not serializable.") - end - end - - # Serialize `value` is possie, i.e. it is `Serializable` or `null` - fun try_to_serialize(value: nullable Object): Bool - do - if value isa Serializable then - value.serialize_to_or_delay(self) - else if value == null then - serialize value - else return false - return true - end - - # Warn of problems and potential errors (such as if an attribute - # is not serializable) - fun warn(msg: String) do print "Serialization warning: {msg}" -end - -# Abstract deserialization service -# -# After initialization of one of its sub-classes, call `deserialize` -abstract class Deserializer - # Main method of this class, returns a Nit object - fun deserialize: nullable Object is abstract - - # Internal method to be implemented by sub-classes - fun deserialize_attribute(name: String): nullable Object is abstract - - # Internal method called by objects in creation, - # to be implemented by sub-classes - fun notify_of_creation(new_object: Object) is abstract - - # Deserialize the next available object as an instance of `class_name` - # - # Returns the deserialized object on success, aborts on error. - # - # This method should be redefined for each custom subclass of `Serializable`. - # All refinement should look for a precise `class_name` and call super - # on unsupported classes. - protected fun deserialize_class(class_name: String): nullable Object do - return deserialize_class_intern(class_name) - end - - # Generated service to deserialize the next available object as an instance of `class_name` - # - # Refinements to this method will be generated by the serialization phase. - # To avoid conflicts, there should not be any other refinements to this method. - # You can instead use `deserialize_class`. - protected fun deserialize_class_intern(class_name: String): nullable Object do - errors.add new Error("Deserialization Error: Doesn't know how to deserialize class \"{class_name}\"") - return null - end - - # Should `self` keep trying to deserialize an object after an error? - # - # This behavior takes effect after each attribute deserialization with - # errors such as a missing attribute or the value is of the wrong type. - # If `keep_going`, the attribute will be skipped but the engine will - # deserialize the next attribute. - # If `not keep_going`, the engine stops deserializing right away. - # - # When at `true`, this may cause the accumulation of a lot of entries in `errors`. - # - # Default at `true`. - var keep_going: nullable Bool = null is writable - - # Errors encountered in the last call to `deserialize` - var errors = new Array[Error] -end - -# Deserialization got wrong attribute names -class AttributeTypeError - super Error - - # Parent object of the problematic attribute - var receiver: Object - - # Name of the problematic attribute in `receiver` - var attribute_name: String - - # Deserialized object that isn't of the `expected_type` - var attribute: nullable Object - - # Name of the type expected for `attribute` - var expected_type: String - - redef fun to_s - do - var attribute = attribute - var found_type = if attribute != null then attribute.class_name else "null" - - return "Deserialization Error: { - }Wrong type on `{receiver.class_name}::{attribute_name}` expected `{expected_type}`, got `{found_type}`" - end -end - -# Instances of this class can be passed to `Serializer::serialize` -interface Serializable - # Serialize `self` to `serializer` - # - # This is a shortcut to `Serializer::serialize`. - fun serialize_to(serializer: Serializer) do serializer.serialize(self) - - # Actual serialization of `self` to `serializer` - # - # This writes the full data of `self` to `serializer`. - # - # This method can be redefined in sub classes and refinements. - # It should use `Serializer::serialize_attribute` to to register real or - # logical attributes. - # - # Any refinement should have its equivalent refinement of - # `Deserializer::deserialize_class` to support this custom deserialization. - fun core_serialize_to(serializer: Serializer) do end - - # Accept references or force direct serialization (using `serialize_to`) - # - # The subclass change the default behavior, which will accept references, - # to force to always serialize copies of `self`. - private fun serialize_to_or_delay(v: Serializer) do v.serialize_reference(self) - - # Create an instance of this class from the `deserializer` - # - # This constructor is refined by subclasses to correctly build their instances. - init from_deserializer(deserializer: Deserializer) do end -end - -redef interface Object - # Is `self` the same as `other` in a serialization context? - # - # Used to determine if an object has already been serialized. - fun is_same_serialized(other: nullable Object): Bool do return is_same_instance(other) - - # Hash value use for serialization - # - # Used in combination with `is_same_serialized`. If two objects are the same - # in a serialization context, they must have the same `serialization_hash`. - fun serialization_hash: Int do return object_id -end - -# Instances of this class are not delayed and instead serialized immediately -# This applies mainly to `universal` types -interface DirectSerializable - super Serializable - - redef fun serialize_to_or_delay(v) do serialize_to(v) -end - -redef class Bool super DirectSerializable end -redef class Char super DirectSerializable end -redef class Int super DirectSerializable end -redef class Float super DirectSerializable end -redef class NativeString super DirectSerializable end -redef class String super DirectSerializable end -redef class SimpleCollection[E] super Serializable end -redef class Map[K, V] super Serializable end - -redef class Couple[F, S] - super Serializable - - redef init from_deserializer(v) - do - v.notify_of_creation self - var first = v.deserialize_attribute("first") - var second = v.deserialize_attribute("second") - init(first, second) - end - - redef fun core_serialize_to(v) - do - v.serialize_attribute("first", first) - v.serialize_attribute("second", second) - end -end - -redef class Ref[E] - super Serializable - - redef init from_deserializer(v) - do - v.notify_of_creation self - var item = v.deserialize_attribute("item") - init item - end +# General serialization services +module serialization - redef fun core_serialize_to(v) - do - v.serialize_attribute("item", first) - end -end +import serialization_core +import inspect