lib/serialization: fix deserialization contructor calling the default init
[nit.git] / lib / serialization / serialization.nit
index 3ba9968..7c689b6 100644 (file)
@@ -16,7 +16,7 @@
 
 # Abstract services to serialize Nit objects to different formats
 #
-# This module declares the `auto_serializable` annotation to mark Nit classes as serializable.
+# 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.
 #
@@ -44,6 +44,8 @@
 #   `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.
@@ -86,7 +88,7 @@ end
 # Abstract deserialization service
 #
 # After initialization of one of its sub-classes, call `deserialize`
-interface Deserializer
+abstract class Deserializer
        # Main method of this class, returns a Nit object
        fun deserialize: nullable Object is abstract
 
@@ -104,9 +106,60 @@ interface Deserializer
        # 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.
-       fun deserialize_class(class_name: String): Object do
-               print "Error: doesn't know how to deserialize class \"{class_name}\""
-               abort
+       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
 
@@ -138,7 +191,7 @@ interface Serializable
        # 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
+       init from_deserializer(deserializer: Deserializer) is nosuper do end
 end
 
 redef interface Object
@@ -146,6 +199,12 @@ redef interface Object
        #
        # 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
@@ -183,7 +242,7 @@ redef class Couple[F, S]
        end
 end
 
-redef class Container[E]
+redef class Ref[E]
        super Serializable
 
        redef init from_deserializer(v)