Skip to content

Fix System.Text.Json source generator constructor accessor for generic types with inaccessible constructors - #133406

Draft
svick wants to merge 1 commit into
dotnet:mainfrom
svick:fix-133369-generic-ctor-accessor
Draft

Fix System.Text.Json source generator constructor accessor for generic types with inaccessible constructors#133406
svick wants to merge 1 commit into
dotnet:mainfrom
svick:fix-133369-generic-ctor-accessor

Conversation

@svick

@svick svick commented Sep 8, 2026

Copy link
Copy Markdown
Member

Summary

Fixes #133369.

The System.Text.Json source generator emitted an invalid [UnsafeAccessor(UnsafeAccessorKind.Constructor)] extern for a generic type with an inaccessible constructor (e.g. a private [JsonConstructor]). The extern named the closed generic type directly:

[UnsafeAccessor(UnsafeAccessorKind.Constructor)]
private static extern MyType<int> __ctor_MyTypeInt32(int value);

That compiles, but UnsafeAccessor does not resolve a constructor against a directly-named closed generic type, so deserialization threw System.MissingMethodException: Method not found: 'MyType`1..ctor' at run time. The member (get/set/field) accessors already handle generics correctly via a wrapper class; only the constructor accessor was missing that treatment.

Fix

Emit the constructor extern inside a generic wrapper class whose type parameters flow into the signature, and reference it through the closed type arguments at the call site:

private static class __GenericCtorAccessor_MyTypeInt32<T>
{
    [UnsafeAccessor(UnsafeAccessorKind.Constructor)]
    public static extern MyType<T> __ctor_MyTypeInt32(T p0);
}
// call site: __GenericCtorAccessor_MyTypeInt32<int>.__ctor_MyTypeInt32((int)args[0])

This mirrors the existing __GenericAccessors_<T> member-accessor wrapper (distinct name, so a type with both inaccessible members and an inaccessible constructor emits both wrappers without clashing). Non-generic types and the downlevel reflection fallback (net462) are unchanged.

Spec additions carrying the open-generic strings (incremental-pipeline safe): TypeGenerationSpec.{TypeParameterNames, OpenTypeFQN, TypeParameterConstraintClauses} and ParameterGenerationSpec.OpenParameterTypeFQN, populated only when the type is generic and generic UnsafeAccessors are supported (.NET 9+).

Tests

  • New output-baseline case UnsafeAccessors_GenericTypeInaccessibleConstructor (netcoreapp UnsafeAccessor wrapper + net462 reflection fallback).
  • New functional test JsonSerializerContextTests.GenericTypeWithInaccessibleConstructor_IsSupported that round-trips a generic type with a private [JsonConstructor]; it throws MissingMethodException before the fix and passes after.

Note

This PR description was generated by GitHub Copilot.

The System.Text.Json source generator emitted an invalid
[UnsafeAccessor(Constructor)] extern for a generic type with an
inaccessible constructor: the extern named the closed generic type
directly, which does not resolve the constructor and threw
MissingMethodException at run time.

Emit the constructor extern inside a generic wrapper class (as the
member get/set/field accessors already do), using the open type
parameters, and reference it through the closed type arguments at the
call site. Non-generic types and the downlevel reflection fallback are
unchanged.

Fixes dotnet#133369.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 4 pipeline(s).
12 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-text-json
See info in area-owners.md if you want to be subscribed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

System.Text.Json source generator emits invalid constructor accessor for generic types with inaccessible constructors (MissingMethodException)

1 participant