public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var context = (LoadingContext)serializer.Context.Context; if (reader.TokenType == JsonToken.String) { if (((string)reader.Value).StartsWith("@")) { Type t; return(PrimitiveTypesConverter.Convert(context.GetVar(((string)reader.Value).Substring(1), out t), objectType)); } } _doWork = false; try { var obj = serializer.Deserialize(reader, objectType); _doWork = true; return(obj); } finally { _doWork = true; } }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { while (reader.TokenType == JsonToken.Comment) { reader.Read(); } var context = (LoadingContext)serializer.Context.Context; var tokenType = reader.TokenType; var readerValue = reader.Value; var lineInfo = reader as IJsonLineInfo; var defType = objectType.GetGenericArguments()[0]; if (tokenType == JsonToken.Null) { return(CreateRef(defType, null)); } if (tokenType == JsonToken.String) { var stringRef = readerValue as string; if (stringRef.StartsWith("/")) { //this is an absolute reference to a resource //if I'm loading a prototype and this is not an embedded prototype then I'm loading external prototype, I should not do anything here until I encounter it again //next time it won't be a child proto file if (context.IsProtoChildFile && !context.ProtoStack.Peek().Embedded) { var rRef = CreateRef(context.IsProto, defType, stringRef); return(rRef); } if (context.IsProto) { context.PushProto(false); var normRef = CreateRef(context.IsProto, defType, stringRef); context.PopProto(); return(normRef); } return(CreateRef(context.IsProto, defType, stringRef)); } else if (stringRef.StartsWith("./")) { //this is a relative reference to a resource if (context.IsProtoChildFile && !context.ProtoStack.Peek().Embedded) { var rRef = CreateRef(context.IsProto, defType, stringRef, context.RootAddress); return(rRef); } if (context.IsProto) { context.PushProto(false); var normRef = CreateRef(context.IsProto, defType, stringRef, context.RootAddress); context.PopProto(); return(normRef); } return(CreateRef(context.IsProto, defType, stringRef, context.RootAddress)); } else if (stringRef.StartsWith("$")) { //this is a local reference to a resource var id = stringRef.Substring(1); IDef res = context.GetInternalRes(id); if (res != null) { return(CreateRef(defType, res)); } else { throw new JsonException($"Reference to internal def not found {stringRef} {lineInfo.LineNumber} {lineInfo.LinePosition} {context.RootAddress}"); } } else if (stringRef.StartsWith("@")) { //this a reference to a variable var name = stringRef.Substring(1); Type t; object var = context.GetVar(name, out t); if (var == null) { Logger.Warn($"Variable has no value {stringRef} {lineInfo.LineNumber} {lineInfo.LinePosition} {context.RootAddress}"); return(CreateRef(defType, null)); } else if (var is IRefBase) { try { return(ConvertToProperRef(var, defType)); } catch (Exception e) { throw new JsonException($"Error converting ref variable type {stringRef} at {lineInfo.LineNumber} {lineInfo.LinePosition} {context.RootAddress}", e); } } else { var attr = defType.GetCustomAttribute <CanBeCreatedFromAliasedPrimitiveAttribute>(inherit: true); if (attr != null) { var objectOfDesiredType = PrimitiveTypesConverter.Convert(var, attr.PrimitiveType); var def = defType.GetMethod(attr.MethodName, BindingFlags.Static | BindingFlags.Public).Invoke(null, new[] { objectOfDesiredType }); return(CreateRef(defType, (IDef)def)); } } } } else if (tokenType == JsonToken.StartObject) { //this is either a template or a def //does it make sense to write a template inside a file? //Well, in principle, why not? if (context.IsProtoChildFile) { context.ProtoStack.Peek().Embedded = true; } var obj = serializer.Deserialize(reader, defType); return(CreateRef(defType, (IDef)obj)); } if (tokenType == JsonToken.Boolean || tokenType == JsonToken.Float || tokenType == JsonToken.Integer || tokenType == JsonToken.String) { var attr = defType.GetCustomAttribute <CanBeCreatedFromAliasedPrimitiveAttribute>(inherit: true); if (attr != null) { var objectOfDesiredType = PrimitiveTypesConverter.Convert(readerValue, attr.PrimitiveType); var def = defType.GetMethod(attr.MethodName, BindingFlags.Static | BindingFlags.Public).Invoke(null, new[] { objectOfDesiredType }); return(CreateRef(defType, (IDef)def)); } } //todo make proper line address throw new JsonException($"Reference to definition is not a string or object {lineInfo.LineNumber} {lineInfo.LinePosition} {context.RootAddress} - is {tokenType} {readerValue}"); }