Repository navigation
docs(stjm): document trimming/NativeAOT limits, annotate reflection entry points, then add trim-safe explicit registration #210
Copy link
Copy link
Closed as not planned
Closed as not planned
Copy link
Labels
documentationImprovements or additions to documentationImprovements or additions to documentationstjmEgil.SystemTextJson.Migration scopeEgil.SystemTextJson.Migration scope
Description
docs/recipes/aot-source-gen.md states that PublishAot / PublishTrimmed are not supported and that "trim-safe explicit registration is tracked as a follow-up". This issue is that follow-up. Start with the documentation and the annotations; the API comes second and the source generator (#ISSUE5) later.
Why it breaks today
Discovery is reflection over members the trimmer removes or cannot see:
StaticMigratorContracts.GetSourceTypes/JsonMigratableConverterFactory.ResolveStaticTryMigrateMethod:GetInterfaces(),GetMethods(...),MethodInfo.CreateDelegate.MigratorInvokerFactory:MakeGenericMethodfor the invoker factories.JsonMigratableConverterFactory.CreateConverterCore:typeof(JsonMigratableConverter<>).MakeGenericType(...)+Activator.CreateInstance(IL3050 for struct targets under NativeAOT).ExternalMigratorInvoker.CreateFallbackMigrator:Activator.CreateInstance(migratorType).JsonMigrationBuilder.RegisterMigratorsFromAssembly:Assembly.GetTypes().UnionCaseRouting.RefusedInsideOwnMigration.For:MakeGenericTypeon a marker; replace with a non-generic marker record.JsonMigratableTypes.IsUnionWithMigratableCase:GetConstructors(); fine for source-generated unions (the ctors are referenced) but should be verified.
Attribute reads (GetCustomAttribute, GetCustomAttributesData) and options.GetTypeInfo are trim-safe.
Documentation first
- Expand the NativeAOT section of
docs/recipes/aot-source-gen.mdwith the list above: what is removed, what the failure looks like ("No migrator was found for discriminator '…'"), and that the workaround today is publishing untrimmed. Link this issue. - Annotate the reflection entry points with
[RequiresUnreferencedCode]/[RequiresDynamicCode]so a consumer withPublishTrimmedgets IL2026/IL3050 warnings at theirAddJsonMigrationSupport()call instead of a silent runtime failure. This is the cheapest correctness win and needs no API design. - Decide whether the package sets
IsTrimmable/IsAotCompatiblenow (with the warnings) or only once the explicit API exists.
Explicit registration API (second step)
Generic methods let the compiler root everything the trimmer would otherwise drop, and give the generator in #ISSUE5 something to emit into:
builder.AddMigratable<UserV2>() // converter instantiated as new JsonMigratableConverter<UserV2>(...)
.AddStaticMigration<UserV1, UserV2>() // where UserV2 : IMigrateFrom<UserV1, UserV2>; calls the static abstract directly
.AddExternalMigration<UserV1, UserV2, UserMigrator>() // where UserMigrator : IMigrate<UserV1, UserV2>, new()- When any explicit registration exists for a target, skip reflection discovery for that target (or require explicit registration for every target when a
TrimSafemode is on; pick one and document it). - Keep
RegisterMigrator*/RegisterMigratorsFromAssemblywith the[RequiresUnreferencedCode]annotation. - Add a
PublishAotsample project undersamples/that CI publishes on at least one platform, so the guarantee is tested rather than asserted.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
documentationImprovements or additions to documentationImprovements or additions to documentationstjmEgil.SystemTextJson.Migration scopeEgil.SystemTextJson.Migration scope
Activity
egil commentedon Sep 24, 2026
Superseded by #256, which makes actionable build diagnostics the first deliverable and preserves AOT-safe explicit registration as follow-up work. Users should receive the limitation and corrective action at their public API call without needing to read documentation.