serialization: add support for Arrays
[nit.git] / lib / json_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 module json_serialization
18
19 import serialization
20
21 class JsonSerializer
22 super Serializer
23
24 # Target writing stream
25 var stream: OStream
26
27 init(stream: OStream) do self.stream = stream
28
29 redef fun serialize(object)
30 do
31 if object == null then
32 stream.write "null"
33 else object.serialize_to_json(self)
34 end
35
36 redef fun serialize_attribute(name, value)
37 do
38 stream.write ", \"{name}\": "
39 super
40 end
41
42 redef fun serialize_reference(object)
43 do
44 if refs_map.keys.has(object) then
45 # if already serialized, add local reference
46 var id = ref_id_for(object)
47 stream.write "\{\"__kind\": \"ref\", \"__id\": {id}\}"
48 else
49 # serialize here
50 serialize object
51 end
52 end
53
54 # Map of references to already serialized objects
55 var refs_map = new HashMap[Serializable,Int]
56
57 private fun ref_id_for(object: Serializable): Int
58 do
59 if refs_map.keys.has(object) then
60 return refs_map[object]
61 else
62 var id = refs_map.length
63 refs_map[object] = id
64 return id
65 end
66 end
67 end
68
69 redef class Serializable
70 private fun serialize_to_json(v: JsonSerializer)
71 do
72 var id = v.ref_id_for(self)
73 v.stream.write "\{\"__kind\": \"obj\", \"__id\": {id}, \"__class\": \"{class_name}\""
74 core_serialize_to(v)
75 v.stream.write "\}"
76 end
77 end
78
79 redef class Int
80 redef fun serialize_to_json(v) do v.stream.write(to_s)
81 end
82
83 redef class Float
84 redef fun serialize_to_json(v) do v.stream.write(to_s)
85 end
86
87 redef class Bool
88 redef fun serialize_to_json(v) do v.stream.write(to_s)
89 end
90
91 redef class Char
92 redef fun serialize_to_json(v) do v.stream.write("'{to_s}'")
93 end
94
95 redef class String
96 redef fun serialize_to_json(v) do v.stream.write("\"{to_json_s}\"")
97
98 private fun to_json_s: String do return self.replace("\\", "\\\\").
99 replace("\"", "\\\"").replace("\b", "\\b").replace("/", "\\/").
100 replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t")
101 # FIXME add support for unicode char when supported by Nit strings
102 # FIXME add support for \f! # .replace("\f", "\\f")
103 end
104
105 redef class NativeString
106 redef fun serialize_to_json(v) do to_s.serialize_to_json(v)
107 end
108
109 redef class Array[E]
110 redef fun serialize_to_json(v) do
111 v.stream.write "["
112 var is_first = true
113 for e in self do
114 if is_first then
115 is_first = false
116 else v.stream.write(", ")
117
118 if not v.try_to_serialize(e) then
119 v.warn("element of type {e.class_name} is not serializable.")
120 end
121 end
122 v.stream.write "]"
123 end
124 end