diff --git a/src/NodaTime.Serialization.JsonNet/NodaConverterBase.cs b/src/NodaTime.Serialization.JsonNet/NodaConverterBase.cs
index 2814489..bdfaedc 100644
--- a/src/NodaTime.Serialization.JsonNet/NodaConverterBase.cs
+++ b/src/NodaTime.Serialization.JsonNet/NodaConverterBase.cs
@@ -128,7 +128,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s
/// to JSON.
///
/// The writer to write JSON data to
- /// The value to serializer
+ /// The value to serialize
/// The serializer to use for nested serialization
protected abstract void WriteJsonImpl(JsonWriter writer, T value, JsonSerializer serializer);
}
diff --git a/src/NodaTime.Serialization.JsonNet/NodaDateTimeZoneConverter.cs b/src/NodaTime.Serialization.JsonNet/NodaDateTimeZoneConverter.cs
index ef07c0a..3aeab85 100644
--- a/src/NodaTime.Serialization.JsonNet/NodaDateTimeZoneConverter.cs
+++ b/src/NodaTime.Serialization.JsonNet/NodaDateTimeZoneConverter.cs
@@ -42,7 +42,7 @@ protected override DateTimeZone ReadJsonImpl(JsonReader reader, JsonSerializer s
/// Writes the time zone ID to the writer.
///
/// The writer to write JSON data to
- /// The value to serializer
+ /// The value to serialize
/// The serializer to use for nested serialization
protected override void WriteJsonImpl(JsonWriter writer, DateTimeZone value, JsonSerializer serializer)
{
diff --git a/src/NodaTime.Serialization.JsonNet/NodaPatternConverter.cs b/src/NodaTime.Serialization.JsonNet/NodaPatternConverter.cs
index 6826d55..dedad05 100644
--- a/src/NodaTime.Serialization.JsonNet/NodaPatternConverter.cs
+++ b/src/NodaTime.Serialization.JsonNet/NodaPatternConverter.cs
@@ -64,7 +64,7 @@ protected override T ReadJsonImpl(JsonReader reader, JsonSerializer serializer)
/// Writes the formatted value to the writer.
///
/// The writer to write JSON data to
- /// The value to serializer
+ /// The value to serialize
/// The serializer to use for nested serialization
protected override void WriteJsonImpl(JsonWriter writer, T value, JsonSerializer serializer)
{
diff --git a/src/NodaTime.Serialization.SystemTextJson/NodaConverterBase.cs b/src/NodaTime.Serialization.SystemTextJson/NodaConverterBase.cs
index 0ee4af8..d059181 100644
--- a/src/NodaTime.Serialization.SystemTextJson/NodaConverterBase.cs
+++ b/src/NodaTime.Serialization.SystemTextJson/NodaConverterBase.cs
@@ -64,6 +64,28 @@ public override T Read(ref Utf8JsonReader reader, Type objectType, JsonSerialize
}
}
+ ///
+ /// Converts the JSON stored in a reader into the relevant Noda Time type.
+ ///
+ /// The json reader to read data from.
+ /// The type to convert the JSON to.
+ /// A serializer options to use for any embedded deserialization.
+ /// The JSON was invalid for this converter.
+ /// The deserialized value.
+ public override T ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert,
+ JsonSerializerOptions options)
+ {
+ try
+ {
+ // Delegate to the concrete subclass.
+ return ReadJsonImpl(ref reader, options);
+ }
+ catch (Exception ex)
+ {
+ throw new JsonException($"Cannot convert value to {typeToConvert}", ex);
+ }
+ }
+
///
/// Implemented by concrete subclasses, this performs the final conversion from a non-null JSON value to
/// a value of type T.
@@ -86,13 +108,33 @@ public override T Read(ref Utf8JsonReader reader, Type objectType, JsonSerialize
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) =>
WriteJsonImpl(writer, value, options);
+ ///
+ /// Writes the value as a string to a Utf8JsonWriter.
+ ///
+ /// The writer to write the JSON to.
+ /// The value to write.
+ /// The serializer options to use for any embedded serialization.
+ public override void WriteAsPropertyName(Utf8JsonWriter writer, T value, JsonSerializerOptions options) =>
+ WriteJsonPropertyNameImpl(writer, value, options);
+
///
/// Implemented by concrete subclasses, this performs the final write operation for a non-null value of type T
/// to JSON.
///
/// The writer to write JSON data to
- /// The value to serializer
+ /// The value to serialize
/// The serializer options to use for nested serialization
protected abstract void WriteJsonImpl(Utf8JsonWriter writer, T value, JsonSerializerOptions options);
+
+ ///
+ /// Implemented by concrete subclasses, this performs the final write operation for a non-null value of type T
+ /// to JSON, writing the value as a property name. The default implementation throws
+ /// for compatibility purposes, but all concrete classes within this package override and implement the method fully.
+ ///
+ /// The writer to write JSON data to
+ /// The value to serialize
+ /// The serializer options to use for nested serialization
+ protected virtual void WriteJsonPropertyNameImpl(Utf8JsonWriter writer, T value, JsonSerializerOptions options) =>
+ throw new NotImplementedException();
}
}
diff --git a/src/NodaTime.Serialization.SystemTextJson/NodaDateIntervalConverter.cs b/src/NodaTime.Serialization.SystemTextJson/NodaDateIntervalConverter.cs
index 627ac93..ffd1517 100644
--- a/src/NodaTime.Serialization.SystemTextJson/NodaDateIntervalConverter.cs
+++ b/src/NodaTime.Serialization.SystemTextJson/NodaDateIntervalConverter.cs
@@ -87,5 +87,15 @@ protected override void WriteJsonImpl(Utf8JsonWriter writer, DateInterval value,
writer.WriteEndObject();
}
+
+ ///
+ /// Unconditionally throws an exception, as a DateInterval cannot be serialized as a JSON property name.
+ ///
+ /// The writer to write JSON to
+ /// The date interval to serialize
+ /// The serializer options for embedded serialization.
+ /// Always thrown to indicate this is not an appropriate method to call on this type.
+ protected override void WriteJsonPropertyNameImpl(Utf8JsonWriter writer, DateInterval value, JsonSerializerOptions options) =>
+ throw new JsonException("Cannot serialize a DateInterval as a JSON property name using this converter");
}
}
diff --git a/src/NodaTime.Serialization.SystemTextJson/NodaDateTimeZoneConverter.cs b/src/NodaTime.Serialization.SystemTextJson/NodaDateTimeZoneConverter.cs
index 8057d9b..307b72d 100644
--- a/src/NodaTime.Serialization.SystemTextJson/NodaDateTimeZoneConverter.cs
+++ b/src/NodaTime.Serialization.SystemTextJson/NodaDateTimeZoneConverter.cs
@@ -39,9 +39,18 @@ protected override DateTimeZone ReadJsonImpl(ref Utf8JsonReader reader, JsonSeri
/// Writes the time zone ID to the writer.
///
/// The writer to write JSON data to.
- /// The value to serializer.
+ /// The value to serialize.
/// The serialization options to use for nested serialization.
protected override void WriteJsonImpl(Utf8JsonWriter writer, DateTimeZone value, JsonSerializerOptions options) =>
writer.WriteStringValue(value.Id);
+
+ ///
+ /// Writes the time zone ID to the writer as a property name
+ ///
+ /// The writer to write JSON data to.
+ /// The value to serialize.
+ /// The serialization options to use for nested serialization.
+ protected override void WriteJsonPropertyNameImpl(Utf8JsonWriter writer, DateTimeZone value, JsonSerializerOptions options) =>
+ writer.WritePropertyName(value.Id);
}
}
diff --git a/src/NodaTime.Serialization.SystemTextJson/NodaIntervalConverter.cs b/src/NodaTime.Serialization.SystemTextJson/NodaIntervalConverter.cs
index 76ed48f..284f474 100644
--- a/src/NodaTime.Serialization.SystemTextJson/NodaIntervalConverter.cs
+++ b/src/NodaTime.Serialization.SystemTextJson/NodaIntervalConverter.cs
@@ -82,5 +82,15 @@ protected override void WriteJsonImpl(Utf8JsonWriter writer, Interval value, Jso
}
writer.WriteEndObject();
}
+
+ ///
+ /// Unconditionally throws an exception, as an Interval cannot be serialized as a JSON property name.
+ ///
+ /// The writer to write JSON to
+ /// The date interval to serialize
+ /// The serializer options for embedded serialization.
+ /// Always thrown to indicate this is not an appropriate method to call on this type.
+ protected override void WriteJsonPropertyNameImpl(Utf8JsonWriter writer, Interval value, JsonSerializerOptions options) =>
+ throw new JsonException("Cannot serialize an Interval as a JSON property name using this converter");
}
}
diff --git a/src/NodaTime.Serialization.SystemTextJson/NodaIsoDateIntervalConverter.cs b/src/NodaTime.Serialization.SystemTextJson/NodaIsoDateIntervalConverter.cs
index 78221df..91199fe 100644
--- a/src/NodaTime.Serialization.SystemTextJson/NodaIsoDateIntervalConverter.cs
+++ b/src/NodaTime.Serialization.SystemTextJson/NodaIsoDateIntervalConverter.cs
@@ -62,8 +62,15 @@ protected override DateInterval ReadJsonImpl(ref Utf8JsonReader reader, JsonSeri
protected override void WriteJsonImpl(Utf8JsonWriter writer, DateInterval value, JsonSerializerOptions options)
{
var pattern = LocalDatePattern.Iso;
- string text = pattern.Format(value.Start) + "/" + pattern.Format(value.End);
+ var text = $"{pattern.Format(value.Start)}/{pattern.Format(value.End)}";
writer.WriteStringValue(text);
}
+
+ protected override void WriteJsonPropertyNameImpl(Utf8JsonWriter writer, DateInterval value, JsonSerializerOptions options)
+ {
+ var pattern = LocalDatePattern.Iso;
+ var text = $"{pattern.Format(value.Start)}/{pattern.Format(value.End)}";
+ writer.WritePropertyName(text);
+ }
}
}
diff --git a/src/NodaTime.Serialization.SystemTextJson/NodaIsoIntervalConverter.cs b/src/NodaTime.Serialization.SystemTextJson/NodaIsoIntervalConverter.cs
index 7da1c49..ecb6d0e 100644
--- a/src/NodaTime.Serialization.SystemTextJson/NodaIsoIntervalConverter.cs
+++ b/src/NodaTime.Serialization.SystemTextJson/NodaIsoIntervalConverter.cs
@@ -52,8 +52,15 @@ protected override Interval ReadJsonImpl(ref Utf8JsonReader reader, JsonSerializ
protected override void WriteJsonImpl(Utf8JsonWriter writer, Interval value, JsonSerializerOptions options)
{
var pattern = InstantPattern.ExtendedIso;
- string text = (value.HasStart ? pattern.Format(value.Start) : "") + "/" + (value.HasEnd ? pattern.Format(value.End) : "");
+ var text = $"{(value.HasStart ? pattern.Format(value.Start) : "")}/{(value.HasEnd ? pattern.Format(value.End) : "")}";
writer.WriteStringValue(text);
}
+
+ protected override void WriteJsonPropertyNameImpl(Utf8JsonWriter writer, Interval value, JsonSerializerOptions options)
+ {
+ var pattern = InstantPattern.ExtendedIso;
+ var text = $"{(value.HasStart ? pattern.Format(value.Start) : "")}/{(value.HasEnd ? pattern.Format(value.End) : "")}";
+ writer.WritePropertyName(text);
+ }
}
}
diff --git a/src/NodaTime.Serialization.SystemTextJson/NodaPatternConverter.cs b/src/NodaTime.Serialization.SystemTextJson/NodaPatternConverter.cs
index 2fb3113..458c324 100644
--- a/src/NodaTime.Serialization.SystemTextJson/NodaPatternConverter.cs
+++ b/src/NodaTime.Serialization.SystemTextJson/NodaPatternConverter.cs
@@ -2,9 +2,9 @@
// Use of this source code is governed by the Apache License 2.0,
// as found in the LICENSE.txt file.
+using NodaTime.Text;
using System;
using System.Text.Json;
-using NodaTime.Text;
namespace NodaTime.Serialization.SystemTextJson
{
@@ -59,12 +59,26 @@ protected override T ReadJsonImpl(ref Utf8JsonReader reader, JsonSerializerOptio
/// Writes the formatted value to the writer.
///
/// The writer to write JSON data to
- /// The value to serializer
+ /// The value to serialize
/// The serializer options to use for nested serialization
protected override void WriteJsonImpl(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
validator?.Invoke(value);
- writer.WriteStringValue(pattern.Format(value));
+ var text = pattern.Format(value);
+ writer.WriteStringValue(text);
+ }
+
+ ///
+ /// Writes the formatted value to the writer.
+ ///
+ /// The writer to write JSON data to.
+ /// The value to serialize.
+ /// The serialization options to use for nested serialization.
+ protected override void WriteJsonPropertyNameImpl(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
+ {
+ validator?.Invoke(value);
+ var text = pattern.Format(value);
+ writer.WritePropertyName(text);
}
}
}
\ No newline at end of file
diff --git a/src/NodaTime.Serialization.Test/SystemTextJson/NodaConverterBaseTest.cs b/src/NodaTime.Serialization.Test/SystemTextJson/NodaConverterBaseTest.cs
index a299b4f..9eb1d22 100644
--- a/src/NodaTime.Serialization.Test/SystemTextJson/NodaConverterBaseTest.cs
+++ b/src/NodaTime.Serialization.Test/SystemTextJson/NodaConverterBaseTest.cs
@@ -75,10 +75,11 @@ protected override int ReadJsonImpl(ref Utf8JsonReader reader, JsonSerializerOpt
return int.Parse(reader.GetString());
}
- protected override void WriteJsonImpl(Utf8JsonWriter writer, int value, JsonSerializerOptions options)
- {
+ protected override void WriteJsonImpl(Utf8JsonWriter writer, int value, JsonSerializerOptions options) =>
writer.WriteStringValue(value.ToString());
- }
+
+ protected override void WriteJsonPropertyNameImpl(Utf8JsonWriter writer, int value, JsonSerializerOptions options) =>
+ writer.WritePropertyName(value.ToString());
}
private class TestStringConverter : NodaConverterBase
@@ -88,10 +89,11 @@ protected override string ReadJsonImpl(ref Utf8JsonReader reader, JsonSerializer
return reader.GetString();
}
- protected override void WriteJsonImpl(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
- {
+ protected override void WriteJsonImpl(Utf8JsonWriter writer, string value, JsonSerializerOptions options) =>
writer.WriteStringValue(value);
- }
+
+ protected override void WriteJsonPropertyNameImpl(Utf8JsonWriter writer, string value, JsonSerializerOptions options) =>
+ writer.WritePropertyName(value);
}
}
}
diff --git a/src/NodaTime.Serialization.Test/SystemTextJson/NodaConvertersTest.cs b/src/NodaTime.Serialization.Test/SystemTextJson/NodaConvertersTest.cs
index a6b8df2..370b43a 100644
--- a/src/NodaTime.Serialization.Test/SystemTextJson/NodaConvertersTest.cs
+++ b/src/NodaTime.Serialization.Test/SystemTextJson/NodaConvertersTest.cs
@@ -3,6 +3,7 @@
// as found in the LICENSE.txt file.
using System;
+using System.Collections.Generic;
using System.Text.Json;
using NodaTime.Serialization.SystemTextJson;
using NUnit.Framework;
@@ -53,6 +54,39 @@ public void LocalDateConverter()
AssertConversions(value, json, NodaConverters.LocalDateConverter);
}
+ [Test]
+ public void LocalDateDictionaryKeySerialize()
+ {
+ const string expected = "{\"2012-12-21\":\"Mayan Calendar\",\"2012-12-22\":\"We Survived\"}";
+ var actual = JsonSerializer.Serialize(new Dictionary
+ {
+ [new LocalDate(2012, 12, 21, CalendarSystem.Iso)] = "Mayan Calendar",
+ [new LocalDate(2012, 12, 22, CalendarSystem.Iso)] = "We Survived"
+ }, new JsonSerializerOptions
+ {
+ WriteIndented = false,
+ Converters = { NodaConverters.LocalDateConverter }
+ });
+ Assert.AreEqual(expected, actual);
+ }
+
+ [Test]
+ public void LocalDateDictionaryKeyDeserialize()
+ {
+ var expected = new Dictionary
+ {
+ [new LocalDate(2012, 12, 21, CalendarSystem.Iso)] = "Mayan Calendar",
+ [new LocalDate(2012, 12, 22, CalendarSystem.Iso)] = "We Survived"
+ };
+ var actual = JsonSerializer.Deserialize>(
+ "{\"2012-12-21\":\"Mayan Calendar\",\"2012-12-22\":\"We Survived\"}",
+ new JsonSerializerOptions
+ {
+ Converters = { NodaConverters.LocalDateConverter }
+ });
+ Assert.AreEqual(expected, actual);
+ }
+
[Test]
public void LocalDateConverter_SerializeNonIso_Throws()
{
diff --git a/src/NodaTime.Serialization.Test/SystemTextJson/NodaDateIntervalConverterTest.cs b/src/NodaTime.Serialization.Test/SystemTextJson/NodaDateIntervalConverterTest.cs
index a5974ba..a991993 100644
--- a/src/NodaTime.Serialization.Test/SystemTextJson/NodaDateIntervalConverterTest.cs
+++ b/src/NodaTime.Serialization.Test/SystemTextJson/NodaDateIntervalConverterTest.cs
@@ -4,6 +4,7 @@
using NodaTime.Serialization.SystemTextJson;
using NUnit.Framework;
+using System.Collections.Generic;
using System.Text.Json;
using static NodaTime.Serialization.Test.SystemText.TestHelper;
@@ -135,7 +136,7 @@ public void Deserialize_CaseInsensitive()
string json = "{\"Interval\":{\"Start\":\"2012-01-02\",\"End\":\"2013-06-07\"}}";
var testObjectPascalCase = JsonSerializer.Deserialize(json, optionsCaseInsensitive);;
- var testObjectCamelCase = JsonSerializer.Deserialize(json, optionsCamelCaseCaseInsensitive); ;
+ var testObjectCamelCase = JsonSerializer.Deserialize(json, optionsCamelCaseCaseInsensitive);
var intervalPascalCase = testObjectPascalCase.Interval;
var intervalCamelCase = testObjectCamelCase.Interval;
@@ -165,6 +166,16 @@ public void Deserialize_CaseInsensitive_CamelCase()
Assert.AreEqual(expectedInterval, intervalCamelCase);
}
+ [Test]
+ public void CannotUseDateIntervalAsPropertyName()
+ {
+ var obj = new Dictionary
+ {
+ { new DateInterval(new LocalDate(2012, 1, 2), new LocalDate(2013, 6, 7)), "Test" }
+ };
+ Assert.Throws(() => JsonSerializer.Serialize(obj, options));
+ }
+
public class TestObject
{
public DateInterval Interval { get; set; }
diff --git a/src/NodaTime.Serialization.Test/SystemTextJson/NodaIntervalConverterTest.cs b/src/NodaTime.Serialization.Test/SystemTextJson/NodaIntervalConverterTest.cs
index 4577a28..57cfa2b 100644
--- a/src/NodaTime.Serialization.Test/SystemTextJson/NodaIntervalConverterTest.cs
+++ b/src/NodaTime.Serialization.Test/SystemTextJson/NodaIntervalConverterTest.cs
@@ -2,6 +2,7 @@
// Use of this source code is governed by the Apache License 2.0,
// as found in the LICENSE.txt file.
+using System.Collections.Generic;
using System.Text.Json;
using NodaTime.Serialization.SystemTextJson;
using NUnit.Framework;
@@ -118,7 +119,7 @@ public void Deserialize_CaseSensitive()
{
string json = "{\"Interval\":{\"Start\":\"2012-01-02T03:04:05Z\",\"end\":\"2013-06-07T08:09:10Z\"}}";
- var testObject = JsonSerializer.Deserialize(json, options); ;
+ var testObject = JsonSerializer.Deserialize(json, options);
Assert.True(testObject.Interval.HasStart);
Assert.False(testObject.Interval.HasEnd);
@@ -129,7 +130,7 @@ public void Deserialize_CaseSensitive_CamelCase()
{
string json = "{\"interval\":{\"Start\":\"2012-01-02T03:04:05Z\",\"end\":\"2013-06-07T08:09:10Z\"}}";
- var testObject = JsonSerializer.Deserialize(json, optionsCamelCase); ;
+ var testObject = JsonSerializer.Deserialize(json, optionsCamelCase);
Assert.False(testObject.Interval.HasStart);
Assert.True(testObject.Interval.HasEnd);
@@ -140,8 +141,8 @@ public void Deserialize_CaseInsensitive()
{
string json = "{\"Interval\":{\"Start\":\"2012-01-02T03:04:05Z\",\"End\":\"2013-06-07T08:09:10Z\"}}";
- var testObjectPascalCase = JsonSerializer.Deserialize(json, optionsCaseInsensitive); ;
- var testObjectCamelCase = JsonSerializer.Deserialize(json, optionsCamelCaseCaseInsensitive); ;
+ var testObjectPascalCase = JsonSerializer.Deserialize(json, optionsCaseInsensitive);
+ var testObjectCamelCase = JsonSerializer.Deserialize(json, optionsCamelCaseCaseInsensitive);
var intervalPascalCase = testObjectPascalCase.Interval;
var intervalCamelCase = testObjectCamelCase.Interval;
@@ -171,6 +172,16 @@ public void Deserialize_CaseInsensitive_CamelCase()
Assert.AreEqual(expectedInterval, intervalCamelCase);
}
+ [Test]
+ public void CannotUseIntervalAsPropertyName()
+ {
+ var obj = new Dictionary
+ {
+ { new Interval(NodaConstants.UnixEpoch, NodaConstants.UnixEpoch), "Test" }
+ };
+ Assert.Throws(() => JsonSerializer.Serialize(obj, options));
+ }
+
public class TestObject
{
public Interval Interval { get; set; }