Skip to content

Commit 4d5625f

Browse files
Extend built-in supported types (#2804)
1 parent eabfafa commit 4d5625f

5 files changed

Lines changed: 76 additions & 33 deletions

File tree

src/Swashbuckle.AspNetCore.Newtonsoft/SchemaGenerator/NewtonsoftDataContractResolver.cs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ public DataContract GetDataContractForType(Type type)
3333

3434
if (jsonContract is JsonPrimitiveContract && !jsonContract.UnderlyingType.IsEnum)
3535
{
36-
var primitiveTypeAndFormat = PrimitiveTypesAndFormats.TryGetValue(jsonContract.UnderlyingType, out var format)
37-
? format
38-
: Tuple.Create(DataType.String, (string)null);
36+
if (!PrimitiveTypesAndFormats.TryGetValue(jsonContract.UnderlyingType, out var primitiveTypeAndFormat))
37+
{
38+
primitiveTypeAndFormat = Tuple.Create(DataType.String, (string)null);
39+
}
3940

4041
return DataContract.ForPrimitive(
4142
underlyingType: jsonContract.UnderlyingType,
@@ -48,7 +49,7 @@ public DataContract GetDataContractForType(Type type)
4849
{
4950
var enumValues = jsonContract.UnderlyingType.GetEnumValues();
5051

51-
//Test to determine if the serializer will treat as string
52+
// Test to determine if the serializer will treat as string
5253
var serializeAsString = (enumValues.Length > 0)
5354
&& JsonConverterFunc(enumValues.GetValue(0)).StartsWith("\"");
5455

@@ -83,7 +84,7 @@ public DataContract GetDataContractForType(Type type)
8384
// This is a special case where we know the possible key values
8485
var enumValuesAsJson = keyType.GetEnumValues()
8586
.Cast<object>()
86-
.Select(value => JsonConverterFunc(value));
87+
.Select(JsonConverterFunc);
8788

8889
keys = enumValuesAsJson.Any(json => json.StartsWith("\""))
8990
? enumValuesAsJson.Select(json => json.Replace("\"", string.Empty))
@@ -99,6 +100,16 @@ public DataContract GetDataContractForType(Type type)
99100

100101
if (jsonContract is JsonObjectContract jsonObjectContract)
101102
{
103+
// This handles DateOnly and TimeOnly
104+
if (PrimitiveTypesAndFormats.TryGetValue(jsonContract.UnderlyingType, out var primitiveTypeAndFormat))
105+
{
106+
return DataContract.ForPrimitive(
107+
underlyingType: jsonContract.UnderlyingType,
108+
dataType: primitiveTypeAndFormat.Item1,
109+
dataFormat: primitiveTypeAndFormat.Item2,
110+
jsonConverter: JsonConverterFunc);
111+
}
112+
102113
string typeNameProperty = null;
103114
string typeNameValue = null;
104115

@@ -186,7 +197,7 @@ private IEnumerable<DataProperty> GetDataPropertiesFor(JsonObjectContract jsonOb
186197
return dataProperties;
187198
}
188199

189-
private static readonly Dictionary<Type, Tuple<DataType, string>> PrimitiveTypesAndFormats = new Dictionary<Type, Tuple<DataType, string>>
200+
private static readonly Dictionary<Type, Tuple<DataType, string>> PrimitiveTypesAndFormats = new()
190201
{
191202
[ typeof(bool) ] = Tuple.Create(DataType.Boolean, (string)null),
192203
[ typeof(byte) ] = Tuple.Create(DataType.Integer, "int32"),
@@ -210,7 +221,11 @@ [ typeof(Uri) ] = Tuple.Create(DataType.String, "uri"),
210221
[ typeof(TimeSpan) ] = Tuple.Create(DataType.String, "date-span"),
211222
#if NET6_0_OR_GREATER
212223
[ typeof(DateOnly) ] = Tuple.Create(DataType.String, "date"),
213-
[ typeof(TimeOnly) ] = Tuple.Create(DataType.String, "time")
224+
[ typeof(TimeOnly) ] = Tuple.Create(DataType.String, "time"),
225+
#endif
226+
#if NET7_0_OR_GREATER
227+
[ typeof(Int128) ] = Tuple.Create(DataType.Integer, "int128"),
228+
[ typeof(UInt128) ] = Tuple.Create(DataType.Integer, "int128"),
214229
#endif
215230
};
216231
}

src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/JsonSerializerDataContractResolver.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ public DataContract GetDataContractForType(Type type)
2727
jsonConverter: JsonConverterFunc);
2828
}
2929

30-
if (PrimitiveTypesAndFormats.TryGetValue(type, out var primitiveTypeAndFormat1))
30+
if (PrimitiveTypesAndFormats.TryGetValue(type, out var primitiveTypeAndFormat))
3131
{
3232
return DataContract.ForPrimitive(
3333
underlyingType: type,
34-
dataType: primitiveTypeAndFormat1.Item1,
35-
dataFormat: primitiveTypeAndFormat1.Item2,
34+
dataType: primitiveTypeAndFormat.Item1,
35+
dataFormat: primitiveTypeAndFormat.Item2,
3636
jsonConverter: JsonConverterFunc);
3737
}
3838

@@ -44,7 +44,7 @@ public DataContract GetDataContractForType(Type type)
4444
var serializeAsString = (enumValues.Length > 0)
4545
&& JsonConverterFunc(enumValues.GetValue(0)).StartsWith("\"");
4646

47-
var primitiveTypeAndFormat = serializeAsString
47+
primitiveTypeAndFormat = serializeAsString
4848
? PrimitiveTypesAndFormats[typeof(string)]
4949
: PrimitiveTypesAndFormats[type.GetEnumUnderlyingType()];
5050

@@ -254,11 +254,17 @@ [ typeof(string) ] = Tuple.Create(DataType.String, (string)null),
254254
[ typeof(char) ] = Tuple.Create(DataType.String, (string)null),
255255
[ typeof(DateTime) ] = Tuple.Create(DataType.String, "date-time"),
256256
[ typeof(DateTimeOffset) ] = Tuple.Create(DataType.String, "date-time"),
257+
[ typeof(TimeSpan) ] = Tuple.Create(DataType.String, "date-span"),
257258
[ typeof(Guid) ] = Tuple.Create(DataType.String, "uuid"),
258259
[ typeof(Uri) ] = Tuple.Create(DataType.String, "uri"),
260+
[ typeof(Version) ] = Tuple.Create(DataType.String, (string)null),
259261
#if NET6_0_OR_GREATER
260262
[ typeof(DateOnly) ] = Tuple.Create(DataType.String, "date"),
261-
[ typeof(TimeOnly) ] = Tuple.Create(DataType.String, "time")
263+
[ typeof(TimeOnly) ] = Tuple.Create(DataType.String, "time"),
264+
#endif
265+
#if NET7_0_OR_GREATER
266+
[ typeof(Int128) ] = Tuple.Create(DataType.Integer, "int128"),
267+
[ typeof(UInt128) ] = Tuple.Create(DataType.Integer, "int128"),
262268
#endif
263269
};
264270
}

src/Swashbuckle.AspNetCore.SwaggerGen/SchemaGenerator/OpenApiSchemaExtensions.cs

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,26 @@ namespace Swashbuckle.AspNetCore.SwaggerGen
99
{
1010
public static class OpenApiSchemaExtensions
1111
{
12+
private static readonly Dictionary<AnnotationsDataType, string> DataFormatMappings = new()
13+
{
14+
[AnnotationsDataType.DateTime] = "date-time",
15+
[AnnotationsDataType.Date] = "date",
16+
[AnnotationsDataType.Time] = "time",
17+
[AnnotationsDataType.Duration] = "duration",
18+
[AnnotationsDataType.PhoneNumber] = "tel",
19+
[AnnotationsDataType.Currency] = "currency",
20+
[AnnotationsDataType.Text] = "string",
21+
[AnnotationsDataType.Html] = "html",
22+
[AnnotationsDataType.MultilineText] = "multiline",
23+
[AnnotationsDataType.EmailAddress] = "email",
24+
[AnnotationsDataType.Password] = "password",
25+
[AnnotationsDataType.Url] = "uri",
26+
[AnnotationsDataType.ImageUrl] = "uri",
27+
[AnnotationsDataType.CreditCard] = "credit-card",
28+
[AnnotationsDataType.PostalCode] = "postal-code",
29+
[AnnotationsDataType.Upload] = "binary",
30+
};
31+
1232
public static void ApplyValidationAttributes(this OpenApiSchema schema, IEnumerable<object> customAttributes)
1333
{
1434
foreach (var attribute in customAttributes)
@@ -88,26 +108,7 @@ public static string ResolveType(this OpenApiSchema schema, SchemaRepository sch
88108

89109
private static void ApplyDataTypeAttribute(OpenApiSchema schema, DataTypeAttribute dataTypeAttribute)
90110
{
91-
var formats = new Dictionary<AnnotationsDataType, string>
92-
{
93-
{ AnnotationsDataType.DateTime, "date-time" },
94-
{ AnnotationsDataType.Date, "date" },
95-
{ AnnotationsDataType.Time, "time" },
96-
{ AnnotationsDataType.Duration, "duration" },
97-
{ AnnotationsDataType.PhoneNumber, "tel" },
98-
{ AnnotationsDataType.Currency, "currency" },
99-
{ AnnotationsDataType.Text, "string" },
100-
{ AnnotationsDataType.Html, "html" },
101-
{ AnnotationsDataType.MultilineText, "multiline" },
102-
{ AnnotationsDataType.EmailAddress, "email" },
103-
{ AnnotationsDataType.Password, "password" },
104-
{ AnnotationsDataType.Url, "uri" },
105-
{ AnnotationsDataType.ImageUrl, "uri" },
106-
{ AnnotationsDataType.CreditCard, "credit-card" },
107-
{ AnnotationsDataType.PostalCode, "postal-code" }
108-
};
109-
110-
if (formats.TryGetValue(dataTypeAttribute.DataType, out string format))
111+
if (DataFormatMappings.TryGetValue(dataTypeAttribute.DataType, out string format))
111112
{
112113
schema.Format = format;
113114
}

test/Swashbuckle.AspNetCore.Newtonsoft.Test/SchemaGenerator/NewtonsoftSchemaGeneratorTests.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public void GenerateSchema_GeneratesFileSchema_BinaryStringResultType(Type type)
3333
}
3434

3535
[Theory]
36+
[InlineData(typeof(bool), "boolean", null)]
3637
[InlineData(typeof(byte), "integer", "int32")]
3738
[InlineData(typeof(sbyte), "integer", "int32")]
3839
[InlineData(typeof(short), "integer", "int32")]
@@ -49,12 +50,24 @@ public void GenerateSchema_GeneratesFileSchema_BinaryStringResultType(Type type)
4950
[InlineData(typeof(byte[]), "string", "byte")]
5051
[InlineData(typeof(DateTime), "string", "date-time")]
5152
[InlineData(typeof(DateTimeOffset), "string", "date-time")]
52-
[InlineData(typeof(Guid), "string", "uuid")]
5353
[InlineData(typeof(TimeSpan), "string", "date-span")]
54+
[InlineData(typeof(Guid), "string", "uuid")]
55+
[InlineData(typeof(Uri), "string", "uri")]
5456
[InlineData(typeof(Version), "string", null)]
57+
[InlineData(typeof(DateOnly), "string", "date")]
58+
[InlineData(typeof(TimeOnly), "string", "time")]
5559
[InlineData(typeof(bool?), "boolean", null)]
5660
[InlineData(typeof(int?), "integer", "int32")]
5761
[InlineData(typeof(DateTime?), "string", "date-time")]
62+
[InlineData(typeof(Guid?), "string", "uuid")]
63+
[InlineData(typeof(DateOnly?), "string", "date")]
64+
[InlineData(typeof(TimeOnly?), "string", "time")]
65+
#if NET7_0_OR_GREATER
66+
[InlineData(typeof(Int128), "integer", "int128")]
67+
[InlineData(typeof(Int128?), "integer", "int128")]
68+
[InlineData(typeof(UInt128), "integer", "int128")]
69+
[InlineData(typeof(UInt128?), "integer", "int128")]
70+
#endif
5871
public void GenerateSchema_GeneratesPrimitiveSchema_IfPrimitiveOrNullablePrimitiveType(
5972
Type type,
6073
string expectedSchemaType,

test/Swashbuckle.AspNetCore.SwaggerGen.Test/SchemaGenerator/JsonSerializerSchemaGeneratorTests.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,10 @@ public void GenerateSchema_GeneratesFileSchema_BinaryStringResultType(Type type)
5353
[InlineData(typeof(byte[]), "string", "byte")]
5454
[InlineData(typeof(DateTime), "string", "date-time")]
5555
[InlineData(typeof(DateTimeOffset), "string", "date-time")]
56+
[InlineData(typeof(TimeSpan), "string", "date-span")]
5657
[InlineData(typeof(Guid), "string", "uuid")]
5758
[InlineData(typeof(Uri), "string", "uri")]
59+
[InlineData(typeof(Version), "string", null)]
5860
[InlineData(typeof(DateOnly), "string", "date")]
5961
[InlineData(typeof(TimeOnly), "string", "time")]
6062
[InlineData(typeof(bool?), "boolean", null)]
@@ -63,6 +65,12 @@ public void GenerateSchema_GeneratesFileSchema_BinaryStringResultType(Type type)
6365
[InlineData(typeof(Guid?), "string", "uuid")]
6466
[InlineData(typeof(DateOnly?), "string", "date")]
6567
[InlineData(typeof(TimeOnly?), "string", "time")]
68+
#if NET7_0_OR_GREATER
69+
[InlineData(typeof(Int128), "integer", "int128")]
70+
[InlineData(typeof(Int128?), "integer", "int128")]
71+
[InlineData(typeof(UInt128), "integer", "int128")]
72+
[InlineData(typeof(UInt128?), "integer", "int128")]
73+
#endif
6674
public void GenerateSchema_GeneratesPrimitiveSchema_IfPrimitiveOrNullablePrimitiveType(
6775
Type type,
6876
string expectedSchemaType,

0 commit comments

Comments
 (0)