Skip to content

Commit d95c0fc

Browse files
authored
Fix "could not resolve reference error" #160 (#246)
1 parent 6fa88b1 commit d95c0fc

File tree

7 files changed

+92
-43
lines changed

7 files changed

+92
-43
lines changed

samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.Models/DummyListModel.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
3+
using Microsoft.AspNetCore.Mvc;
24

35
namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.Models
46
{
@@ -9,5 +11,7 @@ public class DummyListModel
911
public HashSet<int> ListValues2 { get; set; }
1012

1113
public ISet<DummyStringModel> ListValues3 { get; set; }
14+
15+
public ValidationProblemDetails ValidationProblemDetails { get; set; }
1216
}
1317
}

src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Extensions/TypeExtensions.cs

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -68,71 +68,77 @@ public static bool IsSimpleType(this Type type)
6868
}
6969
}
7070

71+
private static HashSet<Type> jObjects = new HashSet<Type>
72+
{
73+
typeof(JObject),
74+
typeof(JToken),
75+
typeof(JArray),
76+
};
77+
78+
/// <summary>
79+
/// Checks whether the given type is Json.NET related <see cref="JObject"/>, <see cref="JToken"/> or not.
80+
/// </summary>
81+
/// <param name="type"><see cref="Type"/> instance.</param>
82+
/// <returns>Returns <c>True</c>, if the type is identified as either <see cref="JObject"/> or <see cref="JToken"/>; otherwise returns <c>False</c>.</returns>
83+
public static bool IsJObjectType(this Type type)
84+
{
85+
if (type.IsNullOrDefault())
86+
{
87+
return false;
88+
}
89+
90+
if (jObjects.Any(p => p == type))
91+
{
92+
return true;
93+
}
94+
95+
return false;
96+
}
97+
98+
private static HashSet<Type> nonReferentialTypes = new HashSet<Type>
99+
{
100+
typeof(Guid),
101+
typeof(DateTime),
102+
typeof(DateTimeOffset),
103+
typeof(object),
104+
};
71105

72106
/// <summary>
73107
/// Checks whether the type can be referenced or not.
74108
/// </summary>
75109
/// <param name="type">Type to check.</param>
76110
/// <returns>Returns <c>True</c>, if the type can be referenced; otherwise returns <c>False</c>.</returns>
111+
77112
public static bool IsReferentialType(this Type type)
78113
{
79114
var @enum = Type.GetTypeCode(type);
80115
var isReferential = @enum == TypeCode.Object;
81116

82-
if (type == typeof(Guid))
83-
{
84-
isReferential = false;
85-
}
86-
if (type == typeof(DateTime))
87-
{
88-
isReferential = false;
89-
}
90-
if (type == typeof(DateTimeOffset))
117+
if (nonReferentialTypes.Contains(type))
91118
{
92119
isReferential = false;
93120
}
121+
94122
if (type.IsOpenApiNullable())
95123
{
96124
isReferential = false;
97125
}
126+
98127
if (type.IsUnflaggedEnumType())
99128
{
100129
isReferential = false;
101130
}
131+
102132
if (type.IsJObjectType())
103133
{
104134
isReferential = false;
105135
}
106136

137+
107138
return isReferential;
108139
}
109140

110-
private static HashSet<Type> jObjects = new HashSet<Type>
111-
{
112-
typeof(JObject),
113-
typeof(JToken),
114-
typeof(JArray),
115-
};
116-
117-
/// <summary>
118-
/// Checks whether the given type is Json.NET related <see cref="JObject"/>, <see cref="JToken"/> or not.
119-
/// </summary>
120-
/// <param name="type"><see cref="Type"/> instance.</param>
121-
/// <returns>Returns <c>True</c>, if the type is identified as either <see cref="JObject"/> or <see cref="JToken"/>; otherwise returns <c>False</c>.</returns>
122-
public static bool IsJObjectType(this Type type)
123-
{
124-
if (type.IsNullOrDefault())
125-
{
126-
return false;
127-
}
128-
129-
if (jObjects.Any(p => p == type))
130-
{
131-
return true;
132-
}
133141

134-
return false;
135-
}
136142

137143
/// <summary>
138144
/// Checks whether the given type is enum without flags or not.
@@ -375,13 +381,17 @@ public static string GetOpenApiReferenceId(this Type type, bool isDictionary, bo
375381
{
376382
namingStrategy = new DefaultNamingStrategy();
377383
}
378-
379-
if (isDictionary || isList)
384+
385+
if(isDictionary)
380386
{
381-
var name = type.Name.Split('`').First() + "_" + type.GetOpenApiSubTypeName(namingStrategy);
382-
387+
var name = type.Name.EndsWith("[]") ? "Dictionary_" + type.GetOpenApiSubTypeName(namingStrategy) : type.Name.Split('`').First() + "_" + type.GetOpenApiSubTypeName(namingStrategy);
383388
return namingStrategy.GetPropertyName(name, hasSpecifiedName: false);
384389
}
390+
if(isList)
391+
{
392+
var name = type.Name.EndsWith("[]") ? "List_" + type.GetOpenApiSubTypeName(namingStrategy): type.Name.Split('`').First() + "_" + type.GetOpenApiSubTypeName(namingStrategy);;
393+
return namingStrategy.GetPropertyName(name, hasSpecifiedName: false);
394+
}
385395

386396
if (type.IsGenericType)
387397
{

src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Visitors/DictionaryObjectTypeVisitor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public override void Visit(IAcceptor acceptor, KeyValuePair<string, Type> type,
7979
var reference = new OpenApiReference()
8080
{
8181
Type = ReferenceType.Schema,
82-
Id = underlyingType.GetOpenApiReferenceId(isDictionary: false, isList: false, namingStrategy)
82+
Id = underlyingType.GetOpenApiReferenceId(underlyingType.IsOpenApiDictionary(), underlyingType.IsOpenApiArray(), namingStrategy)
8383
};
8484

8585
properties.Reference = reference;
@@ -140,7 +140,7 @@ public override OpenApiSchema PayloadVisit(Type type, NamingStrategy namingStrat
140140
var reference = new OpenApiReference()
141141
{
142142
Type = ReferenceType.Schema,
143-
Id = underlyingType.GetOpenApiReferenceId(isDictionary: false, isList: false, namingStrategy)
143+
Id = underlyingType.GetOpenApiReferenceId(underlyingType.IsOpenApiDictionary(), underlyingType.IsOpenApiArray(), namingStrategy)
144144
};
145145

146146
properties.Reference = reference;

src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Visitors/ListObjectTypeVisitor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public override void Visit(IAcceptor acceptor, KeyValuePair<string, Type> type,
7979
var reference = new OpenApiReference()
8080
{
8181
Type = ReferenceType.Schema,
82-
Id = underlyingType.GetOpenApiReferenceId(isDictionary: false, isList: false, namingStrategy)
82+
Id = underlyingType.GetOpenApiReferenceId(underlyingType.IsOpenApiDictionary(), underlyingType.IsOpenApiArray(), namingStrategy)
8383
};
8484

8585
items.Reference = reference;
@@ -155,7 +155,7 @@ public override OpenApiSchema PayloadVisit(Type type, NamingStrategy namingStrat
155155
var reference = new OpenApiReference()
156156
{
157157
Type = ReferenceType.Schema,
158-
Id = underlyingType.GetOpenApiReferenceId(isDictionary: false, isList: false, namingStrategy)
158+
Id = underlyingType.GetOpenApiReferenceId(underlyingType.IsOpenApiDictionary(), underlyingType.IsOpenApiArray(), namingStrategy)
159159
};
160160

161161
items.Reference = reference;

test-integration/Microsoft.Azure.WebJobs.Extensions.OpenApi.Document.Tests/Get_ApplicationJson_DictionaryObject_Tests.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ public void Given_OpenApiDocument_Then_It_Should_Return_ComponentSchema(string @
7171
[DataTestMethod]
7272
[DataRow("dictionaryObjectModel", "int32ObjectValue", "object", "int32ObjectModel")]
7373
[DataRow("dictionaryObjectModel", "stringObjectModel", "object", "stringObjectModel")]
74+
[DataRow("dictionaryObjectModel", "stringArrayValue", "object", "list_string")]
75+
[DataRow("dictionaryObjectModel", "intArrayValue", "object", "list_int32")]
76+
7477
public void Given_OpenApiDocument_Then_It_Should_Return_ComponentSchemaProperty(string @ref, string propertyName, string propertyType, string itemRef)
7578
{
7679
var properties = this._doc["components"]["schemas"][@ref]["properties"];
@@ -84,5 +87,29 @@ public void Given_OpenApiDocument_Then_It_Should_Return_ComponentSchemaProperty(
8487

8588
this._doc["components"]["schemas"][itemRef].Should().NotBeNullOrEmpty();
8689
}
90+
91+
[DataTestMethod]
92+
[DataRow("list_string", "array")]
93+
[DataRow("list_int32", "array")]
94+
public void Given_OpenApiDocument_Then_It_Should_Return_ComponentReferenceSchema(string @ref, string refType)
95+
{
96+
var schemas = this._doc["components"]["schemas"];
97+
var schema = schemas[@ref]["type"];
98+
99+
schema.Should().NotBeNull();
100+
schema.Value<string>().Should().Be(refType);
101+
schema.Value<string>().Should().Be(refType);
102+
}
103+
104+
[DataTestMethod]
105+
[DataRow("list_string", "array", "string")]
106+
[DataRow("list_int32", "array", "integer")]
107+
public void Given_OpenApiDocument_Then_It_Should_Return_ComponentReferenceSchema(string @ref, string refType, string itemType)
108+
{
109+
var items = this._doc["components"]["schemas"][@ref];
110+
var type = items["items"]["type"];
111+
type.Should().NotBeNull();
112+
type.Value<string>().Should().Be(itemType);
113+
}
87114
}
88115
}

test-integration/Microsoft.Azure.WebJobs.Extensions.OpenApi.TestApp/Models/DictionaryObjectModel.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,8 @@ public class DictionaryObjectModel
1010
public KeyValuePair<string, Int32ObjectModel> Int32ObjectValue { get; set; }
1111

1212
public IDictionary<string, StringObjectModel> StringObjectModel { get; set; }
13+
14+
public Dictionary<int, int[]> IntArrayValue { get; set; }
15+
public Dictionary<string, string[]> StringArrayValue { get; set; }
1316
}
1417
}

test/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Tests/Visitors/DictionaryObjectTypeVisitorTests.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public void Init()
3434
}
3535

3636
[DataTestMethod]
37+
[DataRow(typeof(Dictionary<string, string[]>), false)]
3738
[DataRow(typeof(Dictionary<string, string>), false)]
3839
public void Given_Type_When_IsNavigatable_Invoked_Then_It_Should_Return_Result(Type type, bool expected)
3940
{
@@ -43,6 +44,7 @@ public void Given_Type_When_IsNavigatable_Invoked_Then_It_Should_Return_Result(T
4344
}
4445

4546
[DataTestMethod]
47+
[DataRow(typeof(Dictionary<string, string[]>), true)]
4648
[DataRow(typeof(Dictionary<string, string>), true)]
4749
[DataRow(typeof(IDictionary<string, string>), true)]
4850
[DataRow(typeof(IReadOnlyDictionary<string, string>), true)]
@@ -56,6 +58,7 @@ public void Given_Type_When_IsVisitable_Invoked_Then_It_Should_Return_Result(Typ
5658
}
5759

5860
[DataTestMethod]
61+
[DataRow(typeof(Dictionary<string, string[]>), false)]
5962
[DataRow(typeof(Dictionary<string, string>), false)]
6063
[DataRow(typeof(IDictionary<string, string>), false)]
6164
[DataRow(typeof(IReadOnlyDictionary<string, string>), false)]
@@ -69,6 +72,7 @@ public void Given_Type_When_IsParameterVisitable_Invoked_Then_It_Should_Return_R
6972
}
7073

7174
[DataTestMethod]
75+
[DataRow(typeof(Dictionary<string, string[]>), true)]
7276
[DataRow(typeof(Dictionary<string, string>), true)]
7377
[DataRow(typeof(IDictionary<string, string>), true)]
7478
[DataRow(typeof(IReadOnlyDictionary<string, string>), true)]
@@ -87,6 +91,7 @@ public void Given_Type_When_IsPayloadVisitable_Invoked_Then_It_Should_Return_Res
8791
[DataRow(typeof(IReadOnlyDictionary<string, string>), "object", null, "string", false, "string", 0)]
8892
[DataRow(typeof(KeyValuePair<string, string>), "object", null, "string", false, "string", 0)]
8993
[DataRow(typeof(Dictionary<string, FakeModel>), "object", null, "object", true, "fakeModel", 1)]
94+
[DataRow(typeof(Dictionary<string, string[]>), "object", null, "array", true, "list_string", 1)] //
9095
[DataRow(typeof(IDictionary<string, FakeModel>), "object", null, "object", true, "fakeModel", 1)]
9196
[DataRow(typeof(IReadOnlyDictionary<string, FakeModel>), "object", null, "object", true, "fakeModel", 1)]
9297
[DataRow(typeof(KeyValuePair<string, FakeModel>), "object", null, "object", true, "fakeModel", 1)]

0 commit comments

Comments
 (0)