private static void CompareAnnotations(IIonReader it1, IIonReader it2) { SymbolToken[] syms1 = it1.GetTypeAnnotations().ToArray(); SymbolToken[] syms2 = it2.GetTypeAnnotations().ToArray(); AssertSymbolEquals("annotation", syms1, syms2); }
public static void ReadTypeAnnotations_AssertUnknownSymbolException(IIonReader reader) { // $ion_symbol_table::{ imports:[{ name: \"abc\", version: 1, max_id: 1}],symbols: [\"foo\"]}$10::$11::\"value\" reader.MoveNext(); Assert.ThrowsException <UnknownSymbolException>(() => reader.GetTypeAnnotations()); }
public static void ReadTypeAnnotations_ZeroSymbol(IIonReader reader) { // an int with zero symbol annotation // $0::18 reader.MoveNext(); Assert.ThrowsException <UnknownSymbolException>(() => reader.GetTypeAnnotations()); }
private void TryWriteAnnotations(IIonReader reader) { var annots = reader.GetTypeAnnotations(); foreach (var a in annots) { AddTypeAnnotationSymbol(a); } }
private static void CompareAnnotations(IIonReader it1, IIonReader it2) { //Skip assertion if annotation is zero symbol if (it1.GetTypeAnnotationSymbols().Any(a => a.Text == null && a.Sid == 0)) { return; } string[] syms_text1 = it1.GetTypeAnnotations(); string[] syms_text2 = it2.GetTypeAnnotations(); Assert.IsTrue(syms_text1.SequenceEqual(syms_text2)); }
public static void ReadTypeAnnotations_SingleField(IIonReader reader) { // a singlefield structure with annotations // {withannot:years::months::days::hours::minutes::seconds::18} var symbols = new[] { "years", "months", "days", "hours", "minutes", "seconds" }; reader.MoveNext(); reader.StepIn(); reader.MoveNext(); Assert.AreEqual(IonType.Int, reader.CurrentType); Assert.AreEqual("withannot", reader.CurrentFieldName); Assert.AreEqual(18, reader.IntValue()); var annotations = reader.GetTypeAnnotations(); Assert.AreEqual(symbols.Count(), annotations.Count()); Assert.IsTrue(symbols.SequenceEqual(annotations)); }
public static void ReadAnnotations_SingleField(IIonReader reader) { // a singlefield structure with annotations // {withannot:years::months::days::hours::minutes::seconds::18} var symbols = new[] { "years", "months", "days", "hours", "minutes", "seconds" }; reader.MoveNext(); reader.StepIn(); reader.MoveNext(); Assert.AreEqual(IonType.Int, reader.CurrentType); Assert.AreEqual("withannot", reader.CurrentFieldName); Assert.AreEqual(18, reader.IntValue()); foreach (var s in symbols) { Assert.IsTrue(reader.GetTypeAnnotations().Any(a => a.Text == s)); } }
private static void CompareHasAnnotations(IIonReader it1, IIonReader it2) { //Skip assertion if annotation is zero symbol if (it1.GetTypeAnnotationSymbols().Any(a => a.Text == null && a.Sid == 0)) { return; } string[] syms_text1 = it1.GetTypeAnnotations(); string[] syms_text2 = it2.GetTypeAnnotations(); Assert.IsTrue(syms_text1.Count() == syms_text2.Count()); for (int index = 0; index < syms_text1.Count(); index++) { Assert.IsTrue(it1.HasAnnotation(syms_text2[index])); Assert.IsTrue(it2.HasAnnotation(syms_text1[index])); } }
private void TryWriteAnnotations(IIonReader reader) { var annots = reader.GetTypeAnnotations(); // At present, we must always call this, even when the list is empty, // because local symtab diversion leaves the $ion_symbol_table // dangling on the system writer! TODO fix that, it's broken. foreach (var a in annots) { var text = a.Text; if (text is null) { //try to look up the sid text = SymbolTable.FindKnownSymbol(a.Sid); if (text is null) { throw new UnknownSymbolException(a.Sid); } } AddTypeAnnotation(text); } }
/// <inheritdoc/> public override object Deserialize(IIonReader reader) { object targetObject = null; ConstructorInfo ionConstructor = null; ParameterInfo[] parameters = null; object[] constructorArgs = null; Dictionary <string, int> constructorArgIndexMap = null; // Map Ion annotation to C# type. We don't check if the type has IonAnnotateType attribute or not, // because the Ion annotation could be written by: // 1. IonAnnotateType attribute // 2. IncludeTypeInformation option // 3. custom TypeAnnotator option var annotations = reader.GetTypeAnnotations(); if (annotations.Length > 0) { var typeName = annotations[0]; Type typeToCreate = null; if (this.options.AnnotatedTypeAssemblies != null) { foreach (string assemblyName in this.options.AnnotatedTypeAssemblies) { if ((typeToCreate = Type.GetType(this.FullName(typeName, assemblyName))) != null) { break; } } } else { foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { if ((typeToCreate = assembly.GetType(typeName)) != null) { break; } } } // Check typeToCreate is a derived class from targetType if (typeToCreate != null && this.targetType.IsAssignableFrom(typeToCreate)) { this.targetType = typeToCreate; } } // Determine if we are using an annotated constructor. var ionConstructors = this.targetType.GetConstructors(BINDINGS).Where(IsIonConstructor).Take(2); if (ionConstructors.Any()) { if (ionConstructors.Count() > 1) { throw new InvalidOperationException( $"Only one constructor in class {this.targetType.Name} may be annotated with the [IonConstructor] attribute and more than one was detected"); } ionConstructor = ionConstructors.First(); parameters = ionConstructor.GetParameters(); constructorArgs = new object[parameters.Length]; constructorArgIndexMap = this.BuildConstructorArgIndexMap(parameters); } else { // If we are not using an annotated constructor, then we need to construct the object before stepping // into the reader in case we need to read the type annotations during construction. targetObject = this.options.ObjectFactory.Create(this.options, reader, this.targetType); } reader.StepIn(); // Read the Ion and organize deserialized results into three categories: // 1. Values to be set via annotated methods. // 2. Properties to be set. // 3. Fields to be set. // Any of these deserialized results may also be used for the annotated constructor (if there is one). var deserializedMethods = new List <(MethodInfo, object)>(); var deserializedProperties = new List <(PropertyInfo, object)>(); var deserializedFields = new List <(FieldInfo, object)>(); IonType ionType; while ((ionType = reader.MoveNext()) != IonType.None) { MethodInfo method; PropertyInfo property; FieldInfo field; object deserialized = null; bool currentIonFieldProcessed = false; // Check if current Ion field has an annotated method. if ((method = this.FindSetter(reader.CurrentFieldName)) != null) { if (this.TryDeserializeMethod(method, reader, ionType, out deserialized)) { deserializedMethods.Add((method, deserialized)); } currentIonFieldProcessed = true; } // Check if current Ion field is a .NET property. else if ((property = this.FindProperty(reader.CurrentFieldName)) != null) { if (this.TryDeserializeProperty(property, reader, ionType, out deserialized)) { deserializedProperties.Add((property, deserialized)); } currentIonFieldProcessed = true; } // Check if current Ion field is a .NET field. else if ((field = this.FindField(reader.CurrentFieldName)) != null) { if (this.TryDeserializeField(field, reader, ionType, out deserialized)) { deserializedFields.Add((field, deserialized)); } currentIonFieldProcessed = true; } // Check if current Ion field is also an argument for an annotated constructor. if (constructorArgIndexMap != null && constructorArgIndexMap.ContainsKey(reader.CurrentFieldName)) { var index = constructorArgIndexMap[reader.CurrentFieldName]; // Deserialize current Ion field only if it was not already // processed by the above method/property/field logic. if (!currentIonFieldProcessed) { deserialized = this.ionSerializer.Deserialize(reader, parameters[index].ParameterType, ionType); } constructorArgs[index] = deserialized; } } reader.StepOut(); // Construct object with annotated constructor if we have one. if (ionConstructor != null) { targetObject = ionConstructor.Invoke(constructorArgs); } // Set values with annotated methods. foreach (var(method, deserialized) in deserializedMethods) { method.Invoke(targetObject, new[] { deserialized }); } // Set properties. foreach (var(property, deserialized) in deserializedProperties) { property.SetValue(targetObject, deserialized); } // Set fields. foreach (var(field, deserialized) in deserializedFields) { field.SetValue(targetObject, deserialized); } return(targetObject); }
/// <summary> /// Deserialize value from Ion. /// </summary> /// /// <param name="reader">The Ion reader to be used for deserialization.</param> /// <param name="type">The target .NET type for deserialization.</param> /// <param name="ionType">The Ion type of the current Ion field.</param> /// /// <returns>The deserialized value.</returns> internal object Deserialize(IIonReader reader, Type type, IonType ionType) { if (reader.CurrentDepth > this.options.MaxDepth) { return(null); } var annotations = reader.GetTypeAnnotations(); // The AnnotatedIonSerializers takes precedence over IonSerializerAttribute if (this.options.AnnotatedIonSerializers != null) { foreach (var ionAnnotateType in annotations) { if (this.options.AnnotatedIonSerializers.ContainsKey(ionAnnotateType)) { var serializer = this.options.AnnotatedIonSerializers[ionAnnotateType]; return(serializer.Deserialize(reader)); } } } if (type != null) { var customSerializerAttribute = type.GetCustomAttribute <IonSerializerAttribute>(); if (customSerializerAttribute != null) { var customSerializer = this.CreateCustomSerializer(type); return(customSerializer.Deserialize(reader)); } } if (ionType == IonType.None || ionType == IonType.Null) { return(new IonNullSerializer().Deserialize(reader)); } if (ionType == IonType.Bool) { var serializer = this.GetPrimitiveSerializer <bool>(new IonBooleanSerializer()); return(serializer.Deserialize(reader)); } if (ionType == IonType.Int) { if (annotations.Any(s => s.Equals(IonLongSerializer.ANNOTATION))) { var serializer = this.GetPrimitiveSerializer <long>(new IonLongSerializer()); return(serializer.Deserialize(reader)); } else { var serializer = this.GetPrimitiveSerializer <int>(new IonIntSerializer()); return(serializer.Deserialize(reader)); } } if (ionType == IonType.Float) { if (annotations.Any(s => s.Equals(IonFloatSerializer.ANNOTATION))) { var serializer = this.GetPrimitiveSerializer <float>(new IonFloatSerializer()); return(serializer.Deserialize(reader)); } else { var serializer = this.GetPrimitiveSerializer <double>(new IonDoubleSerializer()); return(serializer.Deserialize(reader)); } } if (ionType == IonType.Decimal) { if (annotations.Any(s => s.Equals(IonDecimalSerializer.ANNOTATION))) { var serializer = this.GetPrimitiveSerializer <decimal>(new IonDecimalSerializer()); return(serializer.Deserialize(reader)); } else { var serializer = this.GetPrimitiveSerializer <BigDecimal>(new IonBigDecimalSerializer()); return(serializer.Deserialize(reader)); } } if (ionType == IonType.Blob) { if (annotations.Any(s => s.Equals(IonGuidSerializer.ANNOTATION)) || typeof(Guid).IsAssignableFrom(type) || typeof(Guid?).IsAssignableFrom(type)) { var serializer = this.GetPrimitiveSerializer <Guid>(new IonGuidSerializer(this.options)); return(serializer.Deserialize(reader)); } else { var serializer = this.GetPrimitiveSerializer <byte[]>(new IonByteArraySerializer()); return(serializer.Deserialize(reader)); } } if (ionType == IonType.String) { var serializer = this.GetPrimitiveSerializer <string>(new IonStringSerializer()); return(serializer.Deserialize(reader)); } if (ionType == IonType.Symbol) { var serializer = this.GetPrimitiveSerializer <SymbolToken>(new IonSymbolSerializer()); return(serializer.Deserialize(reader)); } if (ionType == IonType.Timestamp) { var serializer = this.GetPrimitiveSerializer <DateTime>(new IonDateTimeSerializer()); return(serializer.Deserialize(reader)); } if (ionType == IonType.Clob) { return(new IonClobSerializer().Deserialize(reader)); } if (ionType == IonType.List) { return(this.NewIonListSerializer(type).Deserialize(reader)); } if (ionType == IonType.Struct) { if (type.IsGenericType && type.GetGenericTypeDefinition().IsAssignableFrom(typeof(Dictionary <,>))) { var genericArguments = type.GetGenericArguments(); if (typeof(string).IsAssignableFrom(genericArguments[0])) { var dictionarySerializer = new IonDictionarySerializer(this, genericArguments[1]); var deserialized = dictionarySerializer.Deserialize(reader); return(deserialized); } else { throw new NotSupportedException("Can not deserialize into Dictionary when key is not of type string"); } } return(new IonObjectSerializer(this, this.options, type).Deserialize(reader)); } throw new NotSupportedException($"Data with Ion type {ionType} is not supported for deserialization"); }
private void InternalWriteValue(IIonReader reader, int depth = 0) { IonType type = reader.CurrentType; if (type == IonType.None) { return; } if (depth > 0) { string fieldName = reader.CurrentFieldName; if (fieldName != null) { this.SetFieldName(fieldName); } } foreach (var annotation in reader.GetTypeAnnotations()) { this.AddTypeAnnotationSymbol(annotation); } if (reader.CurrentIsNull) { this.WriteNull(type); } else { switch (type) { case IonType.Bool: this.WriteBool(reader.BoolValue()); break; case IonType.Int: this.WriteInt(reader.BigIntegerValue()); break; case IonType.Float: this.WriteFloat(reader.DoubleValue()); break; case IonType.Decimal: this.WriteDecimal(reader.DecimalValue()); break; case IonType.Timestamp: this.WriteTimestamp(reader.TimestampValue()); break; case IonType.Symbol: this.WriteSymbolToken(reader.SymbolValue()); break; case IonType.String: this.WriteString(reader.StringValue()); break; case IonType.Clob: this.WriteClob(reader.NewByteArray()); break; case IonType.Blob: this.WriteBlob(reader.NewByteArray()); break; case IonType.List: this.StepIn(IonType.List); break; case IonType.Sexp: this.StepIn(IonType.Sexp); break; case IonType.Struct: this.StepIn(IonType.Struct); break; default: throw new InvalidOperationException("Unexpected type '" + type + "'"); } if (type.IsContainer()) { reader.StepIn(); this.InternalWriteValues(reader, depth + 1); this.StepOut(); reader.StepOut(); } } }
public static ISymbolTable ImportReaderTable(IIonReader reader, ICatalog catalog, bool isOnStruct) { var table = reader.GetSymbolTable() as ReaderLocalTable ?? new ReaderLocalTable(reader.GetSymbolTable()); var imports = table.Imports; var symbols = table.OwnSymbols; var newSymbols = new List <string>(); if (!isOnStruct) { reader.MoveNext(); } Debug.Assert( reader.CurrentType == IonType.Struct, "Invalid symbol table image passed in reader " + reader.CurrentType + " encountered when a struct was expected."); Debug.Assert( SystemSymbols.IonSymbolTable.Equals(reader.GetTypeAnnotations()[0]), "Local symbol tables must be annotated by " + SystemSymbols.IonSymbolTable + "."); // Assume that we're standing before a struct. reader.StepIn(); IonType fieldType; bool foundImport = false; bool foundLocals = false; while ((fieldType = reader.MoveNext()) != IonType.None) { if (reader.CurrentIsNull) { continue; } var sid = reader.GetFieldNameSymbol().Sid; if (sid == SymbolToken.UnknownSid) { // This is a user-defined IonReader or a pure DOM, fall // back to text. sid = SystemSymbols.ResolveSidForSymbolTableField(reader.CurrentFieldName); } switch (sid) { case SystemSymbols.SymbolsSid: // As per the spec, other field types are treated as // empty lists. if (foundLocals) { throw new IonException("Multiple symbol fields found within a single local symbol table."); } foundLocals = true; if (fieldType == IonType.List) { ReadSymbolList(reader, newSymbols); } break; case SystemSymbols.ImportsSid: if (foundImport) { throw new IonException("Multiple imports fields found within a single local symbol table."); } foundImport = true; if (fieldType == IonType.List) { // List of symbol tables to imports. ReadImportList(reader, catalog, imports); } // Trying to import the current table. else if (fieldType == IonType.Symbol && reader.GetSymbolTable().IsLocal && (SystemSymbols.IonSymbolTable.Equals(reader.StringValue()) || reader.IntValue() == SystemSymbols.IonSymbolTableSid)) { var currentSymbolTable = reader.GetSymbolTable(); var declaredSymbols = currentSymbolTable.GetDeclaredSymbolNames(); if (foundLocals) { // Ordering matters. Maintain order as 'symbols' // and 'imports' fields can come in any order. newSymbols.InsertRange(0, declaredSymbols); } else { newSymbols.AddRange(declaredSymbols); } } break; default: // As per the spec, any other field is ignored. break; } } reader.StepOut(); symbols.Clear(); // If there were prior imports and now only a system table is // seen, then start fresh again as prior imports no longer matter. if (imports.Count > 1 && !foundImport && foundLocals) { imports.RemoveAll(symbolTable => symbolTable.IsSubstitute == true); } symbols.AddRange(newSymbols); table.Refresh(); return(table); }