Skip to content
This repository has been archived by the owner on Feb 18, 2024. It is now read-only.

Commit

Permalink
Add support for JsonPolymorphic and JsonDerivedType attributes. Credi…
Browse files Browse the repository at this point in the history
  • Loading branch information
Havunen committed Feb 10, 2024
1 parent 53c5f75 commit 58976ef
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 94 deletions.
27 changes: 18 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1156,7 +1156,7 @@ services.AddSwaggerGen(c =>
});
```

_NOTE: If you're using the [DotSwashbuckle Annotations library](#swashbuckleaspnetcoreannotations), it contains a custom selector that's based on the presence of `SwaggerSubType` attributes on base class definitions. This way, you can use simple attributes to explicitly list the inheritance and/or polymorphism relationships you want to expose. To enable this behavior, check out the [Annotations docs](#list-known-subtypes-for-inheritance-and-polymorphism)._
_NOTE: If you're using the [DotSwashbuckle Annotations library](#swashbuckleaspnetcoreannotations), it contains a custom selector that's based on the presence of `JsonDerivedType` attributes on base class definitions. This way, you can use simple attributes to explicitly list the inheritance and/or polymorphism relationships you want to expose. To enable this behavior, check out the [Annotations docs](#list-known-subtypes-for-inheritance-and-polymorphism)._

#### Describing Discriminators ####

Expand Down Expand Up @@ -1222,7 +1222,7 @@ services.AddSwaggerGen(c =>
});
```

_NOTE: If you're using the [DotSwashbuckle Annotations library](#swashbuckleaspnetcoreannotations), it contains custom selector functions that are based on the presence of `SwaggerDiscriminator` and `SwaggerSubType` attributes on base class definitions. This way, you can use simple attributes to explicitly provide discriminator metadata. To enable this behavior, check out the [Annotations docs](#enrich-polymorphic-base-classes-with-discriminator-metadata)._
_NOTE: If you're using the [DotSwashbuckle Annotations library](#swashbuckleaspnetcoreannotations), it contains custom selector functions that are based on the presence of `JsonPolymorphic` and `JsonDerivedType` attributes on base class definitions. This way, you can use simple attributes to explicitly provide discriminator metadata. To enable this behavior, check out the [Annotations docs](#enrich-polymorphic-base-classes-with-discriminator-metadata)._

## DotSwashbuckle.AspNetCore.SwaggerUI ##

Expand Down Expand Up @@ -1505,16 +1505,16 @@ services.AddSwaggerGen(c =>
});

// Shape.cs
[SwaggerSubType(typeof(Rectangle))]
[SwaggerSubType(typeof(Circle))]
[JsonDerivedType(typeof(Rectangle))]
[JsonDerivedType(typeof(Circle))]
public abstract class Shape
{
}
```

### Enrich Polymorphic Base Classes with Discriminator Metadata ###

If you're using annotations to _explicitly_ indicate the "known" subtypes for a polymorphic base type, you can combine the `SwaggerDiscriminatorAttribute` with the `SwaggerSubTypeAttribute` to provide additional metadata about the "discriminator" property, which will then be incorporated into the generated schema definition:
If you're using annotations to _explicitly_ indicate the "known" subtypes for a polymorphic base type, you can combine the `JsonPolymorphicAttribute` with the `JsonDerivedTypeAttribute` to provide additional metadata about the "discriminator" property, which will then be incorporated into the generated schema definition:


```csharp
Expand All @@ -1525,12 +1525,21 @@ services.AddSwaggerGen(c =>
});

// Shape.cs
[SwaggerDiscriminator("shapeType")]
[SwaggerSubType(typeof(Rectangle), DiscriminatorValue = "rectangle")]
[SwaggerSubType(typeof(Circle), DiscriminatorValue = "circle")]
[JsonPolymorphic(TypeDiscriminatorPropertyName = "shapeType")]
[JsonDerivedType(typeof(Rectangle), "rectangle")]
[JsonDerivedType(typeof(Circle), "circle")]
public abstract class Shape
{
public ShapeType { get; set; }
// Avoid using a JsonPolymorphicAttribute.TypeDiscriminatorPropertyName
// that conflicts with a property in your type hierarchy.
// Related issue: https://github.com/dotnet/runtime/issues/72170
}

[JsonConverter(typeof(JsonStringEnumConverter))]
public enum AnimalType
{
Circle,
Rectangle
}
```

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using DotSwashbuckle.AspNetCore.SwaggerGen;
using DotSwashbuckle.AspNetCore.Annotations;
using System.Reflection;

namespace Microsoft.Extensions.DependencyInjection
{
Expand Down Expand Up @@ -56,44 +58,27 @@ public static void EnableAnnotations(this SwaggerGenOptions options)

private static IEnumerable<Type> AnnotationsSubTypesSelector(Type type)
{
var subTypeAttributes = type.GetCustomAttributes(false)
.OfType<SwaggerSubTypeAttribute>();
var jsonDerivedTypeAttributes = type.GetCustomAttributes(false)
.OfType<JsonDerivedTypeAttribute>()
.ToArray();

if (subTypeAttributes.Any())
if (jsonDerivedTypeAttributes.Any())
{
return subTypeAttributes.Select(attr => attr.SubType);
}

var obsoleteAttribute = type.GetCustomAttributes(false)
.OfType<SwaggerSubTypesAttribute>()
.FirstOrDefault();

if (obsoleteAttribute != null)
{
return obsoleteAttribute.SubTypes;
return jsonDerivedTypeAttributes.Select(attr => attr.DerivedType);
}

return Enumerable.Empty<Type>();
}

private static string AnnotationsDiscriminatorNameSelector(Type baseType)
{
var discriminatorAttribute = baseType.GetCustomAttributes(false)
.OfType<SwaggerDiscriminatorAttribute>()
.FirstOrDefault();

if (discriminatorAttribute != null)
{
return discriminatorAttribute.PropertyName;
}

var obsoleteAttribute = baseType.GetCustomAttributes(false)
.OfType<SwaggerSubTypesAttribute>()
var jsonPolymorphicAttribute = baseType.GetCustomAttributes(false)
.OfType<JsonPolymorphicAttribute>()
.FirstOrDefault();

if (obsoleteAttribute != null)
if (jsonPolymorphicAttribute is not null)
{
return obsoleteAttribute.Discriminator;
return jsonPolymorphicAttribute.TypeDiscriminatorPropertyName;
}

return null;
Expand All @@ -104,13 +89,13 @@ private static string AnnotationsDiscriminatorValueSelector(Type subType)
if (subType.BaseType == null)
return null;

var subTypeAttribute = subType.BaseType.GetCustomAttributes(false)
.OfType<SwaggerSubTypeAttribute>()
.FirstOrDefault(attr => attr.SubType == subType);
var jsonDerivedTypeAttribute = subType.BaseType.GetCustomAttributes(false)
.OfType<JsonDerivedTypeAttribute>()
.FirstOrDefault(attr => attr.DerivedType == subType);

if (subTypeAttribute != null)
if (jsonDerivedTypeAttribute is not null)
{
return subTypeAttribute.DiscriminatorValue;
return jsonDerivedTypeAttribute.TypeDiscriminator?.ToString();
}

return null;
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ public void CreateAnimal([Required]Animal animal)
}
}

[SwaggerDiscriminator("animalType")]
[SwaggerSubType(typeof(Cat), DiscriminatorValue = "Cat")]
[SwaggerSubType(typeof(Dog), DiscriminatorValue = "Dog")]
[JsonPolymorphic(TypeDiscriminatorPropertyName = "animalType")]
[JsonDerivedType(typeof(Cat), "Cat")]
[JsonDerivedType(typeof(Dog), "Dog")]
public class Animal
{
public AnimalType AnimalType { get; set; }
Expand Down

0 comments on commit 58976ef

Please sign in to comment.