Skip to content

Commit 1226747

Browse files
shuebner-zeissjaredcnance
authored andcommitted
200: fixed check of element type for IEnumerable<T>
1 parent a4f4370 commit 1226747

File tree

3 files changed

+81
-4
lines changed

3 files changed

+81
-4
lines changed

src/JsonApiDotNetCore/Builders/DocumentBuilder.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Collections;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using JsonApiDotNetCore.Extensions;
45
using JsonApiDotNetCore.Internal;
56
using JsonApiDotNetCore.Models;
67
using JsonApiDotNetCore.Services;
@@ -46,9 +47,7 @@ public Document Build(IIdentifiable entity)
4647

4748
public Documents Build(IEnumerable<IIdentifiable> entities)
4849
{
49-
var entityType = entities
50-
.GetType()
51-
.GenericTypeArguments[0];
50+
var entityType = entities.GetElementType();
5251

5352
var contextEntity = _contextGraph.GetContextEntity(entityType);
5453

@@ -229,7 +228,7 @@ private bool RelationshipIsIncluded(string relationshipName)
229228

230229
private List<Dictionary<string, string>> GetRelationships(IEnumerable<object> entities)
231230
{
232-
var objType = entities.GetType().GenericTypeArguments[0];
231+
var objType = entities.GetElementType();
233232

234233
var typeName = _jsonApiContext.ContextGraph.GetContextEntity(objType);
235234

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
6+
namespace JsonApiDotNetCore.Extensions
7+
{
8+
internal static class TypeExtensions
9+
{
10+
public static Type GetElementType(this IEnumerable enumerable)
11+
{
12+
var enumerableTypes = enumerable.GetType()
13+
.GetInterfaces()
14+
.Where(t => t.IsGenericType == true && t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
15+
.ToList();
16+
17+
var numberOfEnumerableTypes = enumerableTypes.Count;
18+
19+
if (numberOfEnumerableTypes == 0)
20+
{
21+
throw new ArgumentException($"{nameof(enumerable)} of type {enumerable.GetType().FullName} does not implement a generic variant of {nameof(IEnumerable)}");
22+
}
23+
24+
if (numberOfEnumerableTypes > 1)
25+
{
26+
throw new ArgumentException($"{nameof(enumerable)} of type {enumerable.GetType().FullName} implements more than one generic variant of {nameof(IEnumerable)}:\n" +
27+
$"{string.Join("\n", enumerableTypes.Select(t => t.FullName))}");
28+
}
29+
30+
var elementType = enumerableTypes[0].GenericTypeArguments[0];
31+
32+
return elementType;
33+
}
34+
}
35+
}

test/UnitTests/Builders/DocumentBuilder_Tests.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections;
23
using System.Collections.Generic;
34
using JsonApiDotNetCore.Builders;
45
using JsonApiDotNetCore.Configuration;
@@ -118,6 +119,28 @@ public void Related_Links_Can_Be_Disabled()
118119
Assert.Null(document.Data.Relationships["related-model"].Links);
119120
}
120121

122+
[Fact]
123+
public void Build_Can_Build_Arrays()
124+
{
125+
var entities = new[] { new Model() };
126+
var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object);
127+
128+
var documents = documentBuilder.Build(entities);
129+
130+
Assert.Equal(1, documents.Data.Count);
131+
}
132+
133+
[Fact]
134+
public void Build_Can_Build_CustomIEnumerables()
135+
{
136+
var entities = new Models(new[] { new Model() });
137+
var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object);
138+
139+
var documents = documentBuilder.Build(entities);
140+
141+
Assert.Equal(1, documents.Data.Count);
142+
}
143+
121144
private class Model : Identifiable
122145
{
123146
[HasOne("related-model", Link.None)]
@@ -130,5 +153,25 @@ private class RelatedModel : Identifiable
130153
[HasMany("models")]
131154
public List<Model> Models { get; set; }
132155
}
156+
157+
private class Models : IEnumerable<Model>
158+
{
159+
private readonly IEnumerable<Model> models;
160+
161+
public Models(IEnumerable<Model> models)
162+
{
163+
this.models = models;
164+
}
165+
166+
public IEnumerator<Model> GetEnumerator()
167+
{
168+
return models.GetEnumerator();
169+
}
170+
171+
IEnumerator IEnumerable.GetEnumerator()
172+
{
173+
return models.GetEnumerator();
174+
}
175+
}
133176
}
134177
}

0 commit comments

Comments
 (0)