Skip to content

Commit 2f5db39

Browse files
committed
Add support for JsonPolymorphic and JsonDerivedType attributes. Credits for @schnerring domaindrivendev#2671
1 parent f2993b7 commit 2f5db39

File tree

7 files changed

+517
-94
lines changed

7 files changed

+517
-94
lines changed

README.md

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,7 +1156,7 @@ services.AddSwaggerGen(c =>
11561156
});
11571157
```
11581158

1159-
_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)._
1159+
_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)._
11601160

11611161
#### Describing Discriminators ####
11621162

@@ -1222,7 +1222,7 @@ services.AddSwaggerGen(c =>
12221222
});
12231223
```
12241224

1225-
_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)._
1225+
_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)._
12261226

12271227
## DotSwashbuckle.AspNetCore.SwaggerUI ##
12281228

@@ -1505,16 +1505,16 @@ services.AddSwaggerGen(c =>
15051505
});
15061506

15071507
// Shape.cs
1508-
[SwaggerSubType(typeof(Rectangle))]
1509-
[SwaggerSubType(typeof(Circle))]
1508+
[JsonDerivedType(typeof(Rectangle))]
1509+
[JsonDerivedType(typeof(Circle))]
15101510
public abstract class Shape
15111511
{
15121512
}
15131513
```
15141514

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

1517-
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:
1517+
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:
15181518

15191519

15201520
```csharp
@@ -1525,12 +1525,21 @@ services.AddSwaggerGen(c =>
15251525
});
15261526

15271527
// Shape.cs
1528-
[SwaggerDiscriminator("shapeType")]
1529-
[SwaggerSubType(typeof(Rectangle), DiscriminatorValue = "rectangle")]
1530-
[SwaggerSubType(typeof(Circle), DiscriminatorValue = "circle")]
1528+
[JsonPolymorphic(TypeDiscriminatorPropertyName = "shapeType")]
1529+
[JsonDerivedType(typeof(Rectangle), "rectangle")]
1530+
[JsonDerivedType(typeof(Circle), "circle")]
15311531
public abstract class Shape
15321532
{
1533-
public ShapeType { get; set; }
1533+
// Avoid using a JsonPolymorphicAttribute.TypeDiscriminatorPropertyName
1534+
// that conflicts with a property in your type hierarchy.
1535+
// Related issue: https://github.com/dotnet/runtime/issues/72170
1536+
}
1537+
1538+
[JsonConverter(typeof(JsonStringEnumConverter))]
1539+
public enum AnimalType
1540+
{
1541+
Circle,
1542+
Rectangle
15341543
}
15351544
```
15361545

src/DotSwashbuckle.AspNetCore.Annotations/AnnotationsSwaggerGenOptionsExtensions.cs

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Text.Json.Serialization;
45
using DotSwashbuckle.AspNetCore.SwaggerGen;
56
using DotSwashbuckle.AspNetCore.Annotations;
7+
using System.Reflection;
68

79
namespace Microsoft.Extensions.DependencyInjection
810
{
@@ -56,44 +58,27 @@ public static void EnableAnnotations(this SwaggerGenOptions options)
5658

5759
private static IEnumerable<Type> AnnotationsSubTypesSelector(Type type)
5860
{
59-
var subTypeAttributes = type.GetCustomAttributes(false)
60-
.OfType<SwaggerSubTypeAttribute>();
61+
var jsonDerivedTypeAttributes = type.GetCustomAttributes(false)
62+
.OfType<JsonDerivedTypeAttribute>()
63+
.ToArray();
6164

62-
if (subTypeAttributes.Any())
65+
if (jsonDerivedTypeAttributes.Any())
6366
{
64-
return subTypeAttributes.Select(attr => attr.SubType);
65-
}
66-
67-
var obsoleteAttribute = type.GetCustomAttributes(false)
68-
.OfType<SwaggerSubTypesAttribute>()
69-
.FirstOrDefault();
70-
71-
if (obsoleteAttribute != null)
72-
{
73-
return obsoleteAttribute.SubTypes;
67+
return jsonDerivedTypeAttributes.Select(attr => attr.DerivedType);
7468
}
7569

7670
return Enumerable.Empty<Type>();
7771
}
7872

7973
private static string AnnotationsDiscriminatorNameSelector(Type baseType)
8074
{
81-
var discriminatorAttribute = baseType.GetCustomAttributes(false)
82-
.OfType<SwaggerDiscriminatorAttribute>()
83-
.FirstOrDefault();
84-
85-
if (discriminatorAttribute != null)
86-
{
87-
return discriminatorAttribute.PropertyName;
88-
}
89-
90-
var obsoleteAttribute = baseType.GetCustomAttributes(false)
91-
.OfType<SwaggerSubTypesAttribute>()
75+
var jsonPolymorphicAttribute = baseType.GetCustomAttributes(false)
76+
.OfType<JsonPolymorphicAttribute>()
9277
.FirstOrDefault();
9378

94-
if (obsoleteAttribute != null)
79+
if (jsonPolymorphicAttribute is not null)
9580
{
96-
return obsoleteAttribute.Discriminator;
81+
return jsonPolymorphicAttribute.TypeDiscriminatorPropertyName;
9782
}
9883

9984
return null;
@@ -104,13 +89,13 @@ private static string AnnotationsDiscriminatorValueSelector(Type subType)
10489
if (subType.BaseType == null)
10590
return null;
10691

107-
var subTypeAttribute = subType.BaseType.GetCustomAttributes(false)
108-
.OfType<SwaggerSubTypeAttribute>()
109-
.FirstOrDefault(attr => attr.SubType == subType);
92+
var jsonDerivedTypeAttribute = subType.BaseType.GetCustomAttributes(false)
93+
.OfType<JsonDerivedTypeAttribute>()
94+
.FirstOrDefault(attr => attr.DerivedType == subType);
11095

111-
if (subTypeAttribute != null)
96+
if (jsonDerivedTypeAttribute is not null)
11297
{
113-
return subTypeAttribute.DiscriminatorValue;
98+
return jsonDerivedTypeAttribute.TypeDiscriminator?.ToString();
11499
}
115100

116101
return null;

src/DotSwashbuckle.AspNetCore.Annotations/SwaggerDiscriminatorAttribute.cs

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/DotSwashbuckle.AspNetCore.Annotations/SwaggerSubTypeAttribute.cs

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/DotSwashbuckle.AspNetCore.Annotations/SwaggerSubTypesAttribute.cs

Lines changed: 0 additions & 19 deletions
This file was deleted.

0 commit comments

Comments
 (0)