diff --git a/JSONAPI.Tests/Data/DeserializeRawJsonTest.json b/JSONAPI.Tests/Data/DeserializeRawJsonTest.json new file mode 100644 index 00000000..684bb5ff --- /dev/null +++ b/JSONAPI.Tests/Data/DeserializeRawJsonTest.json @@ -0,0 +1,14 @@ +{ + "comments": [ + { + "id": "2", + "customData": null + }, + { + "id": "4", + "customData": { + "foo": "bar" + } + } + ] +} diff --git a/JSONAPI.Tests/Data/SerializerIntegrationTest.json b/JSONAPI.Tests/Data/SerializerIntegrationTest.json index 3576bb64..1cc3c50e 100644 --- a/JSONAPI.Tests/Data/SerializerIntegrationTest.json +++ b/JSONAPI.Tests/Data/SerializerIntegrationTest.json @@ -1,3 +1,81 @@ -{"posts":[{"id":"1","title":"Linkbait!","links":{"comments":["2","3","4"],"author":"1"}},{"id":"2","title":"Rant #1023","links":{"comments":["5"],"author":"1"}},{"id":"3","title":"Polemic in E-flat minor #824","links":{"comments":null,"author":"1"}},{"id":"4","title":"This post has no author.","links":{"comments":null,"author":null}}],"linked":{"comments":[{"id":"2","body":"Nuh uh!","links":{"post":"1"}},{"id":"3","body":"Yeah huh!","links":{"post":"1"}},{"id":"4","body":"Third Reich.","links":{"post":"1"}},{"id":"5","body":"I laughed, I cried!","links":{"post":"2"}}],"authors":[{"id":"1","name":"Jason Hater","links":{"posts":["1","2","3"]}}]}} - - +{ + "posts": [ + { + "id": "1", + "title": "Linkbait!", + "links": { + "comments": [ "2", "3", "4" ], + "author": "1" + } + }, + { + "id": "2", + "title": "Rant #1023", + "links": { + "comments": [ "5" ], + "author": "1" + } + }, + { + "id": "3", + "title": "Polemic in E-flat minor #824", + "links": { + "comments": null, + "author": "1" + } + }, + { + "id": "4", + "title": "This post has no author.", + "links": { + "comments": null, + "author": null + } + } + ], + "linked": { + "comments": [ + { + "id": "2", + "body": "Nuh uh!", + "customData": null, + "links": { "post": "1" } + }, + { + "id": "3", + "body": "Yeah huh!", + "customData": null, + "links": { + "post": "1" + } + }, + { + "id": "4", + "body": "Third Reich.", + "customData": { + "foo": "bar" + }, + "links": { + "post": "1" + } + }, + { + "id": "5", + "body": "I laughed, I cried!", + "customData": null, + "links": { + "post": "2" + } + } + ], + "authors": [ + { + "id": "1", + "name": "Jason Hater", + "links": { + "posts": [ "1", "2", "3" ] + } + } + ] + } +} diff --git a/JSONAPI.Tests/JSONAPI.Tests.csproj b/JSONAPI.Tests/JSONAPI.Tests.csproj index 3f00810a..90800908 100644 --- a/JSONAPI.Tests/JSONAPI.Tests.csproj +++ b/JSONAPI.Tests/JSONAPI.Tests.csproj @@ -80,7 +80,6 @@ - @@ -104,6 +103,9 @@ Always + + Always + Always diff --git a/JSONAPI.Tests/Json/JsonApiMediaFormaterTests.cs b/JSONAPI.Tests/Json/JsonApiMediaFormaterTests.cs index 1fd8a6e8..86d80411 100644 --- a/JSONAPI.Tests/Json/JsonApiMediaFormaterTests.cs +++ b/JSONAPI.Tests/Json/JsonApiMediaFormaterTests.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Text.RegularExpressions; +using System.Threading.Tasks; using System.Web.Http; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -85,7 +86,8 @@ public void SetupModels() new Comment() { Id = 4, Body = "Third Reich.", - Post = p + Post = p, + CustomData = "{ \"foo\": \"bar\" }" } }; p2.Comments = new List { @@ -144,7 +146,8 @@ public void SerializerIntegrationTest() // Assert string output = System.Text.Encoding.ASCII.GetString(stream.ToArray()); Trace.WriteLine(output); - Assert.AreEqual(output.Trim(), File.ReadAllText("SerializerIntegrationTest.json").Trim()); + var expected = JsonHelpers.MinifyJson(File.ReadAllText("SerializerIntegrationTest.json")); + Assert.AreEqual(expected, output.Trim()); //Assert.AreEqual("[2,3,4]", sw.ToString()); } @@ -168,7 +171,8 @@ public void SerializeArrayIntegrationTest() // Assert string output = System.Text.Encoding.ASCII.GetString(stream.ToArray()); Trace.WriteLine(output); - Assert.AreEqual(output.Trim(), File.ReadAllText("SerializerIntegrationTest.json").Trim()); + var expected = JsonHelpers.MinifyJson(File.ReadAllText("SerializerIntegrationTest.json")); + Assert.AreEqual(expected, output.Trim()); //Assert.AreEqual("[2,3,4]", sw.ToString()); } @@ -233,8 +237,25 @@ public void DeserializeCollectionIntegrationTest() // Assert Assert.AreEqual(2, posts.Count); Assert.AreEqual(p.Id, posts[0].Id); // Order matters, right? - + } + [TestMethod] + [DeploymentItem(@"Data\DeserializeRawJsonTest.json")] + public async Task DeserializeRawJsonTest() + { + using (var inputStream = File.OpenRead("DeserializeRawJsonTest.json")) + { + // Arrange + var formatter = new JsonApiFormatter(new PluralizationService()); + + // Act + var comments = ((IEnumerable)await formatter.ReadFromStreamAsync(typeof (Comment), inputStream, null, null)).ToArray(); + + // Assert + Assert.AreEqual(2, comments.Count()); + Assert.AreEqual(null, comments[0].CustomData); + Assert.AreEqual("{\"foo\":\"bar\"}", comments[1].CustomData); + } } // Issue #1 diff --git a/JSONAPI.Tests/Models/Comment.cs b/JSONAPI.Tests/Models/Comment.cs index df66264f..86b9f13c 100644 --- a/JSONAPI.Tests/Models/Comment.cs +++ b/JSONAPI.Tests/Models/Comment.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using JSONAPI.Attributes; using JSONAPI.Core; namespace JSONAPI.Tests.Models @@ -11,5 +12,6 @@ class Comment public int Id { get; set; } public string Body { get; set; } public Post Post { get; set; } + [SerializeStringAsRawJson]public string CustomData { get; set; } } } diff --git a/JSONAPI/Attributes/SerializeStringAsRawJsonAttribute.cs b/JSONAPI/Attributes/SerializeStringAsRawJsonAttribute.cs new file mode 100644 index 00000000..941a8823 --- /dev/null +++ b/JSONAPI/Attributes/SerializeStringAsRawJsonAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace JSONAPI.Attributes +{ + [AttributeUsage(AttributeTargets.Property)] + public class SerializeStringAsRawJsonAttribute : Attribute + { + } +} diff --git a/JSONAPI/JSONAPI.csproj b/JSONAPI/JSONAPI.csproj index 5b9fc1e4..8b70800a 100644 --- a/JSONAPI/JSONAPI.csproj +++ b/JSONAPI/JSONAPI.csproj @@ -68,6 +68,7 @@ + @@ -79,6 +80,7 @@ + diff --git a/JSONAPI/Json/JsonApiFormatter.cs b/JSONAPI/Json/JsonApiFormatter.cs index c678b402..a28f3c3a 100644 --- a/JSONAPI/Json/JsonApiFormatter.cs +++ b/JSONAPI/Json/JsonApiFormatter.cs @@ -203,7 +203,26 @@ protected void Serialize(object value, Stream writeStream, JsonWriter writer, Js // numbers, strings, dates... writer.WritePropertyName(_modelManager.GetJsonKeyForProperty(prop)); - serializer.Serialize(writer, prop.GetValue(value, null)); + + var propertyValue = prop.GetValue(value, null); + + if (prop.PropertyType == typeof (string) && + prop.GetCustomAttributes().Any(attr => attr is SerializeStringAsRawJsonAttribute)) + { + if (propertyValue == null) + { + writer.WriteNull(); + } + else + { + var minifiedValue = JsonHelpers.MinifyJson((string) propertyValue); + writer.WriteRawValue(minifiedValue); + } + } + else + { + serializer.Serialize(writer, propertyValue); + } } else { @@ -603,7 +622,27 @@ public object Deserialize(Type objectType, Stream readStream, JsonReader reader, //TODO: Embedded would be dropped here! if (!CanWriteTypeAsPrimitive(prop.PropertyType)) continue; // These aren't supposed to be here, they're supposed to be in "links"! - prop.SetValue(retval, DeserializePrimitive(prop.PropertyType, reader), null); + object propVal; + if (prop.PropertyType == typeof (string) && + prop.GetCustomAttributes().Any(attr => attr is SerializeStringAsRawJsonAttribute)) + { + if (reader.TokenType == JsonToken.Null) + { + propVal = null; + } + else + { + var token = JToken.Load(reader); + var rawPropVal = token.ToString(); + propVal = JsonHelpers.MinifyJson(rawPropVal); + } + } + else + { + propVal = DeserializePrimitive(prop.PropertyType, reader); + } + + prop.SetValue(retval, propVal, null); // Tell the MetadataManager that we deserialized this property MetadataManager.Instance.SetMetaForProperty(retval, prop, true); diff --git a/JSONAPI.Tests/Json/JsonHelpers.cs b/JSONAPI/Json/JsonHelpers.cs similarity index 91% rename from JSONAPI.Tests/Json/JsonHelpers.cs rename to JSONAPI/Json/JsonHelpers.cs index 440e2e1c..a47c48e7 100644 --- a/JSONAPI.Tests/Json/JsonHelpers.cs +++ b/JSONAPI/Json/JsonHelpers.cs @@ -1,6 +1,6 @@ using System.Text.RegularExpressions; -namespace JSONAPI.Tests.Json +namespace JSONAPI.Json { static class JsonHelpers {