Skip to content

Commit 60145a1

Browse files
committed
Fix to get underlying type of nullable, list and dictionary object #113
1 parent a69952d commit 60145a1

File tree

6 files changed

+112
-4
lines changed

6 files changed

+112
-4
lines changed

samples/Aliencube.AzureFunctions.FunctionApp.Models/DummySubResponseModel.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Collections.Generic;
2+
13
using Newtonsoft.Json;
24

35
namespace Aliencube.AzureFunctions.FunctionApp.Models
@@ -8,5 +10,7 @@ public class DummySubResponseModel
810

911
[JsonProperty("CapitalisedJsonRequiredValue", Required = Required.Always)]
1012
public string JsonRequiredValue { get; set; }
13+
14+
public Dictionary<string, List<int>> NestedDictionaryValue { get; set; }
1115
}
1216
}

src/Aliencube.AzureFunctions.Extensions.OpenApi.Core/Extensions/TypeExtensions.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,43 @@ public static bool IsGenericTypeOf(this Type t1, Type t2)
351351
return t1.IsGenericType && t1.GetGenericTypeDefinition() == t2;
352352
}
353353

354+
/// <summary>
355+
/// Gets the underlying type of the given generic type.
356+
/// </summary>
357+
/// <param name="type">Type to check to get its underlying type.</param>
358+
/// <returns>Returns the underlying type.</returns>
359+
public static Type GetUnderlyingType(this Type type)
360+
{
361+
var underlyingType = default(Type);
362+
if (type.IsOpenApiNullable(out var nullableUnderlyingType))
363+
{
364+
underlyingType = nullableUnderlyingType;
365+
}
366+
367+
if (type.IsOpenApiArray())
368+
{
369+
underlyingType = type.GetElementType() ?? type.GetGenericArguments()[0];
370+
}
371+
372+
if (type.IsOpenApiDictionary())
373+
{
374+
underlyingType = type.GetGenericArguments()[1];
375+
}
376+
377+
if (underlyingType.IsNullOrDefault())
378+
{
379+
return underlyingType;
380+
}
381+
382+
if (underlyingType.IsGenericType)
383+
{
384+
var underlyingTypeOfUnderlyingType = underlyingType.GetUnderlyingType();
385+
underlyingType = underlyingTypeOfUnderlyingType;
386+
}
387+
388+
return underlyingType;
389+
}
390+
354391
/// <summary>
355392
/// Gets the Open API description from the given <see cref="Type"/>.
356393
/// </summary>

src/Aliencube.AzureFunctions.Extensions.OpenApi.Core/Visitors/DictionaryObjectTypeVisitor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public override void Visit(IAcceptor acceptor, KeyValuePair<string, Type> type,
4747
}
4848

4949
// Gets the schema for the underlying type.
50-
var underlyingType = type.Value.GetGenericArguments()[1];
50+
var underlyingType = type.Value.GetUnderlyingType();
5151
var types = new Dictionary<string, Type>()
5252
{
5353
{ underlyingType.GetOpenApiTypeName(namingStrategy), underlyingType }

src/Aliencube.AzureFunctions.Extensions.OpenApi.Core/Visitors/ListObjectTypeVisitor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public override void Visit(IAcceptor acceptor, KeyValuePair<string, Type> type,
4747
}
4848

4949
// Gets the schema for the underlying type.
50-
var underlyingType = type.Value.GetElementType() ?? type.Value.GetGenericArguments()[0];
50+
var underlyingType = type.Value.GetUnderlyingType();
5151
var types = new Dictionary<string, Type>()
5252
{
5353
{ underlyingType.GetOpenApiTypeName(namingStrategy), underlyingType }

src/Aliencube.AzureFunctions.Extensions.OpenApi.Core/Visitors/NullableObjectTypeVisitor.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ public override void Visit(IAcceptor acceptor, KeyValuePair<string, Type> type,
4242
}
4343

4444
// Gets the schema for the underlying type.
45-
type.Value.IsOpenApiNullable(out var underlyingType);
46-
45+
var underlyingType = type.Value.GetUnderlyingType();
4746
var types = new Dictionary<string, Type>()
4847
{
4948
{ type.Key, underlyingType }

test/Aliencube.AzureFunctions.Extensions.OpenApi.Core.Tests/Extensions/TypeExtensionsTests.cs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
using System;
12
using System.Collections.Generic;
23

34
using Aliencube.AzureFunctions.Extensions.OpenApi.Core.Extensions;
5+
using Aliencube.AzureFunctions.Extensions.OpenApi.Core.Tests.Fakes;
46

57
using FluentAssertions;
68

@@ -57,5 +59,71 @@ public void Given_CamelCaseNamingStrategy_When_GetOpenApiTypeName_Invoked_Then_I
5759

5860
result.Should().Be("int32");
5961
}
62+
63+
[DataTestMethod]
64+
[DataRow(typeof(int))]
65+
[DataRow(typeof(string))]
66+
[DataRow(typeof(FakeModel))]
67+
public void Given_NonGenericType_When_GetUnderlyingType_Invoked_Then_It_Should_Return_Null(Type type)
68+
{
69+
var result = TypeExtensions.GetUnderlyingType(type);
70+
71+
result.Should().BeNull();
72+
}
73+
74+
[DataTestMethod]
75+
[DataRow(typeof(int?), typeof(int))]
76+
[DataRow(typeof(bool?), typeof(bool))]
77+
[DataRow(typeof(DateTime?), typeof(DateTime))]
78+
public void Given_NullableType_When_GetUnderlyingType_Invoked_Then_It_Should_Return_Result(Type type, Type expected)
79+
{
80+
var result = TypeExtensions.GetUnderlyingType(type);
81+
82+
result.Should().Be(expected);
83+
}
84+
85+
[DataTestMethod]
86+
[DataRow(typeof(List<int>), typeof(int))]
87+
[DataRow(typeof(List<bool>), typeof(bool))]
88+
[DataRow(typeof(List<FakeModel>), typeof(FakeModel))]
89+
public void Given_ListType_When_GetUnderlyingType_Invoked_Then_It_Should_Return_Result(Type type, Type expected)
90+
{
91+
var result = TypeExtensions.GetUnderlyingType(type);
92+
93+
result.Should().Be(expected);
94+
}
95+
96+
[DataTestMethod]
97+
[DataRow(typeof(List<int?>), typeof(int))]
98+
[DataRow(typeof(List<bool?>), typeof(bool))]
99+
[DataRow(typeof(List<DateTime?>), typeof(DateTime))]
100+
public void Given_NullableListType_When_GetUnderlyingType_Invoked_Then_It_Should_Return_Result(Type type, Type expected)
101+
{
102+
var result = TypeExtensions.GetUnderlyingType(type);
103+
104+
result.Should().Be(expected);
105+
}
106+
107+
[DataTestMethod]
108+
[DataRow(typeof(Dictionary<string, int>), typeof(int))]
109+
[DataRow(typeof(Dictionary<string, bool>), typeof(bool))]
110+
[DataRow(typeof(Dictionary<string, FakeModel>), typeof(FakeModel))]
111+
public void Given_DictionaryType_When_GetUnderlyingType_Invoked_Then_It_Should_Return_Result(Type type, Type expected)
112+
{
113+
var result = TypeExtensions.GetUnderlyingType(type);
114+
115+
result.Should().Be(expected);
116+
}
117+
118+
[DataTestMethod]
119+
[DataRow(typeof(Dictionary<string, int?>), typeof(int))]
120+
[DataRow(typeof(Dictionary<string, bool?>), typeof(bool))]
121+
[DataRow(typeof(Dictionary<string, DateTime?>), typeof(DateTime))]
122+
public void Given_NullableDictionaryType_When_GetUnderlyingType_Invoked_Then_It_Should_Return_Result(Type type, Type expected)
123+
{
124+
var result = TypeExtensions.GetUnderlyingType(type);
125+
126+
result.Should().Be(expected);
127+
}
60128
}
61129
}

0 commit comments

Comments
 (0)