Skip to content

Commit

Permalink
Fixed attributes serialization for included objects
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergey Litvinov committed Aug 13, 2020
1 parent c1b5149 commit 68ad016
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 6 deletions.
30 changes: 24 additions & 6 deletions Saule/Serialization/ResourceSerializer.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
Expand All @@ -22,7 +23,7 @@ internal class ResourceSerializer
private readonly IUrlPathBuilder _urlBuilder;
private readonly ResourceGraphPathSet _includedGraphPaths;
private JsonSerializer _serializer;
private JsonSerializer _sourceSerializer;
private Dictionary<ApiResource, JsonSerializer> _sourceSerializers;

public ResourceSerializer(
object value,
Expand All @@ -43,6 +44,7 @@ public ResourceSerializer(
_includeContext = includeContext;
_fieldsetContext = fieldsetContext;
_includedGraphPaths = IncludedGraphPathsFromContext(includeContext);
_sourceSerializers = new Dictionary<ApiResource, JsonSerializer>();
}

public JObject Serialize()
Expand All @@ -55,9 +57,6 @@ public JObject Serialize(JsonSerializer serializer)
serializer.ContractResolver = new JsonApiContractResolver(_propertyNameConverter);
_serializer = serializer;

_sourceSerializer = JsonApiSerializer.GetJsonSerializer(_serializer.Converters);
_sourceSerializer.ContractResolver = new SourceContractResolver(_propertyNameConverter, _resource);

if (_value == null)
{
return SerializeNull();
Expand Down Expand Up @@ -292,8 +291,10 @@ private JObject SerializeNode(ResourceGraphNode node, bool isCollection)

private JObject SerializeAttributes(ResourceGraphNode node)
{
var serializer = GetSourceSerializer(node.Resource);

// The source serializer uses a SourceContractResolver to ensure that we only serialize the properties needed
var serializedSourceObject = JObject.FromObject(node.SourceObject, _sourceSerializer);
var serializedSourceObject = JObject.FromObject(node.SourceObject, serializer);
var attributeHash = node.Resource.Attributes
.Where(a =>
node.SourceObject.IncludesProperty(_propertyNameConverter.ToModelPropertyName(a.InternalName)))
Expand All @@ -313,8 +314,10 @@ private JObject SerializeAttributes(ResourceGraphNode node)

private JObject SerializeAttributes(ResourceGraphNode node, FieldsetProperty fieldset)
{
var serializer = GetSourceSerializer(node.Resource);

// The source serializer uses a SourceContractResolver to ensure that we only serialize the properties needed
var serializedSourceObject = JObject.FromObject(node.SourceObject, _sourceSerializer);
var serializedSourceObject = JObject.FromObject(node.SourceObject, serializer);
var attributeHash = node.Resource.Attributes
.Where(a =>
node.SourceObject.IncludesProperty(_propertyNameConverter.ToModelPropertyName(a.InternalName)) && fieldset.Fields.Contains(a.InternalName.ToComparablePropertyName()))
Expand Down Expand Up @@ -439,5 +442,20 @@ private JObject AddUrl(JObject @object, string name, string path)

return @object;
}

private JsonSerializer GetSourceSerializer(ApiResource resource)
{
JsonSerializer serializer;
if (_sourceSerializers.TryGetValue(resource, out serializer))
{
return serializer;
}

serializer = JsonApiSerializer.GetJsonSerializer(_serializer.Converters);
serializer.ContractResolver = new SourceContractResolver(_propertyNameConverter, resource);

_sourceSerializers.Add(resource, serializer);
return serializer;
}
}
}
27 changes: 27 additions & 0 deletions Tests/Serialization/ResourceSerializerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,33 @@ public void IncludedResourceOnlyOnce()

Assert.Equal(3, included.Count);
}

[Fact(DisplayName = "If object is included, then Included has all attributes with the values")]
public void IncludedResourceHasAttributes()
{
var person = new Person(true)
{
Car = new Car(true),
Job = new Company(true)
};

var include = new IncludeContext(GetQuery("include", "car,job"));
var target = new ResourceSerializer(person, DefaultResource,
GetUri(id: "123"), DefaultPathBuilder, null, include, null);
var result = target.Serialize();
_output.WriteLine(result.ToString());

var included = result["included"] as JArray;

Assert.Equal(2, included.Count);

var corporation = included.FirstOrDefault(node => node.Value<string>("type") == "corporation");
Assert.Equal("Awesome, Inc.", corporation["attributes"]["name"]);
Assert.Equal(24, corporation["attributes"]["number-of-employees"]);

var car = included.FirstOrDefault(node => node.Value<string>("type") == "car");
Assert.Equal("Duster", car["attributes"]["model"]);
}

[Fact(DisplayName = "Handles null relationships and attributes correctly")]
public void HandlesNullValues()
Expand Down

0 comments on commit 68ad016

Please sign in to comment.