0530579ee97df8a3dd668793df9d8629ff4fec7b
[nit.git] / lib / serialization / serialization.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # Abstract services to serialize Nit objects to different formats
18 #
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.
22 #
23 # Interesting entities for end users of serializable classes:
24 #
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.
29 #
30 # Interesting entities to create custom serializable classes:
31 #
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.
38 #
39 # Interesting entities for serialization format:
40 #
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
50 end
51
52 # Abstract serialization service to be sub-classed by specialized services.
53 interface Serializer
54 # Entry point method of this service, serialize the `object`
55 #
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
59
60 # The object currently serialized by `serialized`
61 #
62 # Can be used by a custom serializer to add domain-specific serialization behavior.
63 protected fun current_object: nullable Object is abstract
64
65 # Serialize an object, with full serialization or a simple reference
66 protected fun serialize_reference(object: Serializable) is abstract
67
68 # Serialize an attribute to compose a serializable object
69 #
70 # This method should be called from `Serializable::core_serialize_to`.
71 fun serialize_attribute(name: String, value: nullable Object)
72 do
73 if not try_to_serialize(value) then
74 warn("argument {name} of type {value.class_name} is not serializable.")
75 end
76 end
77
78 # Serialize `value` is possie, i.e. it is `Serializable` or `null`
79 fun try_to_serialize(value: nullable Object): Bool
80 do
81 if value isa Serializable then
82 value.serialize_to_or_delay(self)
83 else if value == null then
84 serialize value
85 else return false
86 return true
87 end
88
89 # The method is called when a standard `value` is serialized
90 #
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)
94 do
95 value.core_serialize_to(self)
96 end
97
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}"
101 end
102
103 # Abstract deserialization service
104 #
105 # The main service is `deserialize`.
106 abstract class Deserializer
107 # Deserialize and return an object, storing errors in the attribute `errors`
108 #
109 # If a `static_type` is given, only subtypes of the `static_type` are accepted.
110 #
111 # This method behavior varies according to the implementation engines.
112 fun deserialize(static_type: nullable String): nullable Object is abstract
113
114 # Deserialize the attribute with `name` from the object open for deserialization
115 #
116 # The `static_type` restricts what kind of object can be deserialized.
117 #
118 # Return the deserialized value or null on error, and set
119 # `deserialize_attribute_missing` to whether the attribute was missing.
120 #
121 # Internal method to be implemented by the engines.
122 fun deserialize_attribute(name: String, static_type: nullable String): nullable Object is abstract
123
124 # Was the attribute queried by the last call to `deserialize_attribute` missing?
125 var deserialize_attribute_missing = false
126
127 # Register a newly allocated object (even if not completely built)
128 #
129 # Internal method called by objects in creation, to be implemented by the engines.
130 fun notify_of_creation(new_object: Object) is abstract
131
132 # Deserialize the next available object as an instance of `class_name`
133 #
134 # Return the deserialized object on success and
135 # record in `errors` if `class_name` is unknown.
136 #
137 # This method should be redefined for each custom subclass of `Serializable`.
138 # All refinement should look for a precise `class_name` and call super
139 # on unsupported classes.
140 protected fun deserialize_class(class_name: String): nullable Object do
141 if class_name == "Error" then return new Error.from_deserializer(self)
142 return deserialize_class_intern(class_name)
143 end
144
145 # Generated service to deserialize the next available object as an instance of `class_name`
146 #
147 # Refinements to this method will be generated by the serialization phase.
148 # To avoid conflicts, there should not be any other refinements to this method.
149 # You can instead use `deserialize_class`.
150 protected fun deserialize_class_intern(class_name: String): nullable Object do
151 errors.add new Error("Deserialization Error: Doesn't know how to deserialize class \"{class_name}\"")
152 return null
153 end
154
155 # Should `self` keep trying to deserialize an object after an error?
156 #
157 # This behavior takes effect after each attribute deserialization with
158 # errors such as a missing attribute or the value is of the wrong type.
159 # If `keep_going`, the attribute will be skipped but the engine will
160 # deserialize the next attribute.
161 # If `not keep_going`, the engine stops deserializing right away.
162 #
163 # When at `true`, this may cause the accumulation of a lot of entries in `errors`.
164 #
165 # Default at `true`.
166 var keep_going: nullable Bool = null is writable
167
168 # Errors encountered in the last call to `deserialize`
169 var errors = new Array[Error]
170 end
171
172 # Deserialization error related to an attribute of `receiver`
173 abstract class AttributeError
174 super Error
175
176 # Parent object of the problematic attribute
177 var receiver: Object
178
179 # Name of the problematic attribute in `receiver`
180 var attribute_name: String
181 end
182
183 # Invalid dynamic type for a deserialized attribute
184 class AttributeTypeError
185 super AttributeError
186
187 autoinit receiver, attribute_name, attribute, expected_type
188
189 # Deserialized object that isn't of the `expected_type`
190 var attribute: nullable Object
191
192 # Name of the type expected for `attribute`
193 var expected_type: String
194
195 redef var message is lazy do
196 var attribute = attribute
197 var found_type = if attribute != null then attribute.class_name else "null"
198
199 return "Deserialization Error: {
200 }Wrong type on `{receiver.class_name}::{attribute_name}` expected `{expected_type}`, got `{found_type}`"
201 end
202 end
203
204 # Missing attribute at deserialization
205 class AttributeMissingError
206 super AttributeError
207
208 autoinit receiver, attribute_name
209
210 redef var message is lazy do
211 return "Deserialization Error: Missing attribute `{receiver.class_name}::{attribute_name}`"
212 end
213 end
214
215 # Instances of this class can be passed to `Serializer::serialize`
216 interface Serializable
217 # Serialize `self` to `serializer`
218 #
219 # This is a shortcut to `Serializer::serialize`.
220 fun serialize_to(serializer: Serializer) do serializer.serialize(self)
221
222 # Actual serialization of `self` to `serializer`
223 #
224 # This writes the full data of `self` to `serializer`.
225 #
226 # This method can be redefined in sub classes and refinements.
227 # It should use `Serializer::serialize_attribute` to to register real or
228 # logical attributes.
229 #
230 # Any refinement should have its equivalent refinement of
231 # `Deserializer::deserialize_class` to support this custom deserialization.
232 fun core_serialize_to(serializer: Serializer) do end
233
234 # Accept references or force direct serialization (using `serialize_to`)
235 #
236 # The subclass change the default behavior, which will accept references,
237 # to force to always serialize copies of `self`.
238 private fun serialize_to_or_delay(v: Serializer) do v.serialize_reference(self)
239
240 # Create an instance of this class from the `deserializer`
241 #
242 # This constructor is refined by subclasses to correctly build their instances.
243 init from_deserializer(deserializer: Deserializer) is nosuper do end
244 end
245
246 redef interface Object
247 # Is `self` the same as `other` in a serialization context?
248 #
249 # Used to determine if an object has already been serialized.
250 fun is_same_serialized(other: nullable Object): Bool do return is_same_instance(other)
251
252 # Hash value use for serialization
253 #
254 # Used in combination with `is_same_serialized`. If two objects are the same
255 # in a serialization context, they must have the same `serialization_hash`.
256 fun serialization_hash: Int do return object_id
257 end
258
259 # Instances of this class are not delayed and instead serialized immediately
260 # This applies mainly to `universal` types
261 interface DirectSerializable
262 super Serializable
263
264 redef fun serialize_to_or_delay(v) do serialize_to(v)
265 end
266
267 redef class Bool super DirectSerializable end
268 redef class Char super DirectSerializable end
269 redef class Int super DirectSerializable end
270 redef class Float super DirectSerializable end
271 redef class CString super DirectSerializable end
272 redef class Text super DirectSerializable end
273 redef class SimpleCollection[E] super Serializable end
274 redef class Map[K, V] super Serializable end
275
276 redef class Couple[F, S]
277 super Serializable
278
279 redef init from_deserializer(v)
280 do
281 v.notify_of_creation self
282 var first = v.deserialize_attribute("first")
283 var second = v.deserialize_attribute("second")
284 init(first, second)
285 end
286
287 redef fun core_serialize_to(v)
288 do
289 v.serialize_attribute("first", first)
290 v.serialize_attribute("second", second)
291 end
292 end
293
294 redef class Ref[E]
295 super Serializable
296
297 redef init from_deserializer(v)
298 do
299 v.notify_of_creation self
300 var item = v.deserialize_attribute("item")
301 init item
302 end
303
304 redef fun core_serialize_to(v)
305 do
306 v.serialize_attribute("item", first)
307 end
308 end
309
310 redef class Error
311 super Serializable
312
313 redef init from_deserializer(v)
314 do
315 v.notify_of_creation self
316
317 var message = v.deserialize_attribute("message")
318 if not message isa String then message = ""
319 init message
320
321 var cause = v.deserialize_attribute("cause")
322 if cause isa nullable Error then self.cause = cause
323 end
324
325 redef fun core_serialize_to(v)
326 do
327 v.serialize_attribute("message", message)
328 v.serialize_attribute("cause", cause)
329 end
330 end