public override void Write(Utf8JsonWriter writer, object? value, JsonSerializerOptions options)
{
- throw new InvalidOperationException();
+ Debug.Assert(value?.GetType() == typeof(object));
+
+ writer.WriteStartObject();
+ writer.WriteEndObject();
}
internal override object ReadWithQuotes(ref Utf8JsonReader reader)
/// </summary>
protected internal JsonConverter()
{
- // Today only typeof(object) can have polymorphic writes.
- // In the future, this will be check for !IsSealed (and excluding value types).
- CanBePolymorphic = TypeToConvert == JsonTypeInfo.ObjectType;
+ IsInternalConverter = GetType().Assembly == typeof(JsonConverter).Assembly;
+ // Today only the internal JsonConverter<object> can have polymorphic writes.
+ CanBePolymorphic = IsInternalConverter && TypeToConvert == JsonTypeInfo.ObjectType;
IsValueType = TypeToConvert.IsValueType;
CanBeNull = default(T) is null;
- IsInternalConverter = GetType().Assembly == typeof(JsonConverter).Assembly;
if (HandleNull)
{
bool ignoreCyclesPopReference = false;
if (
-#if NET6_0_OR_GREATER
+#if NET5_0_OR_GREATER
!typeof(T).IsValueType && // treated as a constant by recent versions of the JIT.
#else
!IsValueType &&
if (CanBePolymorphic)
{
+ Debug.Assert(IsInternalConverter);
+
Type type = value.GetType();
- if (type == JsonTypeInfo.ObjectType)
- {
- writer.WriteStartObject();
- writer.WriteEndObject();
- return true;
- }
- if (type != TypeToConvert && IsInternalConverter)
+ if (type != TypeToConvert)
{
// For internal converter only: Handle polymorphic case and get the new converter.
// Custom converter, even though polymorphic converter, get called for reading AND writing.
}
VerifyWrite(originalPropertyDepth, writer);
+
+ if (
+#if NET5_0_OR_GREATER
+ !typeof(T).IsValueType && // treated as a constant by recent versions of the JIT.
+#endif
+ ignoreCyclesPopReference)
+ {
+ // should only be entered if we're serializing instances
+ // of type object using the internal object converter.
+ Debug.Assert(value?.GetType() == typeof(object) && IsInternalConverter);
+ state.ReferenceResolver.PopReferenceForCycleDetection();
+ }
+
return true;
}
T value = Get!(obj);
if (
-#if NET6_0_OR_GREATER
+#if NET5_0_OR_GREATER
!typeof(T).IsValueType && // treated as a constant by recent versions of the JIT.
#else
!Converter.IsValueType &&
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
{
- throw new InvalidOperationException("Should not get here.");
+ Assert.IsType<object>(value);
+ writer.WriteStartObject();
+ writer.WriteEndObject();
}
}
options.Converters.Add(new SystemObjectNewtonsoftCompatibleConverter());
Verify(options);
}
+
+ [Fact]
+ public static void CanCustomizeSystemObjectSerialization()
+ {
+ var options = new JsonSerializerOptions { Converters = { new CustomSystemObjectConverter() } };
+
+ string expectedJson = "42";
+ string actualJson = JsonSerializer.Serialize(new object(), options);
+ Assert.Equal(expectedJson, actualJson);
+ }
+
+ private class CustomSystemObjectConverter : JsonConverter<object>
+ {
+ public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotImplementedException();
+ public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
+ => writer.WriteNumberValue(42);
+ }
}
+
}
[Fact]
public static void Options_GetConverterForObjectJsonElement_GivesCorrectConverter()
{
- GenericObjectOrJsonElementConverterTestHelper<object>("ObjectConverter", new object(), "[3]", true);
+ GenericObjectOrJsonElementConverterTestHelper<object>("ObjectConverter", new object(), "{}");
JsonElement element = JsonDocument.Parse("[3]").RootElement;
- GenericObjectOrJsonElementConverterTestHelper<JsonElement>("JsonElementConverter", element, "[3]", false);
+ GenericObjectOrJsonElementConverterTestHelper<JsonElement>("JsonElementConverter", element, "[3]");
}
- private static void GenericObjectOrJsonElementConverterTestHelper<T>(string converterName, object objectValue, string stringValue, bool throws)
+ private static void GenericObjectOrJsonElementConverterTestHelper<T>(string converterName, object objectValue, string stringValue)
{
var options = new JsonSerializerOptions();
if (readValue is JsonElement element)
{
- Assert.Equal(JsonValueKind.Array, element.ValueKind);
- JsonElement.ArrayEnumerator iterator = element.EnumerateArray();
- Assert.True(iterator.MoveNext());
- Assert.Equal(3, iterator.Current.GetInt32());
+ JsonTestHelper.AssertJsonEqual(stringValue, element.ToString());
}
else
{
using (var stream = new MemoryStream())
using (var writer = new Utf8JsonWriter(stream))
{
- if (throws)
- {
- Assert.Throws<InvalidOperationException>(() => converter.Write(writer, (T)objectValue, options));
- Assert.Throws<InvalidOperationException>(() => converter.Write(writer, (T)objectValue, null));
- }
- else
- {
- converter.Write(writer, (T)objectValue, options);
- writer.Flush();
- Assert.Equal(stringValue, Encoding.UTF8.GetString(stream.ToArray()));
-
- writer.Reset(stream);
- converter.Write(writer, (T)objectValue, null); // Test with null option
- writer.Flush();
- Assert.Equal(stringValue + stringValue, Encoding.UTF8.GetString(stream.ToArray()));
- }
+ converter.Write(writer, (T)objectValue, options);
+ writer.Flush();
+ Assert.Equal(stringValue, Encoding.UTF8.GetString(stream.ToArray()));
+
+ writer.Reset(stream);
+ converter.Write(writer, (T)objectValue, null); // Test with null option
+ writer.Flush();
+ Assert.Equal(stringValue + stringValue, Encoding.UTF8.GetString(stream.ToArray()));
}
}