Skip to content
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

Allow NewtonsoftJsonSerializer to be parameterized with settings. #989

Merged
merged 1 commit into from May 4, 2017
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
66 changes: 35 additions & 31 deletions Src/Support/GoogleApis.Core/Apis/Json/NewtonsoftJsonSerializer.cs
Expand Up @@ -32,22 +32,17 @@ namespace Google.Apis.Json
/// </summary>
public class RFC3339DateTimeConverter : JsonConverter
{
public override bool CanRead
{
get { return false; }
}
public override bool CanRead => false;

public override object ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
throw new NotImplementedException("Unnecessary because CanRead is false.");
}

public override bool CanConvert(Type objectType)
{
public override bool CanConvert(Type objectType) =>
// Convert DateTime only.
return objectType == typeof(DateTime) || objectType == typeof(Nullable<DateTime>);
}
objectType == typeof(DateTime) || objectType == typeof(Nullable<DateTime>);

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Expand Down Expand Up @@ -83,36 +78,45 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
/// <summary>Class for serialization and deserialization of JSON documents using the Newtonsoft Library.</summary>
public class NewtonsoftJsonSerializer : IJsonSerializer
{
private static readonly JsonSerializerSettings newtonsoftSettings;
private static readonly JsonSerializer newtonsoftSerializer;
private readonly JsonSerializerSettings settings;
private readonly JsonSerializer serializer;

private static NewtonsoftJsonSerializer instance;
/// <summary>The default instance of the Newtonsoft JSON Serializer, with default settings.</summary>
public static NewtonsoftJsonSerializer Instance { get; } = new NewtonsoftJsonSerializer();

/// <summary>A singleton instance of the Newtonsoft JSON Serializer.</summary>
public static NewtonsoftJsonSerializer Instance
/// <summary>
/// Constructs a new instance with the default serialization settings, equivalent to <see cref="Instance"/>.
/// </summary>
public NewtonsoftJsonSerializer() : this(CreateDefaultSettings())
{
get
{
return (instance = instance ?? new NewtonsoftJsonSerializer());
}
}

static NewtonsoftJsonSerializer()
/// <summary>
/// Constructs a new instance with the given settings.
/// </summary>
/// <param name="settings">The settings to apply when serializing and deserializing. Must not be null.</param>
public NewtonsoftJsonSerializer(JsonSerializerSettings settings)
{
// Initialize the Newtonsoft serializer.
newtonsoftSettings = new JsonSerializerSettings
Utilities.ThrowIfNull(settings, nameof(settings));
this.settings = settings;
serializer = JsonSerializer.Create(settings);
}

/// <summary>
/// Creates a new instance of <see cref="JsonSerializerSettings"/> with the same behavior
/// as the ones used in <see cref="Instance"/>. This method is expected to be used to construct
/// settings which are then passed to <see cref="NewtonsoftJsonSerializer.NewtonsoftJsonSerializer(JsonSerializerSettings)"/>.
/// </summary>
/// <returns>A new set of default settings.</returns>
public static JsonSerializerSettings CreateDefaultSettings() =>
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
Converters = { new RFC3339DateTimeConverter(), new ExplicitNullConverter() }
};
newtonsoftSerializer = JsonSerializer.Create(newtonsoftSettings);
}

public string Format
{
get { return "json"; }
}
public string Format => "json";

public void Serialize(object obj, Stream target)
{
Expand All @@ -122,7 +126,7 @@ public void Serialize(object obj, Stream target)
{
obj = string.Empty;
}
newtonsoftSerializer.Serialize(writer, obj);
serializer.Serialize(writer, obj);
}
}

Expand All @@ -134,7 +138,7 @@ public string Serialize(object obj)
{
obj = string.Empty;
}
newtonsoftSerializer.Serialize(tw, obj);
serializer.Serialize(tw, obj);
return tw.ToString();
}
}
Expand All @@ -145,7 +149,7 @@ public T Deserialize<T>(string input)
{
return default(T);
}
return JsonConvert.DeserializeObject<T>(input, newtonsoftSettings);
return JsonConvert.DeserializeObject<T>(input, settings);
}

public object Deserialize(string input, Type type)
Expand All @@ -154,15 +158,15 @@ public object Deserialize(string input, Type type)
{
return null;
}
return JsonConvert.DeserializeObject(input, type, newtonsoftSettings);
return JsonConvert.DeserializeObject(input, type, settings);
}

public T Deserialize<T>(Stream input)
{
// Convert the JSON document into an object.
using (StreamReader streamReader = new StreamReader(input))
{
return (T)newtonsoftSerializer.Deserialize(streamReader, typeof(T));
return (T)serializer.Deserialize(streamReader, typeof(T));
}
}
}
Expand Down
1 change: 1 addition & 0 deletions Src/Support/GoogleApis.Tests/GoogleApis.Tests.csproj
Expand Up @@ -117,6 +117,7 @@
<Compile Include="Apis\Utils\StringValueAttributeTest.cs" />
<Compile Include="Apis\Utils\RepeatableTest.cs" />
<Compile Include="ApplicationContextTests.cs" />
<Compile Include="Json\NewtonsoftJsonSerializer.cs" />
<Compile Include="Json\JsonExplicitNullTest.cs" />
<Compile Include="Logging\Log4NetLogger.cs" />
<Compile Include="Program.cs" />
Expand Down
67 changes: 67 additions & 0 deletions Src/Support/GoogleApis.Tests/Json/NewtonsoftJsonSerializer.cs
@@ -0,0 +1,67 @@
/*
Copyright 2017 Google Inc

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

using Google.Apis.Json;
using Newtonsoft.Json;
using NUnit.Framework;
using System;

namespace Google.Apis.Tests.Json
{
class NewtonsoftJsonSerializerTest
{
[Test]
public void CreateDefaultSettings_Independent()
{
var settings1 = NewtonsoftJsonSerializer.CreateDefaultSettings();
var settings2 = NewtonsoftJsonSerializer.CreateDefaultSettings();

settings1.DateParseHandling = DateParseHandling.DateTimeOffset;
settings2.DateParseHandling = DateParseHandling.None;
// Not affected by changing settings2
Assert.AreEqual(DateParseHandling.DateTimeOffset, settings1.DateParseHandling);
}

[Test]
public void InstanceIsCached()
{
var instance1 = NewtonsoftJsonSerializer.Instance;
var instance2 = NewtonsoftJsonSerializer.Instance;
Assert.AreSame(instance1, instance2);
}

[Test]
public void DefaultInstanceParsesDates()
{
string text = "\"2017-05-03T16:38:00Z\"";
object value = NewtonsoftJsonSerializer.Instance.Deserialize<object>(text);
Assert.IsInstanceOf<DateTime>(value);
}

[Test]
public void CustomInstanceAvoidingDateParsin()
{
string text = "\"2017-05-03T16:38:00Z\"";
var settings = NewtonsoftJsonSerializer.CreateDefaultSettings();
settings.DateParseHandling = DateParseHandling.None;
var instance = new NewtonsoftJsonSerializer(settings);
object value = instance.Deserialize<object>(text);

// No magic parsing to DateTime...
Assert.IsInstanceOf<string>(value);
}
}
}