Skip to content

Commit

Permalink
Merge pull request #100 from Turnerj/system-text-json-update
Browse files Browse the repository at this point in the history
Switch from Newtonsoft.Json to System.Text.Json
  • Loading branch information
Turnerj committed Nov 9, 2021
2 parents 0e20b2f + e7d3ae8 commit 2f222a6
Show file tree
Hide file tree
Showing 25 changed files with 514 additions and 309 deletions.
4 changes: 2 additions & 2 deletions Benchmarks/Schema.NET.Benchmarks/SchemaBenchmarkBase.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
namespace Schema.NET.Benchmarks
{
using System;
using System.Text.Json;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using Newtonsoft.Json;

[KeepBenchmarkFiles]
[MemoryDiagnoser]
Expand Down Expand Up @@ -36,6 +36,6 @@ public virtual void Setup()
public string Serialize() => this.Thing.ToString();

[Benchmark]
public object? Deserialize() => JsonConvert.DeserializeObject(this.SerializedThing, this.ThingType);
public object? Deserialize() => JsonSerializer.Deserialize(this.SerializedThing, this.ThingType);
}
}
4 changes: 3 additions & 1 deletion Schema.NET.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31423.177
VisualStudioVersion = 17.0.31612.314
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{719809C2-A551-4C4A-9EFD-B10FB5E35BC0}"
ProjectSection(SolutionItems) = preProject
Expand Down Expand Up @@ -94,6 +94,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Schema.NET.Pending", "Sourc
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{AF228B8A-7290-4E26-8506-934C290C6AE3}"
ProjectSection(SolutionItems) = preProject
Source\Common\Constants.cs = Source\Common\Constants.cs
Source\Common\ContactType.cs = Source\Common\ContactType.cs
Source\Common\ContextJsonConverter.cs = Source\Common\ContextJsonConverter.cs
Source\Common\DateTimeHelper.cs = Source\Common\DateTimeHelper.cs
Expand All @@ -106,6 +107,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{AF228B
Source\Common\JsonLdObject.cs = Source\Common\JsonLdObject.cs
Source\Common\OneOrMany{T}.cs = Source\Common\OneOrMany{T}.cs
Source\Common\PropertyValueSpecification.Partial.cs = Source\Common\PropertyValueSpecification.Partial.cs
Source\Common\SchemaEnumJsonConverter{T}.cs = Source\Common\SchemaEnumJsonConverter{T}.cs
Source\Common\SchemaSerializer.cs = Source\Common\SchemaSerializer.cs
Source\Common\Thing.Partial.cs = Source\Common\Thing.Partial.cs
Source\Common\TimeSpanToISO8601DurationValuesJsonConverter.cs = Source\Common\TimeSpanToISO8601DurationValuesJsonConverter.cs
Expand Down
18 changes: 18 additions & 0 deletions Source/Common/Constants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Schema.NET
{
/// <summary>
/// Various constants for use within Schema.NET
/// </summary>
public static class Constants
{
/// <summary>
/// The HTTPS URL for Schema.org, excluding trailing slash.
/// </summary>
public const string HttpsSchemaOrgUrl = "https://schema.org";

/// <summary>
/// The HTTP URL for Schema.org, excluding trailing slash.
/// </summary>
public const string HttpSchemaOrgUrl = "http://schema.org";
}
}
105 changes: 45 additions & 60 deletions Source/Common/ContextJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
namespace Schema.NET
{
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;

/// <summary>
/// Converts a <see cref="JsonLdContext"/> object to and from JSON.
Expand All @@ -11,96 +11,81 @@ namespace Schema.NET
public class ContextJsonConverter : JsonConverter<JsonLdContext>
{
/// <inheritdoc />
public override JsonLdContext ReadJson(JsonReader reader, Type objectType, JsonLdContext? existingValue, bool hasExistingValue, JsonSerializer serializer)
public override JsonLdContext Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
#if NET6_0_OR_GREATER
ArgumentNullException.ThrowIfNull(reader);
ArgumentNullException.ThrowIfNull(objectType);
if (hasExistingValue)
{
ArgumentNullException.ThrowIfNull(existingValue);
}

ArgumentNullException.ThrowIfNull(serializer);
ArgumentNullException.ThrowIfNull(typeToConvert);
ArgumentNullException.ThrowIfNull(options);
#else
if (reader is null)
{
throw new ArgumentNullException(nameof(reader));
}

if (objectType is null)
{
throw new ArgumentNullException(nameof(objectType));
}

if (hasExistingValue && existingValue is null)
if (typeToConvert is null)
{
throw new ArgumentNullException(nameof(existingValue));
throw new ArgumentNullException(nameof(typeToConvert));
}

if (serializer is null)
if (options is null)
{
throw new ArgumentNullException(nameof(serializer));
throw new ArgumentNullException(nameof(options));
}
#endif
var context = new JsonLdContext();

var context = hasExistingValue ? existingValue! : new JsonLdContext();

string? name;
string? language;
if (reader.TokenType == JsonToken.String)
string? name = null;
string? language = null;
if (reader.TokenType == JsonTokenType.String)
{
name = (string?)reader.Value;
language = null;
name = reader.GetString();
}
else if (reader.TokenType == JsonToken.StartObject)
else if (reader.TokenType == JsonTokenType.StartObject)
{
var o = JObject.Load(reader);
var document = JsonDocument.ParseValue(ref reader);

var nameProperty = o.Property("name", StringComparison.OrdinalIgnoreCase);
name = nameProperty?.Value?.ToString() ?? "https://schema.org";
if (document.RootElement.TryGetProperty("name", out var nameElement))
{
name = nameElement.GetString() ?? Constants.HttpsSchemaOrgUrl;
}

var languageProperty = o.Property("@language", StringComparison.OrdinalIgnoreCase);
language = languageProperty?.Value?.ToString();
if (document.RootElement.TryGetProperty("@language", out var languageElement))
{
language = languageElement.GetString();
}
}
else
{
var a = JArray.Load(reader);
var array = JsonDocument.ParseValue(ref reader).RootElement.EnumerateArray();

name = language = null;
foreach (var entry in a)
foreach (var entry in array)
{
if (entry.Type == JTokenType.String)
if (entry.ValueKind == JsonValueKind.String)
{
name ??= (string?)entry;
name ??= entry.GetString();
}
else
else if (entry.ValueKind == JsonValueKind.Object)
{
var o = (JObject)entry;

var nameProperty = o.Property("name", StringComparison.OrdinalIgnoreCase);
name ??= nameProperty?.Value?.ToString() ?? "https://schema.org";

var languageProperty = o.Property("@language", StringComparison.OrdinalIgnoreCase);
language ??= languageProperty?.Value?.ToString();
if (entry.TryGetProperty("name", out var nameElement))
{
name ??= nameElement.GetString() ?? Constants.HttpsSchemaOrgUrl;
}

if (entry.TryGetProperty("@language", out var languageElement))
{
language ??= languageElement.GetString();
}
}
}
}

#pragma warning disable CA1062 // Validate arguments of public methods
context.Name = name;
context.Language = language;
#pragma warning restore CA1062 // Validate arguments of public methods
return context;
}

/// <inheritdoc />
public override void WriteJson(JsonWriter writer, JsonLdContext? value, JsonSerializer serializer)
public override void Write(Utf8JsonWriter writer, JsonLdContext value, JsonSerializerOptions options)
{
#if NET6_0_OR_GREATER
ArgumentNullException.ThrowIfNull(writer);
ArgumentNullException.ThrowIfNull(value);
ArgumentNullException.ThrowIfNull(serializer);
ArgumentNullException.ThrowIfNull(options);
#else
if (writer is null)
{
Expand All @@ -112,23 +97,23 @@ public override void WriteJson(JsonWriter writer, JsonLdContext? value, JsonSeri
throw new ArgumentNullException(nameof(value));
}

if (serializer is null)
if (options is null)
{
throw new ArgumentNullException(nameof(serializer));
throw new ArgumentNullException(nameof(options));
}
#endif

if (string.IsNullOrWhiteSpace(value.Language))
{
writer.WriteValue(value.Name);
writer.WriteStringValue(value.Name);
}
else
{
writer.WriteStartObject();
writer.WritePropertyName("name");
writer.WriteValue(value.Name);
writer.WriteStringValue(value.Name);
writer.WritePropertyName("@language");
writer.WriteValue(value.Language);
writer.WriteStringValue(value.Language);
writer.WriteEndObject();
}
}
Expand Down
17 changes: 9 additions & 8 deletions Source/Common/DateTimeToIso8601DateValuesJsonConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ namespace Schema.NET
{
using System;
using System.Globalization;
using Newtonsoft.Json;
using System.Text.Json;
using System.Text.Json.Serialization;

/// <summary>
/// Converts an <see cref="IValues"/> object to JSON. If the <see cref="IValues"/> contains a
Expand All @@ -17,31 +18,31 @@ public class DateTimeToIso8601DateValuesJsonConverter : ValuesJsonConverter
/// </summary>
/// <param name="writer">The JSON writer.</param>
/// <param name="value">The value to write.</param>
/// <param name="serializer">The JSON serializer.</param>
public override void WriteObject(JsonWriter writer, object? value, JsonSerializer serializer)
/// <param name="options">The JSON serializer options.</param>
public override void WriteObject(Utf8JsonWriter writer, object? value, JsonSerializerOptions options)
{
#if NET6_0_OR_GREATER
ArgumentNullException.ThrowIfNull(writer);
ArgumentNullException.ThrowIfNull(serializer);
ArgumentNullException.ThrowIfNull(options);
#else
if (writer is null)
{
throw new ArgumentNullException(nameof(writer));
}

if (serializer is null)
if (options is null)
{
throw new ArgumentNullException(nameof(serializer));
throw new ArgumentNullException(nameof(options));
}
#endif

if (value is DateTime dateTimeType)
{
writer.WriteValue(dateTimeType.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
writer.WriteStringValue(dateTimeType.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
}
else
{
base.WriteObject(writer, value, serializer);
base.WriteObject(writer, value, options);
}
}
}
Expand Down
45 changes: 45 additions & 0 deletions Source/Common/EnumHelper.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace Schema.NET
{
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

/// <summary>
Expand Down Expand Up @@ -43,5 +44,49 @@ public static bool TryParse(
#pragma warning restore IDE0022 // Use expression body for methods
#endif
}

/// <summary>
/// Converts the Schema URI representation of the enum type to an equivalent enumerated object.
/// </summary>
/// <param name="enumType">The enum type to use for parsing.</param>
/// <param name="value">The string representation of the name or numeric value of one or more enumerated constants.</param>
/// <param name="result">When this method returns true, an object containing an enumeration constant representing the parsed value.</param>
/// <returns><see langword="true"/> if the conversion succeeded; <see langword="false"/> otherwise.</returns>
public static bool TryParseEnumFromSchemaUri(
Type enumType,
#if NETCOREAPP3_1_OR_GREATER
[NotNullWhen(true)]
#endif
string? value,
out object? result)
{
string? enumString;
if (value is not null && value.StartsWith(Constants.HttpSchemaOrgUrl, StringComparison.OrdinalIgnoreCase))
{
#pragma warning disable IDE0057 // Use range operator. Need to multi-target.
enumString = value.Substring(Constants.HttpSchemaOrgUrl.Length + 1);
#pragma warning restore IDE0057 // Use range operator. Need to multi-target.
}
else if (value is not null && value.StartsWith(Constants.HttpsSchemaOrgUrl, StringComparison.OrdinalIgnoreCase))
{
#pragma warning disable IDE0057 // Use range operator. Need to multi-target.
enumString = value.Substring(Constants.HttpsSchemaOrgUrl.Length + 1);
#pragma warning restore IDE0057 // Use range operator. Need to multi-target.
}
else
{
enumString = value;
}

if (TryParse(enumType, enumString, out result))
{
return true;
}
else
{
Debug.WriteLine($"Unable to parse enumeration of type {enumType.FullName} with value {enumString}.");
return false;
}
}
}
}
10 changes: 6 additions & 4 deletions Source/Common/JsonLdContext.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace Schema.NET
{
using System;
using System.Runtime.Serialization;
using System.Text.Json.Serialization;

/// <summary>
/// The @context for a JSON-LD document.
Expand All @@ -12,13 +12,15 @@ public class JsonLdContext : IEquatable<JsonLdContext>
/// <summary>
/// Gets or sets the name.
/// </summary>
[DataMember(Name = "name", Order = 0)]
public string? Name { get; set; } = "https://schema.org";
[JsonPropertyName("name")]
[JsonPropertyOrder(0)]
public string? Name { get; set; } = Constants.HttpsSchemaOrgUrl;

/// <summary>
/// Gets or sets the language.
/// </summary>
[DataMember(Name = "@language", Order = 1)]
[JsonPropertyName("@language")]
[JsonPropertyOrder(1)]
public string? Language { get; set; }

/// <summary>
Expand Down
Loading

0 comments on commit 2f222a6

Please sign in to comment.