json :: JsonSerializer :: defaultinit
# Serializer of Nit objects to Json string.
class JsonSerializer
super CachingSerializer
# Target writing stream
var stream: Writer
# Write plain JSON? Standard JSON without metadata for deserialization
#
# If `false`, the default, serialize to support deserialization:
#
# * Write metadata, including the types of the serialized objects so they can
# be deserialized to their original form using `JsonDeserializer`.
# * Use references when an object has already been serialized so to not duplicate it.
# * Support cycles in references.
# * Preserve the Nit `Char` and `Byte` types as special objects.
# * The generated JSON is standard and can be read by non-Nit programs.
# However, some Nit types are not represented by the simplest possible JSON representation.
# With the added metadata, it can be complex to read.
#
# If `true`, serialize for other programs:
#
# * Nit objects are serialized to pure and standard JSON so they can
# be easily read by non-Nit programs and humans.
# * Nit objects are serialized for every references, so they can be duplicated.
# It is easier to read but it creates a larger output.
# * Does not support cycles, will replace the problematic references by `null`.
# * Does not serialize the metadata needed to deserialize the objects
# back to regular Nit objects.
# * Keys of Nit `HashMap` are converted to their string representation using `to_s`.
var plain_json = false is writable
# Write pretty JSON for human eyes?
#
# Toggles skipping lines between attributes of an object and
# properly indent the written JSON.
var pretty_json = false is writable
# Current indentation level used for writing `pretty_json`
private var indent_level = 0
# List of the current open objects, the first is the main target of the serialization
#
# Used only when `plain_json == true` to detect cycles in serialization.
private var open_objects = new Array[Object]
# Has the first attribute of the current object already been serialized?
#
# Used only when `plain_json == true`.
private var first_attribute = false
redef var current_object = null
redef fun serialize(object)
do
if object == null then
stream.write "null"
else
if plain_json then
for o in open_objects do
if object.is_same_serialized(o) then
# Cycle, can't be managed in plain json
warn "Cycle detected in serialized object, replacing reference with 'null'."
stream.write "null"
return
end
end
open_objects.add object
end
first_attribute = true
var last_object = current_object
current_object = object
object.accept_json_serializer self
first_attribute = false
current_object = last_object
if plain_json then open_objects.pop
end
end
redef fun serialize_attribute(name, value)
do
if not plain_json or not first_attribute then
stream.write ","
end
first_attribute = false
new_line_and_indent
stream.write "\""
stream.write name
stream.write "\":"
if pretty_json then stream.write " "
super
end
redef fun serialize_reference(object)
do
if not plain_json and cache.has_object(object) then
# if already serialized, add local reference
var id = cache.id_for(object)
stream.write "\{"
indent_level += 1
new_line_and_indent
stream.write "\"__kind\": \"ref\", \"__id\": "
stream.write id.to_s
indent_level -= 1
new_line_and_indent
stream.write "\}"
else
# serialize here
serialize object
end
end
# Write a new line and indent it, only if `pretty_json`
private fun new_line_and_indent
do
if pretty_json then
stream.write "\n"
for i in indent_level.times do stream.write "\t"
end
end
end
lib/json/serialization_write.nit:21,1--145,3