Merge: doc: fixed some typos and other misc. corrections
[nit.git] / lib / serialization / safe.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Services for safer deserialization engines
16 module safe
17
18 import poset
19
20 import serialization
21 private import engine_tools
22
23 # Deserialization engine limiting which types can be deserialized
24 class SafeDeserializer
25 super Deserializer
26
27 # Accepted parameterized classes to deserialize
28 #
29 # If `whitelist.empty`, all types are accepted.
30 #
31 # ~~~
32 # import json
33 #
34 # class MyClass
35 # serialize
36 # end
37 #
38 # var json_string = """
39 # {"__class": "MyClass"}
40 # """
41 #
42 # var deserializer = new JsonDeserializer(json_string)
43 # var obj = deserializer.deserialize
44 # assert deserializer.errors.is_empty
45 # assert obj isa MyClass
46 #
47 # deserializer = new JsonDeserializer(json_string)
48 # deserializer.whitelist.add "Array[String]"
49 # deserializer.whitelist.add "AnotherAcceptedClass"
50 # obj = deserializer.deserialize
51 # assert deserializer.errors.length == 1
52 # assert obj == null
53 # ~~~
54 var whitelist = new Array[Text]
55
56 # Should objects be checked if they a subtype of the static type before deserialization?
57 #
58 # Defaults to `true`, as it should always be activated.
59 # It can be turned off to implement the subtype check itself.
60 var check_subtypes = true is writable
61
62 # Should `self` accept to deserialize an instance of `dynamic_type` for an attribute wuth `static_type`?
63 #
64 # Uses `whitelist` if not empty...
65 # Check correct inheritance if `check_subtypes`...
66 fun accept(dynamic_type: Text, static_type: nullable Text): Bool
67 do
68 if whitelist.not_empty and not whitelist.has(dynamic_type) then
69 errors.add new Error("Deserialization Error: '{dynamic_type}' not in whitelist")
70 return false
71 end
72
73 if static_type != null and check_subtypes then
74 var static_class = static_type.strip_nullable_and_params.to_s
75 var dynamic_class = dynamic_type.strip_nullable_and_params.to_s
76 if not class_inheritance_metamodel.has_edge(dynamic_class, static_class) then
77 errors.add new Error("Deserialization Error: `{dynamic_type}` is not a subtype of the static type `{static_type}`")
78 return false
79 end
80 end
81
82 return true
83 end
84 end
85
86 redef class Sys
87 # Class inheritance graph, implemented by the `json` package
88 #
89 # ~~~
90 # import json
91 #
92 # var hierarchy = class_inheritance_metamodel
93 # assert hierarchy.has_edge("String", "Object")
94 # assert not hierarchy.has_edge("Object", "String")
95 # ~~~
96 fun class_inheritance_metamodel: POSet[String] is abstract
97 end
98
99 redef class Deserializer
100 redef fun deserialize_class(name)
101 do
102 if name == "POSet[String]" then return new POSet[String].from_deserializer(self)
103 if name == "POSetElement[String]" then return new POSetElement[String].from_deserializer(self)
104 if name == "HashSet[String]" then return new HashSet[String].from_deserializer(self)
105 if name == "HashMap[String, POSetElement[String]]" then return new HashMap[String, POSetElement[String]].from_deserializer(self)
106
107 return super
108 end
109 end