Skip to content

200: fixed check of element type for IEnumerable<T> #204

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/JsonApiDotNetCore/Builders/DocumentBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using JsonApiDotNetCore.Extensions;
using JsonApiDotNetCore.Internal;
using JsonApiDotNetCore.Models;
using JsonApiDotNetCore.Services;
Expand Down Expand Up @@ -46,9 +47,7 @@ public Document Build(IIdentifiable entity)

public Documents Build(IEnumerable<IIdentifiable> entities)
{
var entityType = entities
.GetType()
.GenericTypeArguments[0];
var entityType = entities.GetElementType();

var contextEntity = _contextGraph.GetContextEntity(entityType);

Expand Down Expand Up @@ -229,7 +228,7 @@ private bool RelationshipIsIncluded(string relationshipName)

private List<Dictionary<string, string>> GetRelationships(IEnumerable<object> entities)
{
var objType = entities.GetType().GenericTypeArguments[0];
var objType = entities.GetElementType();

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

Expand Down
35 changes: 35 additions & 0 deletions src/JsonApiDotNetCore/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace JsonApiDotNetCore.Extensions
{
internal static class TypeExtensions
{
public static Type GetElementType(this IEnumerable enumerable)
{
var enumerableTypes = enumerable.GetType()
.GetInterfaces()
.Where(t => t.IsGenericType == true && t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
.ToList();

var numberOfEnumerableTypes = enumerableTypes.Count;

if (numberOfEnumerableTypes == 0)
{
throw new ArgumentException($"{nameof(enumerable)} of type {enumerable.GetType().FullName} does not implement a generic variant of {nameof(IEnumerable)}");
}

if (numberOfEnumerableTypes > 1)
{
throw new ArgumentException($"{nameof(enumerable)} of type {enumerable.GetType().FullName} implements more than one generic variant of {nameof(IEnumerable)}:\n" +
$"{string.Join("\n", enumerableTypes.Select(t => t.FullName))}");
}

var elementType = enumerableTypes[0].GenericTypeArguments[0];

return elementType;
}
}
}
43 changes: 43 additions & 0 deletions test/UnitTests/Builders/DocumentBuilder_Tests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using JsonApiDotNetCore.Builders;
using JsonApiDotNetCore.Configuration;
Expand Down Expand Up @@ -118,6 +119,28 @@ public void Related_Links_Can_Be_Disabled()
Assert.Null(document.Data.Relationships["related-model"].Links);
}

[Fact]
public void Build_Can_Build_Arrays()
{
var entities = new[] { new Model() };
var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object);

var documents = documentBuilder.Build(entities);

Assert.Equal(1, documents.Data.Count);
}

[Fact]
public void Build_Can_Build_CustomIEnumerables()
{
var entities = new Models(new[] { new Model() });
var documentBuilder = new DocumentBuilder(_jsonApiContextMock.Object);

var documents = documentBuilder.Build(entities);

Assert.Equal(1, documents.Data.Count);
}

private class Model : Identifiable
{
[HasOne("related-model", Link.None)]
Expand All @@ -130,5 +153,25 @@ private class RelatedModel : Identifiable
[HasMany("models")]
public List<Model> Models { get; set; }
}

private class Models : IEnumerable<Model>
{
private readonly IEnumerable<Model> models;

public Models(IEnumerable<Model> models)
{
this.models = models;
}

public IEnumerator<Model> GetEnumerator()
{
return models.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return models.GetEnumerator();
}
}
}
}