Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support oneOf inheritance for JsonSchema Generation #832 #839

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 41 additions & 20 deletions src/NJsonSchema/Generation/JsonSchemaGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -274,23 +274,38 @@ public virtual async Task<TSchemaType> GenerateWithReferenceAndNullabilityAsync<
var useDirectReference = Settings.AllowReferencesWithProperties ||
!JsonConvert.DeserializeObject<JObject>(JsonConvert.SerializeObject(referencingSchema)).Properties().Any(); // TODO: Improve performance

if (useDirectReference && referencingSchema.OneOf.Count == 0)
//TODO : use InheritanceMode ?
if (Settings.SchemaType == SchemaType.JsonSchema && referencedSchema.ActualSchema.KnownTypesSchemas?.Any() == true)
{
referencingSchema.Reference = referencedSchema.ActualSchema;
}
else if (Settings.SchemaType != SchemaType.Swagger2)
{
referencingSchema.OneOf.Add(new JsonSchema4
foreach (var schema in referencedSchema.ActualSchema.KnownTypesSchemas)
{
Reference = referencedSchema.ActualSchema
});
referencingSchema.Type = JsonObjectType.Object;
referencingSchema.OneOf.Add(new JsonSchema4
{
Reference = schema
});
}
}
else
{
referencingSchema.AllOf.Add(new JsonSchema4
if (useDirectReference && referencingSchema.OneOf.Count == 0)
{
Reference = referencedSchema.ActualSchema
});
referencingSchema.Reference = referencedSchema.ActualSchema;
}
else if (Settings.SchemaType != SchemaType.Swagger2)
{
referencingSchema.OneOf.Add(new JsonSchema4
{
Reference = referencedSchema.ActualSchema
});
}
else
{
referencingSchema.AllOf.Add(new JsonSchema4
{
Reference = referencedSchema.ActualSchema
});
}
}

return referencingSchema;
Expand Down Expand Up @@ -350,7 +365,7 @@ protected virtual async Task GenerateObjectAsync(Type type,

GenerateInheritanceDiscriminator(type, rootSchema, schema);

await GenerateKnownTypesAsync(type, schemaResolver).ConfigureAwait(false);
schema.KnownTypesSchemas = new System.Collections.ObjectModel.ReadOnlyCollection<JsonSchema4>(await GenerateKnownTypesAsync(type, schemaResolver).ConfigureAwait(false));

if (Settings.GenerateXmlObjects)
schema.GenerateXmlObjectForType(type);
Expand Down Expand Up @@ -645,8 +660,10 @@ protected virtual string[] GetTypeProperties(Type type)
return null;
}

private async Task GenerateKnownTypesAsync(Type type, JsonSchemaResolver schemaResolver)
private async Task<IList<JsonSchema4>> GenerateKnownTypesAsync(Type type, JsonSchemaResolver schemaResolver)
{
var knownTypeSchemas = new List<JsonSchema4>();

var attributes = type.GetTypeInfo()
.GetCustomAttributes(Settings.GetActualFlattenInheritanceHierarchy(type));

Expand All @@ -660,7 +677,7 @@ private async Task GenerateKnownTypesAsync(Type type, JsonSchemaResolver schemaR
foreach (dynamic attribute in knownTypeAttributes)
{
if (attribute.Type != null)
await AddKnownTypeAsync(attribute.Type, schemaResolver).ConfigureAwait(false);
knownTypeSchemas.Add(await AddKnownTypeAsync(attribute.Type, schemaResolver));
else if (attribute.MethodName != null)
{
var methodInfo = type.GetRuntimeMethod((string)attribute.MethodName, new Type[0]);
Expand All @@ -670,7 +687,7 @@ private async Task GenerateKnownTypesAsync(Type type, JsonSchemaResolver schemaR
if (knownTypes != null)
{
foreach (var knownType in knownTypes)
await AddKnownTypeAsync(knownType, schemaResolver).ConfigureAwait(false);
knownTypeSchemas.Add(await AddKnownTypeAsync(knownType, schemaResolver));
}
}
}
Expand All @@ -680,25 +697,29 @@ private async Task GenerateKnownTypesAsync(Type type, JsonSchemaResolver schemaR
}

foreach (var jsonConverterAttribute in attributes
.Where(a => a.GetType().IsAssignableTo("JsonInheritanceAttribute", TypeNameStyle.Name)))
.Where(a => a.GetType().IsAssignableTo("JsonInheritanceAttribute", TypeNameStyle.Name)))
{
var knownType = ReflectionExtensions.TryGetPropertyValue<Type>(
jsonConverterAttribute, "Type", null);

if (knownType != null)
{
await AddKnownTypeAsync(knownType, schemaResolver).ConfigureAwait(false);
knownTypeSchemas.Add(await AddKnownTypeAsync(type, schemaResolver));
}
}
return knownTypeSchemas;
}

private async Task AddKnownTypeAsync(Type type, JsonSchemaResolver schemaResolver)

private async Task<JsonSchema4> AddKnownTypeAsync(Type type, JsonSchemaResolver schemaResolver)
{
var typeDescription = Settings.ReflectionService.GetDescription(type, null, Settings);
var isIntegerEnum = typeDescription.Type == JsonObjectType.Integer;

if (!schemaResolver.HasSchema(type, isIntegerEnum))
await GenerateAsync(type, schemaResolver).ConfigureAwait(false);
if (schemaResolver.HasSchema(type, isIntegerEnum))
return schemaResolver.GetSchema(type, isIntegerEnum);
else
return await GenerateAsync(type, schemaResolver).ConfigureAwait(false);
}

private async Task<JsonSchema4> GenerateInheritanceAsync(Type type, JsonSchema4 schema, JsonSchemaResolver schemaResolver)
Expand Down
4 changes: 4 additions & 0 deletions src/NJsonSchema/JsonSchema4.cs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,10 @@ public IDictionary<string, JsonProperty> ActualProperties
[JsonIgnore]
public JsonSchema4 ParentSchema => Parent as JsonSchema4;

/// <summary>Gets or sets the KnownTypes Schemas</summary>
[JsonIgnore]
public ReadOnlyCollection<JsonSchema4> KnownTypesSchemas { get; set; }

/// <summary>Gets the parent schema of this schema. </summary>
[JsonIgnore]
public virtual object Parent { get; set; }
Expand Down