X-Git-Url: http://nitlanguage.org diff --git a/src/frontend/serialization_phase.nit b/src/frontend/serialization_phase.nit index 4ad749b..1091c47 100644 --- a/src/frontend/serialization_phase.nit +++ b/src/frontend/serialization_phase.nit @@ -173,10 +173,24 @@ private class SerializationPhasePreModel end end + # Implement `core_serialize_to` on `nclassdef` + # + # Are attributes serialized on demand `per_attribute` with `serialize`? + # Otherwise they are serialized by default, and we check instead for `noserialize`. fun generate_serialization_method(nclassdef: AClassdef, per_attribute: Bool) do var npropdefs = nclassdef.n_propdefs + # Do not insert a `core_serialize_to` if it already exists + for npropdef in npropdefs do + if npropdef isa AMethPropdef then + var methid = npropdef.n_methid + if methid != null and methid.collect_text == "core_serialize_to" then + return + end + end + end + var code = new Array[String] code.add "redef fun core_serialize_to(v)" code.add "do" @@ -259,6 +273,7 @@ end private class SerializationPhasePostModel super Phase + # Fill the deserialization init `from_deserializer` and `Deserializer.deserialize_class_intern` redef fun process_nmodule(nmodule) do for npropdef in nmodule.inits_to_retype do @@ -302,23 +317,48 @@ do var type_name = mtype.to_s var name = attribute.name + var resolved_type_name = type_name + var mclassdef = nclassdef.mclassdef + if mclassdef != null then + var bound_mtype = mclassdef.bound_mtype + var resolved_mtype = mtype.resolve_for(bound_mtype, bound_mtype, mclassdef.mmodule, true) + resolved_type_name = resolved_mtype.name + + # TODO Use something like `V.class_name` to get the precise runtime type of virtual types. + # We currently use the upper bound of virtual types as static type in generated code + # for type suggestion and to prevent loading unexected types. + # This leaves a security issue when, for example, `DefaultMap::default_value` + # is bound to `nullable Object` and would allow any object to be loaded. + end + if type_name == "nullable Object" then # Don't type check code.add """ - var {{{name}}} = v.deserialize_attribute("{{{attribute.serialize_name}}}", "{{{type_name}}}") + self.{{{name}}} = v.deserialize_attribute("{{{attribute.serialize_name}}}", "{{{resolved_type_name}}}") """ - else code.add """ - var {{{name}}} = v.deserialize_attribute("{{{attribute.serialize_name}}}", "{{{type_name}}}") - if not {{{name}}} isa {{{type_name}}} then - # Check if it was a subjectent error - v.errors.add new AttributeTypeError(self, "{{{attribute.serialize_name}}}", {{{name}}}, "{{{type_name}}}") + else + code.add """ + var {{{name}}} = v.deserialize_attribute("{{{attribute.serialize_name}}}", "{{{resolved_type_name}}}") + if v.deserialize_attribute_missing then +""" + # What to do when an attribute is missing? + if attribute.has_value then + # Leave it to the default value + else if mtype isa MNullableType then + code.add """ + self.{{{name}}} = null""" + else code.add """ + v.errors.add new Error("Deserialization Error: attribute `{class_name}::{{{name}}}` missing from JSON object")""" - # Clear subjacent error + code.add """ + else if not {{{name}}} isa {{{type_name}}} then + v.errors.add new AttributeTypeError(self, "{{{attribute.serialize_name}}}", {{{name}}}, "{{{resolved_type_name}}}") if v.keep_going == false then return else self.{{{name}}} = {{{name}}} end """ + end end code.add "end"