예제 #1
0
 /// <summary>
 ///     Ctor.
 /// </summary>
 /// <param name="clazz">is the class</param>
 /// <param name="getterFactory">is the getter</param>
 /// <param name="stem">is the property info</param>
 public PropertyInfo(
     Type clazz,
     EventPropertyGetterSPIFactory getterFactory,
     PropertyStem stem)
 {
     Clazz = clazz;
     GetterFactory = getterFactory;
     Descriptor = stem;
 }
예제 #2
0
        public BeanEventTypeStem Make(Type clazz)
        {
            EventTypeUtility.ValidateEventBeanClassVisibility(clazz);

            var propertyListBuilder = PropertyListBuilderFactory.CreateBuilder(_optionalConfig);
            var properties = propertyListBuilder.AssessProperties(clazz);

            var propertyDescriptors = new List<EventPropertyDescriptor>();
            var propertyDescriptorMap = new Dictionary<string, EventPropertyDescriptor>();
            var propertyNames = new SortedSet<string>();
            var simpleProperties = new Dictionary<string, PropertyInfo>();
            var mappedPropertyDescriptors = new Dictionary<string, PropertyStem>();
            var indexedPropertyDescriptors = new Dictionary<string, PropertyStem>();

            IDictionary<string, IList<PropertyInfo>> simpleSmartPropertyTable = null;
            IDictionary<string, IList<PropertyInfo>> mappedSmartPropertyTable = null;
            IDictionary<string, IList<PropertyInfo>> indexedSmartPropertyTable = null;
            if (_smartResolutionStyle) {
                simpleSmartPropertyTable = new Dictionary<string, IList<PropertyInfo>>();
                mappedSmartPropertyTable = new Dictionary<string, IList<PropertyInfo>>();
                indexedSmartPropertyTable = new Dictionary<string, IList<PropertyInfo>>();
            }

            foreach (var desc in properties) {
                var propertyName = desc.PropertyName;
                Type underlyingType = null;
                Type componentType = null;
                bool isRequiresIndex = false;
                bool isRequiresMapkey = false;
                bool isIndexed = false;
                bool isMapped = false;
                bool isFragment = false;
                bool isSimple = false;

                if (desc.PropertyType.IsUndefined()) {
                    continue;
                }

                EventPropertyGetterSPIFactory getter = null;

                // SIMPLE

                if (desc.PropertyType.IsSimple())
                {
                    if (desc.ReadMethod != null) {
                        getter = new ReflectionPropMethodGetterFactory(desc.ReadMethod);
                        underlyingType = desc.ReadMethod.ReturnType;
                    }
                    else if (desc.AccessorProp != null) {
                        getter = new ReflectionPropPropertyGetterFactory(desc.AccessorProp);
                        underlyingType = desc.AccessorProp.PropertyType;
                    }
                    else if (desc.AccessorField != null) {
                        getter = new ReflectionPropFieldGetterFactory(desc.AccessorField);
                        underlyingType = desc.AccessorField.FieldType;
                    }
                    else {
                        throw new IllegalStateException($"invalid property descriptor: {desc}");
                    }

                    isSimple = true;
                    isFragment = underlyingType.IsFragmentableType();

#if false
                    if (TypeHelper.IsImplementsInterface(type, typeof(IDictionary<object, object>))) {
                        isMapped = true;
                        // We do not yet allow to fragment maps entries.
                        // Class genericType = TypeHelper.getGenericReturnTypeMap(desc.getReadMethod(), desc.getAccessorField());
                        isFragment = false;

                        if (desc.ReadMethod != null) {
                            componentType = TypeHelper.GetGenericReturnTypeMap(desc.ReadMethod, false);
                        }
                        else if (desc.AccessorProp != null) {
                            componentType = TypeHelper.GetGenericPropertyTypeMap(desc.AccessorProp, false);
                        }
                        else if (desc.AccessorField != null) {
                            componentType = TypeHelper.GetGenericFieldTypeMap(desc.AccessorField, false);
                        }
                        else {
                            componentType = typeof(object);
                        }
                    }
                    else if (type.IsArray) {
                        isIndexed = true;
                        isFragment = type.GetElementType().IsFragmentableType();
                        componentType = type.GetElementType();
                    }
                    else if (type.IsGenericEnumerable()) {
                        isIndexed = true;
                        var genericType = TypeHelper.GetGenericReturnType(
                            desc.ReadMethod,
                            desc.AccessorField,
                            desc.AccessorProp,
                            true);
                        isFragment = genericType.IsFragmentableType();
                        if (genericType != null) {
                            componentType = genericType;
                        }
                        else {
                            componentType = typeof(object);
                        }
                    }
                    else {
                        isMapped = false;
                        isFragment = type.IsFragmentableType();
                    }
#endif

                    simpleProperties.Put(propertyName, new PropertyInfo(underlyingType, getter, desc));
                }

                // MAPPED

                if (desc.PropertyType.IsMapped()) {
                    // Local function: CheckComponentType
                    void CheckComponentType()
                    {
                        if (underlyingType.IsGenericDictionary()) {
                            componentType = underlyingType.GetDictionaryValueType();
                        }
                    }


                    underlyingType = desc.ReturnType;
                    componentType = typeof(object);

                    if (desc.ReadMethod != null) {
                        isRequiresMapkey = desc.ReadMethod.GetParameters().Length > 0;
                        if (isRequiresMapkey) {
                            componentType = desc.ReadMethod.GetParameters()[0].ParameterType;
                        }
                        else {
                            CheckComponentType();
                        }
                    }
                    else if (desc.AccessorProp != null) {
                        isRequiresMapkey = false; // not required, you can "get" the property
                        CheckComponentType();
                    }
                    else if (desc.AccessorField != null) {
                        isRequiresMapkey = false; // not required, you can "get" the property
                        CheckComponentType();
                    }
                    else {
                        throw new IllegalStateException($"invalid property descriptor: {desc}");
                    }

                    isMapped = true;
                    isFragment = false;

                    mappedPropertyDescriptors.Put(propertyName, desc);
                }

                // INDEXED

                if (desc.PropertyType.IsIndexed()) {
                    // Local function: CheckFragmentation
                    void CheckFragmentation()
                    {
                        if (underlyingType.IsArray) {
                            isFragment = underlyingType.GetElementType().IsFragmentableType();
                            componentType = underlyingType.GetElementType();
                        }
                        else if (underlyingType.IsGenericEnumerable()) {
                            var genericType = TypeHelper.GetGenericReturnType(
                                desc.ReadMethod,
                                desc.AccessorField,
                                desc.AccessorProp,
                                true);
                            isFragment = genericType.IsFragmentableType();
                            componentType = genericType != null ? genericType : typeof(object);
                        }
                        else {
                            isFragment = false;
                            componentType = typeof(object);
                        }
                    }

                    underlyingType = desc.ReturnType;

                    if (desc.ReadMethod != null) {
                        var rmParameters = desc.ReadMethod.GetParameters() ?? new ParameterInfo[0];
                        isRequiresIndex = rmParameters.Length > 0;
                        if (!isRequiresIndex) {
                            //componentType = TypeHelper.GetGenericReturnTypeMap(desc.ReadMethod, false);
                            CheckFragmentation();
                        }
                    }
                    else if (desc.AccessorProp != null) {
                        isRequiresIndex = false; // not required, you can "get" the index
                        //componentType = TypeHelper.GetGenericPropertyTypeMap(desc.AccessorProp, false);
                        CheckFragmentation();
                    }
                    else if (desc.AccessorField != null) {
                        isRequiresIndex = false; // not required, you can "get" the index
                        //componentType = TypeHelper.GetGenericFieldTypeMap(desc.AccessorField, false);
                        CheckFragmentation();
                    }
                    else {
                        throw new IllegalStateException($"invalid property descriptor: {desc}");
                    }

                    //componentType = null;
                    isIndexed = true;
                    indexedPropertyDescriptors.Put(propertyName, desc);
                }

                // ----------------------------------------------------------------------------------------------
                // SMART-INDEXING: Recognize that there may be properties with overlapping case-insensitive names
                // ----------------------------------------------------------------------------------------------

                if (_smartResolutionStyle) {
                    // SIMPLE

                    if (isSimple)
                    {
                        // Find the property in the smart property table
                        var smartPropertyName = propertyName.ToLowerInvariant();
                        var propertyInfoList = simpleSmartPropertyTable.Get(smartPropertyName);
                        if (propertyInfoList == null)
                        {
                            propertyInfoList = new List<PropertyInfo>();
                            simpleSmartPropertyTable.Put(smartPropertyName, propertyInfoList);
                        }

                        // Enter the property into the smart property list
                        var propertyInfo = new PropertyInfo(underlyingType, getter, desc);
                        propertyInfoList.Add(propertyInfo);
                    }

                    // MAPPED

                    if (isMapped) {
                        // Find the property in the smart property table
                        var smartPropertyName = propertyName.ToLowerInvariant();
                        var propertyInfoList = mappedSmartPropertyTable.Get(smartPropertyName);
                        if (propertyInfoList == null) {
                            propertyInfoList = new List<PropertyInfo>();
                            mappedSmartPropertyTable.Put(smartPropertyName, propertyInfoList);
                        }

                        // Enter the property into the smart property list
                        var propertyInfo = new PropertyInfo(underlyingType, null, desc);
                        propertyInfoList.Add(propertyInfo);
                    }

                    // INDEXED

                    if (isIndexed) {
                        // Find the property in the smart property table
                        var smartPropertyName = propertyName.ToLowerInvariant();
                        var propertyInfoList = indexedSmartPropertyTable.Get(smartPropertyName);
                        if (propertyInfoList == null) {
                            propertyInfoList = new List<PropertyInfo>();
                            indexedSmartPropertyTable.Put(smartPropertyName, propertyInfoList);
                        }

                        // Enter the property into the smart property list
                        var propertyInfo = new PropertyInfo(underlyingType, null, desc);
                        propertyInfoList.Add(propertyInfo);
                    }
                }

                // ----------------------------------------------------------------------------------------------
                // STANDARD-INDEXING
                // ----------------------------------------------------------------------------------------------

                propertyNames.Add(desc.PropertyName);

                var descriptor = new EventPropertyDescriptor(
                    desc.PropertyName,
                    underlyingType,
                    componentType,
                    isRequiresIndex,
                    isRequiresMapkey,
                    isIndexed,
                    isMapped,
                    isFragment);

                propertyDescriptors.Add(descriptor);
                propertyDescriptorMap.Put(descriptor.PropertyName, descriptor);
            }

            // Determine event type super types
            var superTypes = GetSuperTypes(clazz);
            if (superTypes != null && superTypes.Length == 0) {
                superTypes = null;
            }

            // Determine deep supertypes
            // Get base types (superclasses and interfaces), deep get of all in the tree
            ISet<Type> deepSuperTypes = new HashSet<Type>();
            GetSuper(clazz, deepSuperTypes);
            RemovePlatformInterfaces(deepSuperTypes);

            return new BeanEventTypeStem(
                clazz,
                _optionalConfig,
                propertyNames.ToArray(),
                simpleProperties,
                mappedPropertyDescriptors,
                indexedPropertyDescriptors,
                superTypes,
                deepSuperTypes,
                _propertyResolutionStyle,
                simpleSmartPropertyTable,
                indexedSmartPropertyTable,
                mappedSmartPropertyTable,
                propertyDescriptors,
                propertyDescriptorMap);
        }