예제 #1
0
        private static void CompareAnnotations(IIonReader it1, IIonReader it2)
        {
            SymbolToken[] syms1 = it1.GetTypeAnnotations().ToArray();
            SymbolToken[] syms2 = it2.GetTypeAnnotations().ToArray();

            AssertSymbolEquals("annotation", syms1, syms2);
        }
예제 #2
0
        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());
        }
예제 #3
0
        public static void ReadTypeAnnotations_ZeroSymbol(IIonReader reader)
        {
            // an int with zero symbol annotation
            // $0::18
            reader.MoveNext();

            Assert.ThrowsException <UnknownSymbolException>(() => reader.GetTypeAnnotations());
        }
예제 #4
0
        private void TryWriteAnnotations(IIonReader reader)
        {
            var annots = reader.GetTypeAnnotations();

            foreach (var a in annots)
            {
                AddTypeAnnotationSymbol(a);
            }
        }
예제 #5
0
        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));
        }
예제 #6
0
        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));
        }
예제 #7
0
        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));
            }
        }
예제 #8
0
        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);
            }
        }
예제 #10
0
        /// <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);
        }
예제 #11
0
        /// <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");
        }
예제 #12
0
        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();
                }
            }
        }
예제 #13
0
        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);
        }