* Improve serialization error message when IsReflectionEnabledByDefault is turned off.
* Update trimming tests
<data name="JsonSerializerOptionsNoTypeInfoResolverSpecified" xml:space="preserve">
<value>JsonSerializerOptions instance must specify a TypeInfoResolver setting before being marked as read-only.</value>
</data>
+ <data name="JsonSerializerIsReflectionDisabled" xml:space="preserve">
+ <value>Reflection-based serialization has been disabled for this application. Either use the source generator APIs or explicitly configure the 'JsonSerializerOptions.TypeInfoResolver' property.</value>
+ </data>
<data name="JsonPolymorphismOptionsAssociatedWithDifferentJsonTypeInfo" xml:space="preserve">
<value>Parameter already associated with a different JsonTypeInfo instance.</value>
</data>
break;
}
}
+ else if (_typeInfoResolver is null or EmptyJsonTypeInfoResolver)
+ {
+ ThrowHelper.ThrowInvalidOperationException_JsonSerializerIsReflectionDisabled();
+ }
MakeReadOnly();
_isConfiguredForJsonSerializer = true;
/// <summary>
/// Gets a resolver that returns null <see cref="JsonTypeInfo"/> for every type.
/// </summary>
- internal static IJsonTypeInfoResolver Empty { get; } = new JsonTypeInfoResolverChain();
+ internal static IJsonTypeInfoResolver Empty { get; } = new EmptyJsonTypeInfoResolver();
/// <summary>
/// Indicates whether the metadata generated by the current resolver
}
/// <summary>
+ /// A <see cref="IJsonTypeInfoResolver"/> that returns null for all inputs.
+ /// </summary>
+ internal sealed class EmptyJsonTypeInfoResolver : IJsonTypeInfoResolver, IBuiltInJsonTypeInfoResolver
+ {
+ public JsonTypeInfo? GetTypeInfo(Type type, JsonSerializerOptions options) => null;
+ public bool IsCompatibleWithOptions(JsonSerializerOptions _) => true;
+ }
+
+ /// <summary>
/// Implemented by the built-in converters to avoid rooting
/// unused resolver dependencies in the context of the trimmer.
/// </summary>
{
switch (resolver)
{
- case null:
+ case null or EmptyJsonTypeInfoResolver:
break;
case JsonTypeInfoResolverChain otherChain:
}
[DoesNotReturn]
+ public static void ThrowInvalidOperationException_JsonSerializerIsReflectionDisabled()
+ {
+ throw new InvalidOperationException(SR.JsonSerializerIsReflectionDisabled);
+ }
+
+ [DoesNotReturn]
public static void ThrowInvalidOperationException_SerializationConverterOnAttributeInvalid(Type classType, MemberInfo? memberInfo)
{
string location = classType.ToString();
public void WriteRootLevelAsyncEnumerableSync_ThrowsNotSupportedException()
{
IAsyncEnumerable<int> asyncEnumerable = new MockedAsyncEnumerable<int>(Enumerable.Range(1, 10));
- Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(asyncEnumerable));
- Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(new MemoryStream(), asyncEnumerable));
+ Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(asyncEnumerable, Serializer.DefaultOptions));
+ Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(new MemoryStream(), asyncEnumerable, Serializer.DefaultOptions));
}
[Fact]
public void WriteNestedAsyncEnumerableSync_ThrowsNotSupportedException()
{
IAsyncEnumerable<int> asyncEnumerable = new MockedAsyncEnumerable<int>(Enumerable.Range(1, 10));
- Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(new { Data = asyncEnumerable }));
- Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(new MemoryStream(), new { Data = asyncEnumerable }));
+ Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(new AsyncEnumerableDto<int> { Data = asyncEnumerable }, Serializer.DefaultOptions));
+ Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize(new MemoryStream(), new AsyncEnumerableDto<int> { Data = asyncEnumerable }, Serializer.DefaultOptions));
}
[Fact]
Assert.NotNull(options.TypeInfoResolver);
Assert.True(options.TypeInfoResolver is not DefaultJsonTypeInfoResolver);
- IList<IJsonTypeInfoResolver> resolverList = Assert.IsAssignableFrom<IList<IJsonTypeInfoResolver>>(options.TypeInfoResolver);
-
- Assert.Empty(resolverList);
Assert.Empty(options.TypeInfoResolverChain);
Assert.Throws<NotSupportedException>(() => options.GetTypeInfo(typeof(string)));
Assert.False(options.TryGetTypeInfo(typeof(string), out JsonTypeInfo? typeInfo));
Assert.Null(typeInfo);
- Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize("string"));
- Assert.Throws<NotSupportedException>(() => JsonSerializer.Serialize("string", options));
+ InvalidOperationException ex;
+
+ ex = Assert.Throws<InvalidOperationException>(() => JsonSerializer.Serialize("string"));
+ Assert.Contains("JsonSerializerOptions.TypeInfoResolver", ex.Message);
+
+ ex = Assert.Throws<InvalidOperationException>(() => JsonSerializer.Serialize("string", options));
+ Assert.Contains("JsonSerializerOptions.TypeInfoResolver", ex.Message);
+
+ ex = Assert.Throws<InvalidOperationException>(() => JsonSerializer.Deserialize<string>("\"string\""));
+ Assert.Contains("JsonSerializerOptions.TypeInfoResolver", ex.Message);
- Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<string>("\"string\""));
- Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<string>("\"string\"", options));
+ ex = Assert.Throws<InvalidOperationException>(() => JsonSerializer.Deserialize<string>("\"string\"", options));
+ Assert.Contains("JsonSerializerOptions.TypeInfoResolver", ex.Message);
}, options).Dispose();
}
Assert.Throws<NotSupportedException>(() => options.GetTypeInfo(typeof(string)));
Assert.Throws<NotSupportedException>(() => options.GetConverter(typeof(string)));
- Assert.Throws<InvalidOperationException>(() => JsonSerializer.Serialize("string", options));
- Assert.Throws<InvalidOperationException>(() => JsonSerializer.Deserialize<string>("\"string\"", options));
+ InvalidOperationException ex;
+
+ ex = Assert.Throws<InvalidOperationException>(() => JsonSerializer.Serialize("string", options));
+ Assert.Contains("JsonSerializerOptions.TypeInfoResolver", ex.Message);
+
+ ex = Assert.Throws<InvalidOperationException>(() => JsonSerializer.Deserialize<string>("\"string\"", options));
+ Assert.Contains("JsonSerializerOptions.TypeInfoResolver", ex.Message);
+
Assert.False(options.TryGetTypeInfo(typeof(string), out JsonTypeInfo? typeInfo));
Assert.Null(typeInfo);
MyPoco valueToSerialize = new MyPoco { Value = 42 };
// The default resolver should not surface DefaultJsonTypeInfoResolver.
- if (JsonSerializerOptions.Default.TypeInfoResolver is not IList<IJsonTypeInfoResolver> { Count: 0 })
+ if (JsonSerializerOptions.Default.TypeInfoResolver is DefaultJsonTypeInfoResolver)
{
return -1;
}
- // Serializing with options unset should throw NotSupportedException.
+ // Serializing with options unset should throw InvalidOperationException.
try
{
JsonSerializer.Serialize(valueToSerialize);
return -2;
}
- catch (NotSupportedException)
+ catch (InvalidOperationException)
{
}