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 module json_serialization
25 # Target writing stream
28 init(stream
: OStream) do self.stream
= stream
30 redef fun serialize
(object
)
32 if object
== null then
34 else object
.serialize_to_json
(self)
37 redef fun serialize_attribute
(name
, value
)
39 stream
.write
", \"{name}\
": "
43 redef fun serialize_reference
(object
)
45 if refs_map
.keys
.has
(object
) then
46 # if already serialized, add local reference
47 var id
= ref_id_for
(object
)
48 stream
.write
"\{\"__kind\": \"ref\", \"__id\": {id}\}"
55 # Map of references to already serialized objects
56 var refs_map
= new HashMap[Serializable,Int]
58 private fun ref_id_for
(object
: Serializable): Int
60 if refs_map
.keys
.has
(object
) then
61 return refs_map
[object
]
63 var id
= refs_map
.length
70 # Deserializer from a Json string
71 class JsonDeserializer
74 var root
: nullable Jsonable
75 var path
= new Array[JsonObject]
76 var id_to_object
= new HashMap[Int, Object]
78 var just_opened_id
: nullable Int = null
82 var root
= text
.parse_json
83 if root
isa JsonObject then path
.add
(root
)
87 redef fun deserialize_attribute
(name
)
89 assert not path
.is_empty
90 var current
= path
.last
92 assert current
.keys
.has
(name
)
93 var value
= current
[name
]
95 return convert_object
(value
)
98 # This may be called multiple times by the same object from constructors
99 # in different nclassdef
100 redef fun notify_of_creation
(new_object
)
102 var id
= just_opened_id
104 id_to_object
[id
] = new_object
107 # Convert from simple Json object to Nit object
108 private fun convert_object
(object
: nullable Object): nullable Object
110 if object
isa JsonObject then
111 assert object
.keys
.has
("__kind")
112 var kind
= object
["__kind"]
115 if kind
== "ref" then
116 assert object
.keys
.has
("__id")
117 var id
= object
["__id"]
120 assert id_to_object
.keys
.has
(id
)
121 return id_to_object
[id
]
125 if kind
== "obj" then
126 assert object
.keys
.has
("__id")
127 var id
= object
["__id"]
130 assert object
.keys
.has
("__class")
131 var class_name
= object
["__class"]
132 assert class_name
isa String
134 assert not id_to_object
.keys
.has
(id
) else print
"Error: Object with id '{id}' is deserialized twice."
140 var value
= deserialize_class
(class_name
)
141 just_opened_id
= null
150 if kind
== "char" then
151 assert object
.keys
.has
("__val")
152 var val
= object
["__val"]
153 assert val
isa String
155 if val
.length
!= 1 then print
"Error: expected a single char when deserializing '{val}'."
157 return val
.chars
.first
160 print
"Malformed Json string: unexpected Json Object kind '{kind or else "null"}'"
164 if object
isa Array[nullable Object] then
165 # special case, isa Array[nullable Serializable]
166 var array
= new Array[nullable Serializable]
167 for e
in object
do array
.add e
.as(nullable Serializable)
174 redef fun deserialize
do return convert_object
(root
)
177 redef class Serializable
178 private fun serialize_to_json
(v
: JsonSerializer)
180 var id
= v
.ref_id_for
(self)
181 v
.stream
.write
"\{\"__kind\": \"obj\", \"__id\": {id}, \"__class\
": \"{class_name}\
""
188 redef fun serialize_to_json
(v
) do v
.stream
.write
(to_s
)
192 redef fun serialize_to_json
(v
) do v
.stream
.write
(to_s
)
196 redef fun serialize_to_json
(v
) do v
.stream
.write
(to_s
)
200 redef fun serialize_to_json
(v
) do v
.stream
.write
"\{\"__kind\": \"char\", \"__val\": {to_s.to_json}\}"
204 redef fun serialize_to_json
(v
) do v
.stream
.write
(to_json
)
207 redef class NativeString
208 redef fun serialize_to_json
(v
) do to_s
.serialize_to_json
(v
)
212 redef fun serialize_to_json
(v
)
214 if class_name
== "Array[nullable Serializable]" then
215 # Using class_name to the the exact type
216 # We do not want Array[Int] or anything else here
222 else v
.stream
.write
(", ")
224 if not v
.try_to_serialize
(e
) then
225 v
.warn
("element of type {e.class_name} is not serializable.")
230 # Register as pseudo object
231 var id
= v
.ref_id_for
(self)
232 v
.stream
.write
"\{\"__kind\": \"obj\", \"__id\": {id}, \"__class\
": \"{class_name}\
""
233 v
.stream
.write
""", "__length": {{{length}}}, "__items": ["""
238 else v
.stream
.write
(", ")
240 if not v
.try_to_serialize
(e
) then
241 v
.warn
("element of type {e.class_name} is not serializable.")
249 init from_deserializer
(v
: Deserializer)
251 if v
isa JsonDeserializer then
252 v
.notify_of_creation
self
254 var length
= v
.deserialize_attribute
("__length").as(Int)
255 var arr
= v
.path
.last
["__items"].as(SequenceRead[nullable Object])
256 for i
in length
.times
do
257 var obj
= v
.convert_object
(arr
[i
])