neo_doxygen: Quiet warning about the old-style `init`.
[nit.git] / lib / json_serialization.nit
index fd04d62..f090b24 100644 (file)
@@ -17,7 +17,7 @@
 module json_serialization
 
 import serialization
-import simple_json_reader
+import json::static
 
 class JsonSerializer
        super Serializer
@@ -71,16 +71,16 @@ end
 class JsonDeserializer
        super Deserializer
 
-       var root: nullable Object
-       var path = new Array[HashMap[String, nullable Object]]
+       var root: nullable Jsonable
+       var path = new Array[JsonObject]
        var id_to_object = new HashMap[Int, Object]
 
        var just_opened_id: nullable Int = null
 
-       init(text: String)
+       init(text: Text)
        do
-               var root = text.json_to_nit_object
-               if root isa HashMap[String, nullable Object] then path.add(root)
+               var root = text.parse_json
+               if root isa JsonObject then path.add(root)
                self.root = root
        end
 
@@ -107,7 +107,7 @@ class JsonDeserializer
        # Convert from simple Json object to Nit object
        private fun convert_object(object: nullable Object): nullable Object
        do
-               if object isa HashMap[String, nullable Object] then
+               if object isa JsonObject then
                        assert object.keys.has("__kind")
                        var kind = object["__kind"]
 
@@ -154,13 +154,20 @@ class JsonDeserializer
 
                                if val.length != 1 then print "Error: expected a single char when deserializing '{val}'."
                                
-                               return val.first
+                               return val.chars.first
                        end
 
-                       print "Malformed Json string: unexpected Json Object kind '{kind}'"
+                       print "Malformed Json string: unexpected Json Object kind '{kind or else "null"}'"
                        abort
                end
 
+               if object isa Array[nullable Object] then
+                       # special case, isa Array[nullable Serializable]
+                       var array = new Array[nullable Serializable]
+                       for e in object do array.add e.as(nullable Serializable)
+                       return array
+               end
+
                return object
        end
 
@@ -190,18 +197,11 @@ redef class Bool
 end
 
 redef class Char
-       redef fun serialize_to_json(v) do v.stream.write "\{\"__kind\": \"char\", \"__val\": \"{to_s.to_json_s}\"\}"
+       redef fun serialize_to_json(v) do v.stream.write "\{\"__kind\": \"char\", \"__val\": {to_s.to_json}\}"
 end
 
 redef class String
-       redef fun serialize_to_json(v) do v.stream.write("\"{to_json_s}\"")
-
-       private fun to_json_s: String do return self.replace("\\", "\\\\").
-               replace("\"", "\\\"").replace("/", "\\/").
-               replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t")
-               # FIXME add support for unicode char when supported by Nit strings
-               # FIXME add support for \f! # .replace("\f", "\\f")
-               # FIXME add support for \b .replace("\b", "\\b")
+       redef fun serialize_to_json(v) do v.stream.write(to_json)
 end
 
 redef class NativeString
@@ -209,18 +209,54 @@ redef class NativeString
 end
 
 redef class Array[E]
-       redef fun serialize_to_json(v) do
-               v.stream.write "["
-               var is_first = true
-               for e in self do
-                       if is_first then
-                               is_first = false
-                       else v.stream.write(", ")
-                       
-                       if not v.try_to_serialize(e) then
-                               v.warn("element of type {e.class_name} is not serializable.")
+       redef fun serialize_to_json(v)
+       do
+               if class_name == "Array[nullable Serializable]" then
+                       # Using class_name to the the exact type
+                       # We do not want Array[Int] or anything else here
+                       v.stream.write "["
+                       var is_first = true
+                       for e in self do
+                               if is_first then
+                                       is_first = false
+                               else v.stream.write(", ")
+
+                               if not v.try_to_serialize(e) then
+                                       v.warn("element of type {e.class_name} is not serializable.")
+                               end
+                       end
+                       v.stream.write "]"
+               else
+                       # Register as pseudo object
+                       var id = v.ref_id_for(self)
+                       v.stream.write "\{\"__kind\": \"obj\", \"__id\": {id}, \"__class\": \"{class_name}\""
+                       v.stream.write """, "__length": {{{length}}}, "__items": ["""
+                       var is_first = true
+                       for e in self do
+                               if is_first then
+                                       is_first = false
+                               else v.stream.write(", ")
+
+                               if not v.try_to_serialize(e) then
+                                       v.warn("element of type {e.class_name} is not serializable.")
+                               end
+                       end
+                       v.stream.write "]"
+                       v.stream.write "\}"
+               end
+       end
+
+       init from_deserializer(v: Deserializer)
+       do
+               if v isa JsonDeserializer then
+                       v.notify_of_creation self
+
+                       var length = v.deserialize_attribute("__length").as(Int)
+                       var arr = v.path.last["__items"].as(SequenceRead[nullable Object])
+                       for i in length.times do
+                               var obj = v.convert_object(arr[i])
+                               self.add obj
                        end
                end
-               v.stream.write "]"
        end
 end