Ejemplo n.º 1
0
        /// <summary>
        /// Parses a Thrift struct from the specified TypeInfo.
        /// </summary>
        public static ThriftStruct ParseStruct(TypeInfo typeInfo)
        {
            if (!_knownStructs.ContainsKey(typeInfo))
            {
                if (typeInfo.IsInterface || typeInfo.IsAbstract)
                {
                    throw ThriftParsingException.NotAConcreteType(typeInfo);
                }

                var attr = typeInfo.GetCustomAttribute <ThriftStructAttribute>();
                if (attr == null)
                {
                    throw ThriftParsingException.StructWithoutAttribute(typeInfo);
                }

                var fields = typeInfo.DeclaredProperties
                             .Select(f => ParseField(f))
                             .Where(f => f != null)
                             .ToArray();

                // The type may have been added during fields parsing
                if (!_knownStructs.ContainsKey(typeInfo))
                {
                    _knownStructs.Add(typeInfo, new ThriftStruct(new ThriftStructHeader(attr.Name), fields, typeInfo));
                }
            }

            return(_knownStructs[typeInfo]);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Parses a Thrift service from the specified TypeInfo.
        /// </summary>
        public static ThriftService ParseService(TypeInfo typeInfo)
        {
            if (!_knownServices.ContainsKey(typeInfo))
            {
                if (!typeInfo.IsInterface)
                {
                    throw ThriftParsingException.NotAService(typeInfo);
                }

                var attr = typeInfo.GetCustomAttribute <ThriftServiceAttribute>();
                if (attr == null)
                {
                    throw ThriftParsingException.ServiceWithoutAttribute(typeInfo);
                }

                var methods = typeInfo.DeclaredMethods.ToDictionary(m => m.Name, m => ParseMethod(m));
                if (methods.Count == 0)
                {
                    throw ThriftParsingException.NoMethods(typeInfo);
                }

                _knownServices.Add(typeInfo, new ThriftService(attr.Name, methods));
            }

            return(_knownServices[typeInfo]);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Parses a Thrift method parameter from the specified ParameterInfo.
        /// </summary>
        private static ThriftParameter ParseMethodParameter(ParameterInfo parameterInfo)
        {
            var attr = parameterInfo.GetCustomAttribute <ThriftParameterAttribute>();

            if (attr == null)
            {
                throw ThriftParsingException.ParameterWithoutAttribute(parameterInfo);
            }

            return(new ThriftParameter(attr.Id, attr.Name, parameterInfo.ParameterType.GetTypeInfo(), attr.ThriftConverter));
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Parses a Thrift field from the specified PropertyInfo.
        /// If the PropertyInfo is not declared as a Thrift field, returns null.
        /// </summary>
        private static ThriftField ParseField(PropertyInfo propertyInfo)
        {
            var attr = propertyInfo.GetCustomAttribute <ThriftFieldAttribute>();

            if (attr == null)
            {
                return(null);
            }

            var propertyTypeInfo = propertyInfo.PropertyType.GetTypeInfo();
            var nullableType     = Nullable.GetUnderlyingType(propertyInfo.PropertyType);

            if (attr.IsRequired)
            {
                if (attr.DefaultValue != null)
                {
                    throw ThriftParsingException.DefaultValueOnRequiredField(propertyInfo);
                }
                if (nullableType != null)
                {
                    throw ThriftParsingException.RequiredNullableField(propertyInfo);
                }
            }
            else
            {
                if (attr.DefaultValue == null && propertyTypeInfo.IsValueType && nullableType == null)
                {
                    throw ThriftParsingException.OptionalValueField(propertyInfo);
                }
            }

            if (attr.DefaultValue != null)
            {
                if (attr.Converter == null)
                {
                    if (attr.DefaultValue.GetType() != (nullableType ?? propertyInfo.PropertyType))
                    {
                        throw ThriftParsingException.DefaultValueOfWrongType(propertyInfo);
                    }
                }
                else
                {
                    if (attr.DefaultValue.GetType() != attr.ThriftConverter.FromType)
                    {
                        throw ThriftParsingException.DefaultValueOfWrongType(propertyInfo);
                    }
                }
            }

            return(new ThriftField(attr.Id, attr.Name, attr.IsRequired, attr.DefaultValue, attr.ThriftConverter, propertyInfo));
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Parses all Thrift "throws" clauses on the specified MethodInfo.
        /// </summary>
        private static ThriftThrowsClause[] ParseThrowsClauses(MethodInfo methodInfo)
        {
            var clauses = methodInfo.GetCustomAttributes <ThriftThrowsAttribute>()
                          .Select(a => new ThriftThrowsClause(a.Id, a.Name, a.ExceptionTypeInfo, a.ThriftConverter))
                          .ToArray();

            var wrongClause = clauses.FirstOrDefault(c => !c.UnderlyingTypeInfo.Extends(typeof(Exception)));

            if (wrongClause != null)
            {
                throw ThriftParsingException.NotAnException(wrongClause.UnderlyingTypeInfo, methodInfo);
            }

            return(clauses);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Gets an instantiable version of the specified type, for the specified interface type,
        /// with the specified concrete type if needed, throwing the specified exception if the type
        /// does implement the interface but cannot be instantiated.
        /// Returns null if the type does not implement the interface.
        /// </summary>
        private static Tuple <TypeInfo, Type[]> GetInstantiableVersion(TypeInfo typeInfo, Type interfaceType, Type concreteType, Func <TypeInfo, Exception> errorProvider)
        {
            if (typeInfo.IsInterface)
            {
                if (typeInfo.GenericTypeArguments.Length > 0)
                {
                    var unbound = typeInfo.GetGenericTypeDefinition();
                    if (unbound == interfaceType)
                    {
                        return(Tuple.Create(
                                   concreteType.MakeGenericType(typeInfo.GenericTypeArguments).GetTypeInfo(),
                                   typeInfo.GenericTypeArguments
                                   ));
                    }
                }
            }

            Tuple <TypeInfo, Type[]> instantiableVersion = null;

            foreach (var iface in typeInfo.ImplementedInterfaces.Where(i => i.GenericTypeArguments.Length > 0))
            {
                var unboundIface = iface.GetGenericTypeDefinition();
                if (unboundIface == interfaceType)
                {
                    if (typeInfo.IsAbstract || !typeInfo.DeclaredConstructors.Any(c => c.GetParameters().Length == 0))
                    {
                        throw errorProvider(typeInfo);
                    }

                    if (instantiableVersion != null)
                    {
                        throw ThriftParsingException.CollectionWithMultipleGenericImplementations(typeInfo);
                    }

                    instantiableVersion = Tuple.Create(typeInfo, iface.GenericTypeArguments);
                }
            }

            return(instantiableVersion);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Parses a Thrift method from the specified MethodInfo.
        /// If the MethodInfo is not declared as a Thrift method, returns null.
        /// </summary>
        private static ThriftMethod ParseMethod(MethodInfo methodInfo)
        {
            var attr = methodInfo.GetCustomAttribute <ThriftMethodAttribute>();

            if (attr == null)
            {
                throw ThriftParsingException.MethodWithoutAttribute(methodInfo);
            }

            var throwsClauses = ParseThrowsClauses(methodInfo);

            if (attr.IsOneWay && throwsClauses.Length != 0)
            {
                throw ThriftParsingException.OneWayMethodWithExceptions(methodInfo);
            }

            var unwrapped = methodInfo.ReturnType.UnwrapTask();

            if (unwrapped == null)
            {
                throw ThriftParsingException.SynchronousMethod(methodInfo);
            }
            if (attr.IsOneWay && unwrapped != typeof(void))
            {
                throw ThriftParsingException.OneWayMethodWithResult(methodInfo);
            }

            var methodParameters = methodInfo.GetParameters();
            var parameters       = methodParameters.Where(p => p.ParameterType != typeof(CancellationToken))
                                   .Select(p => ParseMethodParameter(p))
                                   .ToArray();

            if (methodParameters.Length - parameters.Length > 1)
            {
                throw ThriftParsingException.MoreThanOneCancellationToken(methodInfo);
            }

            return(new ThriftMethod(attr.Name, attr.IsOneWay, new ThriftReturnValue(unwrapped.GetTypeInfo(), attr.ThriftConverter), throwsClauses, parameters));
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Initializes a new instance of the ThriftType class from the specified .NET type.
        /// </summary>
        private ThriftType(Type type)
        {
            Id       = ThriftTypeId.Empty;
            TypeInfo = type.GetTypeInfo();

            if (type == typeof(void))
            {
                return;
            }

            var underlyingNullableType = Nullable.GetUnderlyingType(type);

            if (underlyingNullableType != null)
            {
                NullableType = ThriftType.Get(underlyingNullableType);
                Id           = NullableType.Id;
                IsEnum       = NullableType.IsEnum;
                return;
            }

            if (PrimitiveIds.ContainsKey(type))
            {
                Id = PrimitiveIds[type];
                return;
            }

            if (TypeInfo.IsEnum)
            {
                if (TypeInfo.GetCustomAttribute <ThriftEnumAttribute>() == null)
                {
                    throw ThriftParsingException.EnumWithoutAttribute(TypeInfo);
                }
                if (Enum.GetUnderlyingType(type) != typeof(int))
                {
                    throw ThriftParsingException.NonInt32Enum(TypeInfo);
                }

                Id     = ThriftTypeId.Int32;
                IsEnum = true;
                return;
            }

            if (TypeInfo.IsValueType)
            {
                throw ThriftParsingException.UnknownValueType(TypeInfo);
            }

            if (TypeInfo.IsArray)
            {
                Id = ThriftTypeId.List;
                return;
            }

            var mapInterfaceAndArgs = GetInstantiableVersion(TypeInfo, typeof(IDictionary <,>), typeof(Dictionary <,>), p => ThriftParsingException.UnsupportedMap(p));

            if (mapInterfaceAndArgs != null)
            {
                Id       = ThriftTypeId.Map;
                TypeInfo = mapInterfaceAndArgs.Item1;
                _collectionGenericArgs = mapInterfaceAndArgs.Item2;
            }

            var setInterfaceAndArgs = GetInstantiableVersion(TypeInfo, typeof(ISet <>), typeof(HashSet <>), p => ThriftParsingException.UnsupportedSet(p));

            if (setInterfaceAndArgs != null)
            {
                if (mapInterfaceAndArgs != null)
                {
                    throw ThriftParsingException.CollectionWithOrthogonalInterfaces(TypeInfo);
                }

                Id       = ThriftTypeId.Set;
                TypeInfo = setInterfaceAndArgs.Item1;
                _collectionGenericArgs = setInterfaceAndArgs.Item2;
            }

            var listInterfaceAndArgs = GetInstantiableVersion(TypeInfo, typeof(IList <>), typeof(List <>), p => ThriftParsingException.UnsupportedList(p));

            if (listInterfaceAndArgs != null)
            {
                if (mapInterfaceAndArgs != null || setInterfaceAndArgs != null)
                {
                    throw ThriftParsingException.CollectionWithOrthogonalInterfaces(TypeInfo);
                }

                Id       = ThriftTypeId.List;
                TypeInfo = listInterfaceAndArgs.Item1;
                _collectionGenericArgs = listInterfaceAndArgs.Item2;
            }

            if (Id == ThriftTypeId.Empty)
            {
                Id = ThriftTypeId.Struct;
            }
        }