Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

Commit

Permalink
Merge pull request #10 from ejball/master
Browse files Browse the repository at this point in the history
Miscellaneous improvements.
  • Loading branch information
bgrainger authored Oct 30, 2017
2 parents 3a98261 + 876ed85 commit 382db10
Show file tree
Hide file tree
Showing 23 changed files with 625 additions and 271 deletions.
19 changes: 13 additions & 6 deletions VersionHistory.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,21 @@ Prefix the description of the change with `[major]`, `[minor]` or `[patch]` in a

## Released

### 0.3.0

* [major] Remove `ReadOnlyDictionaryJsonConverter` and `DictionaryKeysAreNotPropertyNamesJsonConverter`. (Json.NET 9+ doesn't need them.)
* [minor] Add `OptionalJsonConverter` and use by default with `JsonUtility`.
* [minor] Add `DefaultValueDefaultAttribute` (used on `Optional<T>` properties to distinguish null from missing).
* [major] Remove empty `IsoDateTimeOffsetJsonConverter` constructor.

### 0.2.0

* **Breaking:** Change .NET Framework minimum version to 4.6.1.
* **Breaking:** Remove `DefaultValueDefaultAttribute`.
* **Breaking:** Remove `JsonPointer` and `JsonPatch`.
* **Breaking:** Simplify `JsonInputSettings` and `JsonOutputSettings`.
* **Breaking:** Rename `JsonFilter.AlternatePathSepartor` to `AlternatePathSeparator`.
* **Breaking:** Move JToken-specific members from `JsonUtility` to `JTokenUtility`.
* [major] Change .NET Framework minimum version to 4.6.1.
* [major] Remove `DefaultValueDefaultAttribute`.
* [major] Remove `JsonPointer` and `JsonPatch`.
* [major] Simplify `JsonInputSettings` and `JsonOutputSettings`.
* [major] Rename `JsonFilter.AlternatePathSepartor` to `AlternatePathSeparator`.
* [major] Move JToken-specific members from `JsonUtility` to `JTokenUtility`.

### 0.1.1

Expand Down
2 changes: 0 additions & 2 deletions src/Faithlife.Json/Converters/CamelCaseEnumJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#pragma warning disable 1591

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
Expand Down

This file was deleted.

2 changes: 0 additions & 2 deletions src/Faithlife.Json/Converters/EnumAsIntegerJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#pragma warning disable 1591

using System;
using Faithlife.Utility;
using Newtonsoft.Json;
Expand Down
2 changes: 0 additions & 2 deletions src/Faithlife.Json/Converters/GuidLowerNoDashJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#pragma warning disable 1591

using System;
using Faithlife.Utility;
using Newtonsoft.Json;
Expand Down
2 changes: 0 additions & 2 deletions src/Faithlife.Json/Converters/IsoDateOnlyJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#pragma warning disable 1591

using System;
using System.Globalization;
using Newtonsoft.Json;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,6 @@ namespace Faithlife.Json.Converters
/// <remarks>Uses DateTimeOffsetUtility.Iso8601Format</remarks>
public class IsoDateTimeOffsetJsonConverter : JsonConverterBase<DateTimeOffset>
{
/// <summary>
/// Initializes a new instance of the <see cref="IsoDateTimeOffsetJsonConverter"/> class.
/// </summary>
public IsoDateTimeOffsetJsonConverter()
{
}

/// <summary>
/// Overrides WriteCore.
/// </summary>
Expand Down
53 changes: 53 additions & 0 deletions src/Faithlife.Json/Converters/OptionalJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System;
using System.Linq;
using System.Reflection;
using Faithlife.Utility;
using Newtonsoft.Json;

namespace Faithlife.Json.Converters
{
/// <summary>
/// Supports JSON conversion of Optional{T}.
/// </summary>
public class OptionalJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType.IsGenericType() && objectType.GetGenericTypeDefinition() == typeof(Optional<>);
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// make sure it has a value; optional instances without a value must be ignored
IOptional optional = (IOptional) value;
if (!optional.HasValue)
{
string optionalValueTypeName = optional.GetType().GenericTypeArguments.Single().Name;
throw new InvalidOperationException(("Optional<{0}>.HasValue is false. " +
"Optional properties should include these attributes: " +
"[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Include), DefaultValueDefault(typeof(Optional<{0}>))]")
.FormatInvariant(optionalValueTypeName));
}

// serialize value
serializer.Serialize(writer, optional.Value);
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// get T of Optional<T>
Type optionalValueType = objectType.GenericTypeArguments.Single();

// deserialize using T
object optionalValue = serializer.Deserialize(reader, optionalValueType);

// call Optional<T>(T value) constructor
ConstructorInfo constructorInfo = GetConstructor(objectType, new[] { optionalValueType });
Verify.IsNotNull(constructorInfo);
return constructorInfo.Invoke(new[] { optionalValue });
}

private static ConstructorInfo GetConstructor(Type type, Type[] types)
=> type.GetTypeInfo().DeclaredConstructors.FirstOrDefault(x => x.IsPublic && EnumerableUtility.AreEqual(x.GetParameters().Select(p => p.ParameterType), types));
}
}
38 changes: 0 additions & 38 deletions src/Faithlife.Json/Converters/ReadOnlyDictionaryJsonConverter.cs

This file was deleted.

20 changes: 20 additions & 0 deletions src/Faithlife.Json/DefaultValueDefaultAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.ComponentModel;

namespace Faithlife.Json
{
/// <summary>
/// Sets the <c>DefaultValue</c> to <c>new T()</c> for the specified type.
/// </summary>
public sealed class DefaultValueDefaultAttribute : DefaultValueAttribute
{
/// <summary>
/// Initializes a new instance of the <see cref="DefaultValueDefaultAttribute"/> class.
/// </summary>
/// <param name="type">The type.</param>
public DefaultValueDefaultAttribute(Type type)
: base(Activator.CreateInstance(type))
{
}
}
}
4 changes: 2 additions & 2 deletions src/Faithlife.Json/Faithlife.Json.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Version>0.2.0</Version>
<VersionPrefix>0.3.0</VersionPrefix>
<TargetFrameworks>netstandard1.4;netstandard2.0;net461</TargetFrameworks>
<FrameworkPathOverride Condition="'$(TargetFramework)' == 'net461' and '$(MONO_ROOT)' != ''">$(MONO_ROOT)/lib/mono/4.6.1-api/</FrameworkPathOverride>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
Expand All @@ -19,7 +19,7 @@
<SourceLinkOriginUrl>https://github.com/Faithlife/FaithlifeJson.git</SourceLinkOriginUrl>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Faithlife.Utility" Version="0.4.1" />
<PackageReference Include="Faithlife.Utility" Version="0.4.2" />
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="SourceLink.Create.GitHub" Version="2.1.0" PrivateAssets="all" />
<PackageReference Include="SourceLink.Test" Version="2.1.0" PrivateAssets="all" />
Expand Down
36 changes: 8 additions & 28 deletions src/Faithlife.Json/JTokenUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,13 @@ public static class JTokenUtility
/// <param name="left">The left JToken.</param>
/// <param name="right">The right JToken.</param>
/// <returns>True if the two JTokens are equal.</returns>
public static bool AreEqual(JToken left, JToken right)
{
return EqualityComparer.Equals(left, right);
}
public static bool AreEqual(JToken left, JToken right) => EqualityComparer.Equals(left, right);

/// <summary>
/// Returns a Boolean corresponding to the JToken if possible.
/// </summary>
/// <returns>This method returns null if the JToken is null or if it doesn't contain a Boolean.</returns>
public static bool? AsBoolean(this JToken jToken)
{
return jToken != null && jToken.Type == JTokenType.Boolean ? (bool) jToken : default(bool?);
}
public static bool? AsBoolean(this JToken jToken) => jToken != null && jToken.Type == JTokenType.Boolean ? (bool) jToken : default(bool?);

/// <summary>
/// Returns a Decimal corresponding to the JToken if possible.
Expand Down Expand Up @@ -116,8 +110,7 @@ public static bool AreEqual(JToken left, JToken right)
/// on the number itself (since numeric representations of the number could lose precision).</remarks>
public static JValue AsNumber(this JToken jToken)
{
JValue jValue = jToken as JValue;
if (jValue == null)
if (!(jToken is JValue jValue))
return null;
JTokenType jTokenType = jValue.Type;
return jTokenType == JTokenType.Integer || jTokenType == JTokenType.Float ? jValue : null;
Expand All @@ -127,10 +120,7 @@ public static JValue AsNumber(this JToken jToken)
/// Returns a string corresponding to the JToken if possible.
/// </summary>
/// <returns>This method returns null if the JToken is null, or if it doesn't contain a string.</returns>
public static string AsString(this JToken jToken)
{
return jToken != null && jToken.Type == JTokenType.String ? (string) jToken : null;
}
public static string AsString(this JToken jToken) => jToken != null && jToken.Type == JTokenType.String ? (string) jToken : null;

/// <summary>
/// Returns true if the JToken is null or represents null.
Expand All @@ -140,8 +130,7 @@ public static bool IsNull(this JToken jToken)
if (jToken == null)
return true;

JValue jValue = jToken as JValue;
return jValue != null && jValue.Value == null;
return jToken is JValue jValue && jValue.Value == null;
}

/// <summary>
Expand All @@ -151,11 +140,7 @@ public static bool IsNull(this JToken jToken)
/// <param name="itemIndex">The index of the array item.</param>
/// <returns>This method returns null if the JToken is null, or if it doesn't contain an array,
/// or if the index is out of bounds.</returns>
public static JToken TryGetValue(this JToken jToken, int itemIndex)
{
JArray jArray = jToken as JArray;
return jArray != null && itemIndex >= 0 && itemIndex < jArray.Count ? jArray[itemIndex] : null;
}
public static JToken TryGetValue(this JToken jToken, int itemIndex) => jToken is JArray jArray && itemIndex >= 0 && itemIndex < jArray.Count ? jArray[itemIndex] : null;

/// <summary>
/// Returns the specified property value if possible.
Expand All @@ -164,11 +149,7 @@ public static JToken TryGetValue(this JToken jToken, int itemIndex)
/// <param name="propertyName">The name of the property.</param>
/// <returns>This method returns null if the JToken is null, or if it doesn't contain an object,
/// or if the property name is null, or if the property doesn't exist.</returns>
public static JToken TryGetValue(this JToken jToken, string propertyName)
{
JObject jObject = jToken as JObject;
return jObject != null && propertyName != null ? jObject[propertyName] : null;
}
public static JToken TryGetValue(this JToken jToken, string propertyName) => jToken is JObject jObject && propertyName != null ? jObject[propertyName] : null;

/// <summary>
/// Gets a persistent hash code for the token.
Expand Down Expand Up @@ -273,8 +254,7 @@ public bool Equals(JToken left, JToken right)
// allow properties to be in any order, but make sure they have the same names and values
foreach (KeyValuePair<string, JToken> leftProperty in leftProperties)
{
JToken rightValue;
if (!rightProperties.TryGetValue(leftProperty.Key, out rightValue))
if (!rightProperties.TryGetValue(leftProperty.Key, out var rightValue))
return false;
if (!Equals(leftProperty.Value, rightValue))
return false;
Expand Down
Loading

0 comments on commit 382db10

Please sign in to comment.