1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Abstract services to serialize Nit objects to different formats
19 # This module declares the `serialize` annotation to mark Nit classes as serializable.
20 # For an introduction to this service, refer to the documentation of the `serialization` group.
21 # This documentation provides more technical information on interesting entitie of this module.
23 # Interesting entities for end users of serializable classes:
25 # * Serialize an instance subclass of `Serializable` with either
26 # `Serializer::serializable` and `Serializable::serialize`.
27 # * Deserialize an object using `Deserializer::deserialize`.
28 # The object type must the be checked with an `assert` or otherwise.
30 # Interesting entities to create custom serializable classes:
32 # * Subclass `Serializable` to declare a class as serializable and to customize
33 # the serialization and deserialization behavior.
34 # * Redefine `Serializable::core_serialize_to` to customize the serialization
35 # of the receiver class.
36 # * Redefine `Deserializer::deserialize_class` to customize the deserialization
37 # of a specific class by name.
39 # Interesting entities for serialization format:
41 # * Subclass `Serializer` and `Deserializer` with custom serices.
42 # * In `Serializer`, `serialize` and `serialize_reference` must be redefined.
43 # * In `Deserializer`; `deserialize`, `deserialize_attribute and
44 # `notify_of_creation` must be redefined.
45 module serialization
is
46 new_annotation auto_serializable
47 new_annotation serialize
48 new_annotation noserialize
49 new_annotation serialize_as
52 # Abstract serialization service to be sub-classed by specialized services.
54 # Entry point method of this service, serialize the `object`
56 # This method, and refinements, should handle `null` and probably
57 # use double dispatch to customize the bahavior per serializable objects.
58 fun serialize
(object
: nullable Serializable) is abstract
60 # The object currently serialized by `serialized`
62 # Can be used by a custom serializer to add domain-specific serialization behavior.
63 protected fun current_object
: nullable Object is abstract
65 # Serialize an object, with full serialization or a simple reference
66 protected fun serialize_reference
(object
: Serializable) is abstract
68 # Serialize an attribute to compose a serializable object
70 # This method should be called from `Serializable::core_serialize_to`.
71 fun serialize_attribute
(name
: String, value
: nullable Object)
73 if not try_to_serialize
(value
) then
74 warn
("argument {name} of type {value.class_name} is not serializable.")
78 # Serialize `value` is possie, i.e. it is `Serializable` or `null`
79 fun try_to_serialize
(value
: nullable Object): Bool
81 if value
isa Serializable then
82 value
.serialize_to_or_delay
(self)
83 else if value
== null then
89 # The method is called when a standard `value` is serialized
91 # The default behavior is to call `value.core_serialize_to(self)` but it
92 # can be redefined by a custom serializer to add domain-specific serialization behavior.
93 fun serialize_core
(value
: Serializable)
95 value
.core_serialize_to
(self)
98 # Warn of problems and potential errors (such as if an attribute
99 # is not serializable)
100 fun warn
(msg
: String) do print
"Serialization warning: {msg}"
103 # Abstract deserialization service
105 # The main service is `deserialize`.
106 abstract class Deserializer
107 # Deserialize and return an object, storing errors in the attribute `errors`
109 # If a `static_type` is given, only subtypes of the `static_type` are accepted.
111 # This method behavior varies according to the implementation engines.
112 fun deserialize
(static_type
: nullable String): nullable Object is abstract
114 # Deserialize the attribute with `name` from the object open for deserialization
116 # The `static_type` can be used as last resort if the deserialized object
117 # desn't have any metadata declaring the dynamic type.
119 # Return the deserialized value or null on error, and set
120 # `deserialize_attribute_missing` to whether the attribute was missing.
122 # Internal method to be implemented by the engines.
123 fun deserialize_attribute
(name
: String, static_type
: nullable String): nullable Object is abstract
125 # Was the attribute queried by the last call to `deserialize_attribute` missing?
126 var deserialize_attribute_missing
= false
128 # Register a newly allocated object (even if not completely built)
130 # Internal method called by objects in creation, to be implemented by the engines.
131 fun notify_of_creation
(new_object
: Object) is abstract
133 # Deserialize the next available object as an instance of `class_name`
135 # Return the deserialized object on success and
136 # record in `errors` if `class_name` is unknown.
138 # This method should be redefined for each custom subclass of `Serializable`.
139 # All refinement should look for a precise `class_name` and call super
140 # on unsupported classes.
141 protected fun deserialize_class
(class_name
: String): nullable Object do
142 if class_name
== "Error" then return new Error.from_deserializer
(self)
143 return deserialize_class_intern
(class_name
)
146 # Generated service to deserialize the next available object as an instance of `class_name`
148 # Refinements to this method will be generated by the serialization phase.
149 # To avoid conflicts, there should not be any other refinements to this method.
150 # You can instead use `deserialize_class`.
151 protected fun deserialize_class_intern
(class_name
: String): nullable Object do
152 errors
.add
new Error("Deserialization Error: Doesn't know how to deserialize class \"{class_name}\
"")
156 # Should `self` keep trying to deserialize an object after an error?
158 # This behavior takes effect after each attribute deserialization with
159 # errors such as a missing attribute or the value is of the wrong type.
160 # If `keep_going`, the attribute will be skipped but the engine will
161 # deserialize the next attribute.
162 # If `not keep_going`, the engine stops deserializing right away.
164 # When at `true`, this may cause the accumulation of a lot of entries in `errors`.
167 var keep_going
: nullable Bool = null is writable
169 # Errors encountered in the last call to `deserialize`
170 var errors
= new Array[Error]
173 # Error on invalid dynamic type for a deserialized attribute
174 class AttributeTypeError
177 autoinit receiver
, attribute_name
, attribute
, expected_type
179 # Parent object of the problematic attribute
182 # Name of the problematic attribute in `receiver`
183 var attribute_name
: String
185 # Deserialized object that isn't of the `expected_type`
186 var attribute
: nullable Object
188 # Name of the type expected for `attribute`
189 var expected_type
: String
191 redef var message
is lazy
do
192 var attribute
= attribute
193 var found_type
= if attribute
!= null then attribute
.class_name
else "null"
195 return "Deserialization Error: {
196 }Wrong type on `{receiver.class_name}::{attribute_name}` expected `{expected_type}`, got `{found_type}`"
200 # Instances of this class can be passed to `Serializer::serialize`
201 interface Serializable
202 # Serialize `self` to `serializer`
204 # This is a shortcut to `Serializer::serialize`.
205 fun serialize_to
(serializer
: Serializer) do serializer
.serialize
(self)
207 # Actual serialization of `self` to `serializer`
209 # This writes the full data of `self` to `serializer`.
211 # This method can be redefined in sub classes and refinements.
212 # It should use `Serializer::serialize_attribute` to to register real or
213 # logical attributes.
215 # Any refinement should have its equivalent refinement of
216 # `Deserializer::deserialize_class` to support this custom deserialization.
217 fun core_serialize_to
(serializer
: Serializer) do end
219 # Accept references or force direct serialization (using `serialize_to`)
221 # The subclass change the default behavior, which will accept references,
222 # to force to always serialize copies of `self`.
223 private fun serialize_to_or_delay
(v
: Serializer) do v
.serialize_reference
(self)
225 # Create an instance of this class from the `deserializer`
227 # This constructor is refined by subclasses to correctly build their instances.
228 init from_deserializer
(deserializer
: Deserializer) is nosuper
do end
231 redef interface Object
232 # Is `self` the same as `other` in a serialization context?
234 # Used to determine if an object has already been serialized.
235 fun is_same_serialized
(other
: nullable Object): Bool do return is_same_instance
(other
)
237 # Hash value use for serialization
239 # Used in combination with `is_same_serialized`. If two objects are the same
240 # in a serialization context, they must have the same `serialization_hash`.
241 fun serialization_hash
: Int do return object_id
244 # Instances of this class are not delayed and instead serialized immediately
245 # This applies mainly to `universal` types
246 interface DirectSerializable
249 redef fun serialize_to_or_delay
(v
) do serialize_to
(v
)
252 redef class Bool super DirectSerializable end
253 redef class Char super DirectSerializable end
254 redef class Int super DirectSerializable end
255 redef class Float super DirectSerializable end
256 redef class CString super DirectSerializable end
257 redef class Text super DirectSerializable end
258 redef class SimpleCollection[E
] super Serializable end
259 redef class Map[K
, V
] super Serializable end
261 redef class Couple[F
, S
]
264 redef init from_deserializer
(v
)
266 v
.notify_of_creation
self
267 var first
= v
.deserialize_attribute
("first")
268 var second
= v
.deserialize_attribute
("second")
272 redef fun core_serialize_to
(v
)
274 v
.serialize_attribute
("first", first
)
275 v
.serialize_attribute
("second", second
)
282 redef init from_deserializer
(v
)
284 v
.notify_of_creation
self
285 var item
= v
.deserialize_attribute
("item")
289 redef fun core_serialize_to
(v
)
291 v
.serialize_attribute
("item", first
)
298 redef init from_deserializer
(v
)
300 v
.notify_of_creation
self
302 var message
= v
.deserialize_attribute
("message")
303 if not message
isa String then message
= ""
306 var cause
= v
.deserialize_attribute
("cause")
307 if cause
isa nullable Error then self.cause
= cause
310 redef fun core_serialize_to
(v
)
312 v
.serialize_attribute
("message", message
)
313 v
.serialize_attribute
("cause", cause
)