Introduce a protected virtual CreateJsonReader method in JsonEventFormatter

(Currently just for Json.NET)

Fixes #151

Signed-off-by: Jon Skeet <jonskeet@google.com>
This commit is contained in:
Jon Skeet 2021-05-25 10:32:00 +01:00 committed by Jon Skeet
parent 55b6df12cd
commit b8e566586c
2 changed files with 115 additions and 1 deletions

View File

@ -524,7 +524,24 @@ namespace CloudNative.CloudEvents.NewtonsoftJson
} }
} }
internal static JsonReader CreateJsonReader(Stream stream, Encoding encoding) => /// <summary>
/// Creates a <see cref="JsonReader"/> for the given stream. This may be overridden in derived classes to
/// customize the JSON parsing process, subject to the constraints listed in the remarks.
/// </summary>
/// <remarks>
/// <para>
/// The default implementation always creates an instance of <see cref="JsonTextReader"/>, and derived classes
/// may assume that (calling this implementation and casting the result before modifying it).
/// </para>
/// <para>
/// Implementations should ensure that <see cref="JsonReader.DateParseHandling"/> is set to <see cref="DateParseHandling.None"/>,
/// as timestamp parsing is performed in a CloudEvent-specific way, and Json.NET's own implementation can obscure that.
/// </para>
/// </remarks>
/// <param name="stream">The stream to read from. Will not be null.</param>
/// <param name="encoding">The expected text encoding. May be null, in which case UTF-8 should be assumed.</param>
/// <returns>A JsonReader suitable for reading the </returns>
protected virtual JsonReader CreateJsonReader(Stream stream, Encoding encoding) =>
new JsonTextReader(new StreamReader(stream, encoding ?? Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 8192, leaveOpen: true)) new JsonTextReader(new StreamReader(stream, encoding ?? Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 8192, leaveOpen: true))
{ {
DateParseHandling = DateParseHandling.None DateParseHandling = DateParseHandling.None

View File

@ -0,0 +1,97 @@
// Copyright 2021 Cloud Native Foundation.
// Licensed under the Apache 2.0 license.
// See LICENSE file in the project root for full license information.
using CloudNative.CloudEvents.UnitTests;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Xunit;
namespace CloudNative.CloudEvents.NewtonsoftJson.UnitTests
{
/// <summary>
/// Tests for the specialization of <see cref="JsonEventFormatter.CreateJsonReader(System.IO.Stream, Encoding)"/>
/// </summary>
public class SpecializedJsonReaderTest
{
[Fact]
public void DefaultImplementation_ReturnsJsonTextReader()
{
var formatter = new CreateJsonReaderExposingFormatter();
var reader = formatter.CreateJsonReaderPublic(CreateJsonStream(), null);
Assert.IsType<JsonTextReader>(reader);
}
[Fact]
public void DefaultImplementation_NoPropertyNameTable()
{
var formatter = new JsonEventFormatter();
var event1 = formatter.DecodeStructuredModeMessage(CreateJsonStream(), null, null);
var event2 = formatter.DecodeStructuredModeMessage(CreateJsonStream(), null, null);
JObject data1 = (JObject)event1.Data;
JObject data2 = (JObject)event2.Data;
var property1 = data1.Properties().Single();
var property2 = data2.Properties().Single();
Assert.Equal(property1.Name, property2.Name);
Assert.NotSame(property1.Name, property2.Name);
}
[Fact]
public void Specialization_WithPropertyNameTable()
{
var formatter = new PropertyNameTableFormatter();
var event1 = formatter.DecodeStructuredModeMessage(CreateJsonStream(), null, null);
var event2 = formatter.DecodeStructuredModeMessage(CreateJsonStream(), null, null);
JObject data1 = (JObject)event1.Data;
JObject data2 = (JObject)event2.Data;
var property1 = data1.Properties().Single();
var property2 = data2.Properties().Single();
Assert.Equal(property1.Name, property2.Name);
Assert.Same(property1.Name, property2.Name);
}
private Stream CreateJsonStream()
{
var cloudEvent = new CloudEvent
{
Data = new { DataName = "DataValue" }
}.PopulateRequiredAttributes();
var bytes = new JsonEventFormatter().EncodeStructuredModeMessage(cloudEvent, out _);
return new MemoryStream(bytes);
}
private class CreateJsonReaderExposingFormatter : JsonEventFormatter
{
public JsonReader CreateJsonReaderPublic(Stream stream, Encoding encoding) =>
base.CreateJsonReader(stream, encoding);
}
private class PropertyNameTableFormatter : JsonEventFormatter
{
private readonly DefaultJsonNameTable table;
public PropertyNameTableFormatter()
{
// Names aren't automatically cached by JsonTextReader, so we need to prepopulate the table.
table = new DefaultJsonNameTable();
table.Add("DataName");
}
protected override JsonReader CreateJsonReader(Stream stream, Encoding encoding)
{
var reader = (JsonTextReader) base.CreateJsonReader(stream, encoding);
reader.PropertyNameTable = table;
return reader;
}
}
}
}