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