Repository navigation
[Java.Interop] Retire obsolete expression-marshaling contracts - #13058
Conversation
Retire the remaining expression-marshaling and activation contracts after JavaInterop1 removal. The supported Android runtime uses generated callbacks and trimmable typemap activation; it does not consume this pipeline or JniValueManager.ActivatePeer. Make the intentional .NET 12 API break without compatibility stubs. Remove expression-only Color/IJavaObject marshalers and their attributes, while retaining ordinary value conversion, array helpers, JNI argument states, and supported peer/reference ownership. Update T4 inputs and generated sources together, record shipped API removals and accepted Mono.Android breakages, and replace the obsolete architecture proposal with current behavior and migration guidance. Keep array trimming annotations consistent across primitive types. Validate the own Release SDK/API gates, 19 host integration tests, 478 generator tests, 50 JCW tests, and complete default device suites: CoreCLR 924 passed/7 skipped; NativeAOT 869 passed/7 skipped, no failures. Do not add new tests, per user request. Co-authored-by: Copilot App <[email protected]>
There was a problem hiding this comment.
🟡 Changes recommended
The generated primitive-array APIs introduce unnecessary public trimming requirements after their expression consumers are removed.
1 open finding
What changed in this PR
Retires obsolete Java.Interop expression-marshaling and peer-activation APIs for .NET 12.
Changes:
- Removes expression-marshaling builders, hooks, overrides, and activation contracts.
- Updates generated primitive-array code and API compatibility baselines.
- Replaces obsolete architecture guidance and adds migration notes.
| File | Description |
|---|---|
tests/api-compatibility/acceptable-breakages-vReference-net11.0.txt |
Records Mono.Android compatibility breaks. |
src/Mono.Android/PublicAPI/API-37/PublicAPI.Unshipped.txt |
Records Color marshaler removal. |
src/Mono.Android/PublicAPI/API-37.2/PublicAPI.Unshipped.txt |
Records API 37.2 removals. |
src/Mono.Android/PublicAPI/API-37.1/PublicAPI.Unshipped.txt |
Records API 37.1 removals. |
src/Mono.Android/PublicAPI/API-36/PublicAPI.Unshipped.txt |
Records API 36 removals. |
src/Mono.Android/PublicAPI/API-36.1/PublicAPI.Unshipped.txt |
Records API 36.1 removals. |
src/Mono.Android/PublicAPI/API-35/PublicAPI.Unshipped.txt |
Records API 35 removals. |
src/Mono.Android/Mono.Android.csproj |
Removes the deleted marshaler source. |
src/Mono.Android/Microsoft.Android.Runtime/TrimmableTypeMapValueManager.cs |
Removes the obsolete activation override. |
src/Mono.Android/Android.Runtime/IJavaObjectValueMarshaler.cs |
Deletes the expression-only marshaler. |
src/Mono.Android/Android.Runtime/IJavaObject.cs |
Removes its marshaler attribute. |
src/Mono.Android/Android.Graphics/Color.cs |
Removes ColorValueMarshaler. |
external/Java.Interop/src/Java.Interop/PublicAPI.Unshipped.txt |
Records Java.Interop API removals. |
external/Java.Interop/src/Java.Interop/Java.Interop/JniValueMarshaler.cs |
Removes expression-generation contracts. |
external/Java.Interop/src/Java.Interop/Java.Interop/JniStringValueMarshaler.cs |
Removes string expression overrides. |
external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniValueManager.cs |
Removes ActivatePeer. |
external/Java.Interop/src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.cs |
Deletes the obsolete builder API. |
external/Java.Interop/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.tt |
Updates built-in marshaler template. |
external/Java.Interop/src/Java.Interop/Java.Interop/JniBuiltinMarshalers.cs |
Regenerates built-in marshalers. |
external/Java.Interop/src/Java.Interop/Java.Interop/JavaPrimitiveArrays.tt |
Updates primitive-array template. |
external/Java.Interop/src/Java.Interop/Java.Interop/JavaPrimitiveArrays.cs |
Regenerates primitive arrays. |
external/Java.Interop/src/Java.Interop/Java.Interop/JavaArray.cs |
Adds shared trimming metadata. |
external/Java.Interop/src/Java.Interop/GlobalSuppressions.cs |
Removes a stale suppression. |
external/Java.Interop/samples/Hello-NativeAOTFromJNI/JavaInteropRuntime.cs |
Removes the sample override. |
external/Java.Interop/Documentation/Architecture.md |
Documents the current architecture. |
Documentation/release-notes/expression-marshalling-retirement.md |
Adds migration guidance. |
🧠 Review effort: Balanced
CreateMarshaledValue constructs its known primitive-array wrapper and converts targetType through equality and assignability checks. It does not inspect or activate targetType constructors, so preserving every constructor and interface is no longer required. Remove the stale parameter annotations uniformly from all eight arrays, update the T4 input, and delete the unused shared constant. Keep the public conversion APIs and their ownership behavior unchanged. Validate the Release Java.Interop build with API and trimming analyzers. Compare emitted IL: all method bodies remain unchanged after accounting for relocated RVAs and compiler-generated iterator numbering. Co-authored-by: Copilot App <[email protected]>
|
@dalexsoto review |
dalexsoto
left a comment
There was a problem hiding this comment.
The complete correctness and integration review found no blocking regression in the intentional .NET 12 API retirement. Supported non-expression conversion, reference ownership, generated callbacks and typemap activation remain intact; the removal baselines and migration notes match the accepted break. The stale array trimming annotations are fixed, and both T4 inputs match their generated files exactly.

Summary
Follow up on #13030 by retiring the remaining obsolete expression-marshaling and activation contracts. This is an intentional .NET 12 source/binary API break, without compatibility stubs. Supported Android interop uses generated callbacks and trimmable typemap activation; source searches found no consumer of the removed expression pipeline or
ActivatePeer.Remove:
JniRuntime.JniMarshalMemberBuilder, its members, the runtimeMarshalMemberBuilderproperty, andCreationOptions.MarshalMemberBuilder/UseMarshalMemberBuilder.Java.Interop.Expressions.JniValueMarshalerContext, the three expression-generation hooks onJniValueMarshaler, and their expression-only helpers and primitive/string/array overrides.ColorValueMarshalerand internalIJavaObjectValueMarshaler, including their referencing attributes.JniValueManager.ActivatePeercontract and its throwing Android/sample overrides.Retain non-expression
JniValueMarshaler/ argument-state conversion, primitive/string/array functionality,CreateLocalObjectReferenceArgument, peer/reference ownership, generated callbacks, and trimmable activation. KeepGetRuntimeType,JniInstanceMethodsallocation helpers, and unrelated public JNI/type-signature APIs unchanged.Update both T4 inputs and checked-in generated files. Remove stale
DynamicallyAccessedMembersrequirements from all eight primitive-arrayCreateMarshaledValuemethods: their remaining conversion path constructs a known wrapper and uses type equality/assignability, not reflective activation of the requested target type. Record contract removals throughPublicAPI.Unshippedentries and the existing Mono.Android ApiCompat baseline mechanism. Replace the obsolete architecture proposal with current behavior and add migration notes. No new tests are included, per request.Validation
All SDK/runtime validation uses this branch's own Release build and repository-pinned SDK
12.0.100-alpha.1.26480.102, not sibling outputs. Framework paths/parameters below reflect the current checkout's build configuration; this change is intended for .NET 12.make prepare CONFIGURATION=Release./dotnet-local.sh build build-tools/scripts/Prepare.proj -t:BuildExtraApiLevels -c Release -v minimal./dotnet-local.sh build build-tools/create-packs/Microsoft.Android.Sdk.proj -t:ConfigureLocalWorkload -c Release -v minimalmake all CONFIGURATION=Releasedotnet build external/Java.Interop/src/Java.Interop/Java.Interop.csproj -c Release -v minimal -p:DotNetTargetFrameworkVersion=11.0./dotnet-local.sh build src/Mono.Android/Mono.Android.csproj -c Release -v minimal -p:DisableApiCompatibilityCheck=False -m:1dotnet test external/Java.Interop/tests/generator-Tests/generator-Tests.csproj -c Release -v minimaldotnet test external/Java.Interop/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csproj -c Release -v minimalHost integration command:
Passed: 19/19, covering CoreCLR/NativeAOT typemap builds, generated callbacks, collection exports, and implementation metadata.
Device install commands, on exclusively leased
emulator-5554(arm64, API 36):Both installs passed. Each install was followed by its matching command below, from
tests/Mono.Android-Tests/Mono.Android-Tests:CoreCLR: 924 passed, 7 existing skips, zero failures. NativeAOT: 869 passed, 7 existing skips, zero failures. TRX results confirm JNI/primitive and object arrays, constructors, callbacks/exports, exceptions, peer control blocks, and reference ownership, including all 38 constructor activation tests and 58 transferred-reference tests on both runtimes. Only the test package was uninstalled afterward.
Both T4 templates regenerate the checked-in files exactly;
git diff --checkpasses.Review follow-up
The runtime/SDK test results above were collected for commit
1251576d3d98f093ca1879314e12f7c97771091f. Follow-up commitce74deda0408d0b8268adc8437d07f66a5d6627conly removes the stale primitive-array trimming annotations and their unused constant../dotnet-local.sh build external/Java.Interop/src/Java.Interop/Java.Interop.csproj -c Release -v minimal -p:DotNetTargetFrameworkVersion=11.0 -p:EnableTrimAnalyzer=true -m:1passed with zero warnings/errors, including API and trimming analyzers. Regeneration matches exactly. IL comparison confirmed all 1,333 emitted method bodies remain identical after normalizing RVA addresses and compiler-generated iterator numbering; all eight public conversion APIs remain and their stale parameter attributes are absent. Full SDK/device suites were not rerun for this metadata-only follow-up.Standalone NativeAOT sample
./dotnet-local.sh build external/Java.Interop/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj -c Release -r osx-arm64 -v minimal -p:DotNetTargetFrameworkVersion=11.0 -p:RestoreConfigFile="$PWD/NuGet.Config" -m:1passes. Running the compiled NativeAOT library from Java passes and returnsHello from .NET NativeAOT!.Optional
publishremains failed with MSB3030 in the unchanged_NativeLibRequiresLibPrefixtarget: it expectsHello-NativeAOTFromJNI.dylib, but the pinned SDK emitslibHello-NativeAOTFromJNI.dylib. This is not claimed to be baseline-proven; no unrelated sample naming-target fix is included. The sample build and actual JNI execution validate the changed override removal.Pull Request
title and
description
should follow the
commit-messages.mdworkflow documentation, and in particular should include:No issue is closed. Existing unit/integration/runtime coverage was run; no new tests were added.