private OpenApiSchema CreateObjectSchema(Type type, SchemaRepository schemaRepository)
        {
            var schema = new OpenApiSchema
            {
                Type       = "object",
                Properties = new Dictionary <string, OpenApiSchema>(),
                Required   = new SortedSet <string>(),
                AdditionalPropertiesAllowed = false
            };

            // If it's a baseType with known subTypes, add the discriminator property
            if (_generatorOptions.GeneratePolymorphicSchemas && _generatorOptions.SubTypesResolver(type).Any())
            {
                var discriminatorName = _generatorOptions.DiscriminatorSelector(type);
                schema.Properties.Add(discriminatorName, new OpenApiSchema {
                    Type = "string"
                });
                schema.Required.Add(discriminatorName);
                schema.Discriminator = new OpenApiDiscriminator {
                    PropertyName = discriminatorName
                };
            }

            var serializableProperties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
                                         .Where(property =>
            {
                return
                ((property.IsPubliclyReadable() || property.IsPubliclyWritable()) &&
                 !(property.GetIndexParameters().Any()) &&
                 !(property.HasAttribute <JsonIgnoreAttribute>()) &&
                 !(_serializerOptions.IgnoreReadOnlyProperties && !property.IsPubliclyWritable()));
            });

            foreach (var property in serializableProperties)
            {
                var customAttributes = property.GetInlineOrMetadataTypeAttributes();

                if (_generatorOptions.IgnoreObsoleteProperties && customAttributes.OfType <ObsoleteAttribute>().Any())
                {
                    continue;
                }

                var name = property.GetCustomAttribute <JsonPropertyNameAttribute>()?.Name
                           ?? _serializerOptions.PropertyNamingPolicy?.ConvertName(property.Name) ?? property.Name;

                schema.Properties[name] = CreatePropertySchema(property, customAttributes, schemaRepository);

                if (customAttributes.OfType <RequiredAttribute>().Any())
                {
                    schema.Required.Add(name);
                }

                if (property.HasAttribute <JsonExtensionDataAttribute>() && property.PropertyType.IsDictionary(out Type keyType, out Type valueType))
                {
                    schema.AdditionalPropertiesAllowed = true;
                    schema.AdditionalProperties        = _schemaGenerator.GenerateSchema(valueType, schemaRepository);
                }
            }


            // If it's a known subType, reference the baseType for inheritied properties
            if (_generatorOptions.GeneratePolymorphicSchemas && type.BaseType != null && _generatorOptions.SubTypesResolver(type.BaseType).Contains(type))
            {
                var baseType = type.BaseType;

                var baseSchemaReference = schemaRepository.GetOrAdd(
                    type: baseType,
                    schemaId: _generatorOptions.SchemaIdSelector(baseType),
                    factoryMethod: () => CreateObjectSchema(baseType, schemaRepository));

                var baseSchema = schemaRepository.Schemas[baseSchemaReference.Reference.Id];

                schema.AllOf = new[] { baseSchemaReference };

                foreach (var basePropertyName in baseSchema.Properties.Keys)
                {
                    schema.Properties.Remove(basePropertyName);
                }
            }

            return(schema);
        }
        private OpenApiSchema GenerateObjectSchema(SerializerMetadata serializerMetadata, SchemaRepository schemaRepository)
        {
            if (serializerMetadata.Properties == null)
            {
                return(new OpenApiSchema {
                    Type = "object"
                });
            }

            var schema = new OpenApiSchema
            {
                Type       = "object",
                Properties = new Dictionary <string, OpenApiSchema>(),
                Required   = new SortedSet <string>()
            };

            // If it's a baseType with known subTypes, add the discriminator property
            if (_generatorOptions.GeneratePolymorphicSchemas && _generatorOptions.SubTypesResolver(serializerMetadata.Type).Any())
            {
                var discriminatorName = _generatorOptions.DiscriminatorSelector(serializerMetadata.Type);

                if (!schema.Properties.ContainsKey(discriminatorName))
                {
                    schema.Properties.Add(discriminatorName, new OpenApiSchema {
                        Type = "string"
                    });
                }

                schema.Required.Add(discriminatorName);
                schema.Discriminator = new OpenApiDiscriminator {
                    PropertyName = discriminatorName
                };
            }

            foreach (var serializerPropertyMetadata in serializerMetadata.Properties)
            {
                var customAttributes = serializerPropertyMetadata.MemberInfo?.GetInlineOrMetadataTypeAttributes() ?? Enumerable.Empty <object>();

                if (_generatorOptions.IgnoreObsoleteProperties && customAttributes.OfType <ObsoleteAttribute>().Any())
                {
                    continue;
                }

                var propertySchema = GenerateSchema(serializerPropertyMetadata.MemberType, schemaRepository, memberInfo: serializerPropertyMetadata.MemberInfo);

                schema.Properties.Add(serializerPropertyMetadata.Name, propertySchema);

                if (serializerPropertyMetadata.IsRequired || customAttributes.OfType <RequiredAttribute>().Any())
                {
                    schema.Required.Add(serializerPropertyMetadata.Name);
                }

                if (propertySchema.Reference == null)
                {
                    propertySchema.Nullable = propertySchema.Nullable && serializerPropertyMetadata.AllowNull;
                }
            }

            if (serializerMetadata.ExtensionDataValueType != null)
            {
                schema.AdditionalProperties = GenerateSchema(serializerMetadata.ExtensionDataValueType, schemaRepository);
            }

            // If it's a known subType, reference the baseType for inheritied properties
            if (_generatorOptions.GeneratePolymorphicSchemas &&
                (serializerMetadata.Type.BaseType != null) &&
                _generatorOptions.SubTypesResolver(serializerMetadata.Type.BaseType).Contains(serializerMetadata.Type))
            {
                var baseSerializerContract = _serializerMetadataResolver.GetSerializerMetadataForType(serializerMetadata.Type.BaseType);
                var baseSchemaReference    = GenerateReferencedSchema(baseSerializerContract, schemaRepository);

                var baseSchema = schemaRepository.Schemas[baseSchemaReference.Reference.Id];
                foreach (var basePropertyName in baseSchema.Properties.Keys)
                {
                    schema.Properties.Remove(basePropertyName);
                }

                return(new OpenApiSchema
                {
                    AllOf = new List <OpenApiSchema> {
                        baseSchemaReference, schema
                    }
                });
            }

            return(schema);
        }
        private OpenApiSchema GenerateObjectSchema(DataContract dataContract, SchemaRepository schemaRepository)
        {
            var schema = new OpenApiSchema
            {
                Type       = "object",
                Properties = new Dictionary <string, OpenApiSchema>(),
                Required   = new SortedSet <string>()
            };

            // If it's a baseType with known subTypes, add the discriminator property
            if (_generatorOptions.GeneratePolymorphicSchemas && _generatorOptions.SubTypesResolver(dataContract.UnderlyingType).Any())
            {
                var discriminatorName = _generatorOptions.DiscriminatorSelector(dataContract.UnderlyingType);

                if (!schema.Properties.ContainsKey(discriminatorName))
                {
                    schema.Properties.Add(discriminatorName, new OpenApiSchema {
                        Type = "string"
                    });
                }

                schema.Required.Add(discriminatorName);
                schema.Discriminator = new OpenApiDiscriminator {
                    PropertyName = discriminatorName
                };
            }

            foreach (var dataProperty in dataContract.Properties ?? Enumerable.Empty <DataProperty>())
            {
                var customAttributes = dataProperty.MemberInfo?.GetInlineOrMetadataTypeAttributes() ?? Enumerable.Empty <object>();

                if (_generatorOptions.IgnoreObsoleteProperties && customAttributes.OfType <ObsoleteAttribute>().Any())
                {
                    continue;
                }

                schema.Properties[dataProperty.Name] = GeneratePropertySchema(dataProperty, schemaRepository);

                if (dataProperty.IsRequired || customAttributes.OfType <RequiredAttribute>().Any())
                {
                    schema.Required.Add(dataProperty.Name);
                }
            }

            if (dataContract.AdditionalPropertiesType != null)
            {
                schema.AdditionalProperties = GenerateSchema(dataContract.AdditionalPropertiesType, schemaRepository);
            }

            // If it's a known subType, reference the baseType for inheritied properties
            if (
                _generatorOptions.GeneratePolymorphicSchemas &&
                (dataContract.UnderlyingType.BaseType != null) &&
                _generatorOptions.SubTypesResolver(dataContract.UnderlyingType.BaseType).Contains(dataContract.UnderlyingType))
            {
                var basedataContract    = _dataContractResolver.GetDataContractForType(dataContract.UnderlyingType.BaseType);
                var baseSchemaReference = GenerateReferencedSchema(basedataContract, schemaRepository);

                var baseSchema = schemaRepository.Schemas[baseSchemaReference.Reference.Id];
                foreach (var basePropertyName in baseSchema.Properties.Keys)
                {
                    schema.Properties.Remove(basePropertyName);
                }

                return(new OpenApiSchema
                {
                    AllOf = new List <OpenApiSchema> {
                        baseSchemaReference, schema
                    }
                });
            }

            return(schema);
        }