New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Do not deserialize using internal or private default ctors for all supported TFMs. #32213
Conversation
src/libraries/System.Text.Json/tests/Serialization/Object.ReadTests.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/tests/Serialization/Object.ReadTests.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Text.Json/tests/Serialization/Object.ReadTests.cs
Outdated
Show resolved
Hide resolved
Waiting on review/approval to get this merged. |
The test failures are unrelated and logs don't indicate much:
Other test failure: #32335 |
cc @dotnet/dnceng about the |
@ahsonkhan We think we have that fixed in the Mac queues as of this afternoon. Let us know if you see it again! |
@layomia this is labeled breaking change. Can you please open an issue if needed with https://github.com/dotnet/docs/issues/new?template=dotnet-breaking-change.md I don't see an existing one |
Breaking change doc filed - dotnet/docs#20887. |
We have a discrepancy in
S.T.Json
behavior between the netstandard2.0 /2.1 implementation (including netcoreapp2.1 and below), and the NC3.0+ one, when deserializing JSON into POCOs with no public default parameterless ctors.MissingMethodException: No parameterless constructor defined for this object.
(fromActivator.CreateInstance
).This happens because of the difference between the reflection-based
MemberAccessor
and the refemit-basedMemberAccessor
.ReflectionMemberAccessor
callsActivator.CreateInstance
without any binding flags, so the default is public ctors only:runtime/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionMemberAccessor.cs
Line 28 in 4a57d14
ReflectionEmitMemberAccessor
gets the constructor using different binding flags (and hence ends up calling internal/private parameterless ctors as well):runtime/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs
Line 18 in 4a57d14
The
JsonSerializer
shouldn't be calling non-public surface area of types, especially by default (whether that's ctor, properties, or fields). Hence, this change is making the behavior consistent across the board by removing support for internal/private default ctors on all supported TFMs (regardless of whether the implementation is using reflection or ref emit). This is also consistent with the rest of the deserializer behavior, where only public properties are supported by default with public getter/setters. We will do the same for fields when they are supported.It is unlikely that many folks are relying on this behavior. However, as a workaround, if the user controls their own type and don't want to make the default ctor public for some reason, they could implement a
JsonConverter<T>
for their type and control the deserialization behavior. Additionally, we are currently working to provide an attribute based opt-in support for non-paramterless/default ctors, so it is possible that we extend that feature to also support internal/private default ctors, by having the user place an attribute on the ctor they want theJsonSerializer
to use. See #29895Note: This only affects deserialization/reading and doesn't change the serialization/writing behavior.