Skip to content

Commit 2a8a02f

Browse files
authored
Merge pull request #461 from json-api-dotnet/fix/#454
Omit null attributes in included array
2 parents c633c71 + 53392fd commit 2a8a02f

File tree

3 files changed

+25
-20
lines changed

3 files changed

+25
-20
lines changed

src/JsonApiDotNetCore/Builders/DocumentBuilder.cs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,15 @@ public ResourceObject GetData(ContextEntity contextEntity, IIdentifiable entity,
138138

139139
return data;
140140
}
141-
private bool ShouldIncludeAttribute(AttrAttribute attr, object attributeValue)
141+
private bool ShouldIncludeAttribute(AttrAttribute attr, object attributeValue, RelationshipAttribute relationship = null)
142142
{
143143
return OmitNullValuedAttribute(attr, attributeValue) == false
144144
&& attr.InternalAttributeName != nameof(Identifiable.Id)
145145
&& ((_jsonApiContext.QuerySet == null
146146
|| _jsonApiContext.QuerySet.Fields.Count == 0)
147-
|| _jsonApiContext.QuerySet.Fields.Contains(attr.InternalAttributeName));
147+
|| _jsonApiContext.QuerySet.Fields.Contains(relationship != null ?
148+
$"{relationship.InternalRelationshipName}.{attr.InternalAttributeName}" :
149+
attr.InternalAttributeName));
148150
}
149151

150152
private bool OmitNullValuedAttribute(AttrAttribute attr, object attributeValue)
@@ -225,13 +227,13 @@ private List<ResourceObject> IncludeRelationshipChain(
225227
{
226228
foreach (IIdentifiable includedEntity in hasManyNavigationEntity)
227229
{
228-
included = AddIncludedEntity(included, includedEntity);
230+
included = AddIncludedEntity(included, includedEntity, relationship);
229231
included = IncludeSingleResourceRelationships(included, includedEntity, relationship, relationshipChain, relationshipChainIndex);
230232
}
231233
}
232234
else
233235
{
234-
included = AddIncludedEntity(included, (IIdentifiable)navigationEntity);
236+
included = AddIncludedEntity(included, (IIdentifiable)navigationEntity, relationship);
235237
included = IncludeSingleResourceRelationships(included, (IIdentifiable)navigationEntity, relationship, relationshipChain, relationshipChainIndex);
236238
}
237239

@@ -254,9 +256,9 @@ private List<ResourceObject> IncludeSingleResourceRelationships(
254256
}
255257

256258

257-
private List<ResourceObject> AddIncludedEntity(List<ResourceObject> entities, IIdentifiable entity)
259+
private List<ResourceObject> AddIncludedEntity(List<ResourceObject> entities, IIdentifiable entity, RelationshipAttribute relationship)
258260
{
259-
var includedEntity = GetIncludedEntity(entity);
261+
var includedEntity = GetIncludedEntity(entity, relationship);
260262

261263
if (entities == null)
262264
entities = new List<ResourceObject>();
@@ -270,7 +272,7 @@ private List<ResourceObject> AddIncludedEntity(List<ResourceObject> entities, II
270272
return entities;
271273
}
272274

273-
private ResourceObject GetIncludedEntity(IIdentifiable entity)
275+
private ResourceObject GetIncludedEntity(IIdentifiable entity, RelationshipAttribute relationship)
274276
{
275277
if (entity == null) return null;
276278

@@ -281,13 +283,14 @@ private ResourceObject GetIncludedEntity(IIdentifiable entity)
281283

282284
data.Attributes = new Dictionary<string, object>();
283285

284-
foreach(var attr in contextEntity.Attributes)
286+
contextEntity.Attributes.ForEach(attr =>
285287
{
286-
if (attr.InternalAttributeName == nameof(Identifiable.Id))
287-
continue;
288-
289-
data.Attributes.Add(attr.PublicAttributeName, attr.GetValue(entity));
290-
}
288+
var attributeValue = attr.GetValue(entity);
289+
if (ShouldIncludeAttribute(attr, attributeValue, relationship))
290+
{
291+
data.Attributes.Add(attr.PublicAttributeName, attributeValue);
292+
}
293+
});
291294

292295
return data;
293296
}

test/JsonApiDotNetCoreExampleTests/Acceptance/Extensibility/NullValuedAttributeHandlingTests.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ public NullValuedAttributeHandlingTests(TestFixture<TestStartup> fixture)
2121
{
2222
_fixture = fixture;
2323
_dbContext = fixture.GetService<AppDbContext>();
24+
var person = new Person { FirstName = "Bob", LastName = null };
2425
_todoItem = new TodoItem
2526
{
2627
Description = null,
2728
Ordinal = 1,
2829
CreatedDate = DateTime.Now,
29-
AchievedDate = DateTime.Now.AddDays(2)
30+
AchievedDate = DateTime.Now.AddDays(2),
31+
Owner = person
3032
};
3133
_todoItem = _dbContext.TodoItems.Add(_todoItem).Entity;
3234
}
@@ -86,9 +88,9 @@ public async Task CheckNullBehaviorCombination(bool? omitNullValuedAttributes, b
8688

8789
var httpMethod = new HttpMethod("GET");
8890
var queryString = allowClientOverride.HasValue
89-
? $"?omitNullValuedAttributes={clientOverride}"
91+
? $"&omitNullValuedAttributes={clientOverride}"
9092
: "";
91-
var route = $"/api/v1/todo-items/{_todoItem.Id}{queryString}";
93+
var route = $"/api/v1/todo-items/{_todoItem.Id}?include=owner{queryString}";
9294
var request = new HttpRequestMessage(httpMethod, route);
9395

9496
// act
@@ -98,6 +100,7 @@ public async Task CheckNullBehaviorCombination(bool? omitNullValuedAttributes, b
98100

99101
// assert. does response contain a null valued attribute
100102
Assert.Equal(omitsNulls, !deserializeBody.Data.Attributes.ContainsKey("description"));
103+
Assert.Equal(omitsNulls, !deserializeBody.Included[0].Attributes.ContainsKey("last-name"));
101104

102105
}
103106
}

test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/SparseFieldSetTests.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,7 @@ public async Task Fields_Query_Selects_Fieldset_With_HasOne()
194194
Assert.Equal(owner.StringId, included.Id);
195195
Assert.Equal(owner.FirstName, included.Attributes["first-name"]);
196196
Assert.Equal((long)owner.Age, included.Attributes["age"]);
197-
Assert.Null(included.Attributes["last-name"]);
198-
197+
Assert.DoesNotContain("last-name", included.Attributes.Keys);
199198
}
200199

201200
[Fact]
@@ -233,8 +232,8 @@ public async Task Fields_Query_Selects_Fieldset_With_HasMany()
233232
var todoItem = todoItems.FirstOrDefault(i => i.StringId == includedItem.Id);
234233
Assert.NotNull(todoItem);
235234
Assert.Equal(todoItem.Description, includedItem.Attributes["description"]);
236-
Assert.Equal(default(long), includedItem.Attributes["ordinal"]);
237-
Assert.Equal(default(DateTime), (DateTime)includedItem.Attributes["created-date"]);
235+
Assert.DoesNotContain("ordinal", includedItem.Attributes.Keys);
236+
Assert.DoesNotContain("created-date", includedItem.Attributes.Keys);
238237
}
239238
}
240239
}

0 commit comments

Comments
 (0)