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); }